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; }