From 22ecc4b589da595a24f25c21842c5f29648e3edd Mon Sep 17 00:00:00 2001 From: Vusumuzi Khoza Date: Thu, 23 Oct 2025 23:54:42 +0200 Subject: [PATCH] adjusting the payment workflow --- .../controllers/TransactonController.java | 40 +++++++++-- .../domain/workflows/TransactionWorkflow.java | 70 +++++++++---------- .../handlers/erp/PaymentEntryHandler.java | 2 +- .../handlers/erp/PurchaseInvoiceHandler.java | 3 + .../erp/PurchasePaymentEntryHandler.java | 3 + 5 files changed, 73 insertions(+), 45 deletions(-) diff --git a/src/main/java/zw/qantra/tm/domain/controllers/TransactonController.java b/src/main/java/zw/qantra/tm/domain/controllers/TransactonController.java index 871c8e7..5e99552 100644 --- a/src/main/java/zw/qantra/tm/domain/controllers/TransactonController.java +++ b/src/main/java/zw/qantra/tm/domain/controllers/TransactonController.java @@ -84,13 +84,13 @@ public class TransactonController { return ResponseEntity.ok(transactionService.findById(id)); } - @GetMapping("/poll/{id}") - public ResponseEntity poll(@PathVariable UUID id) throws ExecutionException, InterruptedException { + @GetMapping("/integration/{id}") + public ResponseEntity 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 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 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 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(); diff --git a/src/main/java/zw/qantra/tm/domain/workflows/TransactionWorkflow.java b/src/main/java/zw/qantra/tm/domain/workflows/TransactionWorkflow.java index 33d744f..f148ac7 100644 --- a/src/main/java/zw/qantra/tm/domain/workflows/TransactionWorkflow.java +++ b/src/main/java/zw/qantra/tm/domain/workflows/TransactionWorkflow.java @@ -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) { diff --git a/src/main/java/zw/qantra/tm/domain/workflows/handlers/erp/PaymentEntryHandler.java b/src/main/java/zw/qantra/tm/domain/workflows/handlers/erp/PaymentEntryHandler.java index a50f0ea..5e5e185 100644 --- a/src/main/java/zw/qantra/tm/domain/workflows/handlers/erp/PaymentEntryHandler.java +++ b/src/main/java/zw/qantra/tm/domain/workflows/handlers/erp/PaymentEntryHandler.java @@ -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)) diff --git a/src/main/java/zw/qantra/tm/domain/workflows/handlers/erp/PurchaseInvoiceHandler.java b/src/main/java/zw/qantra/tm/domain/workflows/handlers/erp/PurchaseInvoiceHandler.java index 3b9f6b0..b1e4453 100644 --- a/src/main/java/zw/qantra/tm/domain/workflows/handlers/erp/PurchaseInvoiceHandler.java +++ b/src/main/java/zw/qantra/tm/domain/workflows/handlers/erp/PurchaseInvoiceHandler.java @@ -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"); diff --git a/src/main/java/zw/qantra/tm/domain/workflows/handlers/erp/PurchasePaymentEntryHandler.java b/src/main/java/zw/qantra/tm/domain/workflows/handlers/erp/PurchasePaymentEntryHandler.java index 4a3e276..6e1e7d5 100644 --- a/src/main/java/zw/qantra/tm/domain/workflows/handlers/erp/PurchasePaymentEntryHandler.java +++ b/src/main/java/zw/qantra/tm/domain/workflows/handlers/erp/PurchasePaymentEntryHandler.java @@ -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");