Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.

...

Note that the simple-method.xsd file is also available at http://ofbiz.apache.org/dtds/simple-methods.xsd .

To specify the XMLschema XML schema for a simple-methods or simple-map-processors XML file use the following:

...

Anchor
smapex
smapex
Simple Map Processors Example

Note that fail-message is used here for the purpose of demonstration but in general it's better to use fail-property because fail-message is not localisable

Code Block
<simple-map-processors xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
		xsi:noNamespaceSchemaLocation="http://ofbiz.apache.org/dtds/simple-methods.xsd">
	<simple-map-processor name="update">
		<make-in-string field="estimatedStartDate">
			<in-field field="estimatedStartYear"><constant>-</constant>
			<in-field field="estimatedStartMonth"><constant>-</constant>
			<in-field field="estimatedStartDay"><constant>T</constant>
			<in-field field="estimatedStartHour"><constant>:</constant>
			<in-field field="estimatedStartMinute"><constant>:</constant>
			<in-field field="estimatedStartSecond">
		</make-in-string>
		<process field="workEffortId"><copy replace="false"/></process>
		<process field="scopeEnumId"><copy/></process>
		<process field="currentStatusId">
			<copy/>
			<not-empty>
				<fail-message message="Status is missing."/>
                                <!-- Note that fail-message is used here for the purpose of demonstration; 
but in general it's better to use fail-property because fail-message is not localisable -->
				<fail-message message="Status is missing."/>
                        but  in general it's better to use fail-property because<!-- Note that fail-message is not localisable -->
			</not-empty>
		</ used here for the purpose of demonstration; 
                                but in general it's better to use fail-property because fail-message is not localisable -->
			</not-empty>
		</process>
		<process field="priority">
			<convert type="Long">
				<fail-message message="Priority is not a valid whole number."/>
			</convert>
		</process>
		<process field="estimatedStartDate">
			<compare-field operator="less" field="estimatedCompletionDate" type="Timestamp" format="yyyy-MM-dd'T'HH:mm:ss">
				<fail-message message="Estimated Start date/time must be BEFORE End date/time."/>
			</compare-field>
			<convert type="Timestamp" format="yyyy-MM-dd'T'HH:mm:ss">
				<fail-message message="Estimated Start Date is not a valid Date-Time."/>
			</convert>
		</process>
		<process field="estimatedCompletionDate">
			<convert type="Timestamp">
				<fail-message message="Estimated Completion Date is not a valid Date-Time."/>
			</convert>
		</process>
		<process field="estimatedMilliSeconds">
			<convert type="Double">
				<fail-message message="Estimated Milli-seconds is not a valid number."/>
			</convert>
		</process>
	</simple-map-processor>
	<simple-map-processor name="delete">
		<process field="workEffortId">
			<copy/>
			<not-empty>
				<fail-message message="Work Effort ID is missing."/>
			</not-empty>
		</process>
	</simple-map-processor>
</simple-map-processors>

...

The ${} (dollar-sign-curly-brace) syntax can be used to insert an environment variable value in pretty much any string constant in a simple-method file. Not only can it be used to reference top-level environment variables, the syntax elements described below can be used to access values in sub-structures.

You can should use the "." (dot) syntax to access Map members (the old map/field syntax is deprecated since 2009). For example if you specify the attribute field-name="product.productName" it will reference the productName member of the productMap. This would be the same as specifying map-name="product" field-name="productName". Note that this is, of course, more flexible than a field-name/map -name combination because the Map structure can be multiple levels deep. For example if you have use the attributefield-nameused the attribute field="products.widget.productName" it will reference the productName in the widget Map which is in the products Map.

Wiki Markup
The "\[\]" (square-brace) syntax can be used to access list elements. For example you can specify the attribute field-name="products\[0\].productName"and it will reference the productName of the first (position zero) element in the products List. To make this more useful you can pull a list index from the environment using something like field-name="products\[$\{currentIndex\}\].productName".

...

Wiki Markup
In fact, you can use the $\{\} syntax to substitute any string or other value at any location in a field-name or other string constant. So, you could even reference a Map member named in some other environment variable. For example you could use field-name="products\[$\{currentIndex\}\].productName".

...

Code Block
<calculate field-name="a">
<calcop operator="get" field-name="b"/>
<calcop operator="divide">
<calcop operator="multiply">
<calcop operator="add" field-name="c">
<calcop operator="get" field-name="x"/>
<number value="2"/>
</calcop>
<calcop operator="negative" field-name="d"/>
</calcop>
<calcop operator="get" field-name="e"/>
</calcop>
</calculate>

...

Simple Methods Example

Note that fail-message is used here for the purpose of demonstration but in general it's better to use fail-property because fail-message is not localisable

Code Block
<simple-methods xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xsi:noNamespaceSchemaLocation="[http://ofbiz.apache.org/dtds/simple-methods.xsd]\]">
        
    <simple-method method-name="createProduct" short-description="Create ana Product">
        <check-permission permission="CATALOG" action="_CREATE">
            <fail<alt-messagepermission messagepermission="CATALOG_ROLE"Security Error: to run createProduct you must have the CATALOG_CREATE or CATALOG_ADMIN permission action="_CREATE"/> 
            <!-- Note that fail-message is used here for the purpose of demonstration but in general it's better to use fail-property because fail-message is not localisable -->
        </check-permission>
        <check-id field-name="productId" map-name="parameters"/>
        <check-errors/>

        <fail-message message="Security Error: to run createProduct you must have the CATALOG_CREATE or CATALOG_ADMIN permission, or the limited CATALOG_ROLE_CREATE permission"/>
        </check-permission>
        <check-errors/>

        <make-value value-namefield="newEntity" entity-name="Product"/>
        <set-nonpk-fields map-name="parameters" value-namefield="newEntity"/>

        <set-pk-fields mapfrom-namefield="parameters.productId" value-namefield="newEntity.productId"/>

        <now-timestamp-to-env env-name<if-empty field="newEntity.lastModifiedDateproductId"/>
        <now-timestamp-to-env env    <sequenced-id sequence-name="Product" field="newEntity.createdDateproductId"/>
        <else>
 <set from-field="userLogin.userLoginId" field="newEntity.lastModifiedByUserLogin"/>
        <set from-field="userLogin.userLoginId"<check-id field="newEntity.createdByUserLoginproductId"/>
          <create-value  value-name="newEntity"<check-errors/>

        <!-- induce keywords if autoCreateKeywords is emtpy or Y-->/else>
        </if-empty>
        <if<field-to-emptyresult field-name="autoCreateKeywordsnewEntity.productId" mapresult-name="newEntityproductId"/>

            <call-bsh><![CDATA[org.ofbiz.commonapp.product.product.KeywordSearch.induceKeywords(newEntity);]]></call-bsh><now-timestamp field="nowTimestamp"/>
        <else>
        <if-compare field-name="autoCreateKeywords" map-name<set from-field="nowTimestamp" field="newEntity.createdDate" operator/>
        <set from-field="equalsnowTimestamp" valuefield="YnewEntity.lastModifiedDate"/>
        <set from-field="userLogin.userLoginId" field="newEntity.lastModifiedByUserLogin"/>
   <call-bsh><![CDATA[org.ofbiz.commonapp.product.product.KeywordSearch.induceKeywords(newEntity);]]></call-bsh>      <set from-field="userLogin.userLoginId" field="newEntity.createdByUserLogin"/>
        <if-empty field="newEntity.isVariant">
            <set field="newEntity.isVariant" value="N"/>
        </if-empty>
        <if-empty field="newEntity.isVirtual">
            <set field="newEntity.isVirtual" value="N"/>
        </if-empty>
        <if-empty field="newEntity.billOfMaterialLevel">
            <set field="newEntity.billOfMaterialLevel" value="0" type="Integer"/>
        </if-empty>

        <create-value value-field="newEntity"/>

        <!-- if setting the primaryProductCategoryId create a member entity too -->
        <!-- THIS IS REMOVED BECAUSE IT CAUSES PROBLEMS FOR WORKING ON PRODUCTION SITES
        <if-not-empty field="newEntity.primaryProductCategoryId">
            <make-value entity-name="ProductCategoryMember" value-field="newMember"/>
            <set from-field="productId" map-name="newEntity" to-field-name="productId" to-map-name="newMember"/>
            <set from-field="primaryProductCategoryId" map-name="newEntity" to-field-name="productCategoryId" to-map-name="newMember"/>
            <now-timestamp field="nowStamp"/>
            <set from-field="nowStamp" field="newMember.fromDate"/>
            <create-value value-field="newMember"/>
        </if-not-empty>
        -->

        <!-- if the user has the role limited position, add this product to the limit category/ies -->
        <if-has-permission permission="CATALOG_ROLE" action="_CREATE">
            <entity-and entity-name="ProductCategoryRole" list="productCategoryRoles" filter-by-date="true">
                <field-map field-name="partyId" from-field="userLogin.partyId"/>
                <field-map field-name="roleTypeId" value="LTD_ADMIN"/>
            </entity-and>
            
            <iterate entry="productCategoryRole" list="productCategoryRoles">
                <!-- add this new product to the category -->
                <make-value value-field="newLimitMember" entity-name="ProductCategoryMember"/>
                <set from-field="newEntity.productId" field="newLimitMember.productId"/>
                <set from-field="productCategoryRole.productCategoryId" field="newLimitMember.productCategoryId"/>
                <set from-field="nowTimestamp" field="newLimitMember.fromDate"/>
                <create-value value-field="newLimitMember"/>
            </iterate>
        </if-has-permission>
    </simple-method>
    
    <simple-method method-name="createWorkEffort" short-description="Create Work Effort">
        <make-value value-field="newEntity" entity-name="WorkEffort"/>
        <if-empty field="parameters.workEffortId">
            <sequenced-id sequence-name="WorkEffort" field="newEntity.workEffortId"/>
            <else>
                <set field="newEntity.workEffortId" from-field="parameters.workEffortId"/>
            </else>
        </if-empty>
        <field-to-result field="newEntity.workEffortId" result-name="workEffortId"/>
        <set-nonpk-fields map="parameters" value-field="newEntity"/>
        
        <now-timestamp field="nowTimestamp"/>
        <set from-field="nowTimestamp" field="newEntity.lastStatusUpdate"/>
        <set from-field="nowTimestamp" field="newEntity.lastModifiedDate"/>
        <set from-field="nowTimestamp" field="newEntity.createdDate"/>
        <set field="newEntity.revisionNumber" value="1" type="Long"/>
        <set from-field="userLogin.userLoginId" field="newEntity.lastModifiedByUserLogin"/>
        <set from-field="userLogin.userLoginId" field="newEntity.createdByUserLogin"/>
        <create-value value-field="newEntity"/>
        
        <!-- create new status entry, and set lastStatusUpdate date -->
        <make-value value-field="newWorkEffortStatus" entity-name="WorkEffortStatus"/>
        <set from-field="newEntity.workEffortId" field="newWorkEffortStatus.workEffortId"/>
        <set from-field="newEntity.currentStatusId" field="newWorkEffortStatus.statusId"/>
        <set from-field="nowTimestamp" field="newWorkEffortStatus.statusDatetime"/>
        <set from-field="userLogin.userLoginId" field="newWorkEffortStatus.setByUserLogin"/>
        <create-value value-field="newWorkEffortStatus"/>
        
        <!-- Attach the workeffort to a requirement if passed -->
        <if-not-empty field="parameters.requirementId">
            <make-value value-field="workFullfillment" entity-name="WorkRequirementFulfillment"/>
            <set from-field="newEntity.workEffortId" field="workFullfillment.workEffortId"/>
            <set from-field="parameters.requirementId" field="workFullfillment.requirementId"/>
            <create-value value-field="workFullfillment"/>
        </if-not-empty>

        <!-- attach to a customer request if passed and copy attached docs -->
        <if-not-empty field="parameters.custRequestId">
            <!-- check status of customer request if valid -->
            <entity-one entity-name="CustRequest" value-field="lookedUpValue"/>
            <set field="goodStatusId" value="CRQ_ACCEPTED"/>
            <if-compare-field operator="not-equals" field="lookedUpValue.statusId" to-field="goodStatusId" >
                <set field="entity" value="Customer request"/>
                <add-error><fail-property resource="CommonUiLabels" property="CommonErrorStatusNotValid"/></add-error>
                <check-errors/>
            </if-compare-field>
            <!-- create customer request / work effort relation -->
            <make-value value-field="custRequestWorkEffort" entity-name="CustRequestWorkEffort"/>
            <set field="custRequestWorkEffort.workEffortId" from-field="newEntity.workEffortId" />
            <set field="custRequestWorkEffort.custRequestId" from-field="parameters.custRequestId"/>
            <create-value value-field="custRequestWorkEffort"/>
            <!-- update status of customer request -->
            <set field="updCustReq.custRequestId" from-field="parameters.custRequestId"/>
            <set field="updCustReq.statusId" value="CRQ_REVIEWED"/>
            <call-service service-name="setCustRequestStatus" in-map-name="updCustReq"/>
            <entity-and list="custRequestContents" entity-name="CustRequestContent">
                <field-map field-name="custRequestId" from-field="parameters.custRequestId"/>
            </entity-and>
            <iterate entry="custRequestContent" list="custRequestContents">
                <set field="newWorkEffortContent.workEffortId" from-field="newEntity.workEffortId"/>
                <set field="newWorkEffortContent.contentId" from-field="custRequestContent.contentId"/>
                <set field="newWorkEffortContent.workEffortContentTypeId" value="SUPPORTING_MEDIA"/>
                <call-service service-name="createWorkEffortContent" in-map-name="newWorkEffortContent"/>
            </iterate>
        </if-not-empty>
    </simple-method>
    <simple-method method-name="updateWorkEffort" short-description="Update Work Effort">
        <!-- check permissions before moving on: if update or delete logged in user must be associated OR have the corresponding UPDATE or DELETE permissions -->
        
        <!-- temporarily commented out, because users assigned to a project or phase should
              have the capability to modify status on sub-tasks, right? Hmmmm.... -->
              
<!--        <set from-field="workEffortId" map-name="parameters" to-map-name="findWepaMap"/>
        <set from-field="partyId" map-name="userLogin" to-map-name="findWepaMap"/>
        <find-by-and entity-name="WorkEffortPartyAssignment" map="findWepaMap" list="wepaList"/>
        <if-empty field="wepaList">
            <check-permission permission="WORKEFFORTMGR" action="_UPDATE">
                <fail-message message="Security Error: to run updateWorkEffort you must have the WORKEFFORTMGR_UPDATE or WORKEFFORTMGR_ADMIN permission"/>
            </check-permission>
            <check-errors/>
        </if-empty>-->
        
        <entity-one entity-name="WorkEffort" value-field="lookedUpValue"/>
        <clone-value value-field="lookedUpValue" new-value-field="savedValue"/>
        
        <now-timestamp field="nowTimestamp"/>
        
        <!-- if necessary create new status entry, and set lastStatusUpdate date -->
        <if>
            <condition>
                <and>
                    <not><if-empty field="parameters.currentStatusId"/></not>
                    <if-compare-field field="parameters.currentStatusId" to-field="lookedUpValue.currentStatusId" operator="not-equals"/>
                </and>
            </condition>
            <then>
                <if-not-empty field="lookedUpValue.currentStatusId">
                    <!-- check if the status change is a valid change -->
                    <entity-and entity-name="StatusValidChange" list="validChange">
                        <field-map field-name="statusId" from-field="lookedUpValue.currentStatusId"/>
                        <field-map field-name="statusIdTo" from-field="parameters.currentStatusId"/>
                    </entity-and>
                    
                    <if-empty field="validChange">
                        <add-error>
                            <fail-message message="The status change from ${lookedUpValue.currentStatusId} to ${parameters.currentStatusId} is not a valid change"/>
                        </add-error>
                        <log level="error" message="The status change from ${lookedUpValue.currentStatusId} to ${parameters.currentStatusId} is not a valid change"/>
                        <check-errors/>
                    </if-empty>
                </if-not-empty>
                
                <set from-field="nowTimestamp" field="lookedUpValue.lastStatusUpdate"/>
                <make-value value-field="newWorkEffortStatus" entity-name="WorkEffortStatus"/>
                <set from-field="lookedUpValue.workEffortId" field="newWorkEffortStatus.workEffortId"/>
                <set from-field="parameters.currentStatusId" field="newWorkEffortStatus.statusId"/>
                <set from-field="parameters.reason" field="newWorkEffortStatus.reason"/>
                <set from-field="nowTimestamp" field="newWorkEffortStatus.statusDatetime"/>
                <set from-field="userLogin.userLoginId" field="newWorkEffortStatus.setByUserLogin"/>
                <create-value value-field="newWorkEffortStatus"/>
            </if-compare>then>
        </else>if>
        </if!--empty> after checking status 
change, set all parameters </simple-method>-->        
    
    <simple-method event-name="create" short-description="Create Work Effort"<set-nonpk-fields map="parameters" value-field="lookedUpValue"/>

        <!-- only save if something has changed -->
        <call-map-processor xml-resource="org/ofbiz/commonapp/workeffort/workeffort/WorkEffortMapProcessors.xml"<if-compare-field field="lookedUpValue" to-field="savedValue" operator="not-equals" type="Object">
            processor-name="update" in-map-name="parameters" out-map-name="context"/>
        <check-errors/>
<!-- only set lastModifiedDate after comparing new & old to see if anything has changed -->
            <call-service<set servicefrom-namefield="createWorkEffortnowTimestamp" in-map-namefield="contextlookedUpValue.lastModifiedDate"/>
            <set <default-message>Work Effort successfully created.</default-message>from-field="userLogin.userLoginId" field="lookedUpValue.lastModifiedByUserLogin"/>
            <result<if-tonot-requestempty result-name="workEffortId"/field="lookedUpValue.revisionNumber">
        </service>
    </simple-method>
    
    <simple-method event-name="update" short-description="Update Work Effort">
<set field="lookedUpValue.revisionNumber" value="${lookedUpValue.revisionNumber + 1}" type="Long"/>
             <call-map-processor xml-resource="org/ofbiz/commonapp/workeffort/workeffort/WorkEffortMapProcessors.xml"
<else>
                <set processor-namefield="updatelookedUpValue.revisionNumber" in-map-namevalue="parameters1" out-map-nametype="contextLong"/>
        <check-errors/>    </else>
          <call-service service-name="updateWorkEffort" in-map-name="context"> </if-not-empty>
            <default<store-message>Work Effort successfully updated.</default-message>value value-field="lookedUpValue"/>
        </service>if-compare-field>
    </simple-method>

</simple-methods>