Updates
This commit is contained in:
@@ -0,0 +1,78 @@
|
||||
package com.test.payment.models.audit;
|
||||
|
||||
import com.test.payment.models.PaymentProviderType;
|
||||
import jakarta.persistence.Column;
|
||||
import jakarta.persistence.Entity;
|
||||
import jakarta.persistence.FetchType;
|
||||
import jakarta.persistence.EnumType;
|
||||
import jakarta.persistence.Enumerated;
|
||||
import jakarta.persistence.GeneratedValue;
|
||||
import jakarta.persistence.GenerationType;
|
||||
import jakarta.persistence.Id;
|
||||
import jakarta.persistence.JoinColumn;
|
||||
import jakarta.persistence.ManyToOne;
|
||||
import jakarta.persistence.Table;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
import lombok.ToString;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.time.Instant;
|
||||
|
||||
/**
|
||||
* An asynchronous result callback from Airtel Money, stored whole alongside the fields
|
||||
* worth querying on, and tied back to the call that caused it. Unlike
|
||||
* PAYMENT_CALLBACKS this keeps every callback, duplicates included — an audit trail
|
||||
* that silently drops repeats is not one.
|
||||
*/
|
||||
@Entity
|
||||
@Getter
|
||||
@Setter
|
||||
@ToString(exclude = "Request")
|
||||
public class AirtelCallbackResponse {
|
||||
|
||||
@Id
|
||||
@GeneratedValue(strategy = GenerationType.IDENTITY)
|
||||
private Long Id;
|
||||
|
||||
/** Null when the callback could not be matched to an outbound request. */
|
||||
@ManyToOne(targetEntity = AirtelRequest.class, fetch = FetchType.LAZY)
|
||||
@JoinColumn(name = "Request")
|
||||
private AirtelRequest Request;
|
||||
|
||||
@Enumerated(EnumType.STRING)
|
||||
@Column(nullable = false, length = 20)
|
||||
private PaymentProviderType Provider;
|
||||
|
||||
@Column(length = 100)
|
||||
private String ProviderReference;
|
||||
|
||||
@Column(length = 30)
|
||||
private String ResultCode;
|
||||
|
||||
@Column(length = 255)
|
||||
private String ResultDesc;
|
||||
|
||||
@Column(length = 50)
|
||||
private String ReceiptNumber;
|
||||
|
||||
@Column(precision = 10, scale = 2)
|
||||
private BigDecimal Amount;
|
||||
|
||||
@Column(length = 15)
|
||||
private String PhoneNumber;
|
||||
|
||||
@Column(length = 20)
|
||||
private String TransactionDate;
|
||||
|
||||
/** The callback exactly as it arrived. */
|
||||
@Column(columnDefinition = "TEXT")
|
||||
private String RawPayload;
|
||||
|
||||
/** False when no matching request could be found — an orphan worth alerting on. */
|
||||
@Column(nullable = false)
|
||||
private boolean Matched;
|
||||
|
||||
@Column(nullable = false)
|
||||
private Instant CreatedAt;
|
||||
}
|
||||
@@ -0,0 +1,68 @@
|
||||
package com.test.payment.models.audit;
|
||||
|
||||
import com.test.payment.models.PaymentProviderType;
|
||||
import jakarta.persistence.Column;
|
||||
import jakarta.persistence.Entity;
|
||||
import jakarta.persistence.EnumType;
|
||||
import jakarta.persistence.Enumerated;
|
||||
import jakarta.persistence.GeneratedValue;
|
||||
import jakarta.persistence.GenerationType;
|
||||
import jakarta.persistence.Id;
|
||||
import jakarta.persistence.Table;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
import lombok.ToString;
|
||||
|
||||
import java.time.Instant;
|
||||
|
||||
/**
|
||||
* One outbound call to Airtel Money, recorded verbatim: what we sent, where, and on whose
|
||||
* behalf. Written asynchronously by ProviderCallAudit — nothing on the payment path
|
||||
* waits for this row.
|
||||
*/
|
||||
@Entity
|
||||
@Getter
|
||||
@Setter
|
||||
@ToString
|
||||
public class AirtelRequest {
|
||||
|
||||
@Id
|
||||
@GeneratedValue(strategy = GenerationType.IDENTITY)
|
||||
private Long Id;
|
||||
|
||||
/** Market-qualified provider, e.g. AIRTEL_KE. */
|
||||
@Enumerated(EnumType.STRING)
|
||||
@Column(nullable = false, length = 20)
|
||||
private PaymentProviderType Provider;
|
||||
|
||||
/** Which call this was: USSD_PUSH, STATUS_QUERY, TOKEN. */
|
||||
@Column(nullable = false, length = 40)
|
||||
private String Operation;
|
||||
|
||||
/**
|
||||
* The payment attempt this call belongs to; null for calls with no payment
|
||||
* (token fetches). A string, not the numeric id, so it can carry a NanoID.
|
||||
*/
|
||||
@Column(length = 36)
|
||||
private String InitiationId;
|
||||
|
||||
/**
|
||||
* The provider's own reference once known, so a later callback can be tied back
|
||||
* to the exact call that produced it.
|
||||
*/
|
||||
@Column(length = 100)
|
||||
private String ProviderReference;
|
||||
|
||||
@Column(length = 10)
|
||||
private String HttpMethod;
|
||||
|
||||
@Column(length = 512)
|
||||
private String Url;
|
||||
|
||||
/** Outbound body as sent, JSON. Credentials are redacted before this is stored. */
|
||||
@Column(columnDefinition = "TEXT")
|
||||
private String RequestBody;
|
||||
|
||||
@Column(nullable = false)
|
||||
private Instant CreatedAt;
|
||||
}
|
||||
@@ -0,0 +1,52 @@
|
||||
package com.test.payment.models.audit;
|
||||
|
||||
import jakarta.persistence.Column;
|
||||
import jakarta.persistence.Entity;
|
||||
import jakarta.persistence.FetchType;
|
||||
import jakarta.persistence.GeneratedValue;
|
||||
import jakarta.persistence.GenerationType;
|
||||
import jakarta.persistence.Id;
|
||||
import jakarta.persistence.JoinColumn;
|
||||
import jakarta.persistence.ManyToOne;
|
||||
import jakarta.persistence.Table;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
import lombok.ToString;
|
||||
|
||||
import java.time.Instant;
|
||||
|
||||
/**
|
||||
* What Airtel Money answered a AirtelRequest with — including the failures, which is
|
||||
* usually what an audit is actually needed for.
|
||||
*/
|
||||
@Entity
|
||||
@Getter
|
||||
@Setter
|
||||
@ToString(exclude = "Request")
|
||||
public class AirtelResponse {
|
||||
|
||||
@Id
|
||||
@GeneratedValue(strategy = GenerationType.IDENTITY)
|
||||
private Long Id;
|
||||
|
||||
@ManyToOne(targetEntity = AirtelRequest.class, fetch = FetchType.LAZY)
|
||||
@JoinColumn(name = "Request", nullable = false)
|
||||
private AirtelRequest Request;
|
||||
|
||||
/** HTTP status, or null when the call never got an answer (timeout, DNS, reset). */
|
||||
private Integer HttpStatus;
|
||||
|
||||
/** Response body verbatim, JSON. */
|
||||
@Column(columnDefinition = "TEXT")
|
||||
private String ResponseBody;
|
||||
|
||||
/** Exception summary when the call failed outright. */
|
||||
@Column(length = 512)
|
||||
private String Error;
|
||||
|
||||
/** Round-trip time, for spotting Airtel Money degrading before it starts erroring. */
|
||||
private Long DurationMs;
|
||||
|
||||
@Column(nullable = false)
|
||||
private Instant CreatedAt;
|
||||
}
|
||||
@@ -0,0 +1,78 @@
|
||||
package com.test.payment.models.audit;
|
||||
|
||||
import com.test.payment.models.PaymentProviderType;
|
||||
import jakarta.persistence.Column;
|
||||
import jakarta.persistence.Entity;
|
||||
import jakarta.persistence.FetchType;
|
||||
import jakarta.persistence.EnumType;
|
||||
import jakarta.persistence.Enumerated;
|
||||
import jakarta.persistence.GeneratedValue;
|
||||
import jakarta.persistence.GenerationType;
|
||||
import jakarta.persistence.Id;
|
||||
import jakarta.persistence.JoinColumn;
|
||||
import jakarta.persistence.ManyToOne;
|
||||
import jakarta.persistence.Table;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
import lombok.ToString;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.time.Instant;
|
||||
|
||||
/**
|
||||
* An asynchronous result callback from M-Pesa, stored whole alongside the fields
|
||||
* worth querying on, and tied back to the call that caused it. Unlike
|
||||
* PAYMENT_CALLBACKS this keeps every callback, duplicates included — an audit trail
|
||||
* that silently drops repeats is not one.
|
||||
*/
|
||||
@Entity
|
||||
@Getter
|
||||
@Setter
|
||||
@ToString(exclude = "Request")
|
||||
public class MpesaCallbackResponse {
|
||||
|
||||
@Id
|
||||
@GeneratedValue(strategy = GenerationType.IDENTITY)
|
||||
private Long Id;
|
||||
|
||||
/** Null when the callback could not be matched to an outbound request. */
|
||||
@ManyToOne(targetEntity = MpesaRequest.class, fetch = FetchType.LAZY)
|
||||
@JoinColumn(name = "Request")
|
||||
private MpesaRequest Request;
|
||||
|
||||
@Enumerated(EnumType.STRING)
|
||||
@Column(nullable = false, length = 20)
|
||||
private PaymentProviderType Provider;
|
||||
|
||||
@Column(length = 100)
|
||||
private String ProviderReference;
|
||||
|
||||
@Column(length = 30)
|
||||
private String ResultCode;
|
||||
|
||||
@Column(length = 255)
|
||||
private String ResultDesc;
|
||||
|
||||
@Column(length = 50)
|
||||
private String ReceiptNumber;
|
||||
|
||||
@Column(precision = 10, scale = 2)
|
||||
private BigDecimal Amount;
|
||||
|
||||
@Column(length = 15)
|
||||
private String PhoneNumber;
|
||||
|
||||
@Column(length = 20)
|
||||
private String TransactionDate;
|
||||
|
||||
/** The callback exactly as it arrived. */
|
||||
@Column(columnDefinition = "TEXT")
|
||||
private String RawPayload;
|
||||
|
||||
/** False when no matching request could be found — an orphan worth alerting on. */
|
||||
@Column(nullable = false)
|
||||
private boolean Matched;
|
||||
|
||||
@Column(nullable = false)
|
||||
private Instant CreatedAt;
|
||||
}
|
||||
@@ -0,0 +1,68 @@
|
||||
package com.test.payment.models.audit;
|
||||
|
||||
import com.test.payment.models.PaymentProviderType;
|
||||
import jakarta.persistence.Column;
|
||||
import jakarta.persistence.Entity;
|
||||
import jakarta.persistence.EnumType;
|
||||
import jakarta.persistence.Enumerated;
|
||||
import jakarta.persistence.GeneratedValue;
|
||||
import jakarta.persistence.GenerationType;
|
||||
import jakarta.persistence.Id;
|
||||
import jakarta.persistence.Table;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
import lombok.ToString;
|
||||
|
||||
import java.time.Instant;
|
||||
|
||||
/**
|
||||
* One outbound call to M-Pesa, recorded verbatim: what we sent, where, and on whose
|
||||
* behalf. Written asynchronously by ProviderCallAudit — nothing on the payment path
|
||||
* waits for this row.
|
||||
*/
|
||||
@Entity
|
||||
@Getter
|
||||
@Setter
|
||||
@ToString
|
||||
public class MpesaRequest {
|
||||
|
||||
@Id
|
||||
@GeneratedValue(strategy = GenerationType.IDENTITY)
|
||||
private Long Id;
|
||||
|
||||
/** Market-qualified provider, e.g. MPESA_KE. */
|
||||
@Enumerated(EnumType.STRING)
|
||||
@Column(nullable = false, length = 20)
|
||||
private PaymentProviderType Provider;
|
||||
|
||||
/** Which call this was: STK_PUSH, STK_QUERY, TOKEN. */
|
||||
@Column(nullable = false, length = 40)
|
||||
private String Operation;
|
||||
|
||||
/**
|
||||
* The payment attempt this call belongs to; null for calls with no payment
|
||||
* (token fetches). A string, not the numeric id, so it can carry a NanoID.
|
||||
*/
|
||||
@Column(length = 5000)
|
||||
private String InitiationId;
|
||||
|
||||
/**
|
||||
* The provider's own reference once known, so a later callback can be tied back
|
||||
* to the exact call that produced it.
|
||||
*/
|
||||
@Column(length = 100)
|
||||
private String ProviderReference;
|
||||
|
||||
@Column(length = 10)
|
||||
private String HttpMethod;
|
||||
|
||||
@Column(length = 512)
|
||||
private String Url;
|
||||
|
||||
/** Outbound body as sent, JSON. Credentials are redacted before this is stored. */
|
||||
@Column(columnDefinition = "TEXT")
|
||||
private String RequestBody;
|
||||
|
||||
@Column(nullable = false)
|
||||
private Instant CreatedAt;
|
||||
}
|
||||
@@ -0,0 +1,52 @@
|
||||
package com.test.payment.models.audit;
|
||||
|
||||
import jakarta.persistence.Column;
|
||||
import jakarta.persistence.Entity;
|
||||
import jakarta.persistence.FetchType;
|
||||
import jakarta.persistence.GeneratedValue;
|
||||
import jakarta.persistence.GenerationType;
|
||||
import jakarta.persistence.Id;
|
||||
import jakarta.persistence.JoinColumn;
|
||||
import jakarta.persistence.ManyToOne;
|
||||
import jakarta.persistence.Table;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
import lombok.ToString;
|
||||
|
||||
import java.time.Instant;
|
||||
|
||||
/**
|
||||
* What M-Pesa answered a MpesaRequest with — including the failures, which is
|
||||
* usually what an audit is actually needed for.
|
||||
*/
|
||||
@Entity
|
||||
@Getter
|
||||
@Setter
|
||||
@ToString(exclude = "Request")
|
||||
public class MpesaResponse {
|
||||
|
||||
@Id
|
||||
@GeneratedValue(strategy = GenerationType.IDENTITY)
|
||||
private Long Id;
|
||||
|
||||
@ManyToOne(targetEntity = MpesaRequest.class, fetch = FetchType.LAZY)
|
||||
@JoinColumn(name = "Request", nullable = false)
|
||||
private MpesaRequest Request;
|
||||
|
||||
/** HTTP status, or null when the call never got an answer (timeout, DNS, reset). */
|
||||
private Integer HttpStatus;
|
||||
|
||||
/** Response body verbatim, JSON. */
|
||||
@Column(columnDefinition = "TEXT")
|
||||
private String ResponseBody;
|
||||
|
||||
/** Exception summary when the call failed outright. */
|
||||
@Column(length = 512)
|
||||
private String Error;
|
||||
|
||||
/** Round-trip time, for spotting M-Pesa degrading before it starts erroring. */
|
||||
private Long DurationMs;
|
||||
|
||||
@Column(nullable = false)
|
||||
private Instant CreatedAt;
|
||||
}
|
||||
@@ -0,0 +1,78 @@
|
||||
package com.test.payment.models.audit;
|
||||
|
||||
import com.test.payment.models.PaymentProviderType;
|
||||
import jakarta.persistence.Column;
|
||||
import jakarta.persistence.Entity;
|
||||
import jakarta.persistence.FetchType;
|
||||
import jakarta.persistence.EnumType;
|
||||
import jakarta.persistence.Enumerated;
|
||||
import jakarta.persistence.GeneratedValue;
|
||||
import jakarta.persistence.GenerationType;
|
||||
import jakarta.persistence.Id;
|
||||
import jakarta.persistence.JoinColumn;
|
||||
import jakarta.persistence.ManyToOne;
|
||||
import jakarta.persistence.Table;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
import lombok.ToString;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.time.Instant;
|
||||
|
||||
/**
|
||||
* An asynchronous result callback from MTN MoMo, stored whole alongside the fields
|
||||
* worth querying on, and tied back to the call that caused it. Unlike
|
||||
* PAYMENT_CALLBACKS this keeps every callback, duplicates included — an audit trail
|
||||
* that silently drops repeats is not one.
|
||||
*/
|
||||
@Entity
|
||||
@Getter
|
||||
@Setter
|
||||
@ToString(exclude = "Request")
|
||||
public class MtnCallbackResponse {
|
||||
|
||||
@Id
|
||||
@GeneratedValue(strategy = GenerationType.IDENTITY)
|
||||
private Long Id;
|
||||
|
||||
/** Null when the callback could not be matched to an outbound request. */
|
||||
@ManyToOne(targetEntity = MtnRequest.class, fetch = FetchType.LAZY)
|
||||
@JoinColumn(name = "Request")
|
||||
private MtnRequest Request;
|
||||
|
||||
@Enumerated(EnumType.STRING)
|
||||
@Column(nullable = false, length = 20)
|
||||
private PaymentProviderType Provider;
|
||||
|
||||
@Column(length = 100)
|
||||
private String ProviderReference;
|
||||
|
||||
@Column(length = 30)
|
||||
private String ResultCode;
|
||||
|
||||
@Column(length = 255)
|
||||
private String ResultDesc;
|
||||
|
||||
@Column(length = 50)
|
||||
private String ReceiptNumber;
|
||||
|
||||
@Column(precision = 10, scale = 2)
|
||||
private BigDecimal Amount;
|
||||
|
||||
@Column(length = 15)
|
||||
private String PhoneNumber;
|
||||
|
||||
@Column(length = 20)
|
||||
private String TransactionDate;
|
||||
|
||||
/** The callback exactly as it arrived. */
|
||||
@Column(columnDefinition = "TEXT")
|
||||
private String RawPayload;
|
||||
|
||||
/** False when no matching request could be found — an orphan worth alerting on. */
|
||||
@Column(nullable = false)
|
||||
private boolean Matched;
|
||||
|
||||
@Column(nullable = false)
|
||||
private Instant CreatedAt;
|
||||
}
|
||||
68
src/main/java/com/test/payment/models/audit/MtnRequest.java
Normal file
68
src/main/java/com/test/payment/models/audit/MtnRequest.java
Normal file
@@ -0,0 +1,68 @@
|
||||
package com.test.payment.models.audit;
|
||||
|
||||
import com.test.payment.models.PaymentProviderType;
|
||||
import jakarta.persistence.Column;
|
||||
import jakarta.persistence.Entity;
|
||||
import jakarta.persistence.EnumType;
|
||||
import jakarta.persistence.Enumerated;
|
||||
import jakarta.persistence.GeneratedValue;
|
||||
import jakarta.persistence.GenerationType;
|
||||
import jakarta.persistence.Id;
|
||||
import jakarta.persistence.Table;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
import lombok.ToString;
|
||||
|
||||
import java.time.Instant;
|
||||
|
||||
/**
|
||||
* One outbound call to MTN MoMo, recorded verbatim: what we sent, where, and on whose
|
||||
* behalf. Written asynchronously by ProviderCallAudit — nothing on the payment path
|
||||
* waits for this row.
|
||||
*/
|
||||
@Entity
|
||||
@Getter
|
||||
@Setter
|
||||
@ToString
|
||||
public class MtnRequest {
|
||||
|
||||
@Id
|
||||
@GeneratedValue(strategy = GenerationType.IDENTITY)
|
||||
private Long Id;
|
||||
|
||||
/** Market-qualified provider, e.g. MTN_UG. */
|
||||
@Enumerated(EnumType.STRING)
|
||||
@Column(nullable = false, length = 20)
|
||||
private PaymentProviderType Provider;
|
||||
|
||||
/** Which call this was: REQUEST_TO_PAY, STATUS_QUERY, TOKEN. */
|
||||
@Column(nullable = false, length = 40)
|
||||
private String Operation;
|
||||
|
||||
/**
|
||||
* The payment attempt this call belongs to; null for calls with no payment
|
||||
* (token fetches). A string, not the numeric id, so it can carry a NanoID.
|
||||
*/
|
||||
@Column(length = 36)
|
||||
private String InitiationId;
|
||||
|
||||
/**
|
||||
* The provider's own reference once known, so a later callback can be tied back
|
||||
* to the exact call that produced it.
|
||||
*/
|
||||
@Column(length = 100)
|
||||
private String ProviderReference;
|
||||
|
||||
@Column(length = 10)
|
||||
private String HttpMethod;
|
||||
|
||||
@Column(length = 512)
|
||||
private String Url;
|
||||
|
||||
/** Outbound body as sent, JSON. Credentials are redacted before this is stored. */
|
||||
@Column(columnDefinition = "TEXT")
|
||||
private String RequestBody;
|
||||
|
||||
@Column(nullable = false)
|
||||
private Instant CreatedAt;
|
||||
}
|
||||
52
src/main/java/com/test/payment/models/audit/MtnResponse.java
Normal file
52
src/main/java/com/test/payment/models/audit/MtnResponse.java
Normal file
@@ -0,0 +1,52 @@
|
||||
package com.test.payment.models.audit;
|
||||
|
||||
import jakarta.persistence.Column;
|
||||
import jakarta.persistence.Entity;
|
||||
import jakarta.persistence.FetchType;
|
||||
import jakarta.persistence.GeneratedValue;
|
||||
import jakarta.persistence.GenerationType;
|
||||
import jakarta.persistence.Id;
|
||||
import jakarta.persistence.JoinColumn;
|
||||
import jakarta.persistence.ManyToOne;
|
||||
import jakarta.persistence.Table;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
import lombok.ToString;
|
||||
|
||||
import java.time.Instant;
|
||||
|
||||
/**
|
||||
* What MTN MoMo answered a MtnRequest with — including the failures, which is
|
||||
* usually what an audit is actually needed for.
|
||||
*/
|
||||
@Entity
|
||||
@Getter
|
||||
@Setter
|
||||
@ToString(exclude = "Request")
|
||||
public class MtnResponse {
|
||||
|
||||
@Id
|
||||
@GeneratedValue(strategy = GenerationType.IDENTITY)
|
||||
private Long Id;
|
||||
|
||||
@ManyToOne(targetEntity = MtnRequest.class, fetch = FetchType.LAZY)
|
||||
@JoinColumn(name = "Request", nullable = false)
|
||||
private MtnRequest Request;
|
||||
|
||||
/** HTTP status, or null when the call never got an answer (timeout, DNS, reset). */
|
||||
private Integer HttpStatus;
|
||||
|
||||
/** Response body verbatim, JSON. */
|
||||
@Column(columnDefinition = "TEXT")
|
||||
private String ResponseBody;
|
||||
|
||||
/** Exception summary when the call failed outright. */
|
||||
@Column(length = 512)
|
||||
private String Error;
|
||||
|
||||
/** Round-trip time, for spotting MTN MoMo degrading before it starts erroring. */
|
||||
private Long DurationMs;
|
||||
|
||||
@Column(nullable = false)
|
||||
private Instant CreatedAt;
|
||||
}
|
||||
Reference in New Issue
Block a user