pax_global_header 0000666 0000000 0000000 00000000064 13456342174 0014523 g ustar 00root root 0000000 0000000 52 comment=b0d269b1f6f770be087f2139d81f05953d676c02
erp5-b0d269b1f6f770be087f2139d81f05953d676c02-bt5-erp5_tiosafe_core/ 0000775 0000000 0000000 00000000000 13456342174 0023254 5 ustar 00root root 0000000 0000000 erp5-b0d269b1f6f770be087f2139d81f05953d676c02-bt5-erp5_tiosafe_core/bt5/ 0000775 0000000 0000000 00000000000 13456342174 0023746 5 ustar 00root root 0000000 0000000 erp5-b0d269b1f6f770be087f2139d81f05953d676c02-bt5-erp5_tiosafe_core/bt5/erp5_tiosafe_core/ 0000775 0000000 0000000 00000000000 13456342174 0027343 5 ustar 00root root 0000000 0000000 ActionTemplateItem/ 0000775 0000000 0000000 00000000000 13456342174 0033014 5 ustar 00root root 0000000 0000000 erp5-b0d269b1f6f770be087f2139d81f05953d676c02-bt5-erp5_tiosafe_core/bt5/erp5_tiosafe_core portal_types/ 0000775 0000000 0000000 00000000000 13456342174 0035541 5 ustar 00root root 0000000 0000000 erp5-b0d269b1f6f770be087f2139d81f05953d676c02-bt5-erp5_tiosafe_core/bt5/erp5_tiosafe_core/ActionTemplateItem Integration%20Base%20Category%20Mapping/ 0000775 0000000 0000000 00000000000 13456342174 0044456 5 ustar 00root root 0000000 0000000 erp5-b0d269b1f6f770be087f2139d81f05953d676c02-bt5-erp5_tiosafe_core/bt5/erp5_tiosafe_core/ActionTemplateItem/portal_types Integration%20Base%20Category%20Mapping/view.xml 0000664 0000000 0000000 00000004465 13456342174 0046163 0 ustar 00root root 0000000 0000000 erp5-b0d269b1f6f770be087f2139d81f05953d676c02-bt5-erp5_tiosafe_core/bt5/erp5_tiosafe_core/ActionTemplateItem/portal_types
-
action
AAAAAAAAAAI=
-
categories
action_type/object_view
-
category
object_view
-
condition
-
description
-
icon
-
id
view
-
permissions
View
-
priority
1.0
-
title
View
-
visible
1
-
text
string:${object_url}/BaseIntegrationMapping_view
Integration%20Base%20Property%20Mapping/ 0000775 0000000 0000000 00000000000 13456342174 0044525 5 ustar 00root root 0000000 0000000 erp5-b0d269b1f6f770be087f2139d81f05953d676c02-bt5-erp5_tiosafe_core/bt5/erp5_tiosafe_core/ActionTemplateItem/portal_types Integration%20Base%20Property%20Mapping/view.xml 0000664 0000000 0000000 00000004465 13456342174 0046232 0 ustar 00root root 0000000 0000000 erp5-b0d269b1f6f770be087f2139d81f05953d676c02-bt5-erp5_tiosafe_core/bt5/erp5_tiosafe_core/ActionTemplateItem/portal_types
-
action
AAAAAAAAAAI=
-
categories
action_type/object_view
-
category
object_view
-
condition
-
description
-
icon
-
id
view
-
permissions
View
-
priority
1.0
-
title
View
-
visible
1
-
text
string:${object_url}/BaseIntegrationMapping_view
Integration%20Category%20Mapping/ 0000775 0000000 0000000 00000000000 13456342174 0043454 5 ustar 00root root 0000000 0000000 erp5-b0d269b1f6f770be087f2139d81f05953d676c02-bt5-erp5_tiosafe_core/bt5/erp5_tiosafe_core/ActionTemplateItem/portal_types view.xml 0000664 0000000 0000000 00000004461 13456342174 0045155 0 ustar 00root root 0000000 0000000 erp5-b0d269b1f6f770be087f2139d81f05953d676c02-bt5-erp5_tiosafe_core/bt5/erp5_tiosafe_core/ActionTemplateItem/portal_types/Integration%20Category%20Mapping
-
action
AAAAAAAAAAI=
-
categories
action_type/object_view
-
category
object_view
-
condition
-
description
-
icon
-
id
view
-
permissions
View
-
priority
1.0
-
title
View
-
visible
1
-
text
string:${object_url}/IntegrationMapping_view
Integration%20Module/ 0000775 0000000 0000000 00000000000 13456342174 0041401 5 ustar 00root root 0000000 0000000 erp5-b0d269b1f6f770be087f2139d81f05953d676c02-bt5-erp5_tiosafe_core/bt5/erp5_tiosafe_core/ActionTemplateItem/portal_types generate_sync_objects.xml 0000664 0000000 0000000 00000005001 13456342174 0046456 0 ustar 00root root 0000000 0000000 erp5-b0d269b1f6f770be087f2139d81f05953d676c02-bt5-erp5_tiosafe_core/bt5/erp5_tiosafe_core/ActionTemplateItem/portal_types/Integration%20Module
-
action
AAAAAAAAAAI=
-
categories
action_type/object_action
-
category
object_action
-
condition
-
description
-
icon
-
id
generate_sync_objects
-
permissions
View
-
portal_type
Action Information
-
priority
5.0
-
title
Generate Pub/Sub
-
visible
1
-
text
string:${object_url}/IntegrationModule_generateSynchronizationObjects
test_create_view.xml 0000664 0000000 0000000 00000004765 13456342174 0045473 0 ustar 00root root 0000000 0000000 erp5-b0d269b1f6f770be087f2139d81f05953d676c02-bt5-erp5_tiosafe_core/bt5/erp5_tiosafe_core/ActionTemplateItem/portal_types/Integration%20Module
-
action
AAAAAAAAAAI=
-
categories
action_type/object_action
-
category
object_action
-
condition
-
description
-
icon
-
id
test_create_view
-
permissions
View
-
portal_type
Action Information
-
priority
1.0
-
title
Test Create Request
-
visible
1
-
text
string:${object_url}/IntegrationModule_viewTestCreateDialog
view.xml 0000664 0000000 0000000 00000004724 13456342174 0043104 0 ustar 00root root 0000000 0000000 erp5-b0d269b1f6f770be087f2139d81f05953d676c02-bt5-erp5_tiosafe_core/bt5/erp5_tiosafe_core/ActionTemplateItem/portal_types/Integration%20Module
-
action
AAAAAAAAAAI=
-
categories
action_type/object_view
-
category
object_view
-
condition
-
description
-
icon
-
id
view
-
permissions
View
-
portal_type
Action Information
-
priority
1.0
-
title
Integration Module
-
visible
1
-
text
string:${object_url}/IntegrationModule_view
view_signature_diff.xml 0000664 0000000 0000000 00000004760 13456342174 0046155 0 ustar 00root root 0000000 0000000 erp5-b0d269b1f6f770be087f2139d81f05953d676c02-bt5-erp5_tiosafe_core/bt5/erp5_tiosafe_core/ActionTemplateItem/portal_types/Integration%20Module
-
action
AAAAAAAAAAI=
-
categories
action_type/object_action
-
category
object_action
-
condition
-
description
-
icon
-
id
view_signature_diff
-
permissions
View
-
portal_type
Action Information
-
priority
1.1
-
title
Signature Diff
-
visible
1
-
text
string:${object_url}/IntegrationModule_viewSignatureDiff
view_xml_diff.xml 0000664 0000000 0000000 00000004745 13456342174 0044757 0 ustar 00root root 0000000 0000000 erp5-b0d269b1f6f770be087f2139d81f05953d676c02-bt5-erp5_tiosafe_core/bt5/erp5_tiosafe_core/ActionTemplateItem/portal_types/Integration%20Module
-
action
AAAAAAAAAAI=
-
categories
action_type/object_action
-
category
object_action
-
condition
-
description
-
icon
-
id
view_xml_diff
-
permissions
View
-
portal_type
Action Information
-
priority
1.0
-
title
XML Diff
-
visible
1
-
text
string:${object_url}/IntegrationModule_viewTioSafeXMLDiff
Integration%20Property%20Mapping/ 0000775 0000000 0000000 00000000000 13456342174 0043523 5 ustar 00root root 0000000 0000000 erp5-b0d269b1f6f770be087f2139d81f05953d676c02-bt5-erp5_tiosafe_core/bt5/erp5_tiosafe_core/ActionTemplateItem/portal_types view.xml 0000664 0000000 0000000 00000004461 13456342174 0045224 0 ustar 00root root 0000000 0000000 erp5-b0d269b1f6f770be087f2139d81f05953d676c02-bt5-erp5_tiosafe_core/bt5/erp5_tiosafe_core/ActionTemplateItem/portal_types/Integration%20Property%20Mapping
-
action
AAAAAAAAAAI=
-
categories
action_type/object_view
-
category
object_view
-
condition
-
description
-
icon
-
id
view
-
permissions
View
-
priority
1.0
-
title
View
-
visible
1
-
text
string:${object_url}/IntegrationMapping_view
Integration%20Site/ 0000775 0000000 0000000 00000000000 13456342174 0041060 5 ustar 00root root 0000000 0000000 erp5-b0d269b1f6f770be087f2139d81f05953d676c02-bt5-erp5_tiosafe_core/bt5/erp5_tiosafe_core/ActionTemplateItem/portal_types category_mapping.xml 0000664 0000000 0000000 00000004544 13456342174 0045141 0 ustar 00root root 0000000 0000000 erp5-b0d269b1f6f770be087f2139d81f05953d676c02-bt5-erp5_tiosafe_core/bt5/erp5_tiosafe_core/ActionTemplateItem/portal_types/Integration%20Site
-
action
AAAAAAAAAAI=
-
categories
action_type/object_view
-
category
object_view
-
condition
-
description
-
icon
-
id
category_mapping
-
permissions
View
-
priority
5.0
-
title
Category Mapping
-
visible
1
-
text
string:${object_url}/IntegrationSite_viewIntegrationCategoryMappingList
define_mapping_fast_input.xml 0000664 0000000 0000000 00000005026 13456342174 0047006 0 ustar 00root root 0000000 0000000 erp5-b0d269b1f6f770be087f2139d81f05953d676c02-bt5-erp5_tiosafe_core/bt5/erp5_tiosafe_core/ActionTemplateItem/portal_types/Integration%20Site
-
action
AAAAAAAAAAI=
-
categories
action_type/object_fast_input
-
category
object_fast_input
-
condition
-
description
-
icon
-
id
define_mapping_fast_input
-
permissions
View
-
portal_type
Action Information
-
priority
1.0
-
title
Define Category Mapping
-
visible
1
-
text
string:${object_url}/IntegrationSite_viewCategoryMappingFastInputDialog
integration_module.xml 0000664 0000000 0000000 00000004540 13456342174 0045475 0 ustar 00root root 0000000 0000000 erp5-b0d269b1f6f770be087f2139d81f05953d676c02-bt5-erp5_tiosafe_core/bt5/erp5_tiosafe_core/ActionTemplateItem/portal_types/Integration%20Site
-
action
AAAAAAAAAAI=
-
categories
action_type/object_view
-
category
object_view
-
condition
-
description
-
icon
-
id
integration_module
-
permissions
View
-
priority
4.0
-
title
Integration Modules
-
visible
1
-
text
string:${object_url}/IntegrationSite_viewIntegrationModuleList
property_mapping.xml 0000664 0000000 0000000 00000004544 13456342174 0045210 0 ustar 00root root 0000000 0000000 erp5-b0d269b1f6f770be087f2139d81f05953d676c02-bt5-erp5_tiosafe_core/bt5/erp5_tiosafe_core/ActionTemplateItem/portal_types/Integration%20Site
-
action
AAAAAAAAAAI=
-
categories
action_type/object_view
-
category
object_view
-
condition
-
description
-
icon
-
id
property_mapping
-
permissions
View
-
priority
3.0
-
title
Property Mapping
-
visible
1
-
text
string:${object_url}/IntegrationSite_viewIntegrationPropertyMappingList
regenerate_sync.xml 0000664 0000000 0000000 00000005014 13456342174 0044757 0 ustar 00root root 0000000 0000000 erp5-b0d269b1f6f770be087f2139d81f05953d676c02-bt5-erp5_tiosafe_core/bt5/erp5_tiosafe_core/ActionTemplateItem/portal_types/Integration%20Site
-
action
AAAAAAAAAAI=
-
categories
action_type/object_action
-
category
object_action
-
condition
-
description
-
icon
-
id
regenerate_sync
-
permissions
View
-
portal_type
Action Information
-
priority
1.0
-
title
Regenerate Synchronization Object
-
visible
1
-
text
string:${object_url}/IntegrationSite_regenerateSynchronizationObjects
synchronization_configuration.xml 0000664 0000000 0000000 00000004601 13456342174 0047773 0 ustar 00root root 0000000 0000000 erp5-b0d269b1f6f770be087f2139d81f05953d676c02-bt5-erp5_tiosafe_core/bt5/erp5_tiosafe_core/ActionTemplateItem/portal_types/Integration%20Site
-
action
AAAAAAAAAAI=
-
categories
action_type/object_view
-
category
object_view
-
condition
-
description
-
icon
-
id
synchronization_configuration
-
permissions
View
-
priority
100.0
-
title
Synchronization Configuration
-
visible
1
-
text
string:${object_url}/IntegrationSite_viewSynchronizationConfiguratorItem
synchronize.xml 0000664 0000000 0000000 00000005447 13456342174 0044167 0 ustar 00root root 0000000 0000000 erp5-b0d269b1f6f770be087f2139d81f05953d676c02-bt5-erp5_tiosafe_core/bt5/erp5_tiosafe_core/ActionTemplateItem/portal_types/Integration%20Site
-
action
AAAAAAAAAAI=
-
categories
action_type/object_action
-
category
object_action
-
condition
AAAAAAAAAAM=
-
description
-
icon
-
id
synchronize
-
permissions
View
-
priority
20.0
-
title
Synchronize
-
visible
1
-
text
string:${object_url}/IntegrationSite_viewSynchronizeDialog
-
text
python: here.getValidationState() == "validated"
view.xml 0000664 0000000 0000000 00000004436 13456342174 0042563 0 ustar 00root root 0000000 0000000 erp5-b0d269b1f6f770be087f2139d81f05953d676c02-bt5-erp5_tiosafe_core/bt5/erp5_tiosafe_core/ActionTemplateItem/portal_types/Integration%20Site
-
action
AAAAAAAAAAI=
-
categories
action_type/object_view
-
category
object_view
-
condition
-
description
-
icon
-
id
view
-
permissions
View
-
priority
1.0
-
title
View
-
visible
1
-
text
string:${object_url}/IntegrationSite_view
Integration%20Tool/ 0000775 0000000 0000000 00000000000 13456342174 0041071 5 ustar 00root root 0000000 0000000 erp5-b0d269b1f6f770be087f2139d81f05953d676c02-bt5-erp5_tiosafe_core/bt5/erp5_tiosafe_core/ActionTemplateItem/portal_types create.xml 0000664 0000000 0000000 00000004560 13456342174 0043063 0 ustar 00root root 0000000 0000000 erp5-b0d269b1f6f770be087f2139d81f05953d676c02-bt5-erp5_tiosafe_core/bt5/erp5_tiosafe_core/ActionTemplateItem/portal_types/Integration%20Tool
-
action
AAAAAAAAAAI=
-
categories
action_type/object_action
-
category
object_action
-
condition
-
description
-
icon
-
id
create
-
permissions
Add portal content
-
priority
1.0
-
title
Create Integration Site
-
visible
1
-
text
string:${object_url}/IntegrationTool_viewCreateIntegrationSiteDialog
view.xml 0000664 0000000 0000000 00000004501 13456342174 0042565 0 ustar 00root root 0000000 0000000 erp5-b0d269b1f6f770be087f2139d81f05953d676c02-bt5-erp5_tiosafe_core/bt5/erp5_tiosafe_core/ActionTemplateItem/portal_types/Integration%20Tool
-
action
AAAAAAAAAAI=
-
categories
action_type/object_view
-
category
object_view
-
condition
-
description
-
icon
-
id
view
-
permissions
View
-
priority
1.0
-
title
View
-
visible
1
-
text
string:${object_url}/IntegrationTool_viewIntegrationSiteList
Synchronization%20Configurator%20Item/ 0000775 0000000 0000000 00000000000 13456342174 0044562 5 ustar 00root root 0000000 0000000 erp5-b0d269b1f6f770be087f2139d81f05953d676c02-bt5-erp5_tiosafe_core/bt5/erp5_tiosafe_core/ActionTemplateItem/portal_types Synchronization%20Configurator%20Item/view.xml 0000664 0000000 0000000 00000004724 13456342174 0046265 0 ustar 00root root 0000000 0000000 erp5-b0d269b1f6f770be087f2139d81f05953d676c02-bt5-erp5_tiosafe_core/bt5/erp5_tiosafe_core/ActionTemplateItem/portal_types
-
action
AAAAAAAAAAI=
-
categories
action_type/object_view
-
category
object_view
-
condition
-
description
-
icon
-
id
view
-
permissions
View
-
portal_type
Action Information
-
priority
1.0
-
title
View
-
visible
1
-
text
string:${object_url}/SynchronizationConfiguratorItem_view
Web%20Service%20Connector/ 0000775 0000000 0000000 00000000000 13456342174 0042070 5 ustar 00root root 0000000 0000000 erp5-b0d269b1f6f770be087f2139d81f05953d676c02-bt5-erp5_tiosafe_core/bt5/erp5_tiosafe_core/ActionTemplateItem/portal_types reset.xml 0000664 0000000 0000000 00000004673 13456342174 0043746 0 ustar 00root root 0000000 0000000 erp5-b0d269b1f6f770be087f2139d81f05953d676c02-bt5-erp5_tiosafe_core/bt5/erp5_tiosafe_core/ActionTemplateItem/portal_types/Web%20Service%20Connector
-
action
AAAAAAAAAAI=
-
categories
action_type/object_action
-
category
object_action
-
condition
-
description
-
icon
-
id
reset
-
permissions
View
-
portal_type
Action Information
-
priority
1.0
-
title
Reset
-
visible
1
-
text
string:${object_url}/reset
view.xml 0000664 0000000 0000000 00000004710 13456342174 0043566 0 ustar 00root root 0000000 0000000 erp5-b0d269b1f6f770be087f2139d81f05953d676c02-bt5-erp5_tiosafe_core/bt5/erp5_tiosafe_core/ActionTemplateItem/portal_types/Web%20Service%20Connector
-
action
AAAAAAAAAAI=
-
categories
action_type/object_view
-
category
object_view
-
condition
-
description
-
icon
-
id
view
-
permissions
View
-
portal_type
Action Information
-
priority
1.0
-
title
View
-
visible
1
-
text
string:${object_url}/WebServiceConnector_view
Web%20Service%20Request%20Group/ 0000775 0000000 0000000 00000000000 13456342174 0043012 5 ustar 00root root 0000000 0000000 erp5-b0d269b1f6f770be087f2139d81f05953d676c02-bt5-erp5_tiosafe_core/bt5/erp5_tiosafe_core/ActionTemplateItem/portal_types view.xml 0000664 0000000 0000000 00000004713 13456342174 0044513 0 ustar 00root root 0000000 0000000 erp5-b0d269b1f6f770be087f2139d81f05953d676c02-bt5-erp5_tiosafe_core/bt5/erp5_tiosafe_core/ActionTemplateItem/portal_types/Web%20Service%20Request%20Group
-
action
AAAAAAAAAAI=
-
categories
action_type/object_view
-
category
object_view
-
condition
-
description
-
icon
-
id
view
-
permissions
View
-
portal_type
Action Information
-
priority
1.0
-
title
View
-
visible
1
-
text
string:${object_url}/WebServiceRequestGroup_view
Web%20Service%20Request/ 0000775 0000000 0000000 00000000000 13456342174 0041566 5 ustar 00root root 0000000 0000000 erp5-b0d269b1f6f770be087f2139d81f05953d676c02-bt5-erp5_tiosafe_core/bt5/erp5_tiosafe_core/ActionTemplateItem/portal_types test_dialog.xml 0000664 0000000 0000000 00000004743 13456342174 0044616 0 ustar 00root root 0000000 0000000 erp5-b0d269b1f6f770be087f2139d81f05953d676c02-bt5-erp5_tiosafe_core/bt5/erp5_tiosafe_core/ActionTemplateItem/portal_types/Web%20Service%20Request
-
action
AAAAAAAAAAI=
-
categories
action_type/object_action
-
category
object_action
-
condition
-
description
-
icon
-
id
test_dialog
-
permissions
View
-
portal_type
Action Information
-
priority
1.0
-
title
Test Request
-
visible
1
-
text
string:${object_url}/WebServiceRequest_viewTestDialog
test_result.xml 0000664 0000000 0000000 00000004737 13456342174 0044700 0 ustar 00root root 0000000 0000000 erp5-b0d269b1f6f770be087f2139d81f05953d676c02-bt5-erp5_tiosafe_core/bt5/erp5_tiosafe_core/ActionTemplateItem/portal_types/Web%20Service%20Request
-
action
AAAAAAAAAAI=
-
categories
action_type/object_view
-
category
object_view
-
condition
-
description
-
icon
-
id
test_result
-
permissions
View
-
portal_type
Action Information
-
priority
2.0
-
title
Test Results
-
visible
1
-
text
string:${object_url}/WebServiceRequest_viewTestResult
view.xml 0000664 0000000 0000000 00000004706 13456342174 0043271 0 ustar 00root root 0000000 0000000 erp5-b0d269b1f6f770be087f2139d81f05953d676c02-bt5-erp5_tiosafe_core/bt5/erp5_tiosafe_core/ActionTemplateItem/portal_types/Web%20Service%20Request
-
action
AAAAAAAAAAI=
-
categories
action_type/object_view
-
category
object_view
-
condition
-
description
-
icon
-
id
view
-
permissions
View
-
portal_type
Action Information
-
priority
1.0
-
title
View
-
visible
1
-
text
string:${object_url}/WebServiceRequest_view
portal_actions/ 0000775 0000000 0000000 00000000000 13456342174 0040562 5 ustar 00root root 0000000 0000000 erp5-b0d269b1f6f770be087f2139d81f05953d676c02-bt5-erp5_tiosafe_core/bt5/erp5_tiosafe_core/ActionTemplateItem/portal_types create_integration_site.xml 0000664 0000000 0000000 00000004232 13456342174 0046177 0 ustar 00root root 0000000 0000000 erp5-b0d269b1f6f770be087f2139d81f05953d676c02-bt5-erp5_tiosafe_core/bt5/erp5_tiosafe_core/ActionTemplateItem/portal_types/portal_actions
-
action
AAAAAAAAAAI=
-
category
global
-
condition
-
description
-
icon
-
id
create_integration_site
-
permissions
Add portal content
-
priority
75.0
-
title
Create Integration Site
-
visible
1
-
text
string:${portal_url}/portal_integrations/IntegrationTool_viewCreateIntegrationSiteDialog
integration_site_tool.xml 0000664 0000000 0000000 00000004151 13456342174 0045711 0 ustar 00root root 0000000 0000000 erp5-b0d269b1f6f770be087f2139d81f05953d676c02-bt5-erp5_tiosafe_core/bt5/erp5_tiosafe_core/ActionTemplateItem/portal_types/portal_actions
-
action
AAAAAAAAAAI=
-
category
global
-
condition
-
description
-
icon
-
id
integration_site_tool
-
permissions
Manage portal
-
priority
100.0
-
title
Manage Integration Site
-
visible
1
-
text
string:${portal_url}/portal_integrations/view
DocumentTemplateItem/ 0000775 0000000 0000000 00000000000 13456342174 0033355 5 ustar 00root root 0000000 0000000 erp5-b0d269b1f6f770be087f2139d81f05953d676c02-bt5-erp5_tiosafe_core/bt5/erp5_tiosafe_core portal_components/ 0000775 0000000 0000000 00000000000 13456342174 0037123 5 ustar 00root root 0000000 0000000 erp5-b0d269b1f6f770be087f2139d81f05953d676c02-bt5-erp5_tiosafe_core/bt5/erp5_tiosafe_core/DocumentTemplateItem document.erp5.WebServiceConnector.py 0000664 0000000 0000000 00000005331 13456342174 0046077 0 ustar 00root root 0000000 0000000 erp5-b0d269b1f6f770be087f2139d81f05953d676c02-bt5-erp5_tiosafe_core/bt5/erp5_tiosafe_core/DocumentTemplateItem/portal_components ##############################################################################
#
# Copyright (c) 2002-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.
#
##############################################################################
from AccessControl import ClassSecurityInfo
from Products.ERP5Type import Permissions, PropertySheet
from Products.ERP5Type.XMLObject import XMLObject
class WebServiceConnector(XMLObject):
# CMF Type Definition
meta_type = 'ERP5 Web Service Connector'
portal_type = 'Web Service Connector'
# Declarative security
security = ClassSecurityInfo()
security.declareObjectProtected(Permissions.AccessContentsInformation)
# Default Properties
property_sheets = ( PropertySheet.Base
, PropertySheet.XMLObject
, PropertySheet.CategoryCore
, PropertySheet.DublinCore
, PropertySheet.SimpleItem
, PropertySheet.Login
, PropertySheet.Url
, PropertySheet.WebServiceConnector
)
security.declarePublic('reset')
def reset(self):
""" Reset volatile variable
"""
if getattr(self, '_v_conn', None) is not None:
delattr(self, '_v_conn')
security.declarePublic('getConnection')
def getConnection(self):
""" Return a connection to a web service
"""
if getattr(self, '_v_conn', None) is None:
self._v_conn = self.portal_web_services.connect(
url = self.getUrlString(),
user_name = self.getUserId(),
password = self.getPassword(),
transport = self.getTransport(),
)
return self._v_conn
document.erp5.WebServiceConnector.xml 0000664 0000000 0000000 00000006557 13456342174 0046262 0 ustar 00root root 0000000 0000000 erp5-b0d269b1f6f770be087f2139d81f05953d676c02-bt5-erp5_tiosafe_core/bt5/erp5_tiosafe_core/DocumentTemplateItem/portal_components
-
default_reference
WebServiceConnector
-
id
document.erp5.WebServiceConnector
-
portal_type
Document Component
-
sid
-
version
erp5
-
workflow_history
AAAAAAAAAAI=
-
data
-
component_validation_workflow
AAAAAAAAAAM=
-
action
validate
-
actor
ERP5TypeTestCase
-
comment
-
time
-
validation_state
validated
document.erp5.WebServiceRequest.py 0000664 0000000 0000000 00000026611 13456342174 0045601 0 ustar 00root root 0000000 0000000 erp5-b0d269b1f6f770be087f2139d81f05953d676c02-bt5-erp5_tiosafe_core/bt5/erp5_tiosafe_core/DocumentTemplateItem/portal_components ##############################################################################
#
# Copyright (c) 2002-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.
#
##############################################################################
from AccessControl import ClassSecurityInfo
from Products.ERP5Type import Permissions, PropertySheet
from Products.ERP5Type.XMLObject import XMLObject
from Products.ERP5TioSafe.Utils import EchoDictTarget, NewEchoDictTarget
from Products.PageTemplates.ZopePageTemplate import ZopePageTemplate
from App.Extensions import getBrain
from lxml import etree
from zLOG import LOG, ERROR, INFO
from Products.ERP5Type.Tool.WebServiceTool import ConnectionError
from Products.ERP5Type.Cache import CachingMethod
ID_SEPARATOR="-"
class WebServiceRequest(XMLObject, ZopePageTemplate):
# CMF Type Definition
meta_type = 'ERP5 Web Service Request'
portal_type = 'Web Service Request'
# Declarative security
security = ClassSecurityInfo()
security.declareObjectProtected(Permissions.AccessContentsInformation)
# Default Properties
property_sheets = ( PropertySheet.Base
, PropertySheet.XMLObject
, PropertySheet.CategoryCore
, PropertySheet.DublinCore
, PropertySheet.Reference
, PropertySheet.SimpleItem
, PropertySheet.Arrow
, PropertySheet.Data
, PropertySheet.WebServiceRequest
)
isIndexable = 0
content_type="text/html"
def getIntegrationSite(self,):
"""
return integration site if the wsr
"""
def cached_getIntegrationSite(self):
parent = self.getParentValue()
while parent.getPortalType() != "Integration Site":
parent = parent.getParentValue()
return parent.getPath()
cached_getIntegrationSite = CachingMethod(cached_getIntegrationSite,
id="WebServiceRequest_getIntegrationSite",
cache_factory="erp5_content_long")
integration_site = cached_getIntegrationSite(self)
return self.getPortalObject().portal_integrations.restrictedTraverse(integration_site)
def edit(self, **kw):
"""
Override the edit method to register page template values
"""
if kw.get('data'):
self.pt_edit(text=kw['data'], content_type=kw['content_type'])
return self._edit(**kw)
def getIDParameterName(self):
"""
Return the parameter name used for id
"""
def cached_getIDParameterName(self):
if self.getDestinationObjectType():
return "%s_id" %(self.getDestinationObjectType().replace(" ", "_").lower())
else:
return "id"
cached_getIDParameterName = CachingMethod(cached_getIDParameterName,
id="WebServiceRequest_getIDParameterName",
cache_factory="erp5_content_long")
return cached_getIDParameterName(self)
def __call__(self, context_document=None, test_mode=False, REQUEST=None, **kw):
"""
Make this object callable. It will call the method defined in reference using
the web service connector it is related to
"""
if REQUEST is not None:
return self.view()
#LOG("_call__", 300, kw)
if kw.has_key("id"):
kw[self.getIDParameterName()] = str(kw.pop("id"))
sub_id = None
if kw.has_key(self.getIDParameterName()) and ID_SEPARATOR in kw[self.getIDParameterName()]:
kw[self.getIDParameterName()], sub_id = kw[self.getIDParameterName()].split(ID_SEPARATOR)
object_list = []
method_name = self.getReference()
try:
connection = self.getSourceValue().getConnection()
except AttributeError:
LOG("__call__ of %s" %(self.getPath(),), ERROR,
"Error on getting connection, connector is %s" %(self.getSourceValue(),))
connection = None
if connection is None:
if test_mode:
self._edit(last_request_parameter=str(kw),
last_request_result="",
last_request_path="",
last_request_error="No connection available, connector is %s" %(self.getSourceValue(),))
return []
else:
raise ValueError, "No connection available"
# Add specific parameters defined on integration site
site = self.getIntegrationSite()
if site.getLanguage():
kw['language'] = site.getLanguage()
if site.getStartDate():
kw['start_date'] = site.getStartDate()
if site.getStopDate():
kw['stop_date'] = site.getStopDate()
# Render page template content
if self.hasData():
#LOG("passing options %s to self %s" %(kw, self.getPath()), 300, "CALL")
pt_data = self.pt_render(extra_context={'options': kw, })
pt_data = pt_data.replace('\n', '')
kw = {'data': pt_data}
# transforms parameters
#LOG("before transformation of params %s" %(kw), 300, self.getPath())
new_kw = kw.copy()
args = []
if self.getDestination():
for k,v in kw.iteritems():
new_key = site.getMappingFromProperty(self.getDestinationValue(), k)
new_kw.pop(k)
if new_key is None:
# Some web service does not need explicit parameters
args.append(v)
else:
new_kw[new_key] = v
kw = new_kw
#LOG("calling with params args = %s, kw = %s" %(args, kw), 300, self.getPath())
error = None
def callRequest(self, method_name, *args, **kw):
connection = self.getSourceValue().getConnection()
return getattr(connection, method_name)(*args, **kw)
# cached_callRequest = CachingMethod(callRequest,
# id="WebServiceRequest_callRequest",
# cache_factory="erp5_content_short")
# Call the method
try:
url, xml = callRequest(self, method_name, *args, **kw)
except ConnectionError, msg:
if test_mode:
error = msg
url = connection.url
xml = ""
else:
raise
# Register information for testing/debug purposes
if test_mode:
self._edit(last_request_parameter="args = %s, kw = %s" %(str(args), str(kw)),
last_request_result=xml,
last_request_path=url,
last_request_error=error)
def buildParserDict(root_mapping):
parser_dict = {}
for mapping in root_mapping.contentValues():
if len(mapping.contentValues()):
sub_parser_dict = buildParserDict(mapping)
parser_dict[mapping.getSourceReference()] = (mapping.getDestinationReference(), sub_parser_dict)
else:
parser_dict[mapping.getSourceReference()] = (mapping.getDestinationReference(), None)
return parser_dict
if self.hasDestination():
sub_parser_dict = buildParserDict(self.getDestinationValue())
parser_dict = {self.getDestinationValue().getSourceReference() : (self.getDestinationValue().getDestinationReference(), sub_parser_dict)}
else:
return []
# Parse the result
if self.getSourceValue().getParserMethodId():
method = getattr(self, self.getSourceValue().getParserMethodId())
result_list = method(result=xml, parser_dict=parser_dict)
else:
if type(xml) == list:
result_list = self.parse_dict(parser_dict, xml)
else:
parser = etree.XMLParser(target = NewEchoDictTarget(parser_dict))
# FIXME: About prestashop sync, '&' and '&' char in xml cause problem
# xml = xml.replace('&', '')
#LOG("got XML from WSR %s = %s" %(method_name, xml), 300, "will call parser with %s" %(parser_dict))
result_list = []
try:
result_list = etree.XML(xml, parser,)
#LOG("result_list = %r" %(result_list), 300, "")
except etree.XMLSyntaxError:
LOG("WebServiceRequest", ERROR, "Bad XML returned by request %s with kw = %s, xml = %s" %(self.getPath(), kw, xml))
if test_mode:
self._edit(last_request_error="Bad XML returned by request, impossible to parse it")
else:
raise ValueError, "Bad XML returned by request %s with kw = %s, xml = %s" %(self.getPath(), kw, xml)
brain = getBrain(self.brain_class_file, self.brain_class_name, reload=1)
script_id = self.getBrainBuilderScript(None)
if script_id is not None:
brain_builder_script = getattr(self, script_id, None)
else:
brain_builder_script = None
if brain_builder_script is not None:
for result in result_list:
object_list.extend(brain_builder_script(result, brain))
if sub_id:
object_list = [object_list[int(sub_id)-1],]
else:
for result in result_list:
#LOG("initialising brain", INFO, "data is %s" %(result))
obj = brain(context=self,
object_type=self.getDestinationObjectType(),
**result)
object_list.append(obj)
return object_list
def __getitem__(self, item):
"""
Simulate the traversable behaviour by retrieving the item through
the web service
"""
# build parameter name
try:
long(item)
except ValueError:
raise KeyError, "Item %s does not exists call by Web Service Request %s : not a long" % (item,
self.getTitle(),)
kw = {self.getIDParameterName() : str(item), }
object_list = self(**kw)
if len(object_list) == 1:
return object_list[0]
else:
raise KeyError, "Item %s does not exists call by Web Service Request %s with params %s return %d results" % (item,
self.getTitle(),
kw,
len(object_list))
def parse_dict(self, parser_dict, dict_list):
""" Render the dict list mapped by the parser dict. """
# TODO: This parser method must be defined in the Web Service Connector
data_list = []
for dictionnary in dict_list:
property_dict = {}
for k, v in dictionnary.items():
k = parser_dict.get(k)
if k is not None:
k = k[0]
property_dict[k] = unicode(v)
data_list.append(property_dict)
return data_list
document.erp5.WebServiceRequest.xml 0000664 0000000 0000000 00000006553 13456342174 0045754 0 ustar 00root root 0000000 0000000 erp5-b0d269b1f6f770be087f2139d81f05953d676c02-bt5-erp5_tiosafe_core/bt5/erp5_tiosafe_core/DocumentTemplateItem/portal_components
-
default_reference
WebServiceRequest
-
id
document.erp5.WebServiceRequest
-
portal_type
Document Component
-
sid
-
version
erp5
-
workflow_history
AAAAAAAAAAI=
-
data
-
component_validation_workflow
AAAAAAAAAAM=
-
action
validate
-
actor
ERP5TypeTestCase
-
comment
-
time
-
validation_state
validated
document.erp5.WebServiceRequestGroup.py 0000664 0000000 0000000 00000005370 13456342174 0046615 0 ustar 00root root 0000000 0000000 erp5-b0d269b1f6f770be087f2139d81f05953d676c02-bt5-erp5_tiosafe_core/bt5/erp5_tiosafe_core/DocumentTemplateItem/portal_components ##############################################################################
#
# Copyright (c) 2002-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.
#
##############################################################################
from AccessControl import ClassSecurityInfo
from Products.ERP5Type import Permissions, PropertySheet
from Products.ERP5Type.XMLObject import XMLObject
class WebServiceRequestGroup(XMLObject):
# CMF Type Definition
meta_type = 'ERP5 Web Service Request Group'
portal_type = 'Web Service Request Group'
# Declarative security
security = ClassSecurityInfo()
security.declareObjectProtected(Permissions.AccessContentsInformation)
# Default Properties
property_sheets = ( PropertySheet.Arrow, )
def __call__(self, **kw):
"""
Make this object callable. It will calls each methods defined in the
multi list field with the given parameters.
"""
object_list = []
for web_service_request in self.getSourceList():
object_list += getattr(self, web_service_request)(**kw)
return object_list
def __getitem__(self, item):
"""
Simulate the traversable behaviour by retrieving the item through
the web service
"""
object_list = []
for web_service_request in self.getSourceList():
try:
object_list.append(
getattr(self, web_service_request).__getitem__(item),
)
except KeyError:
# no need to raise until all web service requests are browsed
continue
# after browsing all web service requests check that item exists and only
# one time
if len(object_list) != 1:
raise KeyError, "No entry for the item %s" % item
return object_list[0]
document.erp5.WebServiceRequestGroup.xml 0000664 0000000 0000000 00000006566 13456342174 0046775 0 ustar 00root root 0000000 0000000 erp5-b0d269b1f6f770be087f2139d81f05953d676c02-bt5-erp5_tiosafe_core/bt5/erp5_tiosafe_core/DocumentTemplateItem/portal_components
-
default_reference
WebServiceRequestGroup
-
id
document.erp5.WebServiceRequestGroup
-
portal_type
Document Component
-
sid
-
version
erp5
-
workflow_history
AAAAAAAAAAI=
-
data
-
component_validation_workflow
AAAAAAAAAAM=
-
action
validate
-
actor
ERP5TypeTestCase
-
comment
-
time
-
validation_state
validated
ExtensionTemplateItem/ 0000775 0000000 0000000 00000000000 13456342174 0033553 5 ustar 00root root 0000000 0000000 erp5-b0d269b1f6f770be087f2139d81f05953d676c02-bt5-erp5_tiosafe_core/bt5/erp5_tiosafe_core portal_components/ 0000775 0000000 0000000 00000000000 13456342174 0037321 5 ustar 00root root 0000000 0000000 erp5-b0d269b1f6f770be087f2139d81f05953d676c02-bt5-erp5_tiosafe_core/bt5/erp5_tiosafe_core/ExtensionTemplateItem extension.erp5.TioSafeBaseConduit.py 0000664 0000000 0000000 00000021765 13456342174 0046246 0 ustar 00root root 0000000 0000000 erp5-b0d269b1f6f770be087f2139d81f05953d676c02-bt5-erp5_tiosafe_core/bt5/erp5_tiosafe_core/ExtensionTemplateItem/portal_components # -*- coding: utf-8 -*-
##############################################################################
#
# Copyright (c) 2010 Nexedi SA and Contributors. All Rights Reserved.
# Aurelien Calonne
# Hervé Poulain
#
# WARNING: This program as such is intended to be used by professional
# programmers who take the whole responsability of assessing all potential
# consequences resulting from its eventual inadequacies and bugs
# End users who are looking for a ready-to-use solution with commercial
# garantees and support are strongly adviced to contract a Free Software
# Service Company
#
# This program is Free Software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#
##############################################################################
from Products.ERP5SyncML.SyncMLConstant import XUPDATE_INSERT_OR_ADD_LIST, \
XUPDATE_DEL, XUPDATE_UPDATE
from Products.ERP5Type.XMLExportImport import MARSHALLER_NAMESPACE_URI
from zLOG import LOG, INFO
from Products.ERP5SyncML.Conduit.ERP5Conduit import ERP5Conduit
from lxml import etree
from copy import deepcopy
parser = etree.XMLParser(remove_blank_text=True)
XUPDATE_INSERT_LIST = ('xupdate:insert-after', 'xupdate:insert-before')
class TioSafeBaseConduit(ERP5Conduit):
"""
This class provides some tools used by different TioSafe Conduits.
"""
def addNode(self, xml=None, object=None, sub_object=None, reset=None,
simulate=None, **kw):
"""
A node is added
xml : the xml wich contains what we want to add
object : from where we want to add something
previous_xml : the previous xml of the object, if any
force : apply updates even if there's a conflict
This fucntion returns conflict_list, wich is of the form,
[conflict1,conflict2,...] where conclict1 is of the form :
[object.getPath(),keyword,local_and_actual_value,subscriber_value]
"""
conflict_list = []
xml = self.convertToXml(xml)
LOG('TioSafeBaseConduit.addNode', INFO, '\n%s' % etree.tostring(xml, pretty_print=True))
if xml is None:
return {'conflict_list': conflict_list, 'object': sub_object}
# In the case where this new node is a object to add
xpath_expression = xml.get('select')
if xml.xpath('name()') in XUPDATE_INSERT_OR_ADD_LIST and\
MARSHALLER_NAMESPACE_URI not in xml.nsmap.values():
# change the context according select expression
get_target_parent = xml.xpath('name()') in XUPDATE_INSERT_LIST
context = self.getContextFromXpath(object, xpath_expression,
get_target_parent=get_target_parent)
for element in xml.findall('{%s}element' % xml.nsmap['xupdate']):
xml = self.getElementFromXupdate(element)
conflict_list += self.addNode(xml=xml, object=context, **kw)\
['conflict_list']
elif xml.xpath('local-name()') == self.xml_object_tag:
sub_object = self._createContent(xml=xml,
object=object,
sub_object=sub_object,
reset=reset,
simulate=simulate,
**kw)
else:
conflict_list += self.updateNode(xml=xml, object=object, reset=reset,
simulate=simulate, **kw)
# We must returns the object created
return {'conflict_list':conflict_list, 'object': sub_object}
def replaceIdFromXML(self, xml, attribute_name, new_id, as_string=True):
"""
return a xml with id replace by a new id
"""
if isinstance(xml, str):
xml = etree.XML(xml, parser=parser)
else:
xml = deepcopy(xml)
if as_string:
return etree.tostring(xml)
return xml
def applyXupdate(self, object=None, xupdate=None, previous_xml=None, **kw):
""" Parse the xupdate and then it will call the conduit. """
conflict_list = []
if isinstance(xupdate, (str, unicode)):
xupdate = etree.XML(xupdate, parser=parser)
if kw.get('conduit', None) is not None:
for subnode in xupdate:
conflict_list += self.updateNode(
xml=self.getContextFromXpath(subnode, subnode.get('select')),
object=object,
previous_xml=previous_xml,
**kw
)
return conflict_list
def getIntegrationSite(self, sync_object):
"""
Return the integration site based on the link with the pub/sub
"""
if getattr(self, 'integration_site', None) is None:
related_object_list = [x.getObject() for x in sync_object.Base_getRelatedObjectList()]
if len(related_object_list) != 1:
raise ValueError, "Impossible to find related object to %s : %s" %(sync_object.getPath(), related_object_list)
integration_site = related_object_list[0].getParentValue()
if integration_site.getPortalType() != "Integration Site":
raise ValueError, "Did not get an Integration Site object instead %s : %s" %(integration_site.getPortalType(),
integration_site.getPath())
self.integration_site = integration_site
return self.integration_site
def getSynchronizationObjectForType(self, sync_object, object_type, synchronization_type):
"""
This method provides a Publication or Subscription base on the relation
set in integration site
"""
site = self.getIntegrationSite(sync_object)
module_id = "%s_module" %(object_type.lower())
module = getattr(site, module_id, None)
if module is None:
raise ValueError, "Impossible to find integration module object on %s for %s" %(site.getPath(), object_type)
if synchronization_type == "publication":
return module.getSourceSectionValue()
elif synchronization_type == "subscription":
return module.getDestinationSectionValue()
else:
raise ValueError, 'Unknown type %s' %(synchronization_type,)
def updateNode(self, xml=None, object=None, previous_xml=None, force=False,
simulate=False, reset=False, xpath_expression=None, **kw):
"""
This method browse the xml which allows to update data and update the
correpsonging object.
"""
conflict_list = []
if simulate:
return conflict_list
if xml is None:
return {'conflict_list': conflict_list, 'object': object}
xml = self.convertToXml(xml)
# we have an xupdate xml
if xml.xpath('name()') == 'xupdate:modifications':
conflict_list += self.applyXupdate(
object=object,
xupdate=xml,
conduit=self,
previous_xml=previous_xml,
force=force,
simulate=simulate,
reset=reset,
**kw
)
# we may have only the part of an xupdate
else:
# previous_xml is required as an etree type
if type(previous_xml) == str:
previous_xml = etree.XML(previous_xml, parser=parser)
if self.isProperty(xml):
xpath = xml.xpath('name()')
# XUPDATE_UPDATE -> update data or sub-object
if xpath in XUPDATE_UPDATE:
conflict_list += self._updateXupdateUpdate(
document=object,
xml=xml,
previous_xml=previous_xml,
**kw
)
# XUPDATE_DEL -> delete data or sub-object
elif xpath in XUPDATE_DEL:
conflict_list += self._updateXupdateDel(
document=object,
xml=xml,
previous_xml=previous_xml,
**kw
)
# XUPDATE_INSERT_OR_ADD_LIST -> add data or sub-object
elif xpath in XUPDATE_INSERT_OR_ADD_LIST:
conflict_list += self._updateXupdateInsertOrAdd(
document=object,
xml=xml,
previous_xml=previous_xml,
**kw
)
return conflict_list
def _updateXupdateUpdate(self, document=None, xml=None, previous_xml=None, **kw):
"""
This method is called in updateNode and allows to work on the update of
elements.
"""
return []
def _updateXupdateDel(self, document=None, xml=None, previous_xml=None, **kw):
""" This method is called in updateNode and allows to remove elements. """
return []
def _updateXupdateInsertOrAdd(self, document=None, xml=None, previous_xml=None, **kw):
""" This method is called in updateNode and allows to add elements. """
return []
extension.erp5.TioSafeBaseConduit.xml 0000664 0000000 0000000 00000006561 13456342174 0046413 0 ustar 00root root 0000000 0000000 erp5-b0d269b1f6f770be087f2139d81f05953d676c02-bt5-erp5_tiosafe_core/bt5/erp5_tiosafe_core/ExtensionTemplateItem/portal_components
-
default_reference
TioSafeBaseConduit
-
id
extension.erp5.TioSafeBaseConduit
-
portal_type
Extension Component
-
sid
-
version
erp5
-
workflow_history
AAAAAAAAAAI=
-
data
-
component_validation_workflow
AAAAAAAAAAM=
-
action
validate
-
actor
ERP5TypeTestCase
-
comment
-
time
-
validation_state
validated
extension.erp5.TioSafeBrain.py 0000664 0000000 0000000 00000104227 13456342174 0045074 0 ustar 00root root 0000000 0000000 erp5-b0d269b1f6f770be087f2139d81f05953d676c02-bt5-erp5_tiosafe_core/bt5/erp5_tiosafe_core/ExtensionTemplateItem/portal_components ##############################################################################
#
# Copyright (c) 2009 Nexedi SA. All Rights Reserved.
# Copyright (c) 2001 Zope Corporation and Contributors. All Rights Reserved.
#
# This software is subject to the provisions of the Zope Public License,
# Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution.
# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
# FOR A PARTICULAR PURPOSE
#
##############################################################################
from Acquisition import Explicit, aq_base
from AccessControl import ClassSecurityInfo
from base64 import b16encode
from lxml import etree
from zLOG import LOG, ERROR
from DateTime import DateTime
import sys
from Products.ERP5Type.Cache import CachingMethod
# Global variables
SEPARATOR = '\n'
class TioSafeBrain(Explicit):
"""
The main brain class provides the generic method used by sub brain which
allows to present the different TioSafe XML.
"""
security = ClassSecurityInfo()
security.declareObjectPublic()
__allow_access_to_unprotected_subobjects__ = 1
def __init__(self, object_type, context, **kw):
self.path = context.getParentValue().getPath() + '/' + kw.get('id', '')
self.object_type = object_type
self.context = context
# save properties as attributes
for k,v in kw.iteritems():
# FIXME: '0000-00-00 00:00:00' is an error find in the Prestashop sync
if v is not None and v != '0000-00-00 00:00:00':
setattr(self, k.lower(), v)
def updateProperties(self, brain):
"""
Update self properties with the one from
another brain
"""
for k,v in brain.__dict__.iteritems():
setattr(self, k, v)
def _asXML(self):
"""
Must be overriden by subclasses
"""
raise NotImplementedError
def asXML(self, debug=False):
"""
Build the TioSafe XML
"""
try:
return self._asXML()
except:
raise
error_type, error_value, error_tb = sys.exc_info()
LOG("TioSafeBrain.asXML", ERROR, "%s - %s" %(error_type, error_value), error=sys.exc_info())
if debug:
raise ValueError, "%s - %s" %(error_type, error_value)
else:
raise
def getDefaultUnknownNodeGID(self):
"""
Resource the gid of the node used when no node can be found
"""
integration_site = self.getIntegrationSite()
default_node = integration_site.getDestinationValue()
return integration_site.person_module.getSourceSectionValue().getGidFromObject(default_node, encoded=False)
def getDefaultUnknownResourceGID(self):
"""
Resource the gid of the node used when no node can be found
"""
integration_site = self.getIntegrationSite()
default_node = integration_site.getResourceValue()
return integration_site.product_module.getSourceSectionValue().getGidFromObject(default_node, encoded=False)
def getDefaultOrganisationGID(self):
"""
Return the gid of the shop
"""
integration_site = self.getIntegrationSite()
default_source = integration_site.getSourceAdministrationValue()
return integration_site.organisation_module.getSourceSectionValue().getGidFromObject(default_source, encoded=False)
def _getSynchronizationObjectList(self, sync_type, object_type_list):
"""
Render the 'SyncML Publication' or the 'SyncML Subscription' list which
correspond to the sync_type and the object_type.
"""
if not isinstance(object_type_list, list):
object_type_list = [object_type_list,]
def cached_getSynchronizationObjectList(sync_type, object_type):
context = self.context
module_list = []
object_module_id = object_type.lower().replace(' ', '_')
for module in context.getIntegrationSite().contentValues(portal_type="Integration Module"):
if object_module_id in module.getId():
module_list.append(module)
if not len(module_list):
raise ValueError, "Impossible to find a module for %s" %(object_type)
sync_object_list = []
for module in module_list:
# init shortcut of module's data
module_source = module.getSourceSectionValue()
module_destination = module.getDestinationSectionValue()
source_portal_type = module_source.getSourceValue().getPortalType()
destination_portal_type = module_destination.getSourceValue().getPortalType()
# only work on the ERP5 or TioSafe sync
assert sync_type in ("tiosafe", "erp5"), sync_type
if (sync_type == "erp5") ^ (source_portal_type == "Integration Module"):
# render the source if:
# 1. sync_type == erp5 and source_portal_type != Integration Module
# 2. sync_type != erp5 and source_portal_type == Integration Module
sync_object_list.append(module_source.getPath())
elif (sync_type == "tiosafe") ^ (destination_portal_type != "Integration Module"):
# render the destination if:
# 1. sync_type == tiosafe and destination_portal_type == Integration Module
# 2. sync_type != tiosafe and destination_portal_type != Integration Module
sync_object_list.append(module_destination.getPath())
else:
raise ValueError, "Impossible to find pub/sub related to Integration Module, pub = %s with source = %s, sub = %s with source = %s" %(
module.getSourceSection(),
module_source.getSource(),
module.getDestinationSection(),
module_destination.getSource(),
)
return sync_object_list
# Cache sync object list
cached_getSynchronizationObjectList = CachingMethod(cached_getSynchronizationObjectList,
id="TioSafeBrain_getSynchronizationObjectList",
cache_factory='erp5_content_long')
object_list = []
for object_type in object_type_list:
object_list.extend(cached_getSynchronizationObjectList(sync_type, object_type))
portal = self.context.getPortalObject()
return [portal.restrictedTraverse(x) for x in object_list]
def getTioSafeSynchronizationObjectList(self, object_type):
""" return the synchronization pub/sub which is used
to retrieve object from plugin
"""
return self._getSynchronizationObjectList(sync_type="tiosafe", object_type_list=object_type)
def getERP5SynchronizationObjectList(self, object_type):
""" return the synchronization pub/sub which is used
to retrieve object from ERP5
"""
return self._getSynchronizationObjectList(sync_type="erp5", object_type_list=object_type)
def getPortalType(self):
""" return the portal type """
return self.object_type
def getGid(self, encoded=None):
""" Return the GID of the object. """
if getattr(self, 'gid', None) is None:
# GID is build from definition on integration module
integration_module = self.context.getParentValue()
prefix = integration_module.getGidPrefix("")
property_list = integration_module.getGidPropertyList()
gid = prefix
for prop in property_list:
try:
prop_value = getattr(self, prop)
except AttributeError:
raise AttributeError, "The brain doesn't have the property %s" % prop
gid += " %s" %(prop_value,)
self.gid = gid
if encoded is not None:
return b16encode(self.gid)
return self.gid
def getIntegrationSite(self):
""" Retrieve the integration site """
parent = self.context.getParentValue()
while not parent.getPortalType() == "Integration Site":
parent = parent.getParentValue()
return parent
def getId(self):
""" Return the id of the element. """
return self.id
def getPhysicalPath(self):
""" Return the Physical Path of the object. """
return tuple(self.path.split('/'))
def getPath(self):
""" Return the Path of the object. """
return str(self.path)
def _setTagList(self, document=None, xml=None, tag_list=None, separator=None):
"""
This method set on an XML node some sub-nodes which are the properties
(define in tag_list) of a document given as parameter.
"""
# only work on the data of the document and not on its parent's data
document = aq_base(document)
# list which allows to realise a specific work on date
date_list = ['birthday', 'start_date', 'stop_date']
# marker for checking property existency
MARKER = object()
for key in tag_list:
# getattr retrieves the MARKER imply that property doesn't provided
if getattr(document, key, MARKER) is not MARKER:
text = getattr(document, key)
# if a separator is provides, browse the element's list else it's a
# single element
if separator:
text_list = text.split(separator)
text_list.sort() # XXX- If the fix point fails se me
else:
text_list = [text,]
for text in text_list:
if text:
if key in date_list:
# work on correct date else put an empty value
try:
text = str(DateTime(text))
except DateTime.DateError:
text = ""
element = etree.SubElement(xml, key)
element.text = text
def _setArrowTag(self, document=None, xml=None, source_tag='source',
destination_tag='destination', category=''):
""" This method build the XML of the arrow. """
# only work on the data of the document and not on its parent's data
document = aq_base(document)
sync_list = self.getTioSafeSynchronizationObjectList(object_type="Person")
# create the arrow tag and set if exist source and destination
arrow = etree.SubElement(xml, 'arrow', type=category)
arrow_list = [(source_tag, 'source'), (destination_tag, 'destination')]
for prop, tag in arrow_list:
if getattr(document, prop, None) is not None:
movement = etree.SubElement(arrow, tag)
object_id = getattr(document, prop)
if object_id != 'default_node':
for sync in sync_list:
try:
brain_node = sync.getObjectFromId(object_id)
node_gid = brain_node.getGid()
break
except (ValueError, AttributeError):
# This is not a document, might be a category, or the gid previously built
# pass it anyway in xml
node_gid = None
if node_gid is None:
node_gid = self.getDefaultUnknownNodeGID()
movement.text = node_gid
else:
movement.text = self.getDefaultOrganisationGID()
def _setArrowTagList(self, document=None, xml=None):
""" This method set all possible arrows on the XML. """
# only work on the data of the document and not on its parent's data
document = aq_base(document)
# marker for checking property existency
MARKER = object()
# build the list which contains the properties
# IF THIS LIST IS UPDATE THINK TO KEEP THE ALPHABETIC ORDER
arrow_data_list = [
['source', 'destination', ''],
['source_accounting', 'destination_accounting', 'Accounting'],
['source_administration', 'destination_administration', 'Administration'],
['source_carrier', 'destination_carrier', 'Carrier'],
['source_decision', 'destination_decision', 'Decision'],
['source_invoice', 'destination_invoice', 'Invoice'],
['source_ownership', 'destination_ownership', 'Ownership'],
['source_payment', 'destination_payment', 'Payment'],
]
# browse the arrow's data and build the arrow when it's possible
for sub_list in arrow_data_list:
source, destination, category = sub_list
if getattr(document, source, MARKER) is not MARKER or \
getattr(document, destination, MARKER) is not MARKER:
# set the arrow tag
self._setArrowTag(
document=document,
xml=xml,
source_tag=source,
destination_tag=destination,
category=category,
)
# ----------- Brain for insert in Integration Site ---------- #
# XXX-Aurel : this must be handle by the base brain class
class LastId(TioSafeBrain):
__allow_access_to_unprotected_subobjects__ = 1
def getId(self):
""" Return the last id of the table in the database. """
# XXX-Aurel : this must be based on the GID definition
# As GID in TioSafe case is unique, it must be used to get
# the last ID of an inserted object (usefull for cases where
# transactionnal operation is not provided like with prestashop)
#raise ValueError, self.last_id
return TioSafeBrain.getId(self)
class Node(TioSafeBrain):
"""
This class allows to build the TioSafe XML of a Node and to sync.
"""
__allow_access_to_unprotected_subobjects__ = 1
def _generateCoordinatesXML(self, node):
""" Generate the XML for addresses sub-objects & phones"""
# Phones
phone_tag_list = ['phone', 'cellphone']
for tag in phone_tag_list:
value = getattr(self, "%s" %(tag), '')
if value:
element = etree.SubElement(node, tag)
element.text = value
# Fax
value = getattr(self, "fax", '')
if value:
element = etree.SubElement(node, 'fax')
element.text = value
MARKER = object()
node_address_method = "get%sAddressList" %(self.getPortalType(),)
module_id = "%s_module" %(self.getPortalType().lower(),)
module = getattr(self.context, module_id)
if getattr(module, node_address_method, MARKER) is not MARKER:
# order address list
ordered_address_list = []
parameter_kw = {"%s_id" %(self.getPortalType().replace(" ", "_").lower(),) : str(self.getId())}
for element in getattr(module, node_address_method)(**parameter_kw):
# Save the country after realisation of the mapping
if getattr(element, 'country', None):
country = self.getIntegrationSite().getCategoryFromMapping(
category = 'Country/%s' % element.country, create_mapping=True,
create_mapping_line=True,
)
element.country = '/'.join(country.split('/')[1:])
full_address = '%s %s %s %s' % (
getattr(element, 'street', ''),
getattr(element, 'zip', ''),
getattr(element, 'city', ''),
getattr(element, 'country', ''),
)
ordered_address_list.append((full_address, element))
ordered_address_list.sort()
for full_address, element in ordered_address_list:
address = etree.SubElement(node, 'address')
tag_list = ('street', 'zip', 'city', 'country', )
self._setTagList(element, address, tag_list)
def _setRoleList(self, node):
"""
Define the role as a client by default
"""
# by default assume we synchronize client
# if not this method must be overriden
element = etree.SubElement(node, 'category')
element.text = 'role/client'
def _setRelation(self, node):
"""
Add the relation tag which link a person to an organisation
"""
if self.object_type == "Person":
if getattr(self, "relation", None) is not None:
# this must be the gid of organisatin
# we suppose here that we get the id in self.relation
# in other cases, this method must be overriden
tiosafe_sync_list = self.getTioSafeSynchronizationObjectList(object_type='Organisation')
for tiosafe_sync in tiosafe_sync_list:
try:
brain_node = tiosafe_sync.getObjectFromId(self.relation)
organisation_gid = brain_node.getGid()
break
except (ValueError, AttributeError):
organisation_gid = None
if organisation_gid is None:
raise ValueError, "Impossible to find organisation for id %s on node %s" %(self.relation, self.path)
else:
organisation_gid = ""
# set the tag
if organisation_gid:
element = etree.SubElement(node, 'relation')
element.text = organisation_gid
def _asXML(self):
node_type = self.context.getDestinationObjectType()
node = etree.Element('node', type=node_type)
# list of possible tags for a node
tag_list = (
'title', 'firstname', 'lastname', 'email', 'birthday',
)
self._setTagList(self, node, tag_list)
try:
self._generateCoordinatesXML(node)
except ValueError:
# Missing mapping
return None
# Role must be defined here if there is specific - client/internal/...
self._setRoleList(node)
# Define relation, must be the GID
self._setRelation(node)
xml = etree.tostring(node, pretty_print=True, encoding='utf-8')
LOG('Node asXML returns : %s' % (xml, ), 300, "")
return xml
class Resource(TioSafeBrain):
"""
This class allows to build the TioSafe XML of a Resource and to sync.
"""
__allow_access_to_unprotected_subobjects__ = 1
def __init__(self, *args, **kw):
self.category = []
self.mapping_property_list = []
TioSafeBrain.__init__(self, *args, **kw)
def _generateMappingXML(self, resource):
"""
Specific part for the mapped property
"""
# sort categories
def cat_cmp(a, b):
return cmp(a['category_list'], b['category_list'])
self.mapping_property_list.sort(cmp=cat_cmp)
for mapping in self.mapping_property_list:
element = etree.SubElement(resource, 'mapping')
category_list = mapping['category_list']
category_list.sort()
for category_value in category_list:
category = etree.SubElement(element, 'category')
category.text = category_value
mapping.pop('category_list')
for k, v in mapping.iteritems():
prop = etree.SubElement(element, k)
prop.text = v
def _asXML(self):
resource_type = self.context.getDestinationObjectType()
resource = etree.Element('resource', type=resource_type)
# First defined basic tags
tag_list = (
'title', 'reference', 'ean13',
'description',
)
self._setTagList(self, resource, tag_list)
# Then build & add the list of variations
category_list = []
# - Categorie can already have been retrieve
if isinstance(self.category, str):
self.category = self.category.split(SEPARATOR)
category_list = self.category[:]
# - Categories can also be retrieved using specific query
module_id = "%s_module" %(self.getPortalType().lower(),)
module = getattr(self.context, module_id)
get_category_method = "get%sCategoryList" % self.getPortalType()
MARKER = object()
if getattr(module, get_category_method, MARKER) is not MARKER:
# add category list
parameter_kw = {"%s_id" %(self.getPortalType().replace(" ", "_").lower(),) : str(self.getId())}
for element in getattr(module, get_category_method)(**parameter_kw):
# XXX-Aurel : This code is bad as it assumes it will return a list in any case
try:
category = self.getIntegrationSite().getCategoryFromMapping(
category=element.category, create_mapping=True
)
except ValueError:
return None
category_list.append(category)
# - Order the category list
category_list.sort()
# - Add the categories to the product's xml
for category_value in category_list:
category = etree.SubElement(resource, 'category')
category.text = category_value
self._generateMappingXML(resource)
xml = etree.tostring(resource, pretty_print=True, encoding='utf-8')
LOG("Resource asXML returns : %s" % (xml, ), 300, "")
return xml
class Transaction(TioSafeBrain):
"""
This class allows to build the TioSafe XML of a Sale Order and to sync.
"""
__allow_access_to_unprotected_subobjects__ = 1
def __init__(self, object_type, context, **kw):
self.source = "default_node"
self.source_ownership = "default_node"
self.source_decision = "default_node"
self.source_administration = "default_node"
TioSafeBrain.__init__(self, object_type, context, **kw)
def getVATCategory(self, vat_value):
"""
This returns the VAT category according to the value set
"""
def cached_buildVATDict():
vat_dict = {}
trade_condition = self.getIntegrationSite().getDefaultSourceTradeValue()
while len(trade_condition.contentValues(portal_type="Trade Model Line")) == 0:
# Must find a better way to browse specialised objects
specialized_trade_condition = trade_condition.getSpecialiseValue()
if specialized_trade_condition is None or specialized_trade_condition.getPortalType() == "Business Process":
raise ValueError, 'Impossible to find a trade condition containing VAT lines, last trade condition was %s, parent was %s' %(specialized_trade_condition, trade_condition)
else:
trade_condition = specialized_trade_condition
for vat_line in trade_condition.contentValues(portal_type="Trade Model Line"):
# LOG("browsing line %s" %(vat_line.getPath(), 300, "%s" %(vat_line.getBaseApplicationList(),)))
for app in vat_line.getBaseApplicationList():
if "base_amount/trade/base/taxable/vat/" in app:
vat_dict["%.2f" %(vat_line.getPrice()*100.)] = app.split('/')[-1]
# LOG("vat_dict is %s" %(vat_dict), 300, "")
return vat_dict
cached_getSynchronizationObjectList = CachingMethod(cached_buildVATDict,
id="TioSafeBrain_cached_buildVATDict",
cache_factory='erp5_content_long')
vat_dict = cached_buildVATDict()
return vat_dict["%.2f" %(float(vat_value))]
def _setPaymentMode(self, txn):
"""
Define the payment mode of a transaction
This must be the category payment_mode/XXX
"""
if getattr(self, 'payment_mode', None) is not None:
payment_mapping = self.getIntegrationSite().getCategoryFromMapping(
category='Payment Mode/%s' % getattr(self, 'payment_mode'),
create_mapping=True,
create_mapping_line=True,
)
element = etree.SubElement(txn, 'payment_mode')
element.text = payment_mapping.split('/', 1)[-1]
def _asXML(self):
transaction_type = self.context.getDestinationObjectType()
transaction = etree.Element('transaction', type=transaction_type)
tiosafe_sync_list = self.getTioSafeSynchronizationObjectList(object_type='Product')
erp5_sync_list = self.getERP5SynchronizationObjectList(object_type='Product')
integration_site = self.getIntegrationSite()
# marker for checking property existency
MARKER = object()
# list of possible tags for a sale order
tag_list = (
'title', 'start_date', 'stop_date', 'reference', 'currency',
)
self._setTagList(self, transaction, tag_list)
self._setTagList(self, transaction, ['category', ], SEPARATOR)
# set arrow list
try:
self._setPaymentMode(transaction)
self._setArrowTagList(self, transaction)
except ValueError:
# A mapping must be missing
return None
# order the movement list
movement_list = []
# build a list of 2-tuple
# the first key contains the sort element
# the second part of the tuple contains a dict which contains all the data
# of the transaction line
method_id = self.getPortalType().replace(' ', '')
portal_type = self.getPortalType().replace(' ', '_').lower()
line_type_list = ['', 'Delivery', 'Discount', ]
module_id = "%s_module" %(portal_type)
module = getattr(integration_site, module_id)
for line_type in line_type_list:
getter_line_method = getattr(
module,
'get%s%sLineList' % (line_type, method_id),
MARKER,
)
if getter_line_method is not MARKER:
# browse each transaction lines, build the sort element and set data
parameter_kw = {'%s_id' % portal_type: str(self.getId()), }
for line in getter_line_method(**parameter_kw):
key_list = ['title', 'resource', 'reference', 'quantity', 'price']
value_list = [getattr(line, x, '') for x in key_list]
movement_dict = {'context': line,}
# set to None the '' value of the list
for k, v in zip(key_list, value_list):
movement_dict[k] = v or None
# set the VAT value
movement_dict['VAT'] = self.getVATCategory(getattr(line, 'vat', None))
# the following boolean var allows to check if variation will be sync
variation_sync = True
# retrieve the resource and the gid in the line
if not line_type:
# work on transaction lines
for tiosafe_sync in tiosafe_sync_list:
try:
# FIXME: Is it always product_id give as parameter ?
brain_node = tiosafe_sync.getObjectFromId(line.product_id)
resource_gid = brain_node.getGid()
break
except (ValueError, AttributeError):
resource_gid = None
if resource_gid is None:
resource_gid = self.getDefaultUnknownResourceGID()
for erp5_sync in erp5_sync_list:
try:
resource = erp5_sync.getDocumentFromGid(b16encode(resource_gid))
break
except (ValueError, AttributeError):
resource = None
# do not sync variations with the Unknown product
variation_sync = False
else:
# do not sync variations with delivery or discount
variation_sync = False
# work on delivery and discount transaction lines
resource_gid = resource_id = line.resource
try:
brain_node = tiosafe_sync.getObjectFromId(resource_id)
resource_gid = brain_node.getGid()
except (ValueError, AttributeError):
# case of default delivery/discount
if not 'Service' in resource_id:
resource_gid = ' Unknown'
LOG(
'Transaction, getting resource failed',
300,
'resource_id = %s, remains %s' % (resource_id, resource_gid),
)
pass
# through the type render the delivery or the discount
if line_type == 'Discount':
resource = integration_site.getSourceCarrierValue()
elif line_type == 'Delivery':
resource = integration_site.getDestinationCarrierValue()
else:
raise ValueError, 'Try to work on "%s" which is an invalid type.' % line_type
# after the work on the line set the resource value which will be
# render in the xml
movement_dict['resource'] = resource_gid
# browse line variations and set them to a list
getter_line_category_method = getattr(
module,
'get%sLineCategoryList' % method_id,
MARKER,
)
category_value_list = [getattr(line, 'category', ''), ]
# FIXME: variation are sync only on line with a product ?
# else don't sync variations for delivery, discount and Unknown prodcut
if variation_sync and \
getter_line_category_method is not MARKER:
parameter_kw = {
'%s_id' % portal_type: str(self.getId()),
'%s_line_id' % portal_type: str(line.getId()),
}
for brain in getter_line_category_method(**parameter_kw):
try:
category_value_list.append(
integration_site.getCategoryFromMapping(
brain.category,
resource,
)
)
except ValueError:
return None
# sort categories, build the sort key and set categoires in the dict
if len(category_value_list):
category_value_list.sort()
movement_dict['category'] = category_value_list
# build the element which allows to sort
movement_list.append(movement_dict)
# Sort the movement list for fix point
def cmp_resource(a,b):
a_str = "%s %s %s" %(a['resource'], a['title'], ' '.join(a['category']))
b_str = "%s %s %s" %(b['resource'], b['title'], ' '.join(b['category']))
return cmp(a_str, b_str)
movement_list.sort(cmp=cmp_resource)
# the second part build the XML of the transaction
# browse the ordered movement list and build the movement list as a result
# the xml through of the line data in the dict
for movement_dict in movement_list:
movement = etree.SubElement(transaction, 'movement')
# set arrow list on the movement
self._setArrowTagList(movement_dict['context'], movement)
# if exist the following tags in the line dict, add them in the xml
tag_list = ('resource', 'title', 'reference', 'quantity', 'price', 'VAT')
for tag in tag_list:
if tag in movement_dict:
element = etree.SubElement(movement, tag)
element.text = movement_dict[tag]
# add the categories to the movement
for category_value in movement_dict['category']:
if len(category_value):
category = etree.SubElement(movement, 'category')
category.text = category_value
xml = etree.tostring(transaction, pretty_print=True, encoding='utf-8')
LOG("Transactions asXML returns : %s" % (xml, ), 300, "")
return xml
# All the following classes has to be removed from the brain
# Use & improve abstract classes instead
# class Opportunity(TioSafeBrain):
# """
# This class allows to build the TioSafe XML of an Opportunity and to sync.
# """
# __allow_access_to_unprotected_subobjects__ = 1
# def asXML(self):
# """
# Generate the TioSafe Opportunity XML through the properties of an object.
# """
# resource = etree.Element('resource', reference=self.getGid())
# # list of possible tags for an product
# tag_list = (
# 'title', 'reference', 'source', 'account', 'campaign', 'probability',
# 'price',
# )
# self._setTags(self, resource, tag_list)
# self._setTags(self, resource, ['category', ], SEPARATOR)
# return etree.tostring(resource, pretty_print=True, encoding='utf-8')
# class Campaign(TioSafeBrain):
# """
# This class allows to build the TioSafe XML of an Camapign and to sync.
# """
# __allow_access_to_unprotected_subobjects__ = 1
# def asXML(self):
# """
# Generate the TioSafe Campaign XML through the properties of an object.
# """
# resource = etree.Element('resource', reference=self.getGid())
# # list of possible tags for an product
# tag_list = (
# 'title', 'reference', 'start_date', 'stop_date', 'source', 'price',
# 'description',
# )
# self._setTags(self, resource, tag_list)
# self._setTags(self, resource, ['category', ], SEPARATOR)
# return etree.tostring(resource, pretty_print=True, encoding='utf-8')
# # ########## Brain for TioSafe Transactions ########## #
# class Accounting(TioSafeBrain):
# """
# This class allows to build the TioSafe XML of an Accounting and to sync.
# """
# __allow_access_to_unprotected_subobjects__ = 1
# def getGid(self):
# """ Return the GID of the object. """
# # FIXME: Why we must remove -, / and : ???
# return self.gid.replace('-', '').replace('/', '').replace(':', '')
# def asXML(self):
# """
# Generate the TioSafe Accounting XML through the properties of an object.
# """
# transaction = etree.Element('transaction', reference=self.getGid())
# # list of possible tags for an accounting
# tag_list = (
# 'start_date', 'stop_date', 'reference', 'currency', 'causality',
# )
# self._setTags(self, transaction, tag_list)
# self._setTags(self, transaction, ['category', ], SEPARATOR)
# # set arrow list
# self._setArrowTagList(self, transaction)
# # add the movements list to the XML
# for element in self.accounting_line(id_accounting=self.getId()):
# movement = etree.SubElement(transaction, 'movement')
# # set arrow list
# self._setArrowTagList(element, movement)
# # list of possible tags for an accounting movement
# tag_list = ('title', 'resource', 'quantity', 'price', )
# self._setTags(element, movement, tag_list)
# self._setTags(element, movement, ['category', ], SEPARATOR)
# return etree.tostring(transaction, pretty_print=True, encoding='utf-8')
# # The brain of a Trasaction type: Event
# class Event(TioSafeBrain):
# """
# This is the Brain which works on Sale Orders.
# """
# __allow_access_to_unprotected_subobjects__ = 1
# def asXML(self):
# """
# Return the GID of the object.
# """
# # Declare the main xml node and build the first xml level
# event = etree.Element('event', reference=self.getGid())
# tag_list = (
# 'title', 'start_date', 'stop_date', 'reference', 'location',
# 'description', 'product', 'account',
# )
# self._setTags(self, event, tag_list)
# self._setTags(self, event, ['category', ], SEPARATOR)
# # Set arrows in the first xml level
# self._setArrowTagList(self, event)
# return etree.tostring(event, pretty_print=True, encoding='utf-8')
# # ########## WebService Brain ########## #
# class LastIdWebServiceBrain(TioSafeBrain, LastId):
# __allow_access_to_unprotected_subobjects__ = 1
# # ---------- SF ---------- #
# class PersonSalesforceBrain(TioSafeBrain, Node):
# __allow_access_to_unprotected_subobjects__ = 1
# def __init__(self, context, **kw):
# super(PersonSalesforceBrain, self).__init__(context, **kw)
# # add properties
# setattr(self, 'path', '%s/%s' % (context.getPath(), self.getId()))
# setattr(self, 'gid', 'Person %s %s' % (self.title, self.email))
# class EventSalesforceBrain(TioSafeBrain, Event):
# __allow_access_to_unprotected_subobjects__ = 1
# def __init__(self, context, **kw):
# super(EventSalesforceBrain, self).__init__(context, **kw)
# # Use person GIDs for source and destination, here context is the
# # integration site
# self.source = context.person_module(id=self.source)[0].getGid()
# self.destination = context.person_module(id=self.destination)[0].getGid()
# # add properties
# setattr(self, 'path', '%s/%s' % (context.getPath(), self.id))
# setattr(self, 'gid', 'Event %s %s %s' % (self.start_date, self.source, self.destination))
extension.erp5.TioSafeBrain.xml 0000664 0000000 0000000 00000006545 13456342174 0045250 0 ustar 00root root 0000000 0000000 erp5-b0d269b1f6f770be087f2139d81f05953d676c02-bt5-erp5_tiosafe_core/bt5/erp5_tiosafe_core/ExtensionTemplateItem/portal_components
-
default_reference
TioSafeBrain
-
id
extension.erp5.TioSafeBrain
-
portal_type
Extension Component
-
sid
-
version
erp5
-
workflow_history
AAAAAAAAAAI=
-
data
-
component_validation_workflow
AAAAAAAAAAM=
-
action
validate
-
actor
ERP5TypeTestCase
-
comment
-
time
-
validation_state
validated
extension.erp5.TioSafeDoNothingConduit.py 0000664 0000000 0000000 00000003302 13456342174 0047250 0 ustar 00root root 0000000 0000000 erp5-b0d269b1f6f770be087f2139d81f05953d676c02-bt5-erp5_tiosafe_core/bt5/erp5_tiosafe_core/ExtensionTemplateItem/portal_components ##############################################################################
#
# Copyright (c) 2010 Nexedi SA and Contributors. All Rights Reserved.
# Aurelien Calonne
#
# WARNING: This program as such is intended to be used by professional
# programmers who take the whole responsability of assessing all potential
# consequences resulting from its eventual inadequacies and bugs
# End users who are looking for a ready-to-use solution with commercial
# garantees and support are strongly adviced to contract a Free Software
# Service Company
#
# This program is Free Software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#
##############################################################################
from Products.ERP5TioSafe.Conduit.TioSafeBaseConduit import TioSafeBaseConduit
class TioSafeDoNothingConduit(TioSafeBaseConduit):
"""
This is the conduit use to do nothing
"""
def addNode(self, *args, **kw):
return {'conflict_list': [], 'object': None}
def updateNode(self, *args, **kw):
return []
def deleteNode(self, *args, **kw):
pass
extension.erp5.TioSafeDoNothingConduit.xml 0000664 0000000 0000000 00000006573 13456342174 0047435 0 ustar 00root root 0000000 0000000 erp5-b0d269b1f6f770be087f2139d81f05953d676c02-bt5-erp5_tiosafe_core/bt5/erp5_tiosafe_core/ExtensionTemplateItem/portal_components
-
default_reference
TioSafeDoNothingConduit
-
id
extension.erp5.TioSafeDoNothingConduit
-
portal_type
Extension Component
-
sid
-
version
erp5
-
workflow_history
AAAAAAAAAAI=
-
data
-
component_validation_workflow
AAAAAAAAAAM=
-
action
validate
-
actor
ERP5TypeTestCase
-
comment
-
time
-
validation_state
validated
extension.erp5.TioSafeNodeConduit.py 0000664 0000000 0000000 00000034423 13456342174 0046254 0 ustar 00root root 0000000 0000000 erp5-b0d269b1f6f770be087f2139d81f05953d676c02-bt5-erp5_tiosafe_core/bt5/erp5_tiosafe_core/ExtensionTemplateItem/portal_components # -*- coding: utf-8 -*-
##############################################################################
#
# Copyright (c) 2009 Nexedi SA and Contributors. All Rights Reserved.
# Hervé Poulain
#
# WARNING: This program as such is intended to be used by professional
# programmers who take the whole responsability of assessing all potential
# consequences resulting from its eventual inadequacies and bugs
# End users who are looking for a ready-to-use solution with commercial
# garantees and support are strongly adviced to contract a Free Software
# Service Company
#
# This program is Free Software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#
##############################################################################
from Products.ERP5TioSafe.Conduit.TioSafeBaseConduit import TioSafeBaseConduit
from Products.ERP5SyncML.Document.SyncMLConflict import SyncMLConflict as Conflict
from lxml import etree
class TioSafeNodeConduit(TioSafeBaseConduit):
"""
This is the conduit use to synchonize TioSafe Persons
"""
def __init__(self):
self.xml_object_tag = 'node'
def _createContent(self, xml=None, object=None, object_id=None, sub_object=None,
reset_local_roles=0, reset_workflow=0, simulate=0, **kw):
# if exist namespace retrieve only the tag
index = 0
if xml.nsmap not in [None, {}]:
index = -1
# this dict contains the element to set to the person
keyword = {}
address_list = []
# browse the xml
for node in xml:
# works on tags, no on comments
if type(node.tag) is not str:
continue
# Retrieve the tag
tag = node.tag.split('}')[index]
if tag == 'address':
# add the address
address_keyword = {}
for subnode in node.getchildren():
# through the mapping retrieve the country
if subnode.tag.split('{')[index] == 'country':
mapping = object.getMappingFromCategory('region/%s' % subnode.text)
country = mapping.split('/', 1)[-1]
address_keyword[subnode.tag.split('{')[index]] = country
else:
address_keyword[subnode.tag.split('{')[index]] = subnode.text
address_list.append(address_keyword)
else:
keyword[tag] = node.text
# Create person once all xml has bee browsed
object.person_module.createPerson(**keyword)
# XXX-AUREL : following call must be changed
new_id = object.IntegrationSite_lastID(type='Person')[0].getId()
# Then create addresses
for address_keyword in address_list:
object.person_module.createPersonAddress(person_id=str(new_id), **address_keyword)
return object.person_module(person_id=new_id)[0]
def _deleteContent(self, object=None, object_id=None):
object.person_module.deletePersonAddress(person_id=object_id)
object.person_module.deletePerson(person_id=object_id)
def _updateXupdateUpdate(self, document=None, xml=None, previous_xml=None, **kw):
"""
This method is called in updateNode and allows to work on the update of
elements.
"""
conflict_list = []
xpath_expression = xml.get('select')
tag = xpath_expression.split('/')[-1]
value = xml.text
# retrieve the previous xml etree through xpath
previous_xml = previous_xml.xpath(xpath_expression)
try:
previous_value = previous_xml[0].text
except IndexError:
raise IndexError, 'Too little or too many value, only one is required for %s' % (
previous_xml
)
# check if it'a work on person or on address
if tag in ['street', 'zip', 'city', 'country']:
try:
# work on the case: "/node/address[x]"
address_index = \
int(xpath_expression.split('address[')[-1].split(']')[0]) - 1
except ValueError:
# Work on the case: "/node/address"
address_index = 0
# build the address list
address_list = document.context.person_module.getPersonAddressList(
person_id=document.getId(),
)
# FIXME: Is the sort can be removed ???
# Build a list of tuple which contains :
# - first, the title build to realise the sort
# - the second element is the brain itself
sorted_address_list = [
(' '.join([address.street,
address.zip,
address.city,
address.country]),
address)
for address in address_list]
sorted_address_list.sort()
address_list = [t[1] for t in sorted_address_list]
try:
address = address_list[address_index]
except IndexError:
# create and fill a conflict when the integration site value, the erp5
# value and the previous value are differents
conflict = Conflict(
object_path=document.getPhysicalPath(),
keyword=tag,
)
conflict.setXupdate(etree.tostring(xml, encoding='utf-8'))
conflict.setLocalValue(None)
conflict.setRemoteValue(value)
conflict_list.append(conflict)
return conflict_list
current_value = getattr(address, tag, None)
if current_value not in [value, previous_value]:
# create and fill a conflict when the integration site value, the erp5
# value and the previous value are differents
conflict = Conflict(
object_path=document.getPhysicalPath(),
keyword=tag,
)
conflict.setXupdate(etree.tostring(xml, encoding='utf-8'))
conflict.setLocalValue(current_value)
conflict.setRemoteValue(value)
conflict_list.append(conflict)
else:
# set the keyword dict which defines what will be updated
keyword = {
'address_id': address.getId(),
'person_id': document.getId(),
}
if tag == 'country':
# through the mapping retrieve the country
mapping = document.context.getMappingFromCategory('region/%s' % value)
value = mapping.split('/', 1)[-1]
keyword[tag] = value
document.context.person_module.updatePersonAddress(**keyword)
else:
# getter used to retrieve the current values and to check conflicts
property_list = ['birthday', ]
getter_value_dict = dict([
(prop, getattr(document, prop))
for prop in property_list
if getattr(document, prop, None) is not None
])
# create and fill a conflict when the integration site value, the erp5
# value and the previous value are differents
current_value = getter_value_dict[tag]
if current_value not in [value, previous_value]:
conflict = Conflict(
object_path=document.getPhysicalPath(),
keyword=tag,
)
conflict.setXupdate(etree.tostring(xml, encoding='utf-8'))
conflict.setLocalValue(current_value)
conflict.setRemoteValue(value)
conflict_list.append(conflict)
else:
# XXX: when the DateTime format will be required to sync date
# - 1 - retrieve the format through the integration site
# - 2 - through using of DateTime build the date and render it
# if tag == 'birthday':
# integration_site = self.getIntegrationSite(kw.get('domain'))
# date_format = integration_site.getDateFormat()
# # build the required format
# format = dict_format[date_format] -> render "%Y/%m/%d", ...
# value = DateTime(value).strftime(format)
keyword = {'person_id': document.getId(), tag: value, }
document.context.person_module.updatePerson(**keyword)
return conflict_list
def _updateXupdateDel(self, document=None, xml=None, previous_xml=None, **kw):
""" This method is called in updateNode and allows to remove elements. """
conflict_list = []
tag = xml.get('select').split('/')[-1]
# this variable is used to retrieve the id of address and to not remove the
# orginal tag (address, street, zip, city or country)
tag_for_id = tag
# specific work for address and address elements
if tag.split('[')[0] in ['address', 'street', 'zip', 'city', 'country']:
# work on the good part of the xml to retrieve the address id
if tag_for_id.split('[')[0] != 'address':
tag_for_id = xml.get('select')
try:
# work on the case: "/node/address[x]"
address_index = int(tag_for_id.split('[')[-1].split(']')[0]) - 1
except ValueError:
# Work on the case: "/node/address"
address_index = 0
# build the address list
address_list = document.context.person_module.getPersonAddressList(
person_id=document.getId(),
)
# FIXME: Is the sort can be removed ???
# Build a list of tuple which contains :
# - first, the title build to realise the sort
# - the second element is the brain itself
sorted_address_list = [
(' '.join([
getattr(address, i, '')
for i in ['street', 'zip', 'city','country']]
), address)
for address in address_list
]
sorted_address_list.sort()
address_list = [t[1] for t in sorted_address_list]
try:
address = address_list[address_index]
except IndexError:
# create and fill a conflict when the integration site value, the erp5
# value and the previous value are differents
conflict = Conflict(
object_path=document.getPhysicalPath(),
keyword=tag,
)
conflict.setXupdate(etree.tostring(xml, encoding='utf-8'))
conflict.setLocalValue(None)
conflict_list.append(conflict)
return conflict_list
# remove the corresponding address or the element of the address
keyword = {'person_id': document.getId(), 'address_id': address.getId()}
if tag.split('[')[0] == 'address':
document.context.person_module.deletePersonAddress(**keyword)
else:
# set the keyword dict which defines what will be updated
keyword[tag] = 'NULL'
document.context.person_module.updatePersonAddress(**keyword)
else:
keyword = {'person_id': document.getId(), tag: 'NULL', }
document.context.person_module.updatePerson(**keyword)
# it always return conflict_list but it's empty
return conflict_list
def _updateXupdateInsertOrAdd(self, document=None, xml=None, previous_xml=None, **kw):
""" This method is called in updateNode and allows to add elements. """
conflict_list = []
for subnode in xml.getchildren():
tag = subnode.attrib['name']
value = subnode.text
if tag == 'address':
keyword = {'person_id': document.getId(), }
for subsubnode in subnode.getchildren():
if subsubnode.tag == 'country':
# through the mapping retrieve the country
keyword[subsubnode.tag] = document.context.getMappingFromCategory(
'region/%s' % subsubnode.text,
).split('/', 1)[-1]
else:
keyword[subsubnode.tag] = subsubnode.text
document.context.person_module.createPersonAddress(**keyword)
elif tag in ['street', 'zip', 'city', 'country']:
try:
# work on the case: "/node/address[x]"
address_index = int(xml.get('select').split('address[')[-1].split(']')[0]) - 1
except ValueError:
# Work on the case: "/node/address"
address_index = 0
# build the address list
address_list = document.context.person_module.getPersonAddressList(
person_id=document.getId(),
)
# FIXME: Is the sort can be removed ???
# Build a list of tuple which contains :
# - first, the title build to realise the sort
# - the second element is the brain itself
sorted_address_list = [
(' '.join([
getattr(address, i, '')
for i in ['street', 'zip', 'city','country']]
), address)
for address in address_list
]
sorted_address_list.sort()
address_list = [t[1] for t in sorted_address_list]
try:
address = address_list[address_index]
except IndexError:
# create and fill a conflict when the integration site value, the erp5
# value and the previous value are differents
conflict = Conflict(
object_path=document.getPhysicalPath(),
keyword=tag,
)
conflict.setXupdate(etree.tostring(xml, encoding='utf-8'))
conflict.setLocalValue(None)
conflict.setRemoteValue(value)
conflict_list.append(conflict)
return conflict_list
# set the keyword dict which defines what will be updated
keyword = {
'person_id': document.getId(),
'address_id': address.getId(),
}
if tag == 'country':
# through the mapping retrieve the country
mapping = document.context.getMappingFromCategory('region/%s' % value)
value = mapping.split('/', 1)[-1]
keyword[tag] = value
document.context.person_module.updatePersonAddress(**keyword)
else:
# XXX: when the DateTime format will be required to sync date
# - 1 - retrieve the format through the integration site
# - 2 - through using of DateTime build the date and render it
# if tag == 'birthday':
# integration_site = self.getIntegrationSite(kw.get('domain'))
# date_format = integration_site.getDateFormat()
# # build the required format
# format = dict_format[date_format] -> render "%Y/%m/%d", ...
# value = DateTime(value).strftime(format)
keyword = {'person_id': document.getId(), tag:value, }
document.context.person_module.updatePerson(**keyword)
return conflict_list
extension.erp5.TioSafeNodeConduit.xml 0000664 0000000 0000000 00000006561 13456342174 0046426 0 ustar 00root root 0000000 0000000 erp5-b0d269b1f6f770be087f2139d81f05953d676c02-bt5-erp5_tiosafe_core/bt5/erp5_tiosafe_core/ExtensionTemplateItem/portal_components
-
default_reference
TioSafeNodeConduit
-
id
extension.erp5.TioSafeNodeConduit
-
portal_type
Extension Component
-
sid
-
version
erp5
-
workflow_history
AAAAAAAAAAI=
-
data
-
component_validation_workflow
AAAAAAAAAAM=
-
action
validate
-
actor
ERP5TypeTestCase
-
comment
-
time
-
validation_state
validated
extension.erp5.TioSafeResourceConduit.py 0000664 0000000 0000000 00000033726 13456342174 0047163 0 ustar 00root root 0000000 0000000 erp5-b0d269b1f6f770be087f2139d81f05953d676c02-bt5-erp5_tiosafe_core/bt5/erp5_tiosafe_core/ExtensionTemplateItem/portal_components # -*- coding: utf-8 -*-
##############################################################################
#
# Copyright (c) 2009 Nexedi SA and Contributors. All Rights Reserved.
# Hervé Poulain
#
# WARNING: This program as such is intended to be used by professional
# programmers who take the whole responsability of assessing all potential
# consequences resulting from its eventual inadequacies and bugs
# End users who are looking for a ready-to-use solution with commercial
# garantees and support are strongly adviced to contract a Free Software
# Service Company
#
# This program is Free Software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#
##############################################################################
from Products.ERP5Type.Utils import cartesianProduct
from Products.ERP5TioSafe.Conduit.TioSafeBaseConduit import TioSafeBaseConduit
from Products.ERP5SyncML.Document.SyncMLConflict import SyncMLConflict as Conflict
from lxml import etree
from zLOG import LOG
class TioSafeResourceConduit(TioSafeBaseConduit):
"""
This is the conduit use to synchonize TioSafe Products
"""
def __init__(self):
self.xml_object_tag = 'resource'
def _createContent(self, xml=None, object=None, object_id=None, sub_object=None,
reset_local_roles=0, reset_workflow=0, simulate=0, **kw):
LOG("TioSafeNodeConduit._createConten", 300, "xml = %s" %(etree.tostring(xml, pretty_print=1),))
# if exist namespace retrieve only the tag
index = 0
if xml.nsmap not in [None, {}]:
index = -1
# init the new_id of the product and the checker of the creation
new_id = None
product_created = False
# this dict contains the element to set to the product
keyword = {}
# this dict will contains a list of tuple (base_category, vairiation)
variation_dict = {}
# browse the xml
for node in xml:
# works on tags, no on comments
if type(node.tag) is not str:
continue
tag = node.tag.split('}')[index]
LOG("browsing tag %s, value %s" %(tag, node.text), 300, "keyword = %s" %(keyword,))
if tag == 'category':
# retrieve through the mapping the base category and the variation
mapping = object.getMappingFromCategory(node.text)
base_category, variation = mapping.split('/', 1)
category_params = {
'document': object,
'base_category': base_category,
'variation': variation,
}
# if exists the variation set it to the builder dict
if self.checkCategoryExistency(**category_params):
variation_dict.setdefault(base_category, []).append(variation)
else:
keyword[tag] = node.text
# Create the product at the end of the xml browsing
object.product_module.createProduct(**keyword)
# XXX-AUREL : this must be changed to use gid definition instead
new_id = object.IntegrationSite_lastID(type='Product')[0].getId()
# create the full variations in the integration site
if variation_dict:
# the cartesianProduct requires to build a list of list of variations
builder_variation_list = []
for key, value in variation_dict.items():
variation_list = []
for variation in value:
variation_list.append((key, variation))
builder_variation_list.append(variation_list)
# build and browse the list of variations
variation_list = cartesianProduct(builder_variation_list)
for var_list in variation_list:
object.product_module.createProductAttribute(id_product=new_id)
id_product_attribute = object.IntegrationSite_lastID(
type='Product Attribute',
)[0].getId()
for variation in var_list:
object.product_module.createProductAttributeCombination(
id_product_attribute=id_product_attribute,
id_product=new_id,
base_category=variation[0],
variation=variation[1],
)
return object.product_module(id=new_id)[0]
def checkCategoryExistency(self, document, **kw):
"""
This method allows to check the category existency in the integration
site.
It coulds create the element required to the calling of the category
creation.
"""
# retrieve from the kw dict the base, the variation and the id_product
variation = kw.get('variation')
base_category = kw.get('base_category')
id_product = kw.get('id_product')
# Check the base_category -> raise if not exists (base_category not mapped)
# Done in Document/IntegrationSite.py into method getMappingFromCategory
# Check the variation ->
# raise if multiple
# raise if not exists or create it ?
variation_list = document.IntegrationSite_checkCategoryExistency(
variation=variation,
base_category=base_category,
)
if not variation_list:
# TODO: is it requires to create the variation in the integration site ?
pass
elif len(variation_list) > 1:
raise "Variation %s/%s counted %d time(s) in the Integration Site" % (
base_category,
variation,
len(variation_list),
)
return True
def _deleteContent(self, object=None, object_id=None):
""" This method allows to remove a product in the integration site """
return object.product_module.deleteProduct(product_id=object_id)
def _updateXupdateUpdate(self, document=None, xml=None, previous_xml=None, **kw):
"""
This method is called in updateNode and allows to work on the update of
elements.
"""
conflict_list = []
xpath_expression = xml.get('select')
tag = xpath_expression.split('/')[-1]
integration_site = document.context.getParentValue()
new_value = xml.text
# retrieve the previous xml etree through xpath
previous_xml = previous_xml.xpath(xpath_expression)
try:
previous_value = previous_xml[0].text
except IndexError:
raise ValueError, 'Too little or too many value, only one is required for %s' % (
previous_xml
)
# check if it'a work on product or on categories
if tag.split('[')[0] == 'category':
# init the base category and the variation through the mapping
mapping = integration_site.getMappingFromCategory(new_value)
base_category, variation = mapping.split('/', 1)
updated = False
# init the previous value through the mapping
previous_value = integration_site.getMappingFromCategory(previous_value)
# work on variations
variation_brain_list = document.context.getProductCategoryList()
for brain in variation_brain_list:
if brain.category == previous_value:
old_base_category, old_variation = previous_value.split('/', 1)
# remove all variations
document.context.product_module.deleteProductAttributeCombination(
product_id=document.getId(),
base_category=old_base_category,
variation=old_variation,
)
# retrieve the variations which have a different axe from the updated
# and build the cartesian variation for this new variations
external_axe_list = [
tuple(x.category.split('/', 1))
for x in document.context.getProductCategoryList()
if x.category.split('/', 1)[0] != brain.category.split('/', 1)[0]
]
builder_variation_list = [
[tuple(mapping.split('/', 1))], external_axe_list,
]
variation_list = cartesianProduct(builder_variation_list)
for var_list in variation_list:
document.context.product_module.createProductAttribute(
id_product=document.getId(),
)
id_product_attribute = document.context.IntegrationSite_lastID(
type='Product Attribute',
)[0].getId()
for variation in var_list:
document.context.product_module.createProductAttributeCombination(
id_product_attribute=id_product_attribute,
id_product=document.getId(),
base_category=variation[0],
variation=variation[1],
)
else:
# previous value not find, so multiple update on the same product
conflict = Conflict(
object_path=document.getPhysicalPath(),
keyword=tag,
)
conflict.setXupdate(etree.tostring(xml, encoding='utf-8'))
conflict.setLocalValue(previous_value)
conflict.setRemoteValue(new_value)
conflict_list.append(conflict)
else:
# getter used to retrieve the current values and to check conflicts
property_list = ['sale_price', 'purchase_price', 'ean13']
getter_value_dict = dict(zip(
property_list, [
getattr(document, prop, None)
for prop in property_list
]
))
# create and fill a conflict when the integration site value, the erp5
# value and the previous value are differents
current_value = getter_value_dict[tag]
if type(current_value) == float:
current_value = '%.6f' % current_value
if current_value not in [new_value, previous_value]:
conflict = Conflict(
object_path=document.getPhysicalPath(),
keyword=tag,
)
conflict.setXupdate(etree.tostring(xml, encoding='utf-8'))
conflict.setLocalValue(current_value)
conflict.setRemoteValue(new_value)
conflict_list.append(conflict)
else:
keyword = {'product_id': document.getId(), tag: new_value , }
document.context.product_module.updateProduct(**keyword)
return conflict_list
def _updateXupdateDel(self, document=None, xml=None, previous_xml=None, **kw):
""" This method is called in updateNode and allows to remove elements. """
conflict_list = []
tag = xml.get('select').split('/')[-1]
integration_site = document.context.getParentValue()
if tag.split('[')[0] == 'category':
# retrieve the previous xml etree through xpath
previous_xml = previous_xml.xpath(tag)
try:
previous_value = integration_site.getMappingFromCategory(
previous_xml[0].text,
)
except IndexError:
raise IndexError, 'Too little or too many value, only one is required for %s' % (
previous_xml
)
# retrieve the current value to check if exists a conflict
current_value = etree.XML(document.asXML()).xpath(tag)[0].text
current_value = integration_site.getMappingFromCategory(current_value)
# work on variations
variation_brain_list = document.context.getProductCategoryList(product_id=document.getId())
for brain in variation_brain_list:
if brain.category == current_value and previous_value == current_value:
base_category, variation = current_value.split('/', 1)
document.context.product_module.deleteProductAttributeCombination(
product_id=document.getId(),
base_category=base_category,
variation=variation,
)
else:
# previous value different from current value
conflict = Conflict(
object_path=document.getPhysicalPath(),
keyword=tag,
)
conflict.setXupdate(etree.tostring(xml, encoding='utf-8'))
conflict.setLocalValue(previous_value)
conflict.setRemoteValue(current_value)
conflict_list.append(conflict)
else:
keyword = {'product_id': document.getId(), tag: 'NULL' , }
document.context.product_module.updateProduct(**keyword)
return conflict_list
def _updateXupdateInsertOrAdd(self, document=None, xml=None, previous_xml=None, **kw):
""" This method is called in updateNode and allows to add elements. """
conflict_list = []
integration_site = document.context.getParentValue()
# browse subnode of the insert and check what will be create
for subnode in xml.getchildren():
new_tag = subnode.attrib['name']
new_value = subnode.text.encode('utf-8')
if new_tag == 'category':
mapping = integration_site.getMappingFromCategory(new_value)
base_category, variation = mapping.split('/', 1)
# retrieve the variations which have a different axe from the updated
# and build the cartesian variation for this new variations
external_axe_list = [
tuple(x.category.split('/', 1))
for x in document.context.getProductCategoryList()
if x.category.split('/', 1)[0] != base_category
]
builder_variation_list = [
[(base_category, variation)], external_axe_list,
]
variation_list = cartesianProduct(builder_variation_list)
for var_list in variation_list:
document.context.product_module.createProductAttribute(
id_product=document.getId(),
)
id_product_attribute = document.context.IntegrationSite_lastID(
type='Product Attribute',
)[0].getId()
for variation in var_list:
document.context.product_module.createProductAttributeCombination(
id_product_attribute=id_product_attribute,
id_product=document.getId(),
base_category=variation[0],
variation=variation[1],
)
else:
keyword = {'product_id': document.getId(), new_tag: new_value, }
document.context.product_module.updateProduct(**keyword)
return conflict_list
extension.erp5.TioSafeResourceConduit.xml 0000664 0000000 0000000 00000006571 13456342174 0047331 0 ustar 00root root 0000000 0000000 erp5-b0d269b1f6f770be087f2139d81f05953d676c02-bt5-erp5_tiosafe_core/bt5/erp5_tiosafe_core/ExtensionTemplateItem/portal_components
-
default_reference
TioSafeResourceConduit
-
id
extension.erp5.TioSafeResourceConduit
-
portal_type
Extension Component
-
sid
-
version
erp5
-
workflow_history
AAAAAAAAAAI=
-
data
-
component_validation_workflow
AAAAAAAAAAM=
-
action
validate
-
actor
ERP5TypeTestCase
-
comment
-
time
-
validation_state
validated
extension.erp5.TioSafeTool.py 0000664 0000000 0000000 00000004606 13456342174 0044756 0 ustar 00root root 0000000 0000000 erp5-b0d269b1f6f770be087f2139d81f05953d676c02-bt5-erp5_tiosafe_core/bt5/erp5_tiosafe_core/ExtensionTemplateItem/portal_components ##############################################################################
#
# Copyright (c) 2002-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.
#
##############################################################################
from lxml import etree
from Products.ERP5SyncML.XMLSyncUtils import getConduitByName
from difflib import unified_diff
from Products.ERP5Type.DiffUtils import DiffFile
def callAddNodeOnConduit(self, conduit_id, uid):
obj = self.getPortalObject().portal_catalog.getObject(uid)
conduit = getConduitByName(conduit_id)
if obj.getPortalType() in ('Person', 'Organisation'):
xml = obj.Node_asTioSafeXML()
elif obj.getPortalType() in ('Product', 'Service'):
xml = obj.Resource_asTioSafeXML()
conduit.addNode(xml=etree.fromstring(xml), object=self)
def diffXML(xml_plugin="", xml_erp5="", html=True):
if isinstance(xml_erp5, unicode):
xml_erp5 = xml_erp5.encode('utf-8')
if isinstance(xml_plugin, unicode):
xml_plugin = xml_plugin.encode('utf-8')
diff_list = list(unified_diff(xml_plugin.split('\n'), xml_erp5.split('\n'), tofile="erp5 xml", fromfile="plugin xml", lineterm=''))
if len(diff_list) != 0:
diff_msg = '\n\nTioSafe XML Diff :\n'
diff_msg += '\n'.join(diff_list)
if html:
return DiffFile(diff_msg).toHTML()
return diff_msg
else:
return 'No diff'
extension.erp5.TioSafeTool.xml 0000664 0000000 0000000 00000006543 13456342174 0045130 0 ustar 00root root 0000000 0000000 erp5-b0d269b1f6f770be087f2139d81f05953d676c02-bt5-erp5_tiosafe_core/bt5/erp5_tiosafe_core/ExtensionTemplateItem/portal_components
-
default_reference
TioSafeTool
-
id
extension.erp5.TioSafeTool
-
portal_type
Extension Component
-
sid
-
version
erp5
-
workflow_history
AAAAAAAAAAI=
-
data
-
component_validation_workflow
AAAAAAAAAAM=
-
action
validate
-
actor
ERP5TypeTestCase
-
comment
-
time
-
validation_state
validated
PortalTypeAllowedContentTypeTemplateItem/ 0000775 0000000 0000000 00000000000 13456342174 0037407 5 ustar 00root root 0000000 0000000 erp5-b0d269b1f6f770be087f2139d81f05953d676c02-bt5-erp5_tiosafe_core/bt5/erp5_tiosafe_core allowed_content_types.xml 0000664 0000000 0000000 00000002106 13456342174 0044535 0 ustar 00root root 0000000 0000000 erp5-b0d269b1f6f770be087f2139d81f05953d676c02-bt5-erp5_tiosafe_core/bt5/erp5_tiosafe_core/PortalTypeAllowedContentTypeTemplateItem
- Integration Category Mapping
- Integration Base Property Mapping
- Integration Property Mapping
- Integration Category Mapping
- Python Script
- Web Service Request
- Web Service Request Group
- Integration Property Mapping
- Integration Base Category Mapping
- Integration Base Property Mapping
- Integration Module
- Web Service Connector
- Web Service Request
- Web Service Request Group
- Integration Site