cancel
Showing results for 
Search instead for 
Did you mean: 

CPI - Property not updated, Iterating splitter/exception

stianbl
Explorer
0 Kudos

Hi guys,
I'm trying to do what seems to be a very simple thing.

I fetch all financial transactions from LMS. Then do an "iterating splitter" to process each one by one (to enrich with User data) after finally combining these again with the "Gather" (XML Same, Combine).

What I'm trying to do is simply process each financial transaction, enrich with User data, and then verify content is OK. (Checking custom fields on user, and certain values from the transaction). If any fail, the transaction should not be processed further (taken out of the flow) and an email should be sent to a receiver with error message for the transactions that fail. Also status for these should be updated to FAILED in LMS.

The mail thing, and update status is no issues (except I'm not able to properly store the data needed here..)

What I have done is this:
Before splitting, I add content modifier to add properties:
FinTransPassed: Expression, Value true. I set this to false in groovy if it fails the data check. A route at the end will send it to Error end (exception) if this is false. If not, it will continue with the flow and process the transaction further.
FinTransErrorsStatusAPI: I want this to hold the API posting body for setting status FAILED for the failed transactions.
FinTransErrorsMsg: This will hold a readable error message to be sent through email.

Email sending is working, but for some reason I cannot get the properties to stick or concatenate or anything.
Sample of my code below:

This works. I can see the value during trace and email sending.

Message processData(Message message) {
	java.io.Reader reader = message.getBody(Reader)
	def props = message.getProperties()
	String allErrorMsgs = props.get("FinTransErrorsMsg")
	requestedBy = sourceXml.Messages.Message2.Users.User.customColumn.'*'.find { node -> node.name() == 'element' && node.columnNumber.text() == '280'}
	customerNo = sourceXml.Messages.Message2.Users.User.customColumn.'*'.find { node -> node.name() == 'element' && node.columnNumber.text() == '200'}

	if(requestedBy == null || requestedBy == '') {
		currentErrorMsg = currentErrorMsg + 'No invoice reference'
	}

	if(customerNo == null || customerNo == '') {
		currentErrorMsg = currentErrorMsg + 'No Customer Number'
	}

	if(currentErrorMsg.length() > 0) {
		allErrorMsgs = allErrorMsgs + ' | ' + currentTxID + ':' + currentErrorMsg + '\n'
		message.setProperty('FinTransPassed', 'false') 	//SBL: Check if any missing data. If so, change TransPassed to false to fail it and throw error.
		currentTxID = ''
		currentErrorMsg = ''
	}
	message.setProperty("FinTransErrorsMsg", allErrorMsgs)
	return message
}


Then inside the exception handling, I try to add data to the FinTransErrorsStatusAPI property mentioned above, but this is not working. Here I try and reset the FinTransPassed to true, so next iteration will start with value true.

And I try to add the posting status to the property, but it never gets saved.

Message processData(Message message) {
	java.io.Reader reader = message.getBody(Reader)
	Map properties = message.getProperties()
	Map headers = message.getHeaders()

	// Define XML parser and builder
	def sourceXml = new XmlSlurper().parse(reader)

	def now = new Date()
	// get epoch milis
	long epoch_millis = now.getTime()

	String FailedTransID = properties.get('FailedTransID');
	String xmlData = '''<FinancialTransactionPostingStatuses>
		<FinancialTransactionPostingStatus>
			<postingStatuses>
				<element>
					<transactionID>''' + sourceXml.Message1.FinancialTransaction.transactionID.text() + '''</transactionID>
					<status>FAILED</status>
					<transactionPostingDate>''' + epoch_millis + '''</transactionPostingDate>
					<error>Error: Unable to get startdate information. \n''' + headers.get("ExceptionMsg") + '''</error>
					<finSystemID>SAP</finSystemID>
				</element>
			</postingStatuses>
		</FinancialTransactionPostingStatus>
	</FinancialTransactionPostingStatuses>'''

	if(FailedTransID != null && FailedTransID.length() > 0){
	    FailedTransID = FailedTransID + '|'
	}
	FailedTransID = FailedTransID + sourceXml.Message1.FinancialTransaction.transactionID.text()

	// Generate output
	message.setProperty('FinTransErrorsStatusAPI', xmlData)
	message.setProperty('FailedTransID', FailedTransID)
	message.setProperty('FinTransPassed', 'true')
	return message
}
Ryan-Crosby
Active Contributor
0 Kudos

I think what you are experiencing here is related to scope as I have experienced the same type of behavior when using a splitter. Values reset during an iteration are not retained in the next pass, but as Federico has noted you can use local variables.

Accepted Solutions (0)

Answers (2)

Answers (2)

Bais
Participant
0 Kudos

Do you want to update a property on a loop? I've used Local Variable write function for this cases.

after run:

On OUTPUT variable you have your updated output.

this is a way...

stianbl
Explorer
0 Kudos

Hi, and thanks for your reply. I will give it a try.

What I try to do is as follows:
1. Fetch Financial Transactions from LMS through API. = OK
2. Iterate each transaction, and enrich with User data through API. = OK
3. Validate the current set of transaction with user data (inside iteration/loop). If something is missing, it should not process this transaction any further. It should populate a variable(property) with error information to be sent in email, and it should populate a variable(property) to store API call to update status of this transaction to FAILED in LMS through API. For each transaction that fails, these variables should be added to, so that once all transactions are validated, only those who passed are still in the body to be further mapped and processed towards our systems, and those who failed are kept in two variables, one with all errors to be sent to email, and one with the body for API call to update FinTra status to Failed in LMS.

I do struggle a bit with part 3. For some reason. I'm quite familiar with java ang programming, but I seem to miss some logic within CPI. It seems to be correct, but still fails to do what I want. And what I want seems fairly simple.

Short version:
Get Financial Transactions (i.e. 10 transaction)
If all values are OK, process and gather.
If value is wrong or missing, do not process. Remove from flow, and note down info in a property.
Further process those passed in the next steps after gathering these. Ignore the one who failed.
Send a seperate API call to set status of those who failed check (based on data now in variable/property).

stianbl
Explorer
0 Kudos

So, a workaround is to store the values not from a groovy script inside the exception, but in a step before it gets to the exception. But shouldn't it work also from inside the exception?
See image below. This is after I moved the script, and it works as intended now. But I wanted it to work from inside exception (update the property while inside exception, close this iteration, and continue to the next iteration, while still keeping the data in the property)