Updating account flow
Introduction
This document will walk you through the implementation of the updating account feature.
The feature allows users to update account details through a web form, processes the input, and updates the account information in the backend system.
We will cover:
- The structure of the update account form.
- Handling form submission and validation.
- Serializing form data to JSON.
- Sending the update request to the backend.
- Processing the backend response.
- Backend service mapping and properties.
- COBOL program updates.
Update account form
The form for updating account details is defined in src/Z-OS-Connect-Customer-Services-Interface/src/main/resources/templates/updateAccountForm.html
. It includes fields for account number, account type, interest rate, and overdraft limit. The form uses Thymeleaf for data binding and error handling.
<form class="bx--form-item form" action="/updateacc" th:action="@{/updateacc}"
th:object="${updateAccountForm}" method="post">
<table>
<tr>
<td>
<h1>Update Account</h1>
</td>
</tr>
<tr>
<td>Account number:</td>
<td><input class="bx--text-input" type="number" th:field="*{acctNumber}" /></td>
<td class="danger" th:if="${#fields.hasErrors('acctNumber')}" th:errors="*{custNumber}">Customer
Number Error</td>
</tr>
<tr>
<td>Account Type:</td>
<td>
<div th:each="type : ${accountTypes}">
<div class="">
<!-- Would love to have Carbon Components radio buttons! but they disappear when you add the class for them -->
<input type="radio" th:field="*{acctType}" th:value="${type}">
<label class="" th:for="${#ids.prev('acctType')}" th:text="${type}">model</label>
</div>
</div>
</td>
<td class="danger" th:if="${#fields.hasErrors('acctType')}" th:errors="*{acctType}">Interest
Rate Error</td>
</tr>
<tr>
<td>Interest Rate:</td>
<td><input class="bx--text-input" type="number" th:field="*{acctInterestRate}" /></td>
<td class="danger" th:if="${#fields.hasErrors('acctInterestRate')}"
th:errors="*{acctInterestRate}">Interest Rate Error</td>
</tr>
<tr>
<td>Overdraft Limit:</td>
<td><input class="bx--text-input" type="number" th:field="*{acctOverdraft}" th:value="9" /></td>
<td class="danger" th:if="${#fields.hasErrors('acctOverdraft')}" th:errors="*{acctOverdraft}">
Overdraft Limit Error</td>
</tr>
<!-- These can't be updated at the moment but writing the code took effort so it's still here just in case they can be updated directly in the future -->
<!-- <tr>
<td>Available Balance:</td>
<td><input class="bx--text-input" type="number" th:field="*{acctAvailableBalance}" /></td>
<td class="danger" th:if="${#fields.hasErrors('acctAvailableBalance')}" th:errors="*{acctAvailableBalance}">Interest Rate Error</td>
</tr>
<tr>
<td>Actual Balance:</td>
<td><input class="bx--text-input" type="number" th:field="*{acctActualBalance}" /></td>
<td class="danger" th:if="${#fields.hasErrors('acctActualBalance')}" th:errors="*{acctActualBalance}">Interest Rate Error</td>
</tr> -->
<tr>
<td><button class="bx--btn bx--btn--primary" type="submit">Submit</button></td>
</tr>
</table>
</form>
Handling form submission and validation
When the form is submitted, the processCreateAcc
WebController
/updateacc
@PostMapping("/updateacc")
public String processCreateAcc(@Valid UpdateAccountForm updateAccountForm,
BindingResult bindingResult, Model model)
throws JsonProcessingException
{
if (bindingResult.hasErrors())
{
// Must add the accountTypes enum here as well, otherwise the radio
// buttons disappear on error
model.addAttribute(ACCOUNT_TYPES, AccountType.values());
return UPDATE_ACCOUNT_FORM;
}
Serializing form data to JSON
If the form data is valid, it is converted into a UpdateAccountJson
UpdateAccountJson transferjson = new UpdateAccountJson(
updateAccountForm);
// Serialise the object to JSON
log.info("{}", transferjson);
String jsonString = new ObjectMapper().writeValueAsString(transferjson);
log.info("{}", jsonString);
Sending the update request to the backend
The JSON string is sent to the backend service using a WebClient
src/zosconnect_artefacts/apis/updacc/api/update/
endpoint, and it expects a JSON response.
// The port is set elsewhere as it changes frequently
WebClient client = WebClient
.create(ConnectionInfo.getAddressAndPort() + "/updacc/update");
try
{
// Create a response object - body of json, accept json back, and
// insert the
// request body created a couple lines up
ResponseSpec response = client.put()
.header(CONTENT_TYPE, APPLICATION_JSON)
.accept(MediaType.APPLICATION_JSON)
.body(BodyInserters.fromValue(jsonString)).retrieve();
String responseBody = response.bodyToMono(String.class).block();
log.info(responseBody);
Processing the backend response
The response from the backend is deserialized into an UpdateAccountJson
// Deserialise into a POJO
UpdateAccountJson responseObj = new ObjectMapper()
.readValue(responseBody, UpdateAccountJson.class);
log.info("{}", responseObj);
// Throws out different exceptions depending on the contents
checkIfResponseValidUpdateAcc(responseObj);
// If successful...
model.addAttribute(LARGE_TEXT, "");
model.addAttribute(SMALL_TEXT, responseObj.toPrettyString());
Backend service mapping and properties
The backend service mapping is defined in src/zosconnect_artefacts/apis/updacc/api/update/PUT/mapping.xml
. It specifies the endpoint, HTTP method, and response code.
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<!-- Copyright IBM Corp. 2023 -->
<ns2:ZosConnectServiceMapping xmlns:ns2="http://www.ibm.com/zosConnect/2.0/zosConnectServiceMapping" mappingSpecVersion="1.0">
<mappingContext basePath="/updacc" relativePath="/update" method="PUT" serviceName="CSaccupd" defaultResponseCode="200"/>
<responseMessages code="200" description="OK"/>
</ns2:ZosConnectServiceMapping>
The service properties are defined in src/zosconnect_artefacts/services/CSaccupd/service.properties
. These properties configure the service interface, executable name, and other settings.
responseSIName=UPDACC.si
bidiConfigRef=
servicetype=cicsCommarea
initializeInputFields=false
requestSIName=UPDACC.si
executableName=UPDACC
trimOutputTrailingWhitespace=true
COBOL program updates
The COBOL program src/base/cobol_src/UPDACC.cbl
is responsible for updating the account information in the database. It includes sections for moving data, performing the update, and finalizing the process.
PREMIERE SECTION.
A010.
MOVE SORTCODE TO COMM-SCODE.
MOVE SORTCODE TO DESIRED-SORT-CODE.
*
* Update the account information
*
PERFORM UPDATE-ACCOUNT-DB2
*
* The COMMAREA values have now been set so all we need to do
* is finish
*
PERFORM GET-ME-OUT-OF-HERE.
This concludes the walkthrough of the updating account flow feature. Each snippet plays a crucial role in ensuring the form data is correctly processed and the account information is updated in the backend system.