adjusting the payment workflow

This commit is contained in:
2025-10-23 23:54:42 +02:00
parent 38173a2370
commit 22ecc4b589
5 changed files with 73 additions and 45 deletions

View File

@@ -84,13 +84,13 @@ public class TransactonController {
return ResponseEntity.ok(transactionService.findById(id));
}
@GetMapping("/poll/{id}")
public ResponseEntity<Object> poll(@PathVariable UUID id) throws ExecutionException, InterruptedException {
@GetMapping("/integration/{id}")
public ResponseEntity<Object> integration(@PathVariable UUID id) throws ExecutionException, InterruptedException {
Transaction transaction = transactionService.findById(id);
// Create an update to move the workflow to the next state
WorkflowInstance update = new WorkflowInstance.Builder()
.setId(transaction.getWorkflowId())
.setState("pollStatus") // The state you want to transition to
.setState("integration") // The state you want to transition to
.setNextActivation(DateTime.now()) // Schedule immediate execution
.setStateText("Resumed from manual state")
.build();
@@ -111,6 +111,33 @@ public class TransactonController {
return ResponseEntity.ok(response);
}
@GetMapping("/poll/{id}")
public ResponseEntity<Object> poll(@PathVariable UUID id) throws ExecutionException, InterruptedException {
Transaction transaction = transactionService.findById(id);
// Create an update to move the workflow to the next state
WorkflowInstance update = new WorkflowInstance.Builder()
.setId(transaction.getWorkflowId())
.setState("pollStatus") // The state you want to transition to
.setNextActivation(DateTime.now()) // Schedule immediate execution
.setStateText("Resumed from manual state")
.build();
WorkflowInstanceAction action = new WorkflowInstanceAction.Builder(update)
.setType(WorkflowInstanceAction.WorkflowActionType.externalChange)
.setExecutionEnd(DateTime.now())
.build();
// Apply the update
workflowInstanceService.updateWorkflowInstance(update, action);
CompletableFuture<Object> future = workflowUtils
.waitForState(transaction.getWorkflowId(), new String[]{"purchaseInvoice", "failed"},
15000, 50);
Object response = future.get();
return ResponseEntity.ok(response);
}
@GetMapping("/request/{id}/{authType}")
public ResponseEntity<Object> request(@PathVariable UUID id, @PathVariable AuthType authType)
throws ExecutionException, InterruptedException {
@@ -118,14 +145,15 @@ public class TransactonController {
Transaction transaction = transactionService.findById(id);
transaction.setType(RequestType.REQUEST);
transaction.setAuthType(authType);
transactionService.save(transaction);
transaction = transactionService.save(transaction);
// Create an update to move the workflow to the next state
Transaction finalTransaction = transaction;
WorkflowInstance update = new WorkflowInstance.Builder()
.setId(transaction.getWorkflowId())
.setState("salesInvoice") // The state you want to transition to
.setState("gatewayPayment") // The state you want to transition to
.setNextActivation(DateTime.now()) // Schedule immediate execution
.setStateVariables(new HashMap<>(){{ put("request", Utils.toJson(transaction)); }})
.setStateVariables(new HashMap<>(){{ put("request", Utils.toJson(finalTransaction)); }})
.setStateText("Resumed from manual state")
.build();

View File

@@ -16,6 +16,7 @@ import zw.qantra.tm.domain.models.Transaction;
import zw.qantra.tm.domain.services.TransactionService;
import zw.qantra.tm.domain.workflows.handlers.HandlerInterface;
import zw.qantra.tm.domain.workflows.handlers.WorkflowHandlerFactory;
import zw.qantra.tm.exceptions.ApiException;
import zw.qantra.tm.utils.Utils;
import java.io.IOException;
@@ -39,13 +40,13 @@ public class TransactionWorkflow extends WorkflowDefinition {
public static final State CONFIRM = new State("confirm");
public static final State RECIPIENTS_UPDATE = new State("recipientsUpdate");
public static final State CONFIRM_SUCCESS = new State("confirmSuccess", WorkflowStateType.manual);
public static final State SALES_INVOICE = new State("salesInvoice");
public static final State GATEWAY_PAYMENT = new State("gatewayPayment");
public static final State GATEWAY_PAYMENT_SUCCESS = new State("gatewayPaymentSuccess", WorkflowStateType.manual);
public static final State JOURNAL_ENTRY = new State("journalEntry");
public static final State POLL_STATUS = new State("pollStatus");
public static final State SALES_INVOICE = new State("salesInvoice");
public static final State JOURNAL_ENTRY = new State("journalEntry");
public static final State SALES_PAYMENT = new State("salesPayment");
public static final State PURCHASE_INVOICE = new State("purchaseInvoice");
public static final State PURCHASE_INVOICE = new State("purchaseInvoice", WorkflowStateType.manual);
public static final State INTEGRATION = new State("integration");
public static final State PURCHASE_INVOICE_PAYMENT = new State("purchaseInvoicePayment");
@@ -59,11 +60,11 @@ public class TransactionWorkflow extends WorkflowDefinition {
permit(CLEANUP, CONFIRM);
permit(CONFIRM, RECIPIENTS_UPDATE, FAILED);
permit(RECIPIENTS_UPDATE, CONFIRM_SUCCESS);
permit(CONFIRM_SUCCESS, SALES_INVOICE);
permit(SALES_INVOICE, GATEWAY_PAYMENT);
permit(CONFIRM_SUCCESS, GATEWAY_PAYMENT);
permit(GATEWAY_PAYMENT, GATEWAY_PAYMENT_SUCCESS, FAILED);
permit(GATEWAY_PAYMENT_SUCCESS, POLL_STATUS);
permit(POLL_STATUS, JOURNAL_ENTRY, FAILED);
permit(POLL_STATUS, SALES_INVOICE, FAILED);
permit(SALES_INVOICE, JOURNAL_ENTRY);
permit(JOURNAL_ENTRY, SALES_PAYMENT);
permit(SALES_PAYMENT, PURCHASE_INVOICE);
permit(PURCHASE_INVOICE, INTEGRATION);
@@ -126,27 +127,10 @@ public class TransactionWorkflow extends WorkflowDefinition {
log.info("Confirm complete");
}
public NextAction salesInvoice(StateExecution execution) {
try {
// cannot cast direct to Transaction object because of some jackson mapper hullabaloo :(
LinkedHashMap map = execution.getVariable("request", LinkedHashMap.class);
byte[] json = objectMapper.writeValueAsBytes(map);
Transaction transaction = objectMapper.readValue(json, Transaction.class);
transaction = process(transaction, "salesInvoice");
execution.setVariable("body", Utils.toJson(transaction));
return NextAction.moveToState(GATEWAY_PAYMENT,
"Sales invoice generated - id:" + transaction.getErpSalesRef());
}catch (Exception e) {
e.printStackTrace();
return NextAction.retryAfter(new DateTime().plusMinutes(1), e.getMessage());
}
}
public NextAction gatewayPayment(StateExecution execution) {
try {
// cannot cast direct to Transaction object because of some jackson mapper hullabaloo :(
LinkedHashMap map = execution.getVariable("body", LinkedHashMap.class);
LinkedHashMap map = execution.getVariable("request", LinkedHashMap.class);
byte[] json = objectMapper.writeValueAsBytes(map);
Transaction transaction = objectMapper.readValue(json, Transaction.class);
@@ -172,13 +156,30 @@ public class TransactionWorkflow extends WorkflowDefinition {
transaction = process(transaction, "pollStatus");
execution.setVariable("body", Utils.toJson(transaction));
return NextAction.moveToState(JOURNAL_ENTRY, "Polling complete");
return NextAction.moveToState(SALES_INVOICE, "Polling complete");
} catch (Exception e) {
e.printStackTrace();
return NextAction.moveToState(FAILED, e.getMessage());
}
}
public NextAction salesInvoice(StateExecution execution) {
try {
// cannot cast direct to Transaction object because of some jackson mapper hullabaloo :(
LinkedHashMap map = execution.getVariable("request", LinkedHashMap.class);
byte[] json = objectMapper.writeValueAsBytes(map);
Transaction transaction = objectMapper.readValue(json, Transaction.class);
transaction = process(transaction, "salesInvoice");
execution.setVariable("body", Utils.toJson(transaction));
return NextAction.moveToState(JOURNAL_ENTRY,
"Sales invoice generated - id:" + transaction.getErpSalesRef());
}catch (Exception e) {
e.printStackTrace();
return NextAction.retryAfter(new DateTime().plusMinutes(1), e.getMessage());
}
}
public NextAction journalEntry(StateExecution execution) {
try {
LinkedHashMap map = execution.getVariable("body", LinkedHashMap.class);
@@ -211,20 +212,13 @@ public class TransactionWorkflow extends WorkflowDefinition {
}
}
public NextAction purchaseInvoice(StateExecution execution) {
try {
LinkedHashMap map = execution.getVariable("body", LinkedHashMap.class);
byte[] json = objectMapper.writeValueAsBytes(map);
Transaction transaction = objectMapper.readValue(json, Transaction.class);
public void purchaseInvoice(StateExecution execution) throws IOException {
LinkedHashMap map = execution.getVariable("body", LinkedHashMap.class);
byte[] json = objectMapper.writeValueAsBytes(map);
Transaction transaction = objectMapper.readValue(json, Transaction.class);
transaction = process(transaction, "purchaseInvoice");
execution.setVariable("body", Utils.toJson(transaction));
return NextAction.moveToState(INTEGRATION,
"Purchase invoice generated - id: " + transaction.getErpPurchaseRef());
}catch (Exception e) {
e.printStackTrace();
return NextAction.retryAfter(new DateTime().plusMinutes(1), e.getMessage());
}
transaction = process(transaction, "purchaseInvoice");
execution.setVariable("body", Utils.toJson(transaction));
}
public NextAction integration(StateExecution execution) {

View File

@@ -117,7 +117,7 @@ public class PaymentEntryHandler implements HandlerInterface {
.paidTo(cashAccount)
.paidAmount(amount)
.receivedAmount(amount)
.referenceNo(transaction.getSdkActionId())
.referenceNo(transaction.getId().toString())
.referenceDate(transaction.getCreatedAt().toLocalDate().toString())
.postingDate(transaction.getCreatedAt().toLocalDate().toString())
.references(Arrays.asList(paymentReferenceDto))

View File

@@ -68,6 +68,9 @@ public class PurchaseInvoiceHandler implements HandlerInterface {
.build();
transactionEventService.save(transactionEvent);
if(transaction.getErpPurchaseRef() != null)
return transaction;
if(transaction.getStatus() == Status.SUCCESS){
try {
logger.info("Creating purchase invoice in ERPNext for successful transaction");

View File

@@ -69,6 +69,9 @@ public class PurchasePaymentEntryHandler implements HandlerInterface {
.build();
transactionEventService.save(transactionEvent);
if(transaction.getErpPurchasePaymentRef() != null)
return transaction;
if(transaction.getStatus() == Status.SUCCESS){
try {
logger.info("Creating purchase payment entry in ERPNext for successful transaction");