añadidos ficheros a falta de modificar el servicio y el controlador redsys

This commit is contained in:
2025-11-02 17:14:29 +01:00
parent 4d451cc85e
commit dc8b67b937
25 changed files with 1115 additions and 3 deletions

View File

@ -0,0 +1,4 @@
package com.imprimelibros.erp.payments.model;
public enum CaptureMethod { AUTOMATIC, MANUAL }

View File

@ -0,0 +1,66 @@
package com.imprimelibros.erp.payments.model;
import jakarta.persistence.*;
import java.time.LocalDateTime;
@Entity
@Table(
name = "idempotency_keys",
uniqueConstraints = {
@UniqueConstraint(name = "uq_idem_scope_key", columnNames = {"scope","idem_key"})
},
indexes = {
@Index(name = "idx_idem_resource", columnList = "resource_id")
}
)
public class IdempotencyKey {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@Enumerated(EnumType.STRING)
@Column(name = "scope", nullable = false, length = 16)
private IdempotencyScope scope;
@Column(name = "idem_key", nullable = false, length = 128)
private String idemKey;
@Column(name = "resource_id")
private Long resourceId;
@Column(name = "response_cache", columnDefinition = "json")
private String responseCache;
@Column(name = "created_at", nullable = false,
columnDefinition = "datetime default current_timestamp")
private LocalDateTime createdAt;
@Column(name = "expires_at")
private LocalDateTime expiresAt;
public IdempotencyKey() {}
// Getters & Setters
public Long getId() { return id; }
public void setId(Long id) { this.id = id; }
public IdempotencyScope getScope() { return scope; }
public void setScope(IdempotencyScope scope) { this.scope = scope; }
public String getIdemKey() { return idemKey; }
public void setIdemKey(String idemKey) { this.idemKey = idemKey; }
public Long getResourceId() { return resourceId; }
public void setResourceId(Long resourceId) { this.resourceId = resourceId; }
public String getResponseCache() { return responseCache; }
public void setResponseCache(String responseCache) { this.responseCache = responseCache; }
public LocalDateTime getCreatedAt() { return createdAt; }
public void setCreatedAt(LocalDateTime createdAt) { this.createdAt = createdAt; }
public LocalDateTime getExpiresAt() { return expiresAt; }
public void setExpiresAt(LocalDateTime expiresAt) { this.expiresAt = expiresAt; }
}

View File

@ -0,0 +1,3 @@
package com.imprimelibros.erp.payments.model;
public enum IdempotencyScope { PAYMENT, REFUND, WEBHOOK }

View File

@ -0,0 +1,164 @@
package com.imprimelibros.erp.payments.model;
import jakarta.persistence.*;
import java.time.LocalDateTime;
@Entity
@Table(name = "payments")
public class Payment {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@Column(name = "order_id", nullable = false)
private Long orderId;
@Column(name = "user_id")
private Long userId;
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "payment_method_id")
private PaymentMethod paymentMethod;
@Column(nullable = false, length = 3)
private String currency;
@Column(name = "amount_total_cents", nullable = false)
private Long amountTotalCents;
@Column(name = "amount_captured_cents", nullable = false)
private Long amountCapturedCents = 0L;
@Column(name = "amount_refunded_cents", nullable = false)
private Long amountRefundedCents = 0L;
@Enumerated(EnumType.STRING)
@Column(nullable = false, length = 32)
private PaymentStatus status = PaymentStatus.REQUIRES_PAYMENT_METHOD;
@Enumerated(EnumType.STRING)
@Column(name = "capture_method", nullable = false, length = 16)
private CaptureMethod captureMethod = CaptureMethod.AUTOMATIC;
@Column(nullable = false, length = 32)
private String gateway;
@Column(name = "gateway_payment_id", length = 128)
private String gatewayPaymentId;
@Column(name = "gateway_order_id", length = 12)
private String gatewayOrderId;
@Column(name = "authorization_code", length = 32)
private String authorizationCode;
@Enumerated(EnumType.STRING)
@Column(name = "three_ds_status", nullable = false, length = 32)
private ThreeDSStatus threeDsStatus = ThreeDSStatus.NOT_APPLICABLE;
@Column(length = 22)
private String descriptor;
@Lob
@Column(name = "client_ip", columnDefinition = "varbinary(16)")
private byte[] clientIp;
@Column(name = "authorized_at")
private LocalDateTime authorizedAt;
@Column(name = "captured_at")
private LocalDateTime capturedAt;
@Column(name = "canceled_at")
private LocalDateTime canceledAt;
@Column(name = "failed_at")
private LocalDateTime failedAt;
@Column(columnDefinition = "json")
private String metadata;
@Column(name = "created_at", nullable = false,
columnDefinition = "datetime default current_timestamp")
private LocalDateTime createdAt;
@Column(name = "updated_at", nullable = false,
columnDefinition = "datetime default current_timestamp on update current_timestamp")
private LocalDateTime updatedAt;
public Payment() {}
// Getters y setters ↓ (los típicos)
public Long getId() { return id; }
public void setId(Long id) { this.id = id; }
public Long getOrderId() { return orderId; }
public void setOrderId(Long orderId) { this.orderId = orderId; }
public Long getUserId() { return userId; }
public void setUserId(Long userId) { this.userId = userId; }
public PaymentMethod getPaymentMethod() { return paymentMethod; }
public void setPaymentMethod(PaymentMethod paymentMethod) { this.paymentMethod = paymentMethod; }
public String getCurrency() { return currency; }
public void setCurrency(String currency) { this.currency = currency; }
public Long getAmountTotalCents() { return amountTotalCents; }
public void setAmountTotalCents(Long amountTotalCents) { this.amountTotalCents = amountTotalCents; }
public Long getAmountCapturedCents() { return amountCapturedCents; }
public void setAmountCapturedCents(Long amountCapturedCents) { this.amountCapturedCents = amountCapturedCents; }
public Long getAmountRefundedCents() { return amountRefundedCents; }
public void setAmountRefundedCents(Long amountRefundedCents) { this.amountRefundedCents = amountRefundedCents; }
public PaymentStatus getStatus() { return status; }
public void setStatus(PaymentStatus status) { this.status = status; }
public CaptureMethod getCaptureMethod() { return captureMethod; }
public void setCaptureMethod(CaptureMethod captureMethod) { this.captureMethod = captureMethod; }
public String getGateway() { return gateway; }
public void setGateway(String gateway) { this.gateway = gateway; }
public String getGatewayPaymentId() { return gatewayPaymentId; }
public void setGatewayPaymentId(String gatewayPaymentId) { this.gatewayPaymentId = gatewayPaymentId; }
public String getGatewayOrderId() { return gatewayOrderId; }
public void setGatewayOrderId(String gatewayOrderId) { this.gatewayOrderId = gatewayOrderId; }
public String getAuthorizationCode() { return authorizationCode; }
public void setAuthorizationCode(String authorizationCode) { this.authorizationCode = authorizationCode; }
public ThreeDSStatus getThreeDsStatus() { return threeDsStatus; }
public void setThreeDsStatus(ThreeDSStatus threeDsStatus) { this.threeDsStatus = threeDsStatus; }
public String getDescriptor() { return descriptor; }
public void setDescriptor(String descriptor) { this.descriptor = descriptor; }
public byte[] getClientIp() { return clientIp; }
public void setClientIp(byte[] clientIp) { this.clientIp = clientIp; }
public LocalDateTime getAuthorizedAt() { return authorizedAt; }
public void setAuthorizedAt(LocalDateTime authorizedAt) { this.authorizedAt = authorizedAt; }
public LocalDateTime getCapturedAt() { return capturedAt; }
public void setCapturedAt(LocalDateTime capturedAt) { this.capturedAt = capturedAt; }
public LocalDateTime getCanceledAt() { return canceledAt; }
public void setCanceledAt(LocalDateTime canceledAt) { this.canceledAt = canceledAt; }
public LocalDateTime getFailedAt() { return failedAt; }
public void setFailedAt(LocalDateTime failedAt) { this.failedAt = failedAt; }
public String getMetadata() { return metadata; }
public void setMetadata(String metadata) { this.metadata = metadata; }
public LocalDateTime getCreatedAt() { return createdAt; }
public void setCreatedAt(LocalDateTime createdAt) { this.createdAt = createdAt; }
public LocalDateTime getUpdatedAt() { return updatedAt; }
public void setUpdatedAt(LocalDateTime updatedAt) { this.updatedAt = updatedAt; }
}

View File

@ -0,0 +1,100 @@
package com.imprimelibros.erp.payments.model;
import jakarta.persistence.*;
import java.time.LocalDateTime;
@Entity
@Table(name = "payment_methods")
public class PaymentMethod {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@Column(name = "user_id")
private Long userId;
@Enumerated(EnumType.STRING)
@Column(nullable = false, length = 32)
private PaymentMethodType type;
@Column(length = 32)
private String brand;
@Column(length = 4)
private String last4;
@Column(name = "exp_month")
private Integer expMonth;
@Column(name = "exp_year")
private Integer expYear;
@Column(length = 128)
private String fingerprint;
@Column(length = 128, unique = true)
private String tokenId;
@Column(length = 128)
private String sepaMandateId;
@Column(length = 190)
private String payerEmail;
@Column(columnDefinition = "json")
private String metadata;
@Column(name = "created_at", nullable = false,
columnDefinition = "datetime default current_timestamp")
private LocalDateTime createdAt;
@Column(name = "updated_at", nullable = false,
columnDefinition = "datetime default current_timestamp on update current_timestamp")
private LocalDateTime updatedAt;
// ---- Getters/Setters ----
public PaymentMethod() {}
public Long getId() { return id; }
public void setId(Long id) { this.id = id; }
public Long getUserId() { return userId; }
public void setUserId(Long userId) { this.userId = userId; }
public PaymentMethodType getType() { return type; }
public void setType(PaymentMethodType type) { this.type = type; }
public String getBrand() { return brand; }
public void setBrand(String brand) { this.brand = brand; }
public String getLast4() { return last4; }
public void setLast4(String last4) { this.last4 = last4; }
public Integer getExpMonth() { return expMonth; }
public void setExpMonth(Integer expMonth) { this.expMonth = expMonth; }
public Integer getExpYear() { return expYear; }
public void setExpYear(Integer expYear) { this.expYear = expYear; }
public String getFingerprint() { return fingerprint; }
public void setFingerprint(String fingerprint) { this.fingerprint = fingerprint; }
public String getTokenId() { return tokenId; }
public void setTokenId(String tokenId) { this.tokenId = tokenId; }
public String getSepaMandateId() { return sepaMandateId; }
public void setSepaMandateId(String sepaMandateId) { this.sepaMandateId = sepaMandateId; }
public String getPayerEmail() { return payerEmail; }
public void setPayerEmail(String payerEmail) { this.payerEmail = payerEmail; }
public String getMetadata() { return metadata; }
public void setMetadata(String metadata) { this.metadata = metadata; }
public LocalDateTime getCreatedAt() { return createdAt; }
public void setCreatedAt(LocalDateTime createdAt) { this.createdAt = createdAt; }
public LocalDateTime getUpdatedAt() { return updatedAt; }
public void setUpdatedAt(LocalDateTime updatedAt) { this.updatedAt = updatedAt; }
}

View File

@ -0,0 +1,4 @@
package com.imprimelibros.erp.payments.model;
public enum PaymentMethodType { CARD, BIZUM, BANK_TRANSFER }

View File

@ -0,0 +1,8 @@
package com.imprimelibros.erp.payments.model;
public enum PaymentStatus {
REQUIRES_PAYMENT_METHOD, REQUIRES_ACTION, AUTHORIZED,
CAPTURED, PARTIALLY_REFUNDED, REFUNDED, CANCELED, FAILED
}

View File

@ -0,0 +1,123 @@
package com.imprimelibros.erp.payments.model;
import jakarta.persistence.*;
import java.time.LocalDateTime;
@Entity
@Table(
name = "payment_transactions",
uniqueConstraints = {
@UniqueConstraint(name = "uq_tx_gateway_txid", columnNames = {"gateway_transaction_id"})
},
indexes = {
@Index(name = "idx_tx_pay", columnList = "payment_id"),
@Index(name = "idx_tx_type_status", columnList = "type,status"),
@Index(name = "idx_tx_idem", columnList = "idempotency_key")
}
)
public class PaymentTransaction {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@ManyToOne(fetch = FetchType.LAZY, optional = false)
@JoinColumn(name = "payment_id", nullable = false)
private Payment payment;
@Enumerated(EnumType.STRING)
@Column(name = "type", nullable = false, length = 16)
private PaymentTransactionType type;
@Enumerated(EnumType.STRING)
@Column(name = "status", nullable = false, length = 16)
private PaymentTransactionStatus status;
@Column(name = "amount_cents", nullable = false)
private Long amountCents;
@Column(name = "currency", nullable = false, length = 3)
private String currency;
@Column(name = "gateway_transaction_id", length = 128)
private String gatewayTransactionId;
@Column(name = "gateway_response_code", length = 64)
private String gatewayResponseCode;
@Column(name = "avs_result", length = 8)
private String avsResult;
@Column(name = "cvv_result", length = 8)
private String cvvResult;
@Column(name = "three_ds_version", length = 16)
private String threeDsVersion;
@Column(name = "idempotency_key", length = 128)
private String idempotencyKey;
@Column(name = "request_payload", columnDefinition = "json")
private String requestPayload;
@Column(name = "response_payload", columnDefinition = "json")
private String responsePayload;
@Column(name = "processed_at")
private LocalDateTime processedAt;
@Column(name = "created_at", nullable = false,
columnDefinition = "datetime default current_timestamp")
private LocalDateTime createdAt;
public PaymentTransaction() {}
// Getters & Setters
public Long getId() { return id; }
public void setId(Long id) { this.id = id; }
public Payment getPayment() { return payment; }
public void setPayment(Payment payment) { this.payment = payment; }
public PaymentTransactionType getType() { return type; }
public void setType(PaymentTransactionType type) { this.type = type; }
public PaymentTransactionStatus getStatus() { return status; }
public void setStatus(PaymentTransactionStatus status) { this.status = status; }
public Long getAmountCents() { return amountCents; }
public void setAmountCents(Long amountCents) { this.amountCents = amountCents; }
public String getCurrency() { return currency; }
public void setCurrency(String currency) { this.currency = currency; }
public String getGatewayTransactionId() { return gatewayTransactionId; }
public void setGatewayTransactionId(String gatewayTransactionId) { this.gatewayTransactionId = gatewayTransactionId; }
public String getGatewayResponseCode() { return gatewayResponseCode; }
public void setGatewayResponseCode(String gatewayResponseCode) { this.gatewayResponseCode = gatewayResponseCode; }
public String getAvsResult() { return avsResult; }
public void setAvsResult(String avsResult) { this.avsResult = avsResult; }
public String getCvvResult() { return cvvResult; }
public void setCvvResult(String cvvResult) { this.cvvResult = cvvResult; }
public String getThreeDsVersion() { return threeDsVersion; }
public void setThreeDsVersion(String threeDsVersion) { this.threeDsVersion = threeDsVersion; }
public String getIdempotencyKey() { return idempotencyKey; }
public void setIdempotencyKey(String idempotencyKey) { this.idempotencyKey = idempotencyKey; }
public String getRequestPayload() { return requestPayload; }
public void setRequestPayload(String requestPayload) { this.requestPayload = requestPayload; }
public String getResponsePayload() { return responsePayload; }
public void setResponsePayload(String responsePayload) { this.responsePayload = responsePayload; }
public LocalDateTime getProcessedAt() { return processedAt; }
public void setProcessedAt(LocalDateTime processedAt) { this.processedAt = processedAt; }
public LocalDateTime getCreatedAt() { return createdAt; }
public void setCreatedAt(LocalDateTime createdAt) { this.createdAt = createdAt; }
}

View File

@ -0,0 +1,4 @@
package com.imprimelibros.erp.payments.model;
public enum PaymentTransactionStatus { PENDING, SUCCEEDED, FAILED }

View File

@ -0,0 +1,4 @@
package com.imprimelibros.erp.payments.model;
public enum PaymentTransactionType { AUTH, CAPTURE, REFUND, VOID }

View File

@ -0,0 +1,99 @@
package com.imprimelibros.erp.payments.model;
import jakarta.persistence.*;
import java.time.LocalDateTime;
@Entity
@Table(
name = "refunds",
uniqueConstraints = {
@UniqueConstraint(name = "uq_refund_gateway_id", columnNames = {"gateway_refund_id"})
},
indexes = {
@Index(name = "idx_ref_pay", columnList = "payment_id"),
@Index(name = "idx_ref_status", columnList = "status")
}
)
public class Refund {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@ManyToOne(fetch = FetchType.LAZY, optional = false)
@JoinColumn(name = "payment_id", nullable = false)
private Payment payment;
@OneToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "transaction_id")
private PaymentTransaction transaction; // el REFUND en payment_transactions
@Column(name = "amount_cents", nullable = false)
private Long amountCents;
@Enumerated(EnumType.STRING)
@Column(name = "reason", nullable = false, length = 32)
private RefundReason reason = RefundReason.CUSTOMER_REQUEST;
@Enumerated(EnumType.STRING)
@Column(name = "status", nullable = false, length = 16)
private RefundStatus status = RefundStatus.PENDING;
@Column(name = "requested_by_user_id")
private Long requestedByUserId;
@Column(name = "requested_at", nullable = false,
columnDefinition = "datetime default current_timestamp")
private LocalDateTime requestedAt;
@Column(name = "processed_at")
private LocalDateTime processedAt;
@Column(name = "gateway_refund_id", length = 128)
private String gatewayRefundId;
@Column(name = "notes", length = 500)
private String notes;
@Column(name = "metadata", columnDefinition = "json")
private String metadata;
public Refund() {}
// Getters & Setters
public Long getId() { return id; }
public void setId(Long id) { this.id = id; }
public Payment getPayment() { return payment; }
public void setPayment(Payment payment) { this.payment = payment; }
public PaymentTransaction getTransaction() { return transaction; }
public void setTransaction(PaymentTransaction transaction) { this.transaction = transaction; }
public Long getAmountCents() { return amountCents; }
public void setAmountCents(Long amountCents) { this.amountCents = amountCents; }
public RefundReason getReason() { return reason; }
public void setReason(RefundReason reason) { this.reason = reason; }
public RefundStatus getStatus() { return status; }
public void setStatus(RefundStatus status) { this.status = status; }
public Long getRequestedByUserId() { return requestedByUserId; }
public void setRequestedByUserId(Long requestedByUserId) { this.requestedByUserId = requestedByUserId; }
public LocalDateTime getRequestedAt() { return requestedAt; }
public void setRequestedAt(LocalDateTime requestedAt) { this.requestedAt = requestedAt; }
public LocalDateTime getProcessedAt() { return processedAt; }
public void setProcessedAt(LocalDateTime processedAt) { this.processedAt = processedAt; }
public String getGatewayRefundId() { return gatewayRefundId; }
public void setGatewayRefundId(String gatewayRefundId) { this.gatewayRefundId = gatewayRefundId; }
public String getNotes() { return notes; }
public void setNotes(String notes) { this.notes = notes; }
public String getMetadata() { return metadata; }
public void setMetadata(String metadata) { this.metadata = metadata; }
}

View File

@ -0,0 +1,6 @@
package com.imprimelibros.erp.payments.model;
public enum RefundReason {
CUSTOMER_REQUEST, PARTIAL_RETURN, PRICING_ADJUSTMENT, DUPLICATE, FRAUD, OTHER
}

View File

@ -0,0 +1,4 @@
package com.imprimelibros.erp.payments.model;
public enum RefundStatus { PENDING, SUCCEEDED, FAILED, CANCELED }

View File

@ -0,0 +1,4 @@
package com.imprimelibros.erp.payments.model;
public enum ThreeDSStatus { NOT_APPLICABLE, ATTEMPTED, CHALLENGE, SUCCEEDED, FAILED }

View File

@ -0,0 +1,88 @@
package com.imprimelibros.erp.payments.model;
import jakarta.persistence.*;
import java.time.LocalDateTime;
@Entity
@Table(
name = "webhook_events",
uniqueConstraints = {
@UniqueConstraint(name = "uq_webhook_provider_event", columnNames = {"provider","event_id"})
},
indexes = {
@Index(name = "idx_webhook_processed", columnList = "processed")
}
)
public class WebhookEvent {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@Column(name = "provider", nullable = false, length = 32)
private String provider; // "redsys", etc.
@Column(name = "event_type", nullable = false, length = 64)
private String eventType;
@Column(name = "event_id", length = 128)
private String eventId;
@Column(name = "signature", length = 512)
private String signature;
@Column(name = "payload", nullable = false, columnDefinition = "json")
private String payload;
@Column(name = "processed", nullable = false)
private Boolean processed = false;
@Column(name = "processed_at")
private LocalDateTime processedAt;
@Column(name = "attempts", nullable = false)
private Integer attempts = 0;
@Column(name = "last_error", length = 500)
private String lastError;
@Column(name = "created_at", nullable = false,
columnDefinition = "datetime default current_timestamp")
private LocalDateTime createdAt;
public WebhookEvent() {}
// Getters & Setters
public Long getId() { return id; }
public void setId(Long id) { this.id = id; }
public String getProvider() { return provider; }
public void setProvider(String provider) { this.provider = provider; }
public String getEventType() { return eventType; }
public void setEventType(String eventType) { this.eventType = eventType; }
public String getEventId() { return eventId; }
public void setEventId(String eventId) { this.eventId = eventId; }
public String getSignature() { return signature; }
public void setSignature(String signature) { this.signature = signature; }
public String getPayload() { return payload; }
public void setPayload(String payload) { this.payload = payload; }
public Boolean getProcessed() { return processed; }
public void setProcessed(Boolean processed) { this.processed = processed; }
public LocalDateTime getProcessedAt() { return processedAt; }
public void setProcessedAt(LocalDateTime processedAt) { this.processedAt = processedAt; }
public Integer getAttempts() { return attempts; }
public void setAttempts(Integer attempts) { this.attempts = attempts; }
public String getLastError() { return lastError; }
public void setLastError(String lastError) { this.lastError = lastError; }
public LocalDateTime getCreatedAt() { return createdAt; }
public void setCreatedAt(LocalDateTime createdAt) { this.createdAt = createdAt; }
}