updating mpgs related changes
This commit is contained in:
@@ -0,0 +1,107 @@
|
||||
package zw.qantra.tm.domain.dtos;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Builder;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.util.List;
|
||||
|
||||
@Data
|
||||
@Builder
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
public class ErpNextSalesInvoiceDto {
|
||||
|
||||
@JsonProperty("doctype")
|
||||
private String doctype = "Sales Invoice";
|
||||
|
||||
@JsonProperty("company")
|
||||
private String company;
|
||||
|
||||
@JsonProperty("customer")
|
||||
private String customer;
|
||||
|
||||
@JsonProperty("posting_date")
|
||||
private String postingDate;
|
||||
|
||||
@JsonProperty("due_date")
|
||||
private String dueDate;
|
||||
|
||||
@JsonProperty("reference_no")
|
||||
private String referenceNo;
|
||||
|
||||
@JsonProperty("remarks")
|
||||
private String remarks;
|
||||
|
||||
@JsonProperty("currency")
|
||||
private String currency;
|
||||
|
||||
@JsonProperty("conversion_rate")
|
||||
private Double conversionRate = 1.0;
|
||||
|
||||
@JsonProperty("items")
|
||||
private List<ErpNextInvoiceItemDto> items;
|
||||
|
||||
@JsonProperty("taxes")
|
||||
private List<ErpNextTaxDto> taxes;
|
||||
|
||||
@Data
|
||||
@Builder
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
public static class ErpNextInvoiceItemDto {
|
||||
@JsonProperty("doctype")
|
||||
private String doctype = "Sales Invoice Item";
|
||||
|
||||
@JsonProperty("item_code")
|
||||
private String itemCode;
|
||||
|
||||
@JsonProperty("item_name")
|
||||
private String itemName;
|
||||
|
||||
@JsonProperty("description")
|
||||
private String description;
|
||||
|
||||
@JsonProperty("qty")
|
||||
private Double qty = 1.0;
|
||||
|
||||
@JsonProperty("rate")
|
||||
private Double rate;
|
||||
|
||||
@JsonProperty("amount")
|
||||
private Double amount;
|
||||
|
||||
@JsonProperty("income_account")
|
||||
private String incomeAccount;
|
||||
|
||||
@JsonProperty("cost_center")
|
||||
private String costCenter;
|
||||
}
|
||||
|
||||
@Data
|
||||
@Builder
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
public static class ErpNextTaxDto {
|
||||
@JsonProperty("doctype")
|
||||
private String doctype = "Sales Taxes and Charges";
|
||||
|
||||
@JsonProperty("charge_type")
|
||||
private String chargeType = "On Net Total";
|
||||
|
||||
@JsonProperty("account_head")
|
||||
private String accountHead;
|
||||
|
||||
@JsonProperty("description")
|
||||
private String description;
|
||||
|
||||
@JsonProperty("rate")
|
||||
private Double rate;
|
||||
|
||||
@JsonProperty("tax_amount")
|
||||
private Double taxAmount;
|
||||
}
|
||||
}
|
||||
@@ -5,14 +5,12 @@ import lombok.RequiredArgsConstructor;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.UUID;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.data.domain.Page;
|
||||
import org.springframework.data.domain.Pageable;
|
||||
import org.springframework.data.domain.Sort;
|
||||
import org.springframework.data.jpa.domain.Specification;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
@@ -20,7 +18,6 @@ import zw.qantra.tm.domain.enums.RequestType;
|
||||
import zw.qantra.tm.domain.enums.Status;
|
||||
import zw.qantra.tm.domain.models.AdditionalData;
|
||||
import zw.qantra.tm.domain.models.Provider;
|
||||
import zw.qantra.tm.domain.models.Recipient;
|
||||
import zw.qantra.tm.domain.models.Transaction;
|
||||
import zw.qantra.tm.domain.repositories.TransactionRepository;
|
||||
import zw.qantra.tm.domain.services.factories.PaymentProcessorFactory;
|
||||
@@ -31,6 +28,8 @@ import zw.qantra.tm.domain.services.processors.handlers.FormattingHandler;
|
||||
import zw.qantra.tm.domain.services.processors.handlers.LogicPipeline;
|
||||
import zw.qantra.tm.domain.services.processors.handlers.RecipientsUpdateHandler;
|
||||
import zw.qantra.tm.domain.services.processors.handlers.ValidationHandler;
|
||||
import zw.qantra.tm.domain.services.processors.handlers.erp.PurchaseInvoiceHandler;
|
||||
import zw.qantra.tm.domain.services.processors.handlers.erp.SalesInvoiceHandler;
|
||||
import zw.qantra.tm.exceptions.ApiException;
|
||||
import zw.qantra.tm.utils.Utils;
|
||||
|
||||
@@ -76,6 +75,12 @@ public class TransactionService {
|
||||
transactionRepository.save(transaction);
|
||||
return transaction;
|
||||
}
|
||||
|
||||
// run post integration logic
|
||||
LogicPipeline<Transaction, Transaction> postTransactionLogic =
|
||||
new LogicPipeline<>(new PurchaseInvoiceHandler());
|
||||
transaction = postTransactionLogic.execute(transaction);
|
||||
|
||||
return transaction;
|
||||
}
|
||||
|
||||
@@ -85,6 +90,10 @@ public class TransactionService {
|
||||
}
|
||||
|
||||
Transaction transaction = transactionRepository.findById(uuid).get();
|
||||
// if the transaction is already successful, return it
|
||||
if(transaction.getStatus() == Status.SUCCESS){
|
||||
return transaction;
|
||||
}
|
||||
|
||||
// no persistence happens during polling unless the transaction status changes
|
||||
String label = getLabel(transaction);
|
||||
@@ -97,11 +106,12 @@ public class TransactionService {
|
||||
transactionProcessorInterface.poll(transaction);
|
||||
|
||||
// if tran was successful deep copy transaction & push integration to the aggregator
|
||||
Transaction transactionCopy = Utils.deepCopy(transaction, Transaction.class);
|
||||
transactionCopy.setType(RequestType.INTEGRATION);
|
||||
transactionCopy.setId(null);
|
||||
integration(transactionCopy);
|
||||
|
||||
if(transaction.getStatus() == Status.SUCCESS){
|
||||
Transaction transactionCopy = Utils.deepCopy(transaction, Transaction.class);
|
||||
transactionCopy.setType(RequestType.INTEGRATION);
|
||||
transactionCopy.setId(null);
|
||||
integration(transactionCopy);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
transaction.setStatus(Status.FAILED);
|
||||
@@ -143,7 +153,8 @@ public class TransactionService {
|
||||
|
||||
// run post transaction logic
|
||||
LogicPipeline<Transaction, Transaction> postTransactionLogic =
|
||||
new LogicPipeline<>(new RecipientsUpdateHandler(recipientService));
|
||||
new LogicPipeline<>(new RecipientsUpdateHandler(recipientService))
|
||||
.addHandler(new SalesInvoiceHandler());
|
||||
transaction = postTransactionLogic.execute(transaction);
|
||||
|
||||
return transaction;
|
||||
|
||||
@@ -3,7 +3,6 @@ package zw.qantra.tm.domain.services.processors.handlers;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Service;
|
||||
import zw.qantra.tm.domain.models.Charge;
|
||||
import zw.qantra.tm.domain.models.ChargeCondition;
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
package zw.qantra.tm.domain.services.processors.handlers;
|
||||
|
||||
interface LogicHandler<I, O> {
|
||||
public interface LogicHandler<I, O> {
|
||||
O process(I input);
|
||||
}
|
||||
|
||||
@@ -1,7 +1,5 @@
|
||||
package zw.qantra.tm.domain.services.processors.handlers;
|
||||
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
public class LogicPipeline<I, O> {
|
||||
|
||||
private final LogicHandler<I, O> currentHandler;
|
||||
|
||||
@@ -0,0 +1,21 @@
|
||||
package zw.qantra.tm.domain.services.processors.handlers.erp;
|
||||
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import zw.qantra.tm.domain.services.processors.handlers.LogicHandler;
|
||||
import zw.qantra.tm.domain.models.Transaction;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
@Service
|
||||
@RequiredArgsConstructor
|
||||
public class PurchaseInvoiceHandler implements LogicHandler<Transaction, Transaction>{
|
||||
Logger logger = LoggerFactory.getLogger(PurchaseInvoiceHandler.class);
|
||||
|
||||
@Override
|
||||
public Transaction process(Transaction transaction) {
|
||||
logger.info("processing purchase invoice");
|
||||
return transaction;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
package zw.qantra.tm.domain.services.processors.handlers.erp;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import zw.qantra.tm.domain.enums.Status;
|
||||
import zw.qantra.tm.domain.models.Transaction;
|
||||
import zw.qantra.tm.domain.services.processors.handlers.LogicHandler;
|
||||
|
||||
@Service
|
||||
@RequiredArgsConstructor
|
||||
public class SalesInvoiceHandler implements LogicHandler<Transaction, Transaction>{
|
||||
Logger logger = LoggerFactory.getLogger(SalesInvoiceHandler.class);
|
||||
|
||||
|
||||
@Override
|
||||
public Transaction process(Transaction transaction) {
|
||||
logger.info("Processing sales invoice for transaction: {}", transaction.getReference());
|
||||
|
||||
if(transaction.getStatus() == Status.SUCCESS){
|
||||
try {
|
||||
logger.info("Creating sales invoice in ERPNext for successful transaction");
|
||||
|
||||
|
||||
|
||||
logger.info("Sales invoice created successfully in ERPNext");
|
||||
} catch (Exception e) {
|
||||
logger.error("Failed to create sales invoice in ERPNext: {}", e.getMessage(), e);
|
||||
// Don't fail the transaction, just log the error
|
||||
// The ERP invoice creation is a side effect, not critical to the payment flow
|
||||
}
|
||||
} else {
|
||||
logger.info("Transaction status is not SUCCESS ({}), skipping sales invoice creation", transaction.getStatus());
|
||||
}
|
||||
|
||||
return transaction;
|
||||
}
|
||||
}
|
||||
@@ -5,6 +5,9 @@ import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import jakarta.transaction.TransactionScoped;
|
||||
import jakarta.transaction.Transactional;
|
||||
import zw.qantra.tm.domain.dtos.BillPaymentDto;
|
||||
import zw.qantra.tm.domain.enums.RequestType;
|
||||
import zw.qantra.tm.domain.enums.Status;
|
||||
@@ -16,6 +19,7 @@ import zw.qantra.tm.domain.services.processors.TransactionProcessorInterface;
|
||||
import zw.qantra.tm.rest.RestService;
|
||||
import zw.qantra.tm.utils.Utils;
|
||||
|
||||
import java.beans.Transient;
|
||||
import java.util.LinkedHashMap;
|
||||
|
||||
@Service("INTEGRATION_STEWARD")
|
||||
@@ -36,6 +40,7 @@ public class StewardIntegrationProcessor implements TransactionProcessorInterfac
|
||||
private String aggregatorAccount;
|
||||
|
||||
@Override
|
||||
@Transactional
|
||||
public Object process(Transaction transaction) throws Exception {
|
||||
logger.info("processing integration");
|
||||
String token = restService.getMerchantToken();
|
||||
@@ -69,12 +74,14 @@ public class StewardIntegrationProcessor implements TransactionProcessorInterfac
|
||||
transaction.setResponseCode((String) body.get("responseCode"));
|
||||
transaction.setCreditRef((String) body.get("creditReference"));
|
||||
transaction.setAdditionalData(body.get("additionalData"));
|
||||
transaction.setErrorMessage(null); // clear any previous error message
|
||||
transactionService.save(transaction);
|
||||
|
||||
AdditionalData additionalData = AdditionalData.builder()
|
||||
.transaction(transaction)
|
||||
.jsonString(Utils.toJson(body.get("additionalData")))
|
||||
.build();
|
||||
AdditionalData additionalData = additionalDataService.getAdditionalDataRepository()
|
||||
.findByTransactionId(transaction.getId()).orElse(new AdditionalData());
|
||||
|
||||
additionalData.setTransaction(transaction);
|
||||
additionalData.setJsonString(Utils.toJson(body.get("additionalData")));
|
||||
additionalDataService.getAdditionalDataRepository().save(additionalData);
|
||||
|
||||
// fetch the corresponding request transaction if it exists
|
||||
@@ -82,16 +89,15 @@ public class StewardIntegrationProcessor implements TransactionProcessorInterfac
|
||||
.findByTraceAndType(transaction.getTrace(), RequestType.REQUEST);
|
||||
if (requestTransaction != null) {
|
||||
// create a new additional data for the request transaction
|
||||
AdditionalData requestAdditionalData = AdditionalData.builder()
|
||||
.transaction(requestTransaction)
|
||||
.jsonString(Utils.toJson(body.get("additionalData")))
|
||||
.build();
|
||||
AdditionalData requestAdditionalData = additionalDataService.getAdditionalDataRepository()
|
||||
.findByTransactionId(requestTransaction.getId()).orElse(new AdditionalData());
|
||||
requestAdditionalData.setTransaction(requestTransaction);
|
||||
requestAdditionalData.setJsonString(Utils.toJson(body.get("additionalData")));
|
||||
additionalDataService.getAdditionalDataRepository().save(requestAdditionalData);
|
||||
}
|
||||
|
||||
} else {
|
||||
transaction.setStatus(Status.FAILED);
|
||||
transaction.setErrorMessage((String) body.get("message"));
|
||||
transaction.setResponseCode((String) body.get("responseCode"));
|
||||
transaction.setErrorMessage((String) body.get("errorMessage"));
|
||||
}
|
||||
|
||||
@@ -88,7 +88,11 @@ public class MPGSWebPaymentProcessor implements TransactionProcessorInterface {
|
||||
transaction.setStatus(Status.FAILED);
|
||||
transaction.setResponseCode("01");
|
||||
LinkedHashMap transactionData = (LinkedHashMap) body.get("transaction");
|
||||
transaction.setErrorMessage((String) transactionData.get("errorMessage"));
|
||||
if (transactionData != null) {
|
||||
transaction.setErrorMessage((String) transactionData.get("errorMessage"));
|
||||
} else {
|
||||
transaction.setErrorMessage(body.get("errorMessage").toString());
|
||||
}
|
||||
}
|
||||
} catch (Exception e) {
|
||||
logger.error("Network error during payment processing: {}", e.getMessage(), e);
|
||||
@@ -117,16 +121,24 @@ public class MPGSWebPaymentProcessor implements TransactionProcessorInterface {
|
||||
LinkedHashMap body = (LinkedHashMap) response.get("body");
|
||||
|
||||
// only update tran status if polling returns a success
|
||||
if(body.get("status").equals("SUCCESS")){
|
||||
transaction.setStatus(Status.SUCCESS);
|
||||
transaction.setResponseCode("00");
|
||||
transaction.setTargetUrl((String) body.get("targetUrl"));
|
||||
|
||||
LinkedHashMap transactionData = (LinkedHashMap) body.get("transaction");
|
||||
transaction.setDebitRef((String) transactionData.get("debitReference"));
|
||||
|
||||
if(!body.get("status").equals("SUCCESS")){
|
||||
logger.error(body.get("errorMessage").toString());
|
||||
transaction.setStatus(Status.FAILED);
|
||||
transaction.setResponseCode(body.get("responseCode").toString());
|
||||
transaction.setErrorMessage(body.get("errorMessage").toString());
|
||||
transactionService.save(transaction);
|
||||
return transaction;
|
||||
}
|
||||
|
||||
transaction.setStatus(Status.SUCCESS);
|
||||
transaction.setResponseCode("00");
|
||||
transaction.setTargetUrl((String) body.get("targetUrl"));
|
||||
|
||||
LinkedHashMap transactionData = (LinkedHashMap) body.get("transaction");
|
||||
transaction.setDebitRef((String) transactionData.get("debitReference"));
|
||||
|
||||
transactionService.save(transaction);
|
||||
|
||||
} catch (Exception e) {
|
||||
logger.error("Network error during payment processing: {}", e.getMessage(), e);
|
||||
transaction.setStatus(Status.FAILED);
|
||||
|
||||
Reference in New Issue
Block a user