This is an automated email from the ASF dual-hosted git repository. nmalin pushed a commit to branch trunk in repository https://gitbox.apache.org/repos/asf/ofbiz-framework.git
commit 95f0eda361ffe730cb8e960ea30e2a4fed720d36 Author: Sebastian Berg <sebastian.b...@ecomify.de> AuthorDate: Fri Apr 17 12:04:25 2020 +0200 Improved: Convert LeadServices.xml mini lang to groovy (OFBIZ-11572) --- .../groovyScripts/sfa/lead/LeadServices.groovy | 201 +++++++++++++++++++ .../marketing/minilang/sfa/lead/LeadServices.xml | 221 --------------------- applications/marketing/servicedef/services.xml | 4 +- .../party/minilang/party/PartySimpleMethods.xml | 1 + applications/party/servicedef/services.xml | 12 +- 5 files changed, 215 insertions(+), 224 deletions(-) diff --git a/applications/marketing/groovyScripts/sfa/lead/LeadServices.groovy b/applications/marketing/groovyScripts/sfa/lead/LeadServices.groovy new file mode 100644 index 0000000..9480ecf --- /dev/null +++ b/applications/marketing/groovyScripts/sfa/lead/LeadServices.groovy @@ -0,0 +1,201 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import java.sql.Timestamp + +import org.apache.ofbiz.base.util.StringUtil +import org.apache.ofbiz.base.util.UtilDateTime +import org.apache.ofbiz.base.util.UtilProperties +import org.apache.ofbiz.entity.GenericValue +import org.apache.ofbiz.minilang.SimpleMapProcessor +import org.apache.ofbiz.service.GenericServiceException +import org.apache.ofbiz.service.ServiceUtil + +def createLead() { + String leadContactPartyId + String partyGroupPartyId + // Check if Person or PartyGroup name is supplied + if ((!parameters.firstName || !parameters.lastName) && !parameters.groupName) { + return error(UtilProperties.getMessage("MarketingUiLabels", + "SfaFirstNameLastNameAndCompanyNameMissingError", locale)) + } + run service: "ensurePartyRole", with: [partyId: userLogin.partyId, + roleTypeId: "OWNER"] + // PartyRole check end + parameters.roleTypeId = "LEAD" + + Map serviceResult = run service: "createPersonRoleAndContactMechs", with: parameters + if (ServiceUtil.isError(serviceResult)) { + return serviceResult + } + leadContactPartyId = serviceResult.partyId + serviceResult = run service: "createPartyRelationship", with: [partyIdFrom: userLogin.partyId, + partyIdTo: leadContactPartyId, + roleTypeIdFrom: "OWNER", + roleTypeIdTo: "LEAD", + partyRelationshipTypeId: "LEAD_OWNER"] + if (ServiceUtil.isError(serviceResult)) { + return serviceResult + } + run service: "setPartyStatus", with: [partyId: leadContactPartyId, + statusId: "LEAD_ASSIGNED"] + + // Now create PartyGroup corresponding to the companyName, if its not null and then set up + // relationship of Person and PartyGroup as Employee and title + parameters.partyTypeId = "PARTY_GROUP" + if (!leadContactPartyId) { + parameters.roleTypeId = "ACCOUNT_LEAD" + // In case we have any contact mech data then associate with party group + serviceResult = run service: "createPartyGroupRoleAndContactMechs", with: parameters + if (ServiceUtil.isError(serviceResult)) { + return serviceResult + } + partyGroupPartyId = serviceResult.partyId + run service: "setPartyStatus", with: [partyId: partyGroupPartyId, + statusId: "LEAD_ASSIGNED"] + } else { + serviceResult = run service: "createPartyGroup", with: resolvePartyProcessMap() + if (ServiceUtil.isError(serviceResult)) { + return serviceResult + } + partyGroupPartyId = serviceResult.partyId + serviceResult = run service: "createPartyRole", with: [partyId: partyGroupPartyId, + roleTypeId: "ACCOUNT_LEAD"] + if (ServiceUtil.isError(serviceResult)) { + return serviceResult + } + } + if (leadContactPartyId) { + run service: "createPartyRelationship", with: [partyIdFrom: partyGroupPartyId, + partyIdTo: leadContactPartyId, + roleTypeIdFrom: "ACCOUNT_LEAD", + roleTypeIdTo: "LEAD", + positionTitle: parameters.title, + partyRelationshipTypeId: "EMPLOYMENT"] + } + run service: "createPartyRelationship", with: [partyIdFrom: userLogin.partyId, + partyIdTo: partyGroupPartyId, + roleTypeIdFrom: "OWNER", + roleTypeIdTo: "ACCOUNT_LEAD", + partyRelationshipTypeId: "LEAD_OWNER"] + + if (parameters.dataSourceId) { + serviceResult = run service: "createPartyDataSource", with: [partyId: leadContactPartyId, + dataSourceId: parameters.dataSourceId] + if (ServiceUtil.isError(serviceResult)) { + return serviceResult + } + } + Map result = success() + result.partyId = leadContactPartyId + result.partyGroupPartyId = partyGroupPartyId + result.roleTypeId = parameters.roleTypeId + result.successMessage = UtilProperties.getMessage("MarketingUiLabels", "SfaLeadCreatedSuccessfully", locale) + return result +} + +/** + * Convert a lead person into a contact and associated lead group to an account + * @return + */ +def convertLeadToContact() { + String partyId = parameters.partyId + String partyGroupId = parameters.partyGroupId + Timestamp nowTimestamp = UtilDateTime.nowTimestamp() + + GenericValue partyRelationship = from("PartyRelationship") + .where(partyIdTo: partyId, + roleTypeIdFrom: "OWNER", + roleTypeIdTo: "LEAD", + partyRelationshipTypeId: "LEAD_OWNER") + .filterByDate() + .orderBy("-fromDate") + .queryFirst() + if (partyRelationship) { + partyRelationship.thruDate = nowTimestamp + run service: "updatePartyRelationship", with: partyRelationship.getAllFields() + logInfo("Expiring relationship ${partyRelationship}") + } + + // Expire relation between lead company and lead person + partyRelationship = from("PartyRelationship") + .where(partyIdFrom: partyGroupId, roleTypeIdTo: "LEAD", roleTypeIdFrom: "ACCOUNT_LEAD", partyRelationshipTypeId: "EMPLOYMENT") + .filterByDate() + .orderBy("-fromDate") + .queryFirst() + if (partyRelationship) { + partyRelationship.thruDate = nowTimestamp + run service: "updatePartyRelationship", with: partyRelationship.getAllFields() + } + + // Expire relation between lead company and its owner + partyRelationship = from("PartyRelationship") + .where(partyIdFrom: userLogin.partyId, partyIdTo: partyGroupId, roleTypeIdTo: "ACCOUNT_LEAD", roleTypeIdFrom: "OWNER") + .filterByDate() + .orderBy("-fromDate") + .queryFirst() + if (partyRelationship) { + partyRelationship.thruDate = nowTimestamp + run service: "updatePartyRelationship", with: partyRelationship.getAllFields() + } + + run service: "ensurePartyRole", with: [partyId: partyGroupId, + roleTypeId: "ACCOUNT"] + + run service: "createPartyRelationship", with: [partyIdFrom: userLogin.partyId, + partyIdTo: partyGroupId, + roleTypeIdFrom: "OWNER", + roleTypeIdTo: "ACCOUNT", + partyRelationshipTypeId: "ACCOUNT"] + + run service: "setPartyStatus", with: [partyId: partyGroupId, + statusId: "LEAD_CONVERTED"] + + run service: "createPartyRole", with: [partyId: partyId, + roleTypeId: "CONTACT"] + + // create new relationship between new account and contact person there + run service: "createPartyRelationship", with: [partyIdFrom: partyGroupId, + roleTypeIdFrom: "ACCOUNT", + partyIdTo: partyId, + roleTypeIdTo: "CONTACT", + partyRelationshipTypeId: "EMPLOYMENT"] + + run service: "setPartyStatus", with: [partyId: partyId, + statusId: "LEAD_CONVERTED"] + + Map result = success() + result.partyId = partyId + result.partyGroupId = partyGroupId + result.successMessage = "Lead ${partyGroupId} ${partyId} succesfully converted to Account/Contact" + return result +} + +def resolvePartyProcessMap() { + List messages = [] + Map resultMap = [:] + //TODO convert map processor + SimpleMapProcessor.runSimpleMapProcessor('component://party/minilang/party/PartyMapProcs.xml', + 'partyGroup', parameters, resultMap, messages, context.locale) + // Check errors + if (messages) { + throw new GenericServiceException(messages.join(',')) + } + return resultMap +} \ No newline at end of file diff --git a/applications/marketing/minilang/sfa/lead/LeadServices.xml b/applications/marketing/minilang/sfa/lead/LeadServices.xml deleted file mode 100644 index d235fa3..0000000 --- a/applications/marketing/minilang/sfa/lead/LeadServices.xml +++ /dev/null @@ -1,221 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<!-- - Licensed to the Apache Software Foundation (ASF) under one - or more contributor license agreements. See the NOTICE file - distributed with this work for additional information - regarding copyright ownership. The ASF licenses this file - to you under the Apache License, Version 2.0 (the - "License"); you may not use this file except in compliance - with the License. You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, - software distributed under the License is distributed on an - "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - KIND, either express or implied. See the License for the - specific language governing permissions and limitations - under the License. ---> - -<simple-methods xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" - xmlns="http://ofbiz.apache.org/Simple-Method" xsi:schemaLocation="http://ofbiz.apache.org/Simple-Method http://ofbiz.apache.org/dtds/simple-methods.xsd"> - - <simple-method method-name="createLead" short-description=""> - <!-- Check if Person or PartyGroup name is supplied --> - <if> - <condition> - <and> - <or> - <if-empty field="parameters.firstName"/> - <if-empty field="parameters.lastName"/> - </or> - <if-empty field="parameters.groupName"/> - </and> - </condition> - <then> - <add-error><fail-property resource="MarketingUiLabels" property="SfaFirstNameLastNameAndCompanyNameMissingError"/></add-error> - </then> - </if> - <check-errors/> - <set field="ensurePartyRoleCtx.partyId" from-field="userLogin.partyId"/> - <set field="ensurePartyRoleCtx.roleTypeId" value="OWNER"/> - - <call-service service-name="ensurePartyRole" in-map-name="ensurePartyRoleCtx"/> - <!-- PartyRole check end --> - - <if> - <condition> - <and> - <not><if-empty field="parameters.firstName"/></not> - <not><if-empty field="parameters.lastName"/></not> - </and> - </condition> - <then> - <set field="parameters.roleTypeId" value="LEAD"/> - <call-simple-method method-name="createPersonRoleAndContactMechs" xml-resource="component://party/minilang/party/PartySimpleMethods.xml"/> - <check-errors/> - - <set field="leadContactPartyId" from-field="partyId"/> - <clear-field field="partyId"/> - <set field="partyRelationshipCtx.partyIdFrom" from-field="userLogin.partyId"/> - <set field="partyRelationshipCtx.partyIdTo" from-field="leadContactPartyId"/> - <set field="partyRelationshipCtx.roleTypeIdFrom" value="OWNER"/> - <set field="partyRelationshipCtx.roleTypeIdTo" value="LEAD"/> - <set field="partyRelationshipCtx.partyRelationshipTypeId" value="LEAD_OWNER"/> - <call-service service-name="createPartyRelationship" in-map-name="partyRelationshipCtx"/> - <check-errors/> - - <set field="updatePartyStatusCtx.partyId" from-field="leadContactPartyId"/> - <set field="updatePartyStatusCtx.statusId" value="LEAD_ASSIGNED"/> - <call-service service-name="setPartyStatus" in-map-name="updatePartyStatusCtx"/> - </then> - </if> - <!-- Now create PartyGroup corresponding to the companyName, if its not null and then set up relationship of Person and PartyGroup as Employee and title --> - <if-not-empty field="parameters.groupName"> - <set field="parameters.partyTypeId" value="PARTY_GROUP"/> - <if-empty field="leadContactPartyId"> - <set field="parameters.roleTypeId" value="ACCOUNT_LEAD"/> - <!-- In case we have any contact mech data then associate with party group --> - <call-simple-method method-name="createPartyGroupRoleAndContactMechs" xml-resource="component://party/minilang/party/PartySimpleMethods.xml"/> - <set field="partyGroupPartyId" from-field="partyId"/> - <clear-field field="partyId"/> - - <set field="updatePartyStatusCtx.partyId" from-field="partyGroupPartyId"/> - <set field="updatePartyStatusCtx.statusId" value="LEAD_ASSIGNED"/> - <call-service service-name="setPartyStatus" in-map-name="updatePartyStatusCtx"/> - - <else> - <call-map-processor processor-name="partyGroup" in-map-name="parameters" out-map-name="partyGroupCtx" - xml-resource="component://party/minilang/party/PartyMapProcs.xml"/> - <call-service service-name="createPartyGroup" in-map-name="partyGroupCtx"> - <result-to-field result-name="partyId" field="partyGroupPartyId"/> - </call-service> - <set field="createPartyRoleCtx.partyId" from-field="partyGroupPartyId"/> - <set field="createPartyRoleCtx.roleTypeId" value="ACCOUNT_LEAD"/> - <call-service service-name="createPartyRole" in-map-name="createPartyRoleCtx"/> - <check-errors/> - </else> - </if-empty> - - <if-not-empty field="leadContactPartyId"> - <set field="partyRelationshipCtx.partyIdFrom" from-field="partyGroupPartyId"/> - <set field="partyRelationshipCtx.partyIdTo" from-field="leadContactPartyId"/> - <set field="partyRelationshipCtx.roleTypeIdFrom" value="ACCOUNT_LEAD"/> - <set field="partyRelationshipCtx.roleTypeIdTo" value="LEAD"/> - <set field="partyRelationshipCtx.positionTitle" from-field="parameters.title"/> - <set field="partyRelationshipCtx.partyRelationshipTypeId" value="EMPLOYMENT"/> - <call-service service-name="createPartyRelationship" in-map-name="partyRelationshipCtx"/> - </if-not-empty> - <set field="partyRelationshipCtx.partyIdFrom" from-field="userLogin.partyId"/> - <set field="partyRelationshipCtx.partyIdTo" from-field="partyGroupPartyId"/> - <set field="partyRelationshipCtx.roleTypeIdFrom" value="OWNER"/> - <set field="partyRelationshipCtx.roleTypeIdTo" value="ACCOUNT_LEAD"/> - <set field="partyRelationshipCtx.partyRelationshipTypeId" value="LEAD_OWNER"/> - <call-service service-name="createPartyRelationship" in-map-name="partyRelationshipCtx"/> - </if-not-empty> - <if-not-empty field="parameters.dataSourceId"> - <set field="partyDataSourceCtx.partyId" from-field="leadContactPartyId"/> - <set field="partyDataSourceCtx.dataSourceId" from-field="parameters.dataSourceId"/> - <call-service service-name="createPartyDataSource" in-map-name="partyDataSourceCtx"/> - <check-errors/> - </if-not-empty> - <field-to-result field="leadContactPartyId" result-name="partyId" /> - <field-to-result field="partyGroupPartyId"/> - <field-to-result field="parameters.roleTypeId" result-name="roleTypeId"/> - <property-to-field resource="MarketingUiLabels" property="SfaLeadCreatedSuccessfully" field="successMessage"/> - </simple-method> - - <simple-method method-name="convertLeadToContact" short-description="Convert a lead person into a contact and associated lead group to an account"> - <set field="partyId" from-field="parameters.partyId"/> - <set field="partyGroupId" from-field="parameters.partyGroupId"/> - <now-timestamp field="nowTimestamp"/> - <entity-and entity-name="PartyRelationship" list="partyRelationships" filter-by-date="true"> - <field-map field-name="partyIdTo" from-field="partyId"/> - <field-map field-name="roleTypeIdFrom" value="OWNER"/> - <field-map field-name="roleTypeIdTo" value="LEAD"/> - <field-map field-name="partyRelationshipTypeId" value="LEAD_OWNER"/> - <order-by field-name="-fromDate"/> - </entity-and> - <first-from-list list="partyRelationships" entry="partyRelationship"/> - <if-not-empty field="partyRelationship"> - <set-service-fields service-name="updatePartyRelationship" map="partyRelationship" to-map="deletePartyRelationship"/> - <set from-field="nowTimestamp" field="deletePartyRelationship.thruDate"/> - <call-service service-name="updatePartyRelationship" in-map-name="deletePartyRelationship"/> - <log level="info" message="Expiring relationship ${deletePartyRelationship}"/> - <clear-field field="deletePartyRelationship"/> - <clear-field field="partyRelationship"/> - </if-not-empty> - - <!-- Expire relation between lead company and lead person --> - <entity-and entity-name="PartyRelationship" list="partyRelationships" filter-by-date="true"> - <field-map field-name="partyIdFrom" from-field="partyGroupId"/> - <field-map field-name="roleTypeIdTo" value="LEAD"/> - <field-map field-name="roleTypeIdFrom" value="ACCOUNT_LEAD"/> - <field-map field-name="partyRelationshipTypeId" value="EMPLOYMENT"/> - <order-by field-name="-fromDate"/> - </entity-and> - - <first-from-list list="partyRelationships" entry="partyRelationship"/> - <if-not-empty field="partyRelationship"> - <set-service-fields service-name="updatePartyRelationship" map="partyRelationship" to-map="deletePartyRelationship"/> - <set from-field="nowTimestamp" field="deletePartyRelationship.thruDate"/> - <call-service service-name="updatePartyRelationship" in-map-name="deletePartyRelationship"/> - <clear-field field="deletePartyRelationship"/> - <clear-field field="partyRelationship"/> - </if-not-empty> - - <!-- Expire relation between lead company and its owner --> - <entity-and entity-name="PartyRelationship" list="partyRelationships" filter-by-date="true"> - <field-map field-name="partyIdFrom" from-field="userLogin.partyId"/> - <field-map field-name="partyIdTo" from-field="partyGroupId"/> - <field-map field-name="roleTypeIdTo" value="ACCOUNT_LEAD"/> - <field-map field-name="roleTypeIdFrom" value="OWNER"/> - <order-by field-name="-fromDate"/> - </entity-and> - <first-from-list list="partyRelationships" entry="partyRelationship"/> - <if-not-empty field="partyRelationship"> - <set-service-fields service-name="updatePartyRelationship" map="partyRelationship" to-map="deletePartyRelationship"/> - <set from-field="nowTimestamp" field="deletePartyRelationship.thruDate"/> - <call-service service-name="updatePartyRelationship" in-map-name="deletePartyRelationship"/> - <clear-field field="deletePartyRelationship"/> - <clear-field field="partyRelationship"/> - </if-not-empty> - - <set field="partyRoleCtx.partyId" from-field="partyGroupId"/> - <set field="partyRoleCtx.roleTypeId" value="ACCOUNT"/> - <call-service service-name="ensurePartyRole" in-map-name="partyRoleCtx"/> - - <set field="partyRelationshipCtx.partyIdFrom" from-field="userLogin.partyId"/> - <set field="partyRelationshipCtx.partyIdTo" from-field="partyGroupId"/> - <set field="partyRelationshipCtx.roleTypeIdFrom" value="OWNER"/> - <set field="partyRelationshipCtx.roleTypeIdTo" value="ACCOUNT"/> - <set field="partyRelationshipCtx.partyRelationshipTypeId" value="ACCOUNT"/> - <call-service service-name="createPartyRelationship" in-map-name="partyRelationshipCtx"/> - <clear-field field="partyRelationshipCtx"/> - - <set field="updatePartyCtx.partyId" from-field="partyGroupId"/> - <set field="updatePartyCtx.statusId" value="LEAD_CONVERTED"/> - <call-service service-name="setPartyStatus" in-map-name="updatePartyCtx"/> - - <set field="createPartyRoleCtx.partyId" from-field="partyId"/> - <set field="createPartyRoleCtx.roleTypeId" value="CONTACT"/> - <call-service service-name="createPartyRole" in-map-name="createPartyRoleCtx"/> - <!-- create new relationship between new account and contact person there --> - <set field="partyRelationshipCtx.partyIdFrom" from-field="partyGroupId"/> - <set field="partyRelationshipCtx.roleTypeIdFrom" value="ACCOUNT"/> - <set field="partyRelationshipCtx.partyIdTo" from-field="partyId"/> - <set field="partyRelationshipCtx.roleTypeIdTo" value="CONTACT"/> - <set field="partyRelationshipCtx.partyRelationshipTypeId" value="EMPLOYMENT"/> - <call-service service-name="createPartyRelationship" in-map-name="partyRelationshipCtx"/> - - <clear-field field="partyRelationshipCtx"/> - <set field="updatePartyCtx.partyId" from-field="partyId"/> - <set field="updatePartyCtx.statusId" value="LEAD_CONVERTED"/> - <call-service service-name="setPartyStatus" in-map-name="updatePartyCtx"/> - - <field-to-result field="partyId"/> - <field-to-result field="partyGroupId"/> - <set field="successMessage" value="Lead ${partyGroupId} ${partyId} succesfully converted to Account/Contact"/> - </simple-method> -</simple-methods> diff --git a/applications/marketing/servicedef/services.xml b/applications/marketing/servicedef/services.xml index ec5d244..28a646b 100644 --- a/applications/marketing/servicedef/services.xml +++ b/applications/marketing/servicedef/services.xml @@ -481,7 +481,7 @@ under the License. </service> <!-- lead services --> - <service name="createLead" engine="simple" location="component://marketing/minilang/sfa/lead/LeadServices.xml" invoke="createLead"> + <service name="createLead" engine="groovy" location="component://marketing/groovyScripts/sfa/lead/LeadServices.groovy" invoke="createLead"> <description> Sales Lead can be just a person or a person representing a company or a company (party group). createLead works 1) If person information is passed. 2) If company (party group) information is passed. 3) If Person and company (party group) information is passed. @@ -563,7 +563,7 @@ under the License. <attribute name="extension" type="String" mode="IN" optional="true"/> <attribute name="partyId" type="String" mode="OUT" optional="false"/> </service> - <service name="convertLeadToContact" engine="simple" location="component://marketing/minilang/sfa/lead/LeadServices.xml" invoke="convertLeadToContact"> + <service name="convertLeadToContact" engine="groovy" location="component://marketing/groovyScripts/sfa/lead/LeadServices.groovy" invoke="convertLeadToContact"> <attribute name="partyId" type="String" mode="INOUT" optional="false"/> <attribute name="partyGroupId" type="String" mode="INOUT" optional="false"/> </service> diff --git a/applications/party/minilang/party/PartySimpleMethods.xml b/applications/party/minilang/party/PartySimpleMethods.xml index a874f11..ed7922a 100644 --- a/applications/party/minilang/party/PartySimpleMethods.xml +++ b/applications/party/minilang/party/PartySimpleMethods.xml @@ -148,6 +148,7 @@ under the License. <set field="emailAddress" from-field="parameters.emailAddress"/> <set field="emailContactMechPurpTypeId" from-field="parameters.emailContactMechPurpTypeId"/> <call-simple-method method-name="createPartyContactMechs"/> + <field-to-result field="partyId"/> </simple-method> <!-- Simple method to create a party group, its role and basic contact mechs --> diff --git a/applications/party/servicedef/services.xml b/applications/party/servicedef/services.xml index 07337ec..0226f83 100644 --- a/applications/party/servicedef/services.xml +++ b/applications/party/servicedef/services.xml @@ -127,7 +127,17 @@ under the License. <attribute name="emailAddress" type="String" mode="IN" optional="true"/> <attribute name="emailContactMechPurpTypeId" type="String" mode="IN" optional="true"/> </service> - + <service name="createPersonRoleAndContactMechs" engine="simple" + location="component://party/minilang/party/PartySimpleMethods.xml" invoke="createPersonRoleAndContactMechs"> + <description>Creates a person, role and contactMechs</description> + <auto-attributes entity-name="Person" mode="IN" include="nonpk" optional="true"/> + <auto-attributes entity-name="PartyRole" mode="IN" include="nonpk" optional="true"/> + <auto-attributes entity-name="PostalAddress" mode="IN" optional="true"/> + <auto-attributes entity-name="TelecomNumber" mode="IN" optional="true"/> + <attribute name="roleTypeId" mode="IN" type="String"/> + <attribute name="emailAddress" type="String" mode="IN" optional="true"/> + <attribute name="partyId" mode="OUT" type="String" optional="false"/> + </service> <service name="updatePerson" engine="java" default-entity-name="Person" location="org.apache.ofbiz.party.party.PartyServices" invoke="updatePerson" auth="true"> <description>Update a Person</description>