Skip to content

Commit 57941e7

Browse files
authored
Add better support for account creation import (#57)
* Update the transaction importer to add manually created accounts to the mapping. * Update logging to make it more readable when application is running. * Add localization messages needed when creating accounts in import job. * Add option to re-run all transaction rules on the result of the import job. * Add mock to tests of rerun transaction rules endpoint. * Add a test to verify the running of transaction rules works as expected.
1 parent 3958163 commit 57941e7

File tree

12 files changed

+253
-79
lines changed

12 files changed

+253
-79
lines changed

bpmn-process/src/.camunda/element-templates/importer.json

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -294,5 +294,49 @@
294294
}
295295
}
296296
]
297+
},
298+
{
299+
"$schema": "https://unpkg.com/@camunda/element-templates-json-schema/resources/schema.json",
300+
"name": "Importer: Add account in mapping",
301+
"description": "Add the account id in the mapping configuration.",
302+
"id": "com.jongsoft.finance.bpmn.delegate.importer.AddToAccountMapping",
303+
"version": 1,
304+
"appliesTo": [
305+
"bpmn:ServiceTask"
306+
],
307+
"properties": [
308+
{
309+
"label": "Implementation",
310+
"type": "String",
311+
"value": "${addToAccountMapping}",
312+
"editable": false,
313+
"binding": {
314+
"type": "property",
315+
"name": "camunda:delegateExpression"
316+
}
317+
},
318+
{
319+
"label": "Account name",
320+
"type": "String",
321+
"binding": {
322+
"type": "camunda:inputParameter",
323+
"name": "name"
324+
},
325+
"constraint": {
326+
"notEmpty": true
327+
}
328+
},
329+
{
330+
"label": "Account id",
331+
"type": "String",
332+
"binding": {
333+
"type": "camunda:inputParameter",
334+
"name": "accountId"
335+
},
336+
"constraint": {
337+
"notEmpty": true
338+
}
339+
}
340+
]
297341
}
298342
]
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
package com.jongsoft.finance.bpmn.delegate.importer;
2+
3+
import com.jongsoft.finance.core.JavaBean;
4+
import jakarta.inject.Singleton;
5+
import lombok.extern.slf4j.Slf4j;
6+
import org.camunda.bpm.engine.delegate.DelegateExecution;
7+
import org.camunda.bpm.engine.delegate.JavaDelegate;
8+
9+
import java.util.Collection;
10+
import java.util.HashSet;
11+
12+
@Slf4j
13+
@Singleton
14+
public class AddToAccountMapping implements JavaDelegate, JavaBean {
15+
@Override
16+
public void execute(DelegateExecution execution) throws Exception {
17+
var accountName = (String) execution.getVariableLocal("name");
18+
var accountId = (Number) execution.getVariableLocal("accountId");
19+
20+
log.debug("{}: Adding account mapping for '{}' with id {}.",
21+
execution.getCurrentActivityName(),
22+
accountName,
23+
accountId);
24+
25+
@SuppressWarnings("unchecked")
26+
var mappings = new HashSet<>((Collection<ExtractionMapping>)execution.getVariable("accountMappings"));
27+
mappings.removeIf(mapping -> mapping.getName().equals(accountName));
28+
mappings.add(new ExtractionMapping(accountName, accountId.longValue()));
29+
30+
execution.setVariable("accountMappings", mappings);
31+
}
32+
}

bpmn-process/src/main/java/com/jongsoft/finance/bpmn/delegate/transaction/CreateTransactionDelegate.java

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,6 @@
1313
import lombok.extern.slf4j.Slf4j;
1414
import org.camunda.bpm.engine.delegate.DelegateExecution;
1515
import org.camunda.bpm.engine.delegate.JavaDelegate;
16-
import org.camunda.bpm.engine.variable.value.LongValue;
1716

1817
/**
1918
* Delegate for creating a transaction in the system.
@@ -85,8 +84,8 @@ public void execute(DelegateExecution execution) throws Exception {
8584
}
8685

8786
private Account lookupAccount(DelegateExecution execution, String variableName) {
88-
var accountId = execution.<LongValue>getVariableLocalTyped(variableName).getValue();
89-
return accountProvider.lookup(accountId)
87+
var accountId = (Number) execution.getVariableLocal(variableName);
88+
return accountProvider.lookup(accountId.longValue())
9089
.getOrThrow(() -> new IllegalStateException("Unable to find account with id " + accountId));
9190
}
9291

bpmn-process/src/main/resources/bpmn/transaction/import-job.bpmn

Lines changed: 51 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
<?xml version="1.0" encoding="UTF-8"?>
22
<bpmn:definitions xmlns:bpmn="http://www.omg.org/spec/BPMN/20100524/MODEL" xmlns:bpmndi="http://www.omg.org/spec/BPMN/20100524/DI" xmlns:dc="http://www.omg.org/spec/DD/20100524/DC" xmlns:camunda="http://camunda.org/schema/1.0/bpmn" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:di="http://www.omg.org/spec/DD/20100524/DI" xmlns:modeler="http://camunda.org/schema/modeler/1.0" id="Definitions_064fh2o" targetNamespace="http://bpmn.io/schema/bpmn" exporter="Camunda Modeler" exporterVersion="5.17.0" modeler:executionPlatform="Camunda Platform" modeler:executionPlatformVersion="7.20.0">
3-
<bpmn:process id="import_job" name="Import Job" isExecutable="true" camunda:versionTag="1.0.0" camunda:historyTimeToLive="P14D">
3+
<bpmn:process id="import_job" name="Import Job" isExecutable="true" camunda:versionTag="1.1.0" camunda:historyTimeToLive="P14D">
44
<bpmn:documentation>Start the import job that belongs to an import entity.
55

66
When calling the flow the following variables must be set:
@@ -187,7 +187,7 @@ When calling the flow the following variables must be set:
187187
<bpmn:conditionExpression xsi:type="bpmn:tFormalExpression">${allowGenerate == true}</bpmn:conditionExpression>
188188
</bpmn:sequenceFlow>
189189
<bpmn:sequenceFlow id="Flow_1n6qs8u" name="no" sourceRef="create_allowed" targetRef="user_create_account" />
190-
<bpmn:sequenceFlow id="Flow_15uycxp" sourceRef="user_create_account" targetRef="create_transaction" />
190+
<bpmn:sequenceFlow id="Flow_15uycxp" sourceRef="user_create_account" targetRef="add_account_mapping" />
191191
<bpmn:sequenceFlow id="Flow_0y3m68u" sourceRef="create_account_extractor" targetRef="create_account" />
192192
<bpmn:exclusiveGateway id="should_apply_rules" name="apply rules" default="Flow_0ycxqnq">
193193
<bpmn:incoming>Flow_01c6qb3</bpmn:incoming>
@@ -248,8 +248,8 @@ When calling the flow the following variables must be set:
248248
</camunda:inputOutput>
249249
</bpmn:extensionElements>
250250
<bpmn:incoming>Flow_0b5s223</bpmn:incoming>
251-
<bpmn:incoming>Flow_15uycxp</bpmn:incoming>
252251
<bpmn:incoming>Flow_1lz7czw</bpmn:incoming>
252+
<bpmn:incoming>Flow_18qem83</bpmn:incoming>
253253
<bpmn:outgoing>Flow_01c6qb3</bpmn:outgoing>
254254
</bpmn:serviceTask>
255255
<bpmn:serviceTask id="apply_rules" name="Apply rules" camunda:modelerTemplate="com.jongsoft.finance.bpmn.delegate.rule.TransactionRuleMatcherDelegate" camunda:modelerTemplateVersion="1" camunda:delegateExpression="${transactionRuleMatcherDelegate}">
@@ -304,6 +304,17 @@ When calling the flow the following variables must be set:
304304
<bpmn:incoming>Flow_00vpxjj</bpmn:incoming>
305305
<bpmn:outgoing>Flow_0rz5nze</bpmn:outgoing>
306306
</bpmn:serviceTask>
307+
<bpmn:serviceTask id="add_account_mapping" name="Add account mapping" camunda:modelerTemplate="com.jongsoft.finance.bpmn.delegate.importer.AddToAccountMapping" camunda:modelerTemplateVersion="1" camunda:delegateExpression="${addToAccountMapping}">
308+
<bpmn:extensionElements>
309+
<camunda:inputOutput>
310+
<camunda:inputParameter name="name">${transaction.opposingName()}</camunda:inputParameter>
311+
<camunda:inputParameter name="accountId">${accountId}</camunda:inputParameter>
312+
</camunda:inputOutput>
313+
</bpmn:extensionElements>
314+
<bpmn:incoming>Flow_15uycxp</bpmn:incoming>
315+
<bpmn:outgoing>Flow_18qem83</bpmn:outgoing>
316+
</bpmn:serviceTask>
317+
<bpmn:sequenceFlow id="Flow_18qem83" sourceRef="add_account_mapping" targetRef="create_transaction" />
307318
</bpmn:subProcess>
308319
<bpmn:sequenceFlow id="Flow_16v2prx" sourceRef="process_create_transactions" targetRef="mark_import_done" />
309320
<bpmn:endEvent id="endJob">
@@ -358,12 +369,6 @@ When calling the flow the following variables must be set:
358369
<bpmndi:BPMNShape id="Activity_1y5d1uo_di" bpmnElement="read_csv_file">
359370
<dc:Bounds x="1060" y="260" width="100" height="80" />
360371
</bpmndi:BPMNShape>
361-
<bpmndi:BPMNShape id="Gateway_02tmvr8_di" bpmnElement="no_transactions" isMarkerVisible="true">
362-
<dc:Bounds x="1085" y="365" width="50" height="50" />
363-
<bpmndi:BPMNLabel>
364-
<dc:Bounds x="1010" y="383" width="65" height="14" />
365-
</bpmndi:BPMNLabel>
366-
</bpmndi:BPMNShape>
367372
<bpmndi:BPMNShape id="Activity_0bn3ft1_di" bpmnElement="process_account_mapping" isExpanded="true">
368373
<dc:Bounds x="810" y="450" width="780" height="330" />
369374
<bpmndi:BPMNLabel />
@@ -451,7 +456,7 @@ When calling the flow the following variables must be set:
451456
<dc:Bounds x="1280" y="250" width="100" height="80" />
452457
</bpmndi:BPMNShape>
453458
<bpmndi:BPMNShape id="Activity_0nxa7la_di" bpmnElement="process_create_transactions" isExpanded="true">
454-
<dc:Bounds x="1710" y="85" width="1220" height="410" />
459+
<dc:Bounds x="1710" y="85" width="1220" height="535" />
455460
<bpmndi:BPMNLabel />
456461
</bpmndi:BPMNShape>
457462
<bpmndi:BPMNShape id="Event_19sbqbc_di" bpmnElement="start_create_transaction">
@@ -464,9 +469,9 @@ When calling the flow the following variables must be set:
464469
</bpmndi:BPMNLabel>
465470
</bpmndi:BPMNShape>
466471
<bpmndi:BPMNShape id="Gateway_0v83u3r_di" bpmnElement="create_allowed" isMarkerVisible="true">
467-
<dc:Bounds x="2215" y="290" width="50" height="50" />
472+
<dc:Bounds x="2215" y="355" width="50" height="50" />
468473
<bpmndi:BPMNLabel>
469-
<dc:Bounds x="2218" y="350" width="44" height="14" />
474+
<dc:Bounds x="2218" y="415" width="44" height="14" />
470475
</bpmndi:BPMNLabel>
471476
</bpmndi:BPMNShape>
472477
<bpmndi:BPMNShape id="Gateway_17mjkeb_di" bpmnElement="should_apply_rules" isMarkerVisible="true">
@@ -479,7 +484,7 @@ When calling the flow the following variables must be set:
479484
<dc:Bounds x="2872" y="297" width="36" height="36" />
480485
</bpmndi:BPMNShape>
481486
<bpmndi:BPMNShape id="Activity_0lhktha_di" bpmnElement="user_create_account">
482-
<dc:Bounds x="2340" y="275" width="100" height="80" />
487+
<dc:Bounds x="2340" y="340" width="100" height="80" />
483488
</bpmndi:BPMNShape>
484489
<bpmndi:BPMNShape id="Activity_0zbcup5_di" bpmnElement="locate_account_mapping">
485490
<dc:Bounds x="2040" y="155" width="100" height="80" />
@@ -494,18 +499,21 @@ When calling the flow the following variables must be set:
494499
<dc:Bounds x="2700" y="155" width="100" height="80" />
495500
</bpmndi:BPMNShape>
496501
<bpmndi:BPMNShape id="Activity_1wb6lyp_di" bpmnElement="create_account_extractor">
497-
<dc:Bounds x="2040" y="275" width="100" height="80" />
502+
<dc:Bounds x="2040" y="340" width="100" height="80" />
498503
<bpmndi:BPMNLabel />
499504
</bpmndi:BPMNShape>
500505
<bpmndi:BPMNShape id="Activity_00e7v83_di" bpmnElement="create_account">
501-
<dc:Bounds x="2040" y="385" width="100" height="80" />
506+
<dc:Bounds x="2040" y="460" width="100" height="80" />
502507
</bpmndi:BPMNShape>
503508
<bpmndi:BPMNShape id="Activity_1thklz0_di" bpmnElement="locate_created_account">
504-
<dc:Bounds x="2270" y="385" width="100" height="80" />
509+
<dc:Bounds x="2270" y="460" width="100" height="80" />
505510
</bpmndi:BPMNShape>
506511
<bpmndi:BPMNShape id="Activity_1iov1tb_di" bpmnElement="detect_duplicates">
507512
<dc:Bounds x="2700" y="275" width="100" height="80" />
508513
</bpmndi:BPMNShape>
514+
<bpmndi:BPMNShape id="Activity_11t29lj_di" bpmnElement="add_account_mapping">
515+
<dc:Bounds x="2340" y="230" width="100" height="80" />
516+
</bpmndi:BPMNShape>
509517
<bpmndi:BPMNEdge id="Flow_0xggr5k_di" bpmnElement="Flow_0xggr5k">
510518
<di:waypoint x="2140" y="195" />
511519
<di:waypoint x="2215" y="195" />
@@ -519,34 +527,32 @@ When calling the flow the following variables must be set:
519527
</bpmndi:BPMNEdge>
520528
<bpmndi:BPMNEdge id="Flow_0prfhkh_di" bpmnElement="Flow_0prfhkh">
521529
<di:waypoint x="2240" y="220" />
522-
<di:waypoint x="2240" y="290" />
530+
<di:waypoint x="2240" y="355" />
523531
<bpmndi:BPMNLabel>
524-
<dc:Bounds x="2248" y="238" width="13" height="14" />
532+
<dc:Bounds x="2248" y="261" width="13" height="14" />
525533
</bpmndi:BPMNLabel>
526534
</bpmndi:BPMNEdge>
527535
<bpmndi:BPMNEdge id="Flow_01kp9n6_di" bpmnElement="Flow_01kp9n6">
528-
<di:waypoint x="2215" y="315" />
529-
<di:waypoint x="2140" y="315" />
536+
<di:waypoint x="2215" y="380" />
537+
<di:waypoint x="2140" y="380" />
530538
<bpmndi:BPMNLabel>
531-
<dc:Bounds x="2184" y="293" width="17" height="14" />
539+
<dc:Bounds x="2184" y="358" width="17" height="14" />
532540
</bpmndi:BPMNLabel>
533541
</bpmndi:BPMNEdge>
534542
<bpmndi:BPMNEdge id="Flow_1n6qs8u_di" bpmnElement="Flow_1n6qs8u">
535-
<di:waypoint x="2265" y="315" />
536-
<di:waypoint x="2340" y="315" />
543+
<di:waypoint x="2265" y="380" />
544+
<di:waypoint x="2340" y="380" />
537545
<bpmndi:BPMNLabel>
538-
<dc:Bounds x="2296" y="297" width="13" height="14" />
546+
<dc:Bounds x="2296" y="362" width="13" height="14" />
539547
</bpmndi:BPMNLabel>
540548
</bpmndi:BPMNEdge>
541549
<bpmndi:BPMNEdge id="Flow_15uycxp_di" bpmnElement="Flow_15uycxp">
542-
<di:waypoint x="2390" y="275" />
543-
<di:waypoint x="2390" y="255" />
544-
<di:waypoint x="2480" y="255" />
545-
<di:waypoint x="2480" y="235" />
550+
<di:waypoint x="2390" y="340" />
551+
<di:waypoint x="2390" y="310" />
546552
</bpmndi:BPMNEdge>
547553
<bpmndi:BPMNEdge id="Flow_0y3m68u_di" bpmnElement="Flow_0y3m68u">
548-
<di:waypoint x="2090" y="355" />
549-
<di:waypoint x="2090" y="385" />
554+
<di:waypoint x="2090" y="420" />
555+
<di:waypoint x="2090" y="460" />
550556
</bpmndi:BPMNEdge>
551557
<bpmndi:BPMNEdge id="Flow_01c6qb3_di" bpmnElement="Flow_01c6qb3">
552558
<di:waypoint x="2540" y="195" />
@@ -584,20 +590,31 @@ When calling the flow the following variables must be set:
584590
<di:waypoint x="2040" y="195" />
585591
</bpmndi:BPMNEdge>
586592
<bpmndi:BPMNEdge id="Flow_1b93w1q_di" bpmnElement="Flow_1b93w1q">
587-
<di:waypoint x="2140" y="425" />
588-
<di:waypoint x="2270" y="425" />
593+
<di:waypoint x="2140" y="500" />
594+
<di:waypoint x="2270" y="500" />
589595
</bpmndi:BPMNEdge>
590596
<bpmndi:BPMNEdge id="Flow_1lz7czw_di" bpmnElement="Flow_1lz7czw">
591-
<di:waypoint x="2370" y="425" />
592-
<di:waypoint x="2510" y="425" />
597+
<di:waypoint x="2370" y="500" />
598+
<di:waypoint x="2510" y="500" />
593599
<di:waypoint x="2510" y="235" />
594600
</bpmndi:BPMNEdge>
601+
<bpmndi:BPMNEdge id="Flow_18qem83_di" bpmnElement="Flow_18qem83">
602+
<di:waypoint x="2440" y="255" />
603+
<di:waypoint x="2480" y="255" />
604+
<di:waypoint x="2480" y="235" />
605+
</bpmndi:BPMNEdge>
595606
<bpmndi:BPMNShape id="Event_1y4khet_di" bpmnElement="endJob">
596607
<dc:Bounds x="3192" y="272" width="36" height="36" />
597608
</bpmndi:BPMNShape>
598609
<bpmndi:BPMNShape id="Activity_11rfwl4_di" bpmnElement="mark_import_done">
599610
<dc:Bounds x="3010" y="250" width="100" height="80" />
600611
</bpmndi:BPMNShape>
612+
<bpmndi:BPMNShape id="Gateway_02tmvr8_di" bpmnElement="no_transactions" isMarkerVisible="true">
613+
<dc:Bounds x="1085" y="365" width="50" height="50" />
614+
<bpmndi:BPMNLabel>
615+
<dc:Bounds x="1010" y="383" width="65" height="14" />
616+
</bpmndi:BPMNLabel>
617+
</bpmndi:BPMNShape>
601618
<bpmndi:BPMNEdge id="Flow_1nv7ilo_di" bpmnElement="Flow_1nv7ilo">
602619
<di:waypoint x="188" y="290" />
603620
<di:waypoint x="280" y="290" />

bpmn-process/src/test/java/com/jongsoft/finance/bpmn/ImportJobIT.java

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -180,6 +180,14 @@ void runWithManualAccountCreate(RuntimeContext context) {
180180
process.task("user_create_account")
181181
.complete(Map.of("accountId", 4L));
182182

183+
process.<Set<ExtractionMapping>>yankVariable("accountMappings", mappings -> {
184+
Assertions.assertThat(mappings)
185+
.hasSize(3)
186+
.anySatisfy(mapping -> {
187+
Assertions.assertThat(mapping.getName()).isEqualTo("MW GA Pieterse");
188+
Assertions.assertThat(mapping.getAccountId()).isEqualTo(4L);
189+
});
190+
});
183191
context.verifyTransactions(assertion -> assertion.hasSize(4)
184192
.anySatisfy(this::verifyPostTransaction)
185193
.anySatisfy(this::verifyJanssenTransaction)

fintrack-api/src/main/java/com/jongsoft/finance/filter/AuthenticationFilter.java

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,11 @@ public Publisher<MutableHttpResponse<?>> doFilter(final HttpRequest<?> request,
5757
.recover(Throwable::getMessage).get())
5858
.log("{}: {} in {} ms, with request body {}.");
5959
} else {
60-
log.info("{}: {} in {} ms", request.getMethod(), request.getPath(), Duration.between(startTime, Instant.now()).toMillis());
60+
log.info("{}: {} in {} ms - Status Code {}.",
61+
request.getMethod(),
62+
request.getPath(),
63+
Duration.between(startTime, Instant.now()).toMillis(),
64+
response.status());
6165
}
6266
}
6367
});

fintrack-api/src/main/java/com/jongsoft/finance/rest/importer/ImporterTransactionResource.java

Lines changed: 30 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
import com.jongsoft.finance.providers.TransactionProvider;
77
import com.jongsoft.finance.rest.model.ResultPageResponse;
88
import com.jongsoft.finance.rest.model.TransactionResponse;
9+
import com.jongsoft.finance.rest.process.RuntimeResource;
910
import com.jongsoft.finance.security.AuthenticationRoles;
1011
import io.micronaut.http.HttpStatus;
1112
import io.micronaut.http.annotation.*;
@@ -17,6 +18,8 @@
1718
import io.swagger.v3.oas.annotations.tags.Tag;
1819
import jakarta.validation.Valid;
1920

21+
import java.util.Map;
22+
2023
@Tag(name = "Importer")
2124
@Secured(AuthenticationRoles.IS_AUTHENTICATED)
2225
@Controller("/api/import/{batchSlug}/transactions")
@@ -26,13 +29,17 @@ public class ImporterTransactionResource {
2629
private final FilterFactory filterFactory;
2730
private final TransactionProvider transactionProvider;
2831

32+
private final RuntimeResource runtimeResource;
33+
2934
public ImporterTransactionResource(
3035
SettingProvider settingProvider,
3136
FilterFactory filterFactory,
32-
TransactionProvider transactionProvider) {
37+
TransactionProvider transactionProvider,
38+
RuntimeResource runtimeResource) {
3339
this.settingProvider = settingProvider;
3440
this.filterFactory = filterFactory;
3541
this.transactionProvider = transactionProvider;
42+
this.runtimeResource = runtimeResource;
3643
}
3744

3845
@Post
@@ -56,6 +63,28 @@ ResultPageResponse<TransactionResponse> search(
5663
return new ResultPageResponse<>(response);
5764
}
5865

66+
@Post("/run-rule-automation")
67+
@Status(HttpStatus.NO_CONTENT)
68+
@Operation(
69+
summary = "Run rule automation",
70+
operationId = "runRuleAutomation",
71+
description = "Run rule automation on transactions created by the importer job",
72+
parameters = @Parameter(name = "batchSlug", in = ParameterIn.PATH, schema = @Schema(implementation = String.class))
73+
)
74+
void runRuleAutomation(@PathVariable String batchSlug) {
75+
var searchFilter = filterFactory.transaction()
76+
.importSlug(batchSlug)
77+
.pageSize(Integer.MAX_VALUE)
78+
.page(0);
79+
80+
transactionProvider.lookup(searchFilter)
81+
.content()
82+
.map(Transaction::getId)
83+
.forEach(transactionId -> runtimeResource.startProcess(
84+
"analyzeRule",
85+
Map.of("transactionId", transactionId)));
86+
}
87+
5988
@Delete("/{transactionId}")
6089
@Status(HttpStatus.NO_CONTENT)
6190
@Post

0 commit comments

Comments
 (0)