diff --git a/CHANGELOG.md b/CHANGELOG.md new file mode 100644 index 00000000..4842ae7f --- /dev/null +++ b/CHANGELOG.md @@ -0,0 +1,27 @@ +# Changelog + +All notable changes to this project will be documented in this file. + +This project follows [Keep a Changelog](https://keepachangelog.com/en/1.0.0/) +and [Semantic Versioning](https://semver.org/spec/v2.0.0.html). + +## [3.2.0] - 2026-05-27 + +### Added + +- **PreApprovalPlan**: subscription plan template management — create, get, update, search + (`POST/GET/PUT /preapproval_plan`). Enables reusable billing templates for subscriptions. + +- **AdvancedPayment**: marketplace split-payment management — create, get, search, capture, cancel, + updateReleaseDate (`POST/GET/PUT /v1/advanced_payments`). Enables distributing a single + payment among multiple sellers. + +- **Invoice**: retrieval and search of subscription billing invoices — get, search + (`GET /authorized_payments`). Enables monitoring of billing cycles generated by preapprovals. + +- **DisbursementRefund**: refunds for split-payment disbursements — createAll, create + (`POST /v1/advanced_payments/{id}/refunds`). Enables partial and full refunds of individual + disbursements within an advanced payment. + +- **Chargeback**: read-only access to payment dispute records — get, search + (`GET /v1/chargebacks`). Enables monitoring and response to cardholder disputes. diff --git a/mp_ref_report.md b/mp_ref_report.md deleted file mode 100644 index dc53fa5f..00000000 --- a/mp_ref_report.md +++ /dev/null @@ -1,121 +0,0 @@ -# MP API Reference Audit Report — Java SDK -_Generado: 2026-04-24_ - -## Resumen -| Categoria | Cantidad | -|-----------|----------| -| Total metodos API | 48 | -| Con reference URL | 28 (58%) | -| Sin reference URL (gaps) | 20 (42%) | -| URLs no canonicas (dominio pais) | 16 | -| URLs canonicas (.com) | 10 | - ---- - -## URLs no canonicas (dominio por pais) - -Estas URLs usan dominios por pais (`.com.br`, `.com.ar`) en lugar del canonico `https://www.mercadopago.com/developers/en/reference/...`: - -| Archivo | URL encontrada | Dominio | -|---------|---------------|---------| -| PaymentRefundClient.java | `https://www.mercadopago.com.br/developers/en/reference/chargebacks/_payments_id_refunds/post` | .com.br | -| PaymentRefundClient.java | `https://www.mercadopago.com.br/developers/en/reference/chargebacks/_payments_id_refunds_refund_id/get` | .com.br | -| PaymentRefundClient.java | `https://www.mercadopago.com.br/developers/en/reference/chargebacks/_payments_id_refunds/get` | .com.br | -| CustomerClient.java | `https://www.mercadopago.com.br/developers/en/reference/online-payments/checkout-api/customers/search-customer/get` | .com.br | -| CustomerCardClient.java | `https://www.mercadopago.com.br/developers/en/reference/cards/_customers_customer_id_cards/get` | .com.br | -| IdentificationTypeClient.java | `https://www.mercadopago.com.br/developers/en/reference/identification_types/_identification_types/get` | .com.br | -| MerchantOrderClient.java | `https://www.mercadopago.com.br/developers/en/reference/merchant_orders/_merchant_orders/post` | .com.br | -| MerchantOrderClient.java | `https://www.mercadopago.com.br/developers/en/reference/merchant_orders/_merchant_orders_id/get` | .com.br | -| MerchantOrderClient.java | `https://www.mercadopago.com.br/developers/en/reference/merchant_orders/_merchant_orders_id/put` | .com.br | -| MerchantOrderClient.java | `https://www.mercadopago.com.br/developers/en/reference/merchant_orders/_merchant_orders_search/get` | .com.br | -| OauthClient.java | `https://www.mercadopago.com.br/developers/en/reference/oauth/_oauth_token/post` | .com.br | -| PreferenceClient.java | `https://www.mercadopago.com.br/developers/en/reference/preferences/_checkout_preferences/post` | .com.br | -| PreferenceClient.java | `https://www.mercadopago.com.br/developers/en/reference/preferences/_checkout_preferences_id/get` | .com.br | -| PreferenceClient.java | `https://www.mercadopago.com.br/developers/en/reference/preferences/_checkout_preferences_id/put` | .com.br | -| PreferenceClient.java | `https://www.mercadopago.com.br/developers/en/reference/preferences/_checkout_preferences_search/get` | .com.br | -| PaymentMethodClient.java | `https://www.mercadopago.com.br/developers/en/reference/payment_methods/_payment_methods/get` | .com.br | -| PointClient.java | `https://www.mercadopago.com.ar/developers/en/reference/in-person-payments/point/orders/create-order/post` | .com.ar | -| PointClient.java | `https://www.mercadopago.com.ar/developers/en/reference/in-person-payments/point/orders/get-order/get` | .com.ar | -| PointClient.java | `https://www.mercadopago.com.ar/developers/en/reference/in-person-payments/point/orders/cancel-order/post` | .com.ar | -| PointClient.java | `https://www.mercadopago.com.ar/developers/en/reference/in-person-payments/point/terminals/get-terminals/get` | .com.ar | -| PointClient.java | `https://www.mercadopago.com.ar/developers/en/reference/in-person-payments/point/terminals/update-operation-mode/patch` | .com.ar | - ---- - -## Links faltantes (gaps) — 20 metodos sin referencia - -### PaymentClient.java (4 gaps de 5 metodos) -- [ ] `get(Long id)` — GET /v1/payments/{id} -- [ ] `cancel(Long id)` — PUT /v1/payments/{id} (status=cancelled) -- [ ] `capture(Long id, BigDecimal amount)` — PUT /v1/payments/{id} (capture=true) -- [ ] `search(MPSearchRequest request)` — GET /v1/payments/search - -### CustomerCardClient.java (4 gaps de 4 metodos) -- [ ] `get(String customerId, String cardId)` — GET /v1/customers/{id}/cards/{cardId} -- [ ] `create(String customerId, CustomerCardCreateRequest request)` — POST /v1/customers/{id}/cards -- [ ] `delete(String customerId, String cardId)` — DELETE /v1/customers/{id}/cards/{cardId} -- [ ] `listAll(String customerId)` — GET /v1/customers/{id}/cards - -### CardTokenClient.java (2 gaps de 2 metodos) -- [ ] `get(String id)` — GET /v1/card_tokens/{id} -- [ ] `create(CardTokenRequest request)` — POST /v1/card_tokens - -### OrderClient.java (9 gaps de 10 metodos) -- [ ] `get(String id)` — GET /v1/orders/{id} -- [ ] `process(String id)` — POST /v1/orders/{id}/process -- [ ] `createTransaction(String orderId, OrderTransactionRequest request)` — POST /v1/orders/{id}/transactions -- [ ] `updateTransaction(String orderId, String transactionId, OrderPaymentRequest request)` — PUT /v1/orders/{id}/transactions/{transactionId} -- [ ] `cancel(String orderId)` — POST /v1/orders/{id}/cancel -- [ ] `capture(String orderId)` — POST /v1/orders/{id}/capture -- [ ] `deleteTransaction(String orderId, String transactionId)` — DELETE /v1/orders/{id}/transactions/{transactionId} -- [ ] `refund(String orderId, OrderRefundRequest request)` — POST /v1/orders/{id}/refund -- [ ] `search(MPSearchRequest request)` — GET /v1/orders - -### PreapprovalClient.java (4 gaps de 4 metodos) -- [ ] `get(String id)` — GET /preapproval/{id} -- [ ] `create(PreapprovalCreateRequest request)` — POST /preapproval -- [ ] `update(String id, PreapprovalUpdateRequest request)` — PUT /preapproval/{id} -- [ ] `search(MPSearchRequest request)` — GET /preapproval/search - -### Otros -- [ ] `CustomerClient.delete(String customerId)` — DELETE /v1/customers/{id} -- [ ] `OauthClient.getAuthorizationURL(...)` — URL builder (no endpoint directo) -- [ ] `PointClient.getPaymentIntentStatus(String id)` — GET /point/integration-api/payment-intents/{id}/events -- [ ] `UserClient.get()` — GET /users/me - ---- - -## Cobertura por cliente - -| Cliente | Metodos | Con URL | Sin URL | Cobertura | -|---------|---------|---------|---------|-----------| -| PaymentClient | 6 | 1 | 5* | 17% | -| PaymentRefundClient | 3 | 3 | 0 | 100% | -| CustomerClient | 5 | 4 | 1 | 80% | -| CustomerCardClient | 4 | 0 | 4 | 0% | -| CardTokenClient | 2 | 0 | 2 | 0% | -| IdentificationTypeClient | 1 | 1 | 0 | 100% | -| MerchantOrderClient | 4 | 4 | 0 | 100% | -| OauthClient | 3 | 2 | 1 | 67% | -| OrderClient | 10 | 1 | 9 | 10% | -| PointClient | 7 | 6 | 1 | 86% | -| PreapprovalClient | 4 | 0 | 4 | 0% | -| PreferenceClient | 4 | 4 | 0 | 100% | -| PaymentMethodClient | 1 | 1 | 0 | 100% | -| UserClient | 1 | 0 | 1 | 0% | - -*PaymentClient: tiene 1 URL a nivel de clase pero solo cubre create() - ---- - -## Lista de revision manual -- [ ] PaymentClient.java — 4 metodos sin referencia API -- [ ] CustomerCardClient.java — 4 metodos sin referencia API (0% cobertura) -- [ ] CardTokenClient.java — 2 metodos sin referencia API (0% cobertura) -- [ ] OrderClient.java — 9 metodos sin referencia API (10% cobertura) -- [ ] PreapprovalClient.java — 4 metodos sin referencia API (0% cobertura) -- [ ] CustomerClient.java — delete() sin referencia API -- [ ] OauthClient.java — getAuthorizationURL() sin referencia API -- [ ] PointClient.java — getPaymentIntentStatus() sin referencia API -- [ ] UserClient.java — get() sin referencia API -- [ ] 16 URLs usan dominio por pais (.com.br/.com.ar) en lugar del canonico (.com) diff --git a/pom.xml b/pom.xml index 9b2aaf3c..ad6ec1eb 100644 --- a/pom.xml +++ b/pom.xml @@ -4,7 +4,7 @@ com.mercadopago sdk-java - 3.1.0 + 3.2.0 jar Mercadopago SDK diff --git a/src/main/java/com/mercadopago/MercadoPagoConfig.java b/src/main/java/com/mercadopago/MercadoPagoConfig.java index 30ecaac1..2d9b7dcd 100644 --- a/src/main/java/com/mercadopago/MercadoPagoConfig.java +++ b/src/main/java/com/mercadopago/MercadoPagoConfig.java @@ -35,7 +35,7 @@ */ public class MercadoPagoConfig { - public static final String CURRENT_VERSION = "3.1.0"; + public static final String CURRENT_VERSION = "3.2.0"; /** Internal MercadoPago product identifier sent in every API request for analytics. */ public static final String PRODUCT_ID = "BC32A7VTRPP001U8NHJ0"; diff --git a/src/main/java/com/mercadopago/client/advancedpayment/AdvancedPaymentCancelRequest.java b/src/main/java/com/mercadopago/client/advancedpayment/AdvancedPaymentCancelRequest.java new file mode 100644 index 00000000..e1572fc0 --- /dev/null +++ b/src/main/java/com/mercadopago/client/advancedpayment/AdvancedPaymentCancelRequest.java @@ -0,0 +1,9 @@ +package com.mercadopago.client.advancedpayment; + +import lombok.Getter; + +/** Request to cancel an advanced payment (sets {@code status} to {@code "cancelled"}). */ +@Getter +public class AdvancedPaymentCancelRequest { + private final String status = "cancelled"; +} diff --git a/src/main/java/com/mercadopago/client/advancedpayment/AdvancedPaymentCaptureRequest.java b/src/main/java/com/mercadopago/client/advancedpayment/AdvancedPaymentCaptureRequest.java new file mode 100644 index 00000000..5a70355b --- /dev/null +++ b/src/main/java/com/mercadopago/client/advancedpayment/AdvancedPaymentCaptureRequest.java @@ -0,0 +1,11 @@ +package com.mercadopago.client.advancedpayment; + +import lombok.Builder; +import lombok.Getter; + +/** Request to capture an advanced payment (sets {@code capture} to {@code true}). */ +@Getter +@Builder +public class AdvancedPaymentCaptureRequest { + private final boolean capture = true; +} diff --git a/src/main/java/com/mercadopago/client/advancedpayment/AdvancedPaymentClient.java b/src/main/java/com/mercadopago/client/advancedpayment/AdvancedPaymentClient.java new file mode 100644 index 00000000..77c66cdb --- /dev/null +++ b/src/main/java/com/mercadopago/client/advancedpayment/AdvancedPaymentClient.java @@ -0,0 +1,277 @@ +package com.mercadopago.client.advancedpayment; + +import static com.mercadopago.MercadoPagoConfig.getStreamHandler; +import static com.mercadopago.serialization.Serializer.deserializeFromJson; +import static com.mercadopago.serialization.Serializer.deserializeResultsResourcesPageFromJson; +import static com.mercadopago.serialization.Serializer.serializeToJson; + +import com.google.gson.reflect.TypeToken; +import com.mercadopago.MercadoPagoConfig; +import com.mercadopago.client.MercadoPagoClient; +import com.mercadopago.core.MPRequestOptions; +import com.mercadopago.exceptions.MPApiException; +import com.mercadopago.exceptions.MPException; +import com.mercadopago.net.HttpMethod; +import com.mercadopago.net.MPHttpClient; +import com.mercadopago.net.MPResponse; +import com.mercadopago.net.MPResultsResourcesPage; +import com.mercadopago.net.MPSearchRequest; +import com.mercadopago.resources.advancedpayment.AdvancedPayment; +import java.lang.reflect.Type; +import java.util.logging.Logger; +import java.util.logging.StreamHandler; + +/** + * Client for the MercadoPago Advanced Payments (Marketplace Split Payments) API. + * + *

Enables marketplace integrations to collect a single payment and distribute funds among + * multiple sellers (disbursements). Supports two-step flows (authorise → capture) and individual + * disbursement release-date control. + * + *

Usage example: + *

{@code
+ * AdvancedPaymentClient client = new AdvancedPaymentClient();
+ * AdvancedPayment payment = client.create(createRequest);
+ * AdvancedPayment captured = client.capture(payment.getId());
+ * }
+ * + * @see + * Advanced Payments API reference + */ +public class AdvancedPaymentClient extends MercadoPagoClient { + + /** Class-level logger for advanced payment operations. */ + private static final Logger LOGGER = Logger.getLogger(AdvancedPaymentClient.class.getName()); + + /** URL for the advanced payments collection endpoint. */ + private static final String URL = "/v1/advanced_payments"; + + /** URL template for single advanced payment endpoints. */ + private static final String URL_WITH_ID = "/v1/advanced_payments/%s"; + + /** URL template for the disburses (release date) endpoint. */ + private static final String URL_DISBURSES = "/v1/advanced_payments/%s/disburses"; + + /** + * Default constructor. Uses the default HTTP client provided by {@link MercadoPagoConfig}. + */ + public AdvancedPaymentClient() { + this(MercadoPagoConfig.getHttpClient()); + } + + /** + * Constructs an {@code AdvancedPaymentClient} with a custom HTTP client. + * + * @param httpClient the {@link MPHttpClient} used to execute HTTP requests + */ + public AdvancedPaymentClient(MPHttpClient httpClient) { + super(httpClient); + StreamHandler streamHandler = getStreamHandler(); + streamHandler.setLevel(MercadoPagoConfig.getLoggingLevel()); + LOGGER.addHandler(streamHandler); + LOGGER.setLevel(MercadoPagoConfig.getLoggingLevel()); + } + + /** + * Retrieves an advanced payment by its unique identifier. + * + * @param id the unique identifier of the advanced payment + * @return the requested {@link AdvancedPayment} + * @throws MPException if a transport-level or SDK-internal error occurs + * @throws MPApiException if the API returns a non-successful HTTP status code + */ + public AdvancedPayment get(Long id) throws MPException, MPApiException { + return this.get(id, null); + } + + /** + * Retrieves an advanced payment by its unique identifier with custom request options. + * + * @param id the unique identifier of the advanced payment + * @param requestOptions optional {@link MPRequestOptions}; may be {@code null} + * @return the requested {@link AdvancedPayment} + * @throws MPException if a transport-level or SDK-internal error occurs + * @throws MPApiException if the API returns a non-successful HTTP status code + */ + public AdvancedPayment get(Long id, MPRequestOptions requestOptions) + throws MPException, MPApiException { + LOGGER.info("Sending get advanced payment request"); + MPResponse response = + send(String.format(URL_WITH_ID, id), HttpMethod.GET, null, null, requestOptions); + + AdvancedPayment result = deserializeFromJson(AdvancedPayment.class, response.getContent()); + result.setResponse(response); + return result; + } + + /** + * Creates a new advanced (split) payment. + * + * @param request the {@link AdvancedPaymentCreateRequest} with payment and disbursement details + * @return the created {@link AdvancedPayment} + * @throws MPException if a transport-level or SDK-internal error occurs + * @throws MPApiException if the API returns a non-successful HTTP status code + */ + public AdvancedPayment create(AdvancedPaymentCreateRequest request) + throws MPException, MPApiException { + return this.create(request, null); + } + + /** + * Creates a new advanced (split) payment with custom request options. + * + * @param request the {@link AdvancedPaymentCreateRequest} with payment and disbursement details + * @param requestOptions optional {@link MPRequestOptions}; may be {@code null} + * @return the created {@link AdvancedPayment} + * @throws MPException if a transport-level or SDK-internal error occurs + * @throws MPApiException if the API returns a non-successful HTTP status code + */ + public AdvancedPayment create(AdvancedPaymentCreateRequest request, + MPRequestOptions requestOptions) throws MPException, MPApiException { + LOGGER.info("Sending create advanced payment request"); + MPResponse response = + send(URL, HttpMethod.POST, serializeToJson(request), null, requestOptions); + + AdvancedPayment result = deserializeFromJson(AdvancedPayment.class, response.getContent()); + result.setResponse(response); + return result; + } + + /** + * Captures a previously authorised advanced payment. + * + * @param id the unique identifier of the advanced payment to capture + * @return the captured {@link AdvancedPayment} + * @throws MPException if a transport-level or SDK-internal error occurs + * @throws MPApiException if the API returns a non-successful HTTP status code + */ + public AdvancedPayment capture(Long id) throws MPException, MPApiException { + return this.capture(id, null); + } + + /** + * Captures a previously authorised advanced payment with custom request options. + * + * @param id the unique identifier of the advanced payment to capture + * @param requestOptions optional {@link MPRequestOptions}; may be {@code null} + * @return the captured {@link AdvancedPayment} + * @throws MPException if a transport-level or SDK-internal error occurs + * @throws MPApiException if the API returns a non-successful HTTP status code + */ + public AdvancedPayment capture(Long id, MPRequestOptions requestOptions) + throws MPException, MPApiException { + LOGGER.info("Sending capture advanced payment request"); + MPResponse response = + send(String.format(URL_WITH_ID, id), HttpMethod.PUT, + serializeToJson(new AdvancedPaymentCaptureRequest()), null, requestOptions); + + AdvancedPayment result = deserializeFromJson(AdvancedPayment.class, response.getContent()); + result.setResponse(response); + return result; + } + + /** + * Cancels an advanced payment by setting its status to "cancelled". + * + * @param id the unique identifier of the advanced payment to cancel + * @return the cancelled {@link AdvancedPayment} + * @throws MPException if a transport-level or SDK-internal error occurs + * @throws MPApiException if the API returns a non-successful HTTP status code + */ + public AdvancedPayment cancel(Long id) throws MPException, MPApiException { + return this.cancel(id, null); + } + + /** + * Cancels an advanced payment with custom request options. + * + * @param id the unique identifier of the advanced payment to cancel + * @param requestOptions optional {@link MPRequestOptions}; may be {@code null} + * @return the cancelled {@link AdvancedPayment} + * @throws MPException if a transport-level or SDK-internal error occurs + * @throws MPApiException if the API returns a non-successful HTTP status code + */ + public AdvancedPayment cancel(Long id, MPRequestOptions requestOptions) + throws MPException, MPApiException { + LOGGER.info("Sending cancel advanced payment request"); + MPResponse response = + send(String.format(URL_WITH_ID, id), HttpMethod.PUT, + serializeToJson(new AdvancedPaymentCancelRequest()), null, requestOptions); + + AdvancedPayment result = deserializeFromJson(AdvancedPayment.class, response.getContent()); + result.setResponse(response); + return result; + } + + /** + * Changes the money release date for all disbursements of an advanced payment. + * + * @param id the unique identifier of the advanced payment + * @param releaseDate the new release date in ISO 8601 format + * @return the updated {@link AdvancedPayment} + * @throws MPException if a transport-level or SDK-internal error occurs + * @throws MPApiException if the API returns a non-successful HTTP status code + */ + public AdvancedPayment updateReleaseDate(Long id, String releaseDate) + throws MPException, MPApiException { + return this.updateReleaseDate(id, releaseDate, null); + } + + /** + * Changes the money release date for all disbursements with custom request options. + * + * @param id the unique identifier of the advanced payment + * @param releaseDate the new release date in ISO 8601 format + * @param requestOptions optional {@link MPRequestOptions}; may be {@code null} + * @return the updated {@link AdvancedPayment} + * @throws MPException if a transport-level or SDK-internal error occurs + * @throws MPApiException if the API returns a non-successful HTTP status code + */ + public AdvancedPayment updateReleaseDate(Long id, String releaseDate, + MPRequestOptions requestOptions) throws MPException, MPApiException { + LOGGER.info("Sending update release date advanced payment request"); + AdvancedPaymentUpdateReleaseDateRequest releaseDateRequest = + AdvancedPaymentUpdateReleaseDateRequest.builder().moneyReleaseDate(releaseDate).build(); + MPResponse response = + send(String.format(URL_DISBURSES, id), HttpMethod.POST, + serializeToJson(releaseDateRequest), null, requestOptions); + + AdvancedPayment result = deserializeFromJson(AdvancedPayment.class, response.getContent()); + result.setResponse(response); + return result; + } + + /** + * Searches advanced payments matching the given criteria. + * + * @param request the {@link MPSearchRequest} with search filters and pagination parameters + * @return an {@link MPResultsResourcesPage} of {@link AdvancedPayment} results + * @throws MPException if a transport-level or SDK-internal error occurs + * @throws MPApiException if the API returns a non-successful HTTP status code + */ + public MPResultsResourcesPage search(MPSearchRequest request) + throws MPException, MPApiException { + return this.search(request, null); + } + + /** + * Searches advanced payments matching the given criteria with custom request options. + * + * @param request the {@link MPSearchRequest} with search filters and pagination parameters + * @param requestOptions optional {@link MPRequestOptions}; may be {@code null} + * @return an {@link MPResultsResourcesPage} of {@link AdvancedPayment} results + * @throws MPException if a transport-level or SDK-internal error occurs + * @throws MPApiException if the API returns a non-successful HTTP status code + */ + public MPResultsResourcesPage search(MPSearchRequest request, + MPRequestOptions requestOptions) throws MPException, MPApiException { + LOGGER.info("Sending search advanced payment request"); + MPResponse response = search("/v1/advanced_payments/search", request, requestOptions); + + Type responseType = new TypeToken>() {}.getType(); + MPResultsResourcesPage result = + deserializeResultsResourcesPageFromJson(responseType, response.getContent()); + result.setResponse(response); + return result; + } +} diff --git a/src/main/java/com/mercadopago/client/advancedpayment/AdvancedPaymentCreateRequest.java b/src/main/java/com/mercadopago/client/advancedpayment/AdvancedPaymentCreateRequest.java new file mode 100644 index 00000000..c5d1a856 --- /dev/null +++ b/src/main/java/com/mercadopago/client/advancedpayment/AdvancedPaymentCreateRequest.java @@ -0,0 +1,39 @@ +package com.mercadopago.client.advancedpayment; + +import java.util.List; +import lombok.Builder; +import lombok.Getter; + +/** + * Request to create a new advanced (split) payment. + * + * @see com.mercadopago.client.advancedpayment.AdvancedPaymentClient + */ +@Getter +@Builder +public class AdvancedPaymentCreateRequest { + + /** List of payment sources (card tokens, amounts). */ + private final List payments; + + /** List of receivers (collector IDs and amounts). */ + private final List disbursements; + + /** Buyer information. */ + private final AdvancedPaymentPayerRequest payer; + + /** MercadoPago application identifier. */ + private final String applicationId; + + /** Human-readable description of the payment. */ + private final String description; + + /** Integrator-provided external reference. */ + private final String externalReference; + + /** When false, creates an authorised but uncaptured payment. */ + private final Boolean capture; + + /** When true, the payment is approved or rejected immediately. */ + private final Boolean binaryMode; +} diff --git a/src/main/java/com/mercadopago/client/advancedpayment/AdvancedPaymentDisbursementRequest.java b/src/main/java/com/mercadopago/client/advancedpayment/AdvancedPaymentDisbursementRequest.java new file mode 100644 index 00000000..f587985f --- /dev/null +++ b/src/main/java/com/mercadopago/client/advancedpayment/AdvancedPaymentDisbursementRequest.java @@ -0,0 +1,30 @@ +package com.mercadopago.client.advancedpayment; + +import java.math.BigDecimal; +import lombok.Builder; +import lombok.Getter; + +/** + * A single disbursement receiver in an advanced payment create request. + * + * @see AdvancedPaymentCreateRequest + */ +@Getter +@Builder +public class AdvancedPaymentDisbursementRequest { + + /** MercadoPago user identifier of the seller who receives the funds. */ + private final Long collectorId; + + /** Amount to disburse to this collector. */ + private final BigDecimal amount; + + /** Integrator-provided external reference for this disbursement. */ + private final String externalReference; + + /** Marketplace application fee retained from this disbursement. */ + private final BigDecimal applicationFee; + + /** Scheduled date when funds are released to the seller (ISO 8601). */ + private final String moneyReleaseDate; +} diff --git a/src/main/java/com/mercadopago/client/advancedpayment/AdvancedPaymentPayerRequest.java b/src/main/java/com/mercadopago/client/advancedpayment/AdvancedPaymentPayerRequest.java new file mode 100644 index 00000000..dc05fac7 --- /dev/null +++ b/src/main/java/com/mercadopago/client/advancedpayment/AdvancedPaymentPayerRequest.java @@ -0,0 +1,29 @@ +package com.mercadopago.client.advancedpayment; + +import lombok.Builder; +import lombok.Getter; + +/** + * Payer (buyer) information for an advanced payment. + * + * @see AdvancedPaymentCreateRequest + */ +@Getter +@Builder +public class AdvancedPaymentPayerRequest { + + /** Payer type. */ + private final String type; + + /** MercadoPago payer identifier. */ + private final String id; + + /** Payer email address. */ + private final String email; + + /** Payer first name. */ + private final String firstName; + + /** Payer last name. */ + private final String lastName; +} diff --git a/src/main/java/com/mercadopago/client/advancedpayment/AdvancedPaymentPaymentRequest.java b/src/main/java/com/mercadopago/client/advancedpayment/AdvancedPaymentPaymentRequest.java new file mode 100644 index 00000000..dc126e4d --- /dev/null +++ b/src/main/java/com/mercadopago/client/advancedpayment/AdvancedPaymentPaymentRequest.java @@ -0,0 +1,45 @@ +package com.mercadopago.client.advancedpayment; + +import java.math.BigDecimal; +import lombok.Builder; +import lombok.Getter; + +/** + * A single payment source within an advanced payment. + * + * @see AdvancedPaymentCreateRequest + */ +@Getter +@Builder +public class AdvancedPaymentPaymentRequest { + + /** Payment method identifier (e.g., master, visa). */ + private final String paymentMethodId; + + /** Payment type identifier (e.g., credit_card). */ + private final String paymentTypeId; + + /** Card token for the payment. */ + private final String token; + + /** Expiration date for the payment intent. */ + private final String dateOfExpiration; + + /** Gross transaction amount. */ + private final BigDecimal transactionAmount; + + /** Number of installments. */ + private final Integer installments; + + /** Processing mode (e.g., aggregator). */ + private final String processingMode; + + /** Human-readable description of the payment. */ + private final String description; + + /** Integrator-provided external reference. */ + private final String externalReference; + + /** Text displayed on the cardholder's statement. */ + private final String statementDescriptor; +} diff --git a/src/main/java/com/mercadopago/client/advancedpayment/AdvancedPaymentUpdateReleaseDateRequest.java b/src/main/java/com/mercadopago/client/advancedpayment/AdvancedPaymentUpdateReleaseDateRequest.java new file mode 100644 index 00000000..5e2a62d6 --- /dev/null +++ b/src/main/java/com/mercadopago/client/advancedpayment/AdvancedPaymentUpdateReleaseDateRequest.java @@ -0,0 +1,13 @@ +package com.mercadopago.client.advancedpayment; + +import lombok.Builder; +import lombok.Getter; + +/** Request to change the money release date for all disbursements. */ +@Getter +@Builder +public class AdvancedPaymentUpdateReleaseDateRequest { + + /** New release date in ISO 8601 format. */ + private final String moneyReleaseDate; +} diff --git a/src/main/java/com/mercadopago/client/chargeback/ChargebackClient.java b/src/main/java/com/mercadopago/client/chargeback/ChargebackClient.java new file mode 100644 index 00000000..765c80dd --- /dev/null +++ b/src/main/java/com/mercadopago/client/chargeback/ChargebackClient.java @@ -0,0 +1,131 @@ +package com.mercadopago.client.chargeback; + +import static com.mercadopago.MercadoPagoConfig.getStreamHandler; +import static com.mercadopago.serialization.Serializer.deserializeFromJson; +import static com.mercadopago.serialization.Serializer.deserializeResultsResourcesPageFromJson; + +import com.google.gson.reflect.TypeToken; +import com.mercadopago.MercadoPagoConfig; +import com.mercadopago.client.MercadoPagoClient; +import com.mercadopago.core.MPRequestOptions; +import com.mercadopago.exceptions.MPApiException; +import com.mercadopago.exceptions.MPException; +import com.mercadopago.net.HttpMethod; +import com.mercadopago.net.MPHttpClient; +import com.mercadopago.net.MPResponse; +import com.mercadopago.net.MPResultsResourcesPage; +import com.mercadopago.net.MPSearchRequest; +import com.mercadopago.resources.chargeback.Chargeback; +import java.lang.reflect.Type; +import java.util.logging.Logger; +import java.util.logging.StreamHandler; + +/** + * Client for the MercadoPago Chargebacks API. + * + *

Provides read-only access to chargeback dispute records initiated by cardholders through + * their issuing bank. + * + *

Usage example: + *

{@code
+ * ChargebackClient client = new ChargebackClient();
+ * Chargeback chargeback = client.get("CB-001");
+ * }
+ * + * @see + * Chargebacks API reference + */ +public class ChargebackClient extends MercadoPagoClient { + + /** Class-level logger for chargeback operations. */ + private static final Logger LOGGER = Logger.getLogger(ChargebackClient.class.getName()); + + /** URL template for single-chargeback endpoints. */ + private static final String URL_WITH_ID = "/v1/chargebacks/%s"; + + /** + * Default constructor. Uses the default HTTP client provided by {@link MercadoPagoConfig}. + */ + public ChargebackClient() { + this(MercadoPagoConfig.getHttpClient()); + } + + /** + * Constructs a {@code ChargebackClient} with a custom HTTP client. + * + * @param httpClient the {@link MPHttpClient} used to execute HTTP requests + */ + public ChargebackClient(MPHttpClient httpClient) { + super(httpClient); + StreamHandler streamHandler = getStreamHandler(); + streamHandler.setLevel(MercadoPagoConfig.getLoggingLevel()); + LOGGER.addHandler(streamHandler); + LOGGER.setLevel(MercadoPagoConfig.getLoggingLevel()); + } + + /** + * Retrieves a chargeback by its unique identifier. + * + * @param id the unique identifier of the chargeback + * @return the requested {@link Chargeback} + * @throws MPException if a transport-level or SDK-internal error occurs + * @throws MPApiException if the API returns a non-successful HTTP status code + */ + public Chargeback get(String id) throws MPException, MPApiException { + return this.get(id, null); + } + + /** + * Retrieves a chargeback by its unique identifier with custom request options. + * + * @param id the unique identifier of the chargeback + * @param requestOptions optional {@link MPRequestOptions}; may be {@code null} + * @return the requested {@link Chargeback} + * @throws MPException if a transport-level or SDK-internal error occurs + * @throws MPApiException if the API returns a non-successful HTTP status code + */ + public Chargeback get(String id, MPRequestOptions requestOptions) + throws MPException, MPApiException { + LOGGER.info("Sending get chargeback request"); + MPResponse response = + send(String.format(URL_WITH_ID, id), HttpMethod.GET, null, null, requestOptions); + + Chargeback result = deserializeFromJson(Chargeback.class, response.getContent()); + result.setResponse(response); + return result; + } + + /** + * Searches chargebacks matching the given criteria. + * + * @param request the {@link MPSearchRequest} with search filters and pagination parameters + * @return an {@link MPResultsResourcesPage} of {@link Chargeback} results + * @throws MPException if a transport-level or SDK-internal error occurs + * @throws MPApiException if the API returns a non-successful HTTP status code + */ + public MPResultsResourcesPage search(MPSearchRequest request) + throws MPException, MPApiException { + return this.search(request, null); + } + + /** + * Searches chargebacks matching the given criteria with custom request options. + * + * @param request the {@link MPSearchRequest} with search filters and pagination parameters + * @param requestOptions optional {@link MPRequestOptions}; may be {@code null} + * @return an {@link MPResultsResourcesPage} of {@link Chargeback} results + * @throws MPException if a transport-level or SDK-internal error occurs + * @throws MPApiException if the API returns a non-successful HTTP status code + */ + public MPResultsResourcesPage search( + MPSearchRequest request, MPRequestOptions requestOptions) throws MPException, MPApiException { + LOGGER.info("Sending search chargeback request"); + MPResponse response = search("/v1/chargebacks/search", request, requestOptions); + + Type responseType = new TypeToken>() {}.getType(); + MPResultsResourcesPage result = + deserializeResultsResourcesPageFromJson(responseType, response.getContent()); + result.setResponse(response); + return result; + } +} diff --git a/src/main/java/com/mercadopago/client/disbursementrefund/DisbursementRefundClient.java b/src/main/java/com/mercadopago/client/disbursementrefund/DisbursementRefundClient.java new file mode 100644 index 00000000..223f5fd6 --- /dev/null +++ b/src/main/java/com/mercadopago/client/disbursementrefund/DisbursementRefundClient.java @@ -0,0 +1,140 @@ +package com.mercadopago.client.disbursementrefund; + +import static com.mercadopago.MercadoPagoConfig.getStreamHandler; +import static com.mercadopago.serialization.Serializer.deserializeFromJson; +import static com.mercadopago.serialization.Serializer.serializeToJson; + +import com.mercadopago.MercadoPagoConfig; +import com.mercadopago.client.MercadoPagoClient; +import com.mercadopago.core.MPRequestOptions; +import com.mercadopago.exceptions.MPApiException; +import com.mercadopago.exceptions.MPException; +import com.mercadopago.net.HttpMethod; +import com.mercadopago.net.MPHttpClient; +import com.mercadopago.net.MPResponse; +import com.mercadopago.resources.disbursementrefund.DisbursementRefund; +import java.util.logging.Logger; +import java.util.logging.StreamHandler; + +/** + * Client for the MercadoPago Disbursement Refunds API. + * + *

Enables full and partial refunds of individual disbursements within an advanced (split) + * payment. Use this client alongside {@link com.mercadopago.client.advancedpayment.AdvancedPaymentClient}. + * + *

Usage example: + *

{@code
+ * DisbursementRefundClient client = new DisbursementRefundClient();
+ * DisbursementRefund refund = client.create(advancedPaymentId, disbursementId, createRequest);
+ * }
+ */ +public class DisbursementRefundClient extends MercadoPagoClient { + + /** Class-level logger for disbursement refund operations. */ + private static final Logger LOGGER = Logger.getLogger(DisbursementRefundClient.class.getName()); + + /** URL template for bulk refund endpoints. */ + private static final String URL_REFUNDS = "/v1/advanced_payments/%s/refunds"; + + /** URL template for individual disbursement refund endpoints. */ + private static final String URL_DISBURSEMENT_REFUND = + "/v1/advanced_payments/%s/disbursements/%s/refunds"; + + /** + * Default constructor. Uses the default HTTP client provided by {@link MercadoPagoConfig}. + */ + public DisbursementRefundClient() { + this(MercadoPagoConfig.getHttpClient()); + } + + /** + * Constructs a {@code DisbursementRefundClient} with a custom HTTP client. + * + * @param httpClient the {@link MPHttpClient} used to execute HTTP requests + */ + public DisbursementRefundClient(MPHttpClient httpClient) { + super(httpClient); + StreamHandler streamHandler = getStreamHandler(); + streamHandler.setLevel(MercadoPagoConfig.getLoggingLevel()); + LOGGER.addHandler(streamHandler); + LOGGER.setLevel(MercadoPagoConfig.getLoggingLevel()); + } + + /** + * Refunds all disbursements of an advanced payment at once. + * + * @param advancedPaymentId the unique identifier of the advanced payment + * @param request the {@link DisbursementRefundCreateRequest} with refund details + * @return the created bulk {@link DisbursementRefund} + * @throws MPException if a transport-level or SDK-internal error occurs + * @throws MPApiException if the API returns a non-successful HTTP status code + */ + public DisbursementRefund createAll(Long advancedPaymentId, + DisbursementRefundCreateRequest request) throws MPException, MPApiException { + return this.createAll(advancedPaymentId, request, null); + } + + /** + * Refunds all disbursements of an advanced payment at once with custom request options. + * + * @param advancedPaymentId the unique identifier of the advanced payment + * @param request the {@link DisbursementRefundCreateRequest} with refund details + * @param requestOptions optional {@link MPRequestOptions}; may be {@code null} + * @return the created bulk {@link DisbursementRefund} + * @throws MPException if a transport-level or SDK-internal error occurs + * @throws MPApiException if the API returns a non-successful HTTP status code + */ + public DisbursementRefund createAll(Long advancedPaymentId, + DisbursementRefundCreateRequest request, MPRequestOptions requestOptions) + throws MPException, MPApiException { + LOGGER.info("Sending create all disbursement refund request"); + MPResponse response = send( + String.format(URL_REFUNDS, advancedPaymentId), + HttpMethod.POST, serializeToJson(request), null, requestOptions); + + DisbursementRefund result = + deserializeFromJson(DisbursementRefund.class, response.getContent()); + result.setResponse(response); + return result; + } + + /** + * Refunds a specific disbursement by amount. + * + * @param advancedPaymentId the unique identifier of the parent advanced payment + * @param disbursementId the unique identifier of the disbursement to refund + * @param request the {@link DisbursementRefundCreateRequest} with the refund amount + * @return the created {@link DisbursementRefund} + * @throws MPException if a transport-level or SDK-internal error occurs + * @throws MPApiException if the API returns a non-successful HTTP status code + */ + public DisbursementRefund create(Long advancedPaymentId, Long disbursementId, + DisbursementRefundCreateRequest request) throws MPException, MPApiException { + return this.create(advancedPaymentId, disbursementId, request, null); + } + + /** + * Refunds a specific disbursement by amount with custom request options. + * + * @param advancedPaymentId the unique identifier of the parent advanced payment + * @param disbursementId the unique identifier of the disbursement to refund + * @param request the {@link DisbursementRefundCreateRequest} with the refund amount + * @param requestOptions optional {@link MPRequestOptions}; may be {@code null} + * @return the created {@link DisbursementRefund} + * @throws MPException if a transport-level or SDK-internal error occurs + * @throws MPApiException if the API returns a non-successful HTTP status code + */ + public DisbursementRefund create(Long advancedPaymentId, Long disbursementId, + DisbursementRefundCreateRequest request, MPRequestOptions requestOptions) + throws MPException, MPApiException { + LOGGER.info("Sending create disbursement refund request"); + MPResponse response = send( + String.format(URL_DISBURSEMENT_REFUND, advancedPaymentId, disbursementId), + HttpMethod.POST, serializeToJson(request), null, requestOptions); + + DisbursementRefund result = + deserializeFromJson(DisbursementRefund.class, response.getContent()); + result.setResponse(response); + return result; + } +} diff --git a/src/main/java/com/mercadopago/client/disbursementrefund/DisbursementRefundCreateRequest.java b/src/main/java/com/mercadopago/client/disbursementrefund/DisbursementRefundCreateRequest.java new file mode 100644 index 00000000..7f80c3af --- /dev/null +++ b/src/main/java/com/mercadopago/client/disbursementrefund/DisbursementRefundCreateRequest.java @@ -0,0 +1,18 @@ +package com.mercadopago.client.disbursementrefund; + +import java.math.BigDecimal; +import lombok.Builder; +import lombok.Getter; + +/** + * Request to create a disbursement refund. + * + * @see com.mercadopago.client.disbursementrefund.DisbursementRefundClient + */ +@Getter +@Builder +public class DisbursementRefundCreateRequest { + + /** Amount to refund. When {@code null}, the full disbursement amount is refunded. */ + private final BigDecimal amount; +} diff --git a/src/main/java/com/mercadopago/client/invoice/InvoiceClient.java b/src/main/java/com/mercadopago/client/invoice/InvoiceClient.java new file mode 100644 index 00000000..db338edc --- /dev/null +++ b/src/main/java/com/mercadopago/client/invoice/InvoiceClient.java @@ -0,0 +1,131 @@ +package com.mercadopago.client.invoice; + +import static com.mercadopago.MercadoPagoConfig.getStreamHandler; +import static com.mercadopago.serialization.Serializer.deserializeFromJson; +import static com.mercadopago.serialization.Serializer.deserializeResultsResourcesPageFromJson; + +import com.google.gson.reflect.TypeToken; +import com.mercadopago.MercadoPagoConfig; +import com.mercadopago.client.MercadoPagoClient; +import com.mercadopago.core.MPRequestOptions; +import com.mercadopago.exceptions.MPApiException; +import com.mercadopago.exceptions.MPException; +import com.mercadopago.net.HttpMethod; +import com.mercadopago.net.MPHttpClient; +import com.mercadopago.net.MPResponse; +import com.mercadopago.net.MPResultsResourcesPage; +import com.mercadopago.net.MPSearchRequest; +import com.mercadopago.resources.invoice.Invoice; +import java.lang.reflect.Type; +import java.util.logging.Logger; +import java.util.logging.StreamHandler; + +/** + * Client for the MercadoPago Authorized Payments (Invoice) API. + * + *

Provides access to invoices generated from subscription (preapproval) billing cycles. Each + * invoice represents a scheduled payment attempt against the subscriber's payment method. + * + *

Usage example: + *

{@code
+ * InvoiceClient client = new InvoiceClient();
+ * Invoice invoice = client.get(6114264375L);
+ * }
+ * + * @see + * Invoice API reference + */ +public class InvoiceClient extends MercadoPagoClient { + + /** Class-level logger for invoice operations. */ + private static final Logger LOGGER = Logger.getLogger(InvoiceClient.class.getName()); + + /** URL template for single-invoice endpoints. */ + private static final String URL_WITH_ID = "/authorized_payments/%s"; + + /** + * Default constructor. Uses the default HTTP client provided by {@link MercadoPagoConfig}. + */ + public InvoiceClient() { + this(MercadoPagoConfig.getHttpClient()); + } + + /** + * Constructs an {@code InvoiceClient} with a custom HTTP client. + * + * @param httpClient the {@link MPHttpClient} used to execute HTTP requests + */ + public InvoiceClient(MPHttpClient httpClient) { + super(httpClient); + StreamHandler streamHandler = getStreamHandler(); + streamHandler.setLevel(MercadoPagoConfig.getLoggingLevel()); + LOGGER.addHandler(streamHandler); + LOGGER.setLevel(MercadoPagoConfig.getLoggingLevel()); + } + + /** + * Retrieves an invoice (authorized payment) by its unique identifier. + * + * @param id the unique numeric identifier of the invoice + * @return the requested {@link Invoice} + * @throws MPException if a transport-level or SDK-internal error occurs + * @throws MPApiException if the API returns a non-successful HTTP status code + */ + public Invoice get(Long id) throws MPException, MPApiException { + return this.get(id, null); + } + + /** + * Retrieves an invoice (authorized payment) by its unique identifier with custom request options. + * + * @param id the unique numeric identifier of the invoice + * @param requestOptions optional {@link MPRequestOptions}; may be {@code null} + * @return the requested {@link Invoice} + * @throws MPException if a transport-level or SDK-internal error occurs + * @throws MPApiException if the API returns a non-successful HTTP status code + */ + public Invoice get(Long id, MPRequestOptions requestOptions) + throws MPException, MPApiException { + LOGGER.info("Sending get invoice request"); + MPResponse response = + send(String.format(URL_WITH_ID, id), HttpMethod.GET, null, null, requestOptions); + + Invoice result = deserializeFromJson(Invoice.class, response.getContent()); + result.setResponse(response); + return result; + } + + /** + * Searches invoices matching the given criteria. + * + * @param request the {@link MPSearchRequest} with filters such as preapproval_id and payer_id + * @return an {@link MPResultsResourcesPage} of {@link Invoice} results + * @throws MPException if a transport-level or SDK-internal error occurs + * @throws MPApiException if the API returns a non-successful HTTP status code + */ + public MPResultsResourcesPage search(MPSearchRequest request) + throws MPException, MPApiException { + return this.search(request, null); + } + + /** + * Searches invoices matching the given criteria with custom request options. + * + * @param request the {@link MPSearchRequest} with filters and pagination parameters + * @param requestOptions optional {@link MPRequestOptions}; may be {@code null} + * @return an {@link MPResultsResourcesPage} of {@link Invoice} results + * @throws MPException if a transport-level or SDK-internal error occurs + * @throws MPApiException if the API returns a non-successful HTTP status code + */ + public MPResultsResourcesPage search( + MPSearchRequest request, MPRequestOptions requestOptions) throws MPException, MPApiException { + LOGGER.info("Sending search invoice request"); + MPResponse response = search("/authorized_payments/search", request, requestOptions); + + Type responseType = new TypeToken>() {}.getType(); + MPResultsResourcesPage result = + deserializeResultsResourcesPageFromJson(responseType, response.getContent()); + result.setResponse(response); + return result; + } +} diff --git a/src/main/java/com/mercadopago/client/preapprovalplan/PreApprovalPlanAutoRecurringCreateRequest.java b/src/main/java/com/mercadopago/client/preapprovalplan/PreApprovalPlanAutoRecurringCreateRequest.java new file mode 100644 index 00000000..53925261 --- /dev/null +++ b/src/main/java/com/mercadopago/client/preapprovalplan/PreApprovalPlanAutoRecurringCreateRequest.java @@ -0,0 +1,30 @@ +package com.mercadopago.client.preapprovalplan; + +import java.math.BigDecimal; +import lombok.Builder; +import lombok.Getter; + +/** + * Auto-recurring billing configuration for creating a subscription plan. + * + * @see PreApprovalPlanCreateRequest + */ +@Getter +@Builder +public class PreApprovalPlanAutoRecurringCreateRequest { + + /** Billing frequency unit (e.g., days, months). */ + private final String frequencyType; + + /** Number of frequency units between each billing cycle. */ + private final Integer frequency; + + /** ISO 4217 currency code for the recurring charge. */ + private final String currencyId; + + /** Amount charged to the subscriber on each billing cycle. */ + private final BigDecimal transactionAmount; + + /** Maximum number of billing cycles; {@code null} for indefinite. */ + private final Integer repetitions; +} diff --git a/src/main/java/com/mercadopago/client/preapprovalplan/PreApprovalPlanAutoRecurringUpdateRequest.java b/src/main/java/com/mercadopago/client/preapprovalplan/PreApprovalPlanAutoRecurringUpdateRequest.java new file mode 100644 index 00000000..2d25ddd7 --- /dev/null +++ b/src/main/java/com/mercadopago/client/preapprovalplan/PreApprovalPlanAutoRecurringUpdateRequest.java @@ -0,0 +1,30 @@ +package com.mercadopago.client.preapprovalplan; + +import java.math.BigDecimal; +import lombok.Builder; +import lombok.Getter; + +/** + * Auto-recurring billing configuration for updating a subscription plan. + * + * @see PreApprovalPlanUpdateRequest + */ +@Getter +@Builder +public class PreApprovalPlanAutoRecurringUpdateRequest { + + /** Updated billing frequency unit. */ + private final String frequencyType; + + /** Updated number of frequency units. */ + private final Integer frequency; + + /** Updated ISO 4217 currency code. */ + private final String currencyId; + + /** Updated charge amount. */ + private final BigDecimal transactionAmount; + + /** Updated maximum number of billing cycles. */ + private final Integer repetitions; +} diff --git a/src/main/java/com/mercadopago/client/preapprovalplan/PreApprovalPlanClient.java b/src/main/java/com/mercadopago/client/preapprovalplan/PreApprovalPlanClient.java new file mode 100644 index 00000000..02aced12 --- /dev/null +++ b/src/main/java/com/mercadopago/client/preapprovalplan/PreApprovalPlanClient.java @@ -0,0 +1,205 @@ +package com.mercadopago.client.preapprovalplan; + +import static com.mercadopago.MercadoPagoConfig.getStreamHandler; +import static com.mercadopago.serialization.Serializer.deserializeFromJson; +import static com.mercadopago.serialization.Serializer.deserializeResultsResourcesPageFromJson; +import static com.mercadopago.serialization.Serializer.serializeToJson; + +import com.google.gson.reflect.TypeToken; +import com.mercadopago.MercadoPagoConfig; +import com.mercadopago.client.MercadoPagoClient; +import com.mercadopago.core.MPRequestOptions; +import com.mercadopago.exceptions.MPApiException; +import com.mercadopago.exceptions.MPException; +import com.mercadopago.net.HttpMethod; +import com.mercadopago.net.MPHttpClient; +import com.mercadopago.net.MPResponse; +import com.mercadopago.net.MPResultsResourcesPage; +import com.mercadopago.net.MPSearchRequest; +import com.mercadopago.resources.preapprovalplan.PreApprovalPlan; +import java.lang.reflect.Type; +import java.util.logging.Logger; +import java.util.logging.StreamHandler; + +/** + * Client for the MercadoPago PreApproval Plan (Subscription Plans) API. + * + *

Provides operations to create, retrieve, update, and search subscription plan templates. + * A plan defines the billing frequency, currency, and amount shared by all subscriptions + * attached to it. + * + *

Usage example: + *

{@code
+ * PreApprovalPlanClient client = new PreApprovalPlanClient();
+ * PreApprovalPlan plan = client.create(createRequest);
+ * }
+ * + * @see + * PreApproval Plan API reference + */ +public class PreApprovalPlanClient extends MercadoPagoClient { + + /** Class-level logger for preapproval plan operations. */ + private static final Logger LOGGER = Logger.getLogger(PreApprovalPlanClient.class.getName()); + + /** URL for the preapproval plan collection endpoint. */ + private static final String URL = "/preapproval_plan"; + + /** URL template for single-plan endpoints. */ + private static final String URL_WITH_ID = "/preapproval_plan/%s"; + + /** + * Default constructor. Uses the default HTTP client provided by {@link MercadoPagoConfig}. + */ + public PreApprovalPlanClient() { + this(MercadoPagoConfig.getHttpClient()); + } + + /** + * Constructs a {@code PreApprovalPlanClient} with a custom HTTP client. + * + * @param httpClient the {@link MPHttpClient} used to execute HTTP requests + */ + public PreApprovalPlanClient(MPHttpClient httpClient) { + super(httpClient); + StreamHandler streamHandler = getStreamHandler(); + streamHandler.setLevel(MercadoPagoConfig.getLoggingLevel()); + LOGGER.addHandler(streamHandler); + LOGGER.setLevel(MercadoPagoConfig.getLoggingLevel()); + } + + /** + * Retrieves a subscription plan by its unique identifier. + * + * @param id the unique identifier of the plan + * @return the requested {@link PreApprovalPlan} + * @throws MPException if a transport-level or SDK-internal error occurs + * @throws MPApiException if the API returns a non-successful HTTP status code + */ + public PreApprovalPlan get(String id) throws MPException, MPApiException { + return this.get(id, null); + } + + /** + * Retrieves a subscription plan by its unique identifier with custom request options. + * + * @param id the unique identifier of the plan + * @param requestOptions optional {@link MPRequestOptions}; may be {@code null} + * @return the requested {@link PreApprovalPlan} + * @throws MPException if a transport-level or SDK-internal error occurs + * @throws MPApiException if the API returns a non-successful HTTP status code + */ + public PreApprovalPlan get(String id, MPRequestOptions requestOptions) + throws MPException, MPApiException { + LOGGER.info("Sending get preapproval plan request"); + MPResponse response = + send(String.format(URL_WITH_ID, id), HttpMethod.GET, null, null, requestOptions); + + PreApprovalPlan result = deserializeFromJson(PreApprovalPlan.class, response.getContent()); + result.setResponse(response); + return result; + } + + /** + * Creates a new subscription plan. + * + * @param request the {@link PreApprovalPlanCreateRequest} with plan details + * @return the created {@link PreApprovalPlan} + * @throws MPException if a transport-level or SDK-internal error occurs + * @throws MPApiException if the API returns a non-successful HTTP status code + */ + public PreApprovalPlan create(PreApprovalPlanCreateRequest request) + throws MPException, MPApiException { + return this.create(request, null); + } + + /** + * Creates a new subscription plan with custom request options. + * + * @param request the {@link PreApprovalPlanCreateRequest} with plan details + * @param requestOptions optional {@link MPRequestOptions}; may be {@code null} + * @return the created {@link PreApprovalPlan} + * @throws MPException if a transport-level or SDK-internal error occurs + * @throws MPApiException if the API returns a non-successful HTTP status code + */ + public PreApprovalPlan create(PreApprovalPlanCreateRequest request, + MPRequestOptions requestOptions) throws MPException, MPApiException { + LOGGER.info("Sending create preapproval plan request"); + MPResponse response = + send(URL, HttpMethod.POST, serializeToJson(request), null, requestOptions); + + PreApprovalPlan result = deserializeFromJson(PreApprovalPlan.class, response.getContent()); + result.setResponse(response); + return result; + } + + /** + * Updates an existing subscription plan. + * + * @param id the unique identifier of the plan to update + * @param request the {@link PreApprovalPlanUpdateRequest} with the fields to modify + * @return the updated {@link PreApprovalPlan} + * @throws MPException if a transport-level or SDK-internal error occurs + * @throws MPApiException if the API returns a non-successful HTTP status code + */ + public PreApprovalPlan update(String id, PreApprovalPlanUpdateRequest request) + throws MPException, MPApiException { + return this.update(id, request, null); + } + + /** + * Updates an existing subscription plan with custom request options. + * + * @param id the unique identifier of the plan to update + * @param request the {@link PreApprovalPlanUpdateRequest} with the fields to modify + * @param requestOptions optional {@link MPRequestOptions}; may be {@code null} + * @return the updated {@link PreApprovalPlan} + * @throws MPException if a transport-level or SDK-internal error occurs + * @throws MPApiException if the API returns a non-successful HTTP status code + */ + public PreApprovalPlan update(String id, PreApprovalPlanUpdateRequest request, + MPRequestOptions requestOptions) throws MPException, MPApiException { + LOGGER.info("Sending update preapproval plan request"); + MPResponse response = + send(String.format(URL_WITH_ID, id), HttpMethod.PUT, serializeToJson(request), null, + requestOptions); + + PreApprovalPlan result = deserializeFromJson(PreApprovalPlan.class, response.getContent()); + result.setResponse(response); + return result; + } + + /** + * Searches subscription plans matching the given criteria. + * + * @param request the {@link MPSearchRequest} with search filters and pagination parameters + * @return an {@link MPResultsResourcesPage} of {@link PreApprovalPlan} results + * @throws MPException if a transport-level or SDK-internal error occurs + * @throws MPApiException if the API returns a non-successful HTTP status code + */ + public MPResultsResourcesPage search(MPSearchRequest request) + throws MPException, MPApiException { + return this.search(request, null); + } + + /** + * Searches subscription plans matching the given criteria with custom request options. + * + * @param request the {@link MPSearchRequest} with search filters and pagination parameters + * @param requestOptions optional {@link MPRequestOptions}; may be {@code null} + * @return an {@link MPResultsResourcesPage} of {@link PreApprovalPlan} results + * @throws MPException if a transport-level or SDK-internal error occurs + * @throws MPApiException if the API returns a non-successful HTTP status code + */ + public MPResultsResourcesPage search(MPSearchRequest request, + MPRequestOptions requestOptions) throws MPException, MPApiException { + LOGGER.info("Sending search preapproval plan request"); + MPResponse response = search("/preapproval_plan/search", request, requestOptions); + + Type responseType = new TypeToken>() {}.getType(); + MPResultsResourcesPage result = + deserializeResultsResourcesPageFromJson(responseType, response.getContent()); + result.setResponse(response); + return result; + } +} diff --git a/src/main/java/com/mercadopago/client/preapprovalplan/PreApprovalPlanCreateRequest.java b/src/main/java/com/mercadopago/client/preapprovalplan/PreApprovalPlanCreateRequest.java new file mode 100644 index 00000000..26f29ebd --- /dev/null +++ b/src/main/java/com/mercadopago/client/preapprovalplan/PreApprovalPlanCreateRequest.java @@ -0,0 +1,26 @@ +package com.mercadopago.client.preapprovalplan; + +import lombok.Builder; +import lombok.Getter; + +/** + * Request to create a new subscription plan. + * + * @see com.mercadopago.client.preapprovalplan.PreApprovalPlanClient + */ +@Getter +@Builder +public class PreApprovalPlanCreateRequest { + + /** Short descriptive title of the plan visible to subscribers during checkout. */ + private final String reason; + + /** URL to redirect the subscriber after completing the checkout flow. */ + private final String backUrl; + + /** Integrator-provided external reference for reconciliation. */ + private final String externalReference; + + /** Recurring billing configuration (frequency, currency, amount). */ + private final PreApprovalPlanAutoRecurringCreateRequest autoRecurring; +} diff --git a/src/main/java/com/mercadopago/client/preapprovalplan/PreApprovalPlanUpdateRequest.java b/src/main/java/com/mercadopago/client/preapprovalplan/PreApprovalPlanUpdateRequest.java new file mode 100644 index 00000000..fff2bbc3 --- /dev/null +++ b/src/main/java/com/mercadopago/client/preapprovalplan/PreApprovalPlanUpdateRequest.java @@ -0,0 +1,26 @@ +package com.mercadopago.client.preapprovalplan; + +import lombok.Builder; +import lombok.Getter; + +/** + * Request to update an existing subscription plan. + * + * @see com.mercadopago.client.preapprovalplan.PreApprovalPlanClient + */ +@Getter +@Builder +public class PreApprovalPlanUpdateRequest { + + /** New title for the plan. */ + private final String reason; + + /** New back URL for the plan. */ + private final String backUrl; + + /** New status (e.g., cancelled). */ + private final String status; + + /** Updated recurring billing configuration. */ + private final PreApprovalPlanAutoRecurringUpdateRequest autoRecurring; +} diff --git a/src/main/java/com/mercadopago/example/apis/advancedpayment/CreateAdvancedPayment.java b/src/main/java/com/mercadopago/example/apis/advancedpayment/CreateAdvancedPayment.java new file mode 100644 index 00000000..2fc47d3f --- /dev/null +++ b/src/main/java/com/mercadopago/example/apis/advancedpayment/CreateAdvancedPayment.java @@ -0,0 +1,47 @@ +package com.mercadopago.example.apis.advancedpayment; + +import com.mercadopago.MercadoPagoConfig; +import com.mercadopago.client.advancedpayment.AdvancedPaymentClient; +import com.mercadopago.client.advancedpayment.AdvancedPaymentCreateRequest; +import com.mercadopago.client.advancedpayment.AdvancedPaymentDisbursementRequest; +import com.mercadopago.client.advancedpayment.AdvancedPaymentPayerRequest; +import com.mercadopago.client.advancedpayment.AdvancedPaymentPaymentRequest; +import com.mercadopago.resources.advancedpayment.AdvancedPayment; +import java.math.BigDecimal; +import java.util.Arrays; + +/** Example: Create a MercadoPago advanced (split) payment. */ +public class CreateAdvancedPayment { + + public static void main(String[] args) throws Exception { + MercadoPagoConfig.setAccessToken("{{ACCESS_TOKEN}}"); + + AdvancedPaymentClient client = new AdvancedPaymentClient(); + + AdvancedPaymentCreateRequest request = AdvancedPaymentCreateRequest.builder() + .applicationId("{{APPLICATION_ID}}") + .payments(Arrays.asList(AdvancedPaymentPaymentRequest.builder() + .paymentMethodId("master") + .paymentTypeId("credit_card") + .token("{{CARD_TOKEN}}") + .transactionAmount(new BigDecimal("100.00")) + .installments(1) + .processingMode("aggregator") + .build())) + .disbursements(Arrays.asList(AdvancedPaymentDisbursementRequest.builder() + .collectorId(488656838L) + .amount(new BigDecimal("80.00")) + .applicationFee(new BigDecimal("2.00")) + .build())) + .payer(AdvancedPaymentPayerRequest.builder().email("buyer@example.com").build()) + .externalReference("ADV-REF-001") + .capture(false) + .build(); + + AdvancedPayment payment = client.create(request); + System.out.println("Advanced Payment ID: " + payment.getId()); + + AdvancedPayment captured = client.capture(payment.getId()); + System.out.println("Captured status: " + captured.getStatus()); + } +} diff --git a/src/main/java/com/mercadopago/example/apis/chargeback/SearchChargeback.java b/src/main/java/com/mercadopago/example/apis/chargeback/SearchChargeback.java new file mode 100644 index 00000000..e874ca11 --- /dev/null +++ b/src/main/java/com/mercadopago/example/apis/chargeback/SearchChargeback.java @@ -0,0 +1,25 @@ +package com.mercadopago.example.apis.chargeback; + +import com.mercadopago.MercadoPagoConfig; +import com.mercadopago.client.chargeback.ChargebackClient; +import com.mercadopago.net.MPResultsResourcesPage; +import com.mercadopago.net.MPSearchRequest; +import com.mercadopago.resources.chargeback.Chargeback; + +/** Example: Retrieve and search chargebacks. */ +public class SearchChargeback { + + public static void main(String[] args) throws Exception { + MercadoPagoConfig.setAccessToken("{{ACCESS_TOKEN}}"); + + ChargebackClient client = new ChargebackClient(); + + Chargeback chargeback = client.get("{{CHARGEBACK_ID}}"); + System.out.println("Chargeback status: " + chargeback.getStatus()); + System.out.println("Amount: " + chargeback.getAmount()); + + MPSearchRequest searchRequest = MPSearchRequest.builder().limit(10).offset(0).build(); + MPResultsResourcesPage results = client.search(searchRequest); + System.out.println("Total chargebacks: " + results.getPaging().getTotal()); + } +} diff --git a/src/main/java/com/mercadopago/example/apis/disbursementrefund/CreateDisbursementRefund.java b/src/main/java/com/mercadopago/example/apis/disbursementrefund/CreateDisbursementRefund.java new file mode 100644 index 00000000..01a0c16c --- /dev/null +++ b/src/main/java/com/mercadopago/example/apis/disbursementrefund/CreateDisbursementRefund.java @@ -0,0 +1,24 @@ +package com.mercadopago.example.apis.disbursementrefund; + +import com.mercadopago.MercadoPagoConfig; +import com.mercadopago.client.disbursementrefund.DisbursementRefundClient; +import com.mercadopago.client.disbursementrefund.DisbursementRefundCreateRequest; +import com.mercadopago.resources.disbursementrefund.DisbursementRefund; +import java.math.BigDecimal; + +/** Example: Create a disbursement refund for an advanced payment. */ +public class CreateDisbursementRefund { + + public static void main(String[] args) throws Exception { + MercadoPagoConfig.setAccessToken("{{ACCESS_TOKEN}}"); + + DisbursementRefundClient client = new DisbursementRefundClient(); + + DisbursementRefundCreateRequest request = + DisbursementRefundCreateRequest.builder().amount(new BigDecimal("50.00")).build(); + + DisbursementRefund refund = client.create(20458724L, 123456L, request); + System.out.println("Refund ID: " + refund.getId()); + System.out.println("Status: " + refund.getStatus()); + } +} diff --git a/src/main/java/com/mercadopago/example/apis/invoice/GetInvoice.java b/src/main/java/com/mercadopago/example/apis/invoice/GetInvoice.java new file mode 100644 index 00000000..170091bd --- /dev/null +++ b/src/main/java/com/mercadopago/example/apis/invoice/GetInvoice.java @@ -0,0 +1,29 @@ +package com.mercadopago.example.apis.invoice; + +import com.mercadopago.MercadoPagoConfig; +import com.mercadopago.client.invoice.InvoiceClient; +import com.mercadopago.net.MPResultsResourcesPage; +import com.mercadopago.net.MPSearchRequest; +import com.mercadopago.resources.invoice.Invoice; + +/** Example: Retrieve and search subscription invoices. */ +public class GetInvoice { + + public static void main(String[] args) throws Exception { + MercadoPagoConfig.setAccessToken("{{ACCESS_TOKEN}}"); + + InvoiceClient client = new InvoiceClient(); + + Invoice invoice = client.get(6114264375L); + System.out.println("Invoice status: " + invoice.getStatus()); + System.out.println("Transaction amount: " + invoice.getTransactionAmount()); + + MPSearchRequest searchRequest = MPSearchRequest.builder() + .limit(10) + .offset(0) + .filters(java.util.Collections.singletonMap("preapproval_id", "{{PREAPPROVAL_ID}}")) + .build(); + MPResultsResourcesPage results = client.search(searchRequest); + System.out.println("Total invoices: " + results.getPaging().getTotal()); + } +} diff --git a/src/main/java/com/mercadopago/example/apis/preapprovalplan/CreatePreApprovalPlan.java b/src/main/java/com/mercadopago/example/apis/preapprovalplan/CreatePreApprovalPlan.java new file mode 100644 index 00000000..ccc58458 --- /dev/null +++ b/src/main/java/com/mercadopago/example/apis/preapprovalplan/CreatePreApprovalPlan.java @@ -0,0 +1,33 @@ +package com.mercadopago.example.apis.preapprovalplan; + +import com.mercadopago.MercadoPagoConfig; +import com.mercadopago.client.preapprovalplan.PreApprovalPlanAutoRecurringCreateRequest; +import com.mercadopago.client.preapprovalplan.PreApprovalPlanClient; +import com.mercadopago.client.preapprovalplan.PreApprovalPlanCreateRequest; +import com.mercadopago.resources.preapprovalplan.PreApprovalPlan; +import java.math.BigDecimal; + +/** Example: Create a MercadoPago subscription plan. */ +public class CreatePreApprovalPlan { + + public static void main(String[] args) throws Exception { + MercadoPagoConfig.setAccessToken("{{ACCESS_TOKEN}}"); + + PreApprovalPlanClient client = new PreApprovalPlanClient(); + + PreApprovalPlanCreateRequest request = PreApprovalPlanCreateRequest.builder() + .reason("Monthly yoga subscription") + .backUrl("https://yourapp.com/back") + .autoRecurring(PreApprovalPlanAutoRecurringCreateRequest.builder() + .frequency(1) + .frequencyType("months") + .currencyId("BRL") + .transactionAmount(new BigDecimal("49.90")) + .build()) + .build(); + + PreApprovalPlan plan = client.create(request); + System.out.println("Plan ID: " + plan.getId()); + System.out.println("Init point: " + plan.getInitPoint()); + } +} diff --git a/src/main/java/com/mercadopago/resources/advancedpayment/AdvancedPayment.java b/src/main/java/com/mercadopago/resources/advancedpayment/AdvancedPayment.java new file mode 100644 index 00000000..4c7e5001 --- /dev/null +++ b/src/main/java/com/mercadopago/resources/advancedpayment/AdvancedPayment.java @@ -0,0 +1,49 @@ +package com.mercadopago.resources.advancedpayment; + +import com.mercadopago.net.MPResource; +import java.time.OffsetDateTime; +import java.util.List; +import lombok.Getter; + +/** + * Resource representing a MercadoPago advanced (split) payment. + * + *

An advanced payment allows a marketplace to collect a single payment and distribute the + * funds among multiple sellers (disbursements). Supports two-step flows (authorise → capture) + * and individual disbursement release-date control. + * + * @see com.mercadopago.client.advancedpayment.AdvancedPaymentClient + */ +@Getter +public class AdvancedPayment extends MPResource { + + /** Unique identifier of the advanced payment. */ + private Long id; + + /** Identifier of the MercadoPago application that created this payment. */ + private String applicationId; + + /** Integrator-provided external reference for reconciliation. */ + private String externalReference; + + /** Human-readable description of the payment. */ + private String description; + + /** Overall status of the advanced payment. */ + private String status; + + /** Whether the payment has been captured. */ + private Boolean capture; + + /** When true, the payment is approved or rejected immediately. */ + private Boolean binaryMode; + + /** Timestamp when this advanced payment was created. */ + private OffsetDateTime dateCreated; + + /** Timestamp of the last update. */ + private OffsetDateTime dateLastUpdated; + + /** List of disbursements associated with this advanced payment. */ + private List disbursements; +} diff --git a/src/main/java/com/mercadopago/resources/advancedpayment/AdvancedPaymentDisbursement.java b/src/main/java/com/mercadopago/resources/advancedpayment/AdvancedPaymentDisbursement.java new file mode 100644 index 00000000..86757f2a --- /dev/null +++ b/src/main/java/com/mercadopago/resources/advancedpayment/AdvancedPaymentDisbursement.java @@ -0,0 +1,37 @@ +package com.mercadopago.resources.advancedpayment; + +import java.math.BigDecimal; +import lombok.Getter; + +/** + * A single disbursement receiver within an advanced payment. + * + * @see AdvancedPayment + */ +@Getter +public class AdvancedPaymentDisbursement { + + /** Unique disbursement identifier. */ + private Long id; + + /** MercadoPago user identifier of the seller receiving the funds. */ + private Long collectorId; + + /** Amount disbursed to this collector. */ + private BigDecimal amount; + + /** Integrator-provided external reference for this disbursement. */ + private String externalReference; + + /** Marketplace application fee retained from this disbursement. */ + private BigDecimal applicationFee; + + /** Scheduled date when funds are released to the seller. */ + private String moneyReleaseDate; + + /** Current status of this disbursement. */ + private String status; + + /** Additional detail about the disbursement status. */ + private String statusDetail; +} diff --git a/src/main/java/com/mercadopago/resources/chargeback/Chargeback.java b/src/main/java/com/mercadopago/resources/chargeback/Chargeback.java new file mode 100644 index 00000000..9b94308c --- /dev/null +++ b/src/main/java/com/mercadopago/resources/chargeback/Chargeback.java @@ -0,0 +1,45 @@ +package com.mercadopago.resources.chargeback; + +import com.mercadopago.net.MPResource; +import java.math.BigDecimal; +import java.time.OffsetDateTime; +import lombok.Getter; + +/** + * Resource representing a MercadoPago chargeback dispute. + * + *

A chargeback is initiated by a cardholder through their issuing bank when they dispute a + * payment. This resource provides read-only access to the dispute details. + * + * @see com.mercadopago.client.chargeback.ChargebackClient + */ +@Getter +public class Chargeback extends MPResource { + + /** Unique identifier of the chargeback. */ + private String id; + + /** Identifier of the payment that originated the dispute. */ + private Long paymentId; + + /** Current status of the chargeback (e.g., new, in_review, won, lost). */ + private String status; + + /** Amount disputed by the cardholder. */ + private BigDecimal amount; + + /** ISO 4217 currency code of the disputed amount. */ + private String currencyId; + + /** Card-network reason code for the dispute. */ + private String reasonId; + + /** Human-readable description of the dispute reason. */ + private String reason; + + /** Timestamp when the chargeback was created. */ + private OffsetDateTime dateCreated; + + /** Timestamp of the last modification. */ + private OffsetDateTime lastModified; +} diff --git a/src/main/java/com/mercadopago/resources/disbursementrefund/DisbursementRefund.java b/src/main/java/com/mercadopago/resources/disbursementrefund/DisbursementRefund.java new file mode 100644 index 00000000..055b47ee --- /dev/null +++ b/src/main/java/com/mercadopago/resources/disbursementrefund/DisbursementRefund.java @@ -0,0 +1,33 @@ +package com.mercadopago.resources.disbursementrefund; + +import com.mercadopago.net.MPResource; +import java.math.BigDecimal; +import java.time.OffsetDateTime; +import lombok.Getter; + +/** + * Resource representing a refund on a disbursement within an advanced payment. + * + * @see com.mercadopago.client.disbursementrefund.DisbursementRefundClient + */ +@Getter +public class DisbursementRefund extends MPResource { + + /** Unique identifier of this disbursement refund. */ + private Long id; + + /** Identifier of the parent advanced payment. */ + private Long advancedPaymentId; + + /** Identifier of the disbursement that was refunded. */ + private Long disbursementId; + + /** Amount refunded. */ + private BigDecimal amount; + + /** Current status of the refund. */ + private String status; + + /** Timestamp when the refund was created. */ + private OffsetDateTime dateCreated; +} diff --git a/src/main/java/com/mercadopago/resources/invoice/Invoice.java b/src/main/java/com/mercadopago/resources/invoice/Invoice.java new file mode 100644 index 00000000..eec036e1 --- /dev/null +++ b/src/main/java/com/mercadopago/resources/invoice/Invoice.java @@ -0,0 +1,66 @@ +package com.mercadopago.resources.invoice; + +import com.mercadopago.net.MPResource; +import java.math.BigDecimal; +import java.time.OffsetDateTime; +import lombok.Getter; + +/** + * Resource representing a subscription invoice (authorized payment) in MercadoPago. + * + *

Each invoice corresponds to a billing cycle of a {@code Preapproval} and tracks the charge + * amount, status, retry attempts, and the resulting payment. + * + * @see com.mercadopago.client.invoice.InvoiceClient + */ +@Getter +public class Invoice extends MPResource { + + /** Unique invoice identifier assigned by MercadoPago. */ + private Long id; + + /** Invoice type (e.g., scheduled). */ + private String type; + + /** Timestamp when the invoice was created. */ + private OffsetDateTime dateCreated; + + /** Timestamp of the last modification. */ + private OffsetDateTime lastModified; + + /** Identifier of the preapproval (subscription) that generated this invoice. */ + private String preapprovalId; + + /** Description or reason for the invoice charge. */ + private String reason; + + /** Integrator-provided external reference for reconciliation. */ + private String externalReference; + + /** ISO 4217 currency code for the invoice amount. */ + private String currencyId; + + /** Amount charged to the subscriber. */ + private BigDecimal transactionAmount; + + /** Scheduled date for the next retry if the payment failed. */ + private OffsetDateTime nextRetryDate; + + /** Scheduled date for the payment debit. */ + private OffsetDateTime debitDate; + + /** Payment method identifier used for this invoice. */ + private String paymentMethodId; + + /** Current retry attempt number. */ + private Integer retryAttempt; + + /** Invoice status (e.g., scheduled, processed, recycling, cancelled). */ + private String status; + + /** Summary description of the invoice status. */ + private String summarized; + + /** Payment details associated with this invoice. */ + private InvoicePayment payment; +} diff --git a/src/main/java/com/mercadopago/resources/invoice/InvoicePayment.java b/src/main/java/com/mercadopago/resources/invoice/InvoicePayment.java new file mode 100644 index 00000000..6f10a55c --- /dev/null +++ b/src/main/java/com/mercadopago/resources/invoice/InvoicePayment.java @@ -0,0 +1,21 @@ +package com.mercadopago.resources.invoice; + +import lombok.Getter; + +/** + * Payment details embedded within a subscription invoice. + * + * @see Invoice + */ +@Getter +public class InvoicePayment { + + /** Unique payment identifier. */ + private Long id; + + /** Payment status (e.g., approved, rejected, pending). */ + private String status; + + /** Additional detail about the payment status. */ + private String statusDetail; +} diff --git a/src/main/java/com/mercadopago/resources/preapprovalplan/PreApprovalPlan.java b/src/main/java/com/mercadopago/resources/preapprovalplan/PreApprovalPlan.java new file mode 100644 index 00000000..a872ae97 --- /dev/null +++ b/src/main/java/com/mercadopago/resources/preapprovalplan/PreApprovalPlan.java @@ -0,0 +1,53 @@ +package com.mercadopago.resources.preapprovalplan; + +import com.mercadopago.net.MPResource; +import java.time.OffsetDateTime; +import lombok.Getter; + +/** + * Resource representing a MercadoPago subscription plan template. + * + *

A plan defines the billing frequency, currency, and amount shared by all subscriptions + * attached to it. Create one plan and link multiple subscribers to it. + * + * @see com.mercadopago.client.preapprovalplan.PreApprovalPlanClient + */ +@Getter +public class PreApprovalPlan extends MPResource { + + /** Unique identifier of this subscription plan. */ + private String id; + + /** Short descriptive title of the plan. */ + private String reason; + + /** Integrator-provided external reference. */ + private String externalReference; + + /** Current status of the plan (active, cancelled). */ + private String status; + + /** URL to redirect the subscriber after completing the checkout flow. */ + private String backUrl; + + /** MercadoPago user identifier of the seller who receives the charges. */ + private Long collectorId; + + /** Identifier of the application that created this plan. */ + private String applicationId; + + /** Timestamp when the plan was created. */ + private OffsetDateTime dateCreated; + + /** Timestamp of the last modification. */ + private OffsetDateTime lastModified; + + /** Production checkout URL for subscribing to this plan. */ + private String initPoint; + + /** Sandbox checkout URL for testing. */ + private String sandboxInitPoint; + + /** Recurring billing configuration. */ + private PreApprovalPlanAutoRecurring autoRecurring; +} diff --git a/src/main/java/com/mercadopago/resources/preapprovalplan/PreApprovalPlanAutoRecurring.java b/src/main/java/com/mercadopago/resources/preapprovalplan/PreApprovalPlanAutoRecurring.java new file mode 100644 index 00000000..f7f959cc --- /dev/null +++ b/src/main/java/com/mercadopago/resources/preapprovalplan/PreApprovalPlanAutoRecurring.java @@ -0,0 +1,28 @@ +package com.mercadopago.resources.preapprovalplan; + +import java.math.BigDecimal; +import lombok.Getter; + +/** + * Recurring billing configuration of a subscription plan. + * + * @see PreApprovalPlan + */ +@Getter +public class PreApprovalPlanAutoRecurring { + + /** Billing frequency unit (e.g., days, months). */ + private String frequencyType; + + /** Number of frequency units between each billing cycle. */ + private Integer frequency; + + /** ISO 4217 currency code for the recurring charge. */ + private String currencyId; + + /** Amount charged to the subscriber on each billing cycle. */ + private BigDecimal transactionAmount; + + /** Maximum number of billing cycles; {@code null} for indefinite. */ + private Integer repetitions; +} diff --git a/src/test/java/com/mercadopago/client/advancedpayment/AdvancedPaymentClientTest.java b/src/test/java/com/mercadopago/client/advancedpayment/AdvancedPaymentClientTest.java new file mode 100644 index 00000000..b5bad117 --- /dev/null +++ b/src/test/java/com/mercadopago/client/advancedpayment/AdvancedPaymentClientTest.java @@ -0,0 +1,88 @@ +package com.mercadopago.client.advancedpayment; + +import static com.mercadopago.helper.MockHelper.generateHttpResponseFromFile; +import static com.mercadopago.net.HttpStatus.CREATED; +import static com.mercadopago.net.HttpStatus.OK; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.doReturn; + +import com.mercadopago.BaseClientTest; +import com.mercadopago.exceptions.MPApiException; +import com.mercadopago.exceptions.MPException; +import com.mercadopago.net.MPResultsResourcesPage; +import com.mercadopago.net.MPSearchRequest; +import com.mercadopago.resources.advancedpayment.AdvancedPayment; +import java.io.IOException; +import java.math.BigDecimal; +import java.util.Arrays; +import org.apache.http.HttpResponse; +import org.apache.http.client.methods.HttpRequestBase; +import org.apache.http.protocol.HttpContext; +import org.junit.jupiter.api.Test; + +class AdvancedPaymentClientTest extends BaseClientTest { + + private static final String paymentBaseJson = "advancedPayment/advancedpayment_base.json"; + private static final String paymentListJson = "advancedPayment/advancedpayment_list.json"; + private final AdvancedPaymentClient client = new AdvancedPaymentClient(); + + @Test + void getSuccess() throws IOException, MPException, MPApiException { + HttpResponse httpResponse = generateHttpResponseFromFile(paymentBaseJson, OK); + doReturn(httpResponse) + .when(HTTP_CLIENT) + .execute(any(HttpRequestBase.class), any(HttpContext.class)); + + AdvancedPayment payment = client.get(20458724L); + + assertNotNull(payment.getResponse()); + assertEquals(OK, payment.getResponse().getStatusCode()); + assertEquals(20458724L, payment.getId()); + assertEquals("approved", payment.getStatus()); + assertNotNull(payment.getDisbursements()); + assertEquals(1, payment.getDisbursements().size()); + } + + @Test + void createSuccess() throws IOException, MPException, MPApiException { + HttpResponse httpResponse = generateHttpResponseFromFile(paymentBaseJson, CREATED); + doReturn(httpResponse) + .when(HTTP_CLIENT) + .execute(any(HttpRequestBase.class), any(HttpContext.class)); + + AdvancedPaymentCreateRequest request = AdvancedPaymentCreateRequest.builder() + .applicationId("59441713004005") + .disbursements(Arrays.asList(AdvancedPaymentDisbursementRequest.builder() + .collectorId(488656838L) + .amount(new BigDecimal("80.00")) + .build())) + .payer(AdvancedPaymentPayerRequest.builder().email("buyer@example.com").build()) + .externalReference("ADV-REF-001") + .capture(false) + .build(); + + AdvancedPayment payment = client.create(request); + + assertNotNull(payment.getResponse()); + assertEquals(CREATED, payment.getResponse().getStatusCode()); + assertEquals(20458724L, payment.getId()); + } + + @Test + void searchSuccess() throws IOException, MPException, MPApiException { + HttpResponse httpResponse = generateHttpResponseFromFile(paymentListJson, OK); + doReturn(httpResponse) + .when(HTTP_CLIENT) + .execute(any(HttpRequestBase.class), any(HttpContext.class)); + + MPSearchRequest searchRequest = MPSearchRequest.builder().limit(30).offset(0).build(); + MPResultsResourcesPage result = client.search(searchRequest); + + assertNotNull(result.getResponse()); + assertEquals(OK, result.getResponse().getStatusCode()); + assertEquals(1, result.getPaging().getTotal()); + assertEquals(20458724L, result.getResults().get(0).getId()); + } +} diff --git a/src/test/java/com/mercadopago/client/chargeback/ChargebackClientTest.java b/src/test/java/com/mercadopago/client/chargeback/ChargebackClientTest.java new file mode 100644 index 00000000..14daa2cb --- /dev/null +++ b/src/test/java/com/mercadopago/client/chargeback/ChargebackClientTest.java @@ -0,0 +1,59 @@ +package com.mercadopago.client.chargeback; + +import static com.mercadopago.helper.MockHelper.generateHttpResponseFromFile; +import static com.mercadopago.net.HttpStatus.OK; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.doReturn; + +import com.mercadopago.BaseClientTest; +import com.mercadopago.exceptions.MPApiException; +import com.mercadopago.exceptions.MPException; +import com.mercadopago.net.MPResultsResourcesPage; +import com.mercadopago.net.MPSearchRequest; +import com.mercadopago.resources.chargeback.Chargeback; +import java.io.IOException; +import org.apache.http.HttpResponse; +import org.apache.http.client.methods.HttpRequestBase; +import org.apache.http.protocol.HttpContext; +import org.junit.jupiter.api.Test; + +class ChargebackClientTest extends BaseClientTest { + + private static final String chargebackBaseJson = "chargeback/chargeback_base.json"; + private static final String chargebackListJson = "chargeback/chargeback_list.json"; + private final ChargebackClient client = new ChargebackClient(); + + @Test + void getSuccess() throws IOException, MPException, MPApiException { + HttpResponse httpResponse = generateHttpResponseFromFile(chargebackBaseJson, OK); + doReturn(httpResponse) + .when(HTTP_CLIENT) + .execute(any(HttpRequestBase.class), any(HttpContext.class)); + + Chargeback chargeback = client.get("CB-001-2022"); + + assertNotNull(chargeback.getResponse()); + assertEquals(OK, chargeback.getResponse().getStatusCode()); + assertEquals("CB-001-2022", chargeback.getId()); + assertEquals("in_review", chargeback.getStatus()); + } + + @Test + void searchSuccess() throws IOException, MPException, MPApiException { + HttpResponse httpResponse = generateHttpResponseFromFile(chargebackListJson, OK); + doReturn(httpResponse) + .when(HTTP_CLIENT) + .execute(any(HttpRequestBase.class), any(HttpContext.class)); + + MPSearchRequest searchRequest = MPSearchRequest.builder().limit(30).offset(0).build(); + MPResultsResourcesPage result = client.search(searchRequest); + + assertNotNull(result.getResponse()); + assertEquals(OK, result.getResponse().getStatusCode()); + assertEquals(1, result.getPaging().getTotal()); + assertEquals(1, result.getResults().size()); + assertEquals("CB-001-2022", result.getResults().get(0).getId()); + } +} diff --git a/src/test/java/com/mercadopago/client/disbursementrefund/DisbursementRefundClientTest.java b/src/test/java/com/mercadopago/client/disbursementrefund/DisbursementRefundClientTest.java new file mode 100644 index 00000000..cfe77f99 --- /dev/null +++ b/src/test/java/com/mercadopago/client/disbursementrefund/DisbursementRefundClientTest.java @@ -0,0 +1,60 @@ +package com.mercadopago.client.disbursementrefund; + +import static com.mercadopago.helper.MockHelper.generateHttpResponseFromFile; +import static com.mercadopago.net.HttpStatus.CREATED; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.doReturn; + +import com.mercadopago.BaseClientTest; +import com.mercadopago.exceptions.MPApiException; +import com.mercadopago.exceptions.MPException; +import com.mercadopago.resources.disbursementrefund.DisbursementRefund; +import java.io.IOException; +import java.math.BigDecimal; +import org.apache.http.HttpResponse; +import org.apache.http.client.methods.HttpRequestBase; +import org.apache.http.protocol.HttpContext; +import org.junit.jupiter.api.Test; + +class DisbursementRefundClientTest extends BaseClientTest { + + private static final String refundBaseJson = "disbursementrefund/disbursementrefund_base.json"; + private final DisbursementRefundClient client = new DisbursementRefundClient(); + + @Test + void createSuccess() throws IOException, MPException, MPApiException { + HttpResponse httpResponse = generateHttpResponseFromFile(refundBaseJson, CREATED); + doReturn(httpResponse) + .when(HTTP_CLIENT) + .execute(any(HttpRequestBase.class), any(HttpContext.class)); + + DisbursementRefundCreateRequest request = + DisbursementRefundCreateRequest.builder().amount(new BigDecimal("50.00")).build(); + + DisbursementRefund refund = client.create(20458724L, 123456L, request); + + assertNotNull(refund.getResponse()); + assertEquals(CREATED, refund.getResponse().getStatusCode()); + assertEquals(78901234L, refund.getId()); + assertEquals("approved", refund.getStatus()); + } + + @Test + void createAllSuccess() throws IOException, MPException, MPApiException { + HttpResponse httpResponse = generateHttpResponseFromFile(refundBaseJson, CREATED); + doReturn(httpResponse) + .when(HTTP_CLIENT) + .execute(any(HttpRequestBase.class), any(HttpContext.class)); + + DisbursementRefundCreateRequest request = + DisbursementRefundCreateRequest.builder().amount(new BigDecimal("50.00")).build(); + + DisbursementRefund refund = client.createAll(20458724L, request); + + assertNotNull(refund.getResponse()); + assertEquals(CREATED, refund.getResponse().getStatusCode()); + assertEquals(78901234L, refund.getId()); + } +} diff --git a/src/test/java/com/mercadopago/client/invoice/InvoiceClientTest.java b/src/test/java/com/mercadopago/client/invoice/InvoiceClientTest.java new file mode 100644 index 00000000..f6055ebd --- /dev/null +++ b/src/test/java/com/mercadopago/client/invoice/InvoiceClientTest.java @@ -0,0 +1,60 @@ +package com.mercadopago.client.invoice; + +import static com.mercadopago.helper.MockHelper.generateHttpResponseFromFile; +import static com.mercadopago.net.HttpStatus.OK; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.doReturn; + +import com.mercadopago.BaseClientTest; +import com.mercadopago.exceptions.MPApiException; +import com.mercadopago.exceptions.MPException; +import com.mercadopago.net.MPResultsResourcesPage; +import com.mercadopago.net.MPSearchRequest; +import com.mercadopago.resources.invoice.Invoice; +import java.io.IOException; +import org.apache.http.HttpResponse; +import org.apache.http.client.methods.HttpRequestBase; +import org.apache.http.protocol.HttpContext; +import org.junit.jupiter.api.Test; + +class InvoiceClientTest extends BaseClientTest { + + private static final String invoiceBaseJson = "invoice/invoice_base.json"; + private static final String invoiceListJson = "invoice/invoice_list.json"; + private final InvoiceClient client = new InvoiceClient(); + + @Test + void getSuccess() throws IOException, MPException, MPApiException { + HttpResponse httpResponse = generateHttpResponseFromFile(invoiceBaseJson, OK); + doReturn(httpResponse) + .when(HTTP_CLIENT) + .execute(any(HttpRequestBase.class), any(HttpContext.class)); + + Invoice invoice = client.get(6114264375L); + + assertNotNull(invoice.getResponse()); + assertEquals(OK, invoice.getResponse().getStatusCode()); + assertEquals(6114264375L, invoice.getId()); + assertEquals("scheduled", invoice.getStatus()); + assertEquals("2c938084726fca480172750000000000", invoice.getPreapprovalId()); + } + + @Test + void searchSuccess() throws IOException, MPException, MPApiException { + HttpResponse httpResponse = generateHttpResponseFromFile(invoiceListJson, OK); + doReturn(httpResponse) + .when(HTTP_CLIENT) + .execute(any(HttpRequestBase.class), any(HttpContext.class)); + + MPSearchRequest searchRequest = MPSearchRequest.builder().limit(30).offset(0).build(); + MPResultsResourcesPage result = client.search(searchRequest); + + assertNotNull(result.getResponse()); + assertEquals(OK, result.getResponse().getStatusCode()); + assertEquals(1, result.getPaging().getTotal()); + assertEquals(1, result.getResults().size()); + assertEquals(6114264375L, result.getResults().get(0).getId()); + } +} diff --git a/src/test/java/com/mercadopago/client/preapprovalplan/PreApprovalPlanClientTest.java b/src/test/java/com/mercadopago/client/preapprovalplan/PreApprovalPlanClientTest.java new file mode 100644 index 00000000..75d5333e --- /dev/null +++ b/src/test/java/com/mercadopago/client/preapprovalplan/PreApprovalPlanClientTest.java @@ -0,0 +1,86 @@ +package com.mercadopago.client.preapprovalplan; + +import static com.mercadopago.helper.MockHelper.generateHttpResponseFromFile; +import static com.mercadopago.net.HttpStatus.CREATED; +import static com.mercadopago.net.HttpStatus.OK; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.doReturn; + +import com.mercadopago.BaseClientTest; +import com.mercadopago.exceptions.MPApiException; +import com.mercadopago.exceptions.MPException; +import com.mercadopago.net.MPResultsResourcesPage; +import com.mercadopago.net.MPSearchRequest; +import com.mercadopago.resources.preapprovalplan.PreApprovalPlan; +import java.io.IOException; +import java.math.BigDecimal; +import org.apache.http.HttpResponse; +import org.apache.http.client.methods.HttpRequestBase; +import org.apache.http.protocol.HttpContext; +import org.junit.jupiter.api.Test; + +class PreApprovalPlanClientTest extends BaseClientTest { + + private static final String planBaseJson = "preapprovalplan/preapprovalplan_base.json"; + private static final String planListJson = "preapprovalplan/preapprovalplan_list.json"; + private final PreApprovalPlanClient client = new PreApprovalPlanClient(); + + @Test + void getSuccess() throws IOException, MPException, MPApiException { + HttpResponse httpResponse = generateHttpResponseFromFile(planBaseJson, OK); + doReturn(httpResponse) + .when(HTTP_CLIENT) + .execute(any(HttpRequestBase.class), any(HttpContext.class)); + + PreApprovalPlan plan = client.get("plan-abc-123"); + + assertNotNull(plan.getResponse()); + assertEquals(OK, plan.getResponse().getStatusCode()); + assertEquals("plan-abc-123", plan.getId()); + assertEquals("Monthly yoga subscription", plan.getReason()); + assertEquals("active", plan.getStatus()); + } + + @Test + void createSuccess() throws IOException, MPException, MPApiException { + HttpResponse httpResponse = generateHttpResponseFromFile(planBaseJson, CREATED); + doReturn(httpResponse) + .when(HTTP_CLIENT) + .execute(any(HttpRequestBase.class), any(HttpContext.class)); + + PreApprovalPlanCreateRequest request = PreApprovalPlanCreateRequest.builder() + .reason("Monthly yoga subscription") + .backUrl("https://example.com/back") + .autoRecurring(PreApprovalPlanAutoRecurringCreateRequest.builder() + .frequency(1) + .frequencyType("months") + .currencyId("BRL") + .transactionAmount(new BigDecimal("49.90")) + .build()) + .build(); + + PreApprovalPlan plan = client.create(request); + + assertNotNull(plan.getResponse()); + assertEquals(CREATED, plan.getResponse().getStatusCode()); + assertEquals("plan-abc-123", plan.getId()); + } + + @Test + void searchSuccess() throws IOException, MPException, MPApiException { + HttpResponse httpResponse = generateHttpResponseFromFile(planListJson, OK); + doReturn(httpResponse) + .when(HTTP_CLIENT) + .execute(any(HttpRequestBase.class), any(HttpContext.class)); + + MPSearchRequest searchRequest = MPSearchRequest.builder().limit(30).offset(0).build(); + MPResultsResourcesPage result = client.search(searchRequest); + + assertNotNull(result.getResponse()); + assertEquals(OK, result.getResponse().getStatusCode()); + assertEquals(1, result.getPaging().getTotal()); + assertEquals("plan-abc-123", result.getResults().get(0).getId()); + } +} diff --git a/src/test/java/com/mercadopago/resources/mocks/response/advancedPayment/advancedpayment_base.json b/src/test/java/com/mercadopago/resources/mocks/response/advancedPayment/advancedpayment_base.json new file mode 100644 index 00000000..d91279c0 --- /dev/null +++ b/src/test/java/com/mercadopago/resources/mocks/response/advancedPayment/advancedpayment_base.json @@ -0,0 +1,21 @@ +{ + "id": 20458724, + "application_id": "59441713004005", + "external_reference": "ADV-REF-001", + "description": "Advanced payment description", + "status": "approved", + "capture": false, + "binary_mode": false, + "date_created": "2022-07-01T08:00:00.000-04:00", + "date_last_updated": "2022-07-01T08:01:00.000-04:00", + "disbursements": [ + { + "id": 17070479752, + "amount": 80.00, + "collector_id": 488656838, + "external_reference": "DISB-REF-001", + "application_fee": 1.0, + "money_release_days": 30 + } + ] +} diff --git a/src/test/java/com/mercadopago/resources/mocks/response/advancedPayment/advancedpayment_list.json b/src/test/java/com/mercadopago/resources/mocks/response/advancedPayment/advancedpayment_list.json new file mode 100644 index 00000000..7075abd6 --- /dev/null +++ b/src/test/java/com/mercadopago/resources/mocks/response/advancedPayment/advancedpayment_list.json @@ -0,0 +1,23 @@ +{ + "paging": { + "total": 1, + "limit": 30, + "offset": 0 + }, + "results": [ + { + "id": 20458724, + "application_id": "59441713004005", + "external_reference": "ADV-REF-001", + "status": "approved", + "capture": false, + "disbursements": [ + { + "id": 17070479752, + "amount": 80.00, + "collector_id": 488656838 + } + ] + } + ] +} diff --git a/src/test/java/com/mercadopago/resources/mocks/response/chargeback/chargeback_base.json b/src/test/java/com/mercadopago/resources/mocks/response/chargeback/chargeback_base.json new file mode 100644 index 00000000..3c1761bf --- /dev/null +++ b/src/test/java/com/mercadopago/resources/mocks/response/chargeback/chargeback_base.json @@ -0,0 +1,11 @@ +{ + "id": "CB-001-2022", + "payment_id": 19951521071, + "status": "in_review", + "amount": 100.00, + "currency_id": "BRL", + "reason_id": "4853", + "reason": "Cardholder dispute", + "date_created": "2022-07-01T08:00:00.000-00:00", + "last_modified": "2022-07-02T10:00:00.000-00:00" +} diff --git a/src/test/java/com/mercadopago/resources/mocks/response/chargeback/chargeback_list.json b/src/test/java/com/mercadopago/resources/mocks/response/chargeback/chargeback_list.json new file mode 100644 index 00000000..d03bc6e4 --- /dev/null +++ b/src/test/java/com/mercadopago/resources/mocks/response/chargeback/chargeback_list.json @@ -0,0 +1,12 @@ +{ + "paging": { "total": 1, "limit": 30, "offset": 0 }, + "results": [ + { + "id": "CB-001-2022", + "payment_id": 19951521071, + "status": "in_review", + "amount": 100.00, + "currency_id": "BRL" + } + ] +} diff --git a/src/test/java/com/mercadopago/resources/mocks/response/disbursementrefund/disbursementrefund_base.json b/src/test/java/com/mercadopago/resources/mocks/response/disbursementrefund/disbursementrefund_base.json new file mode 100644 index 00000000..7ea5ab20 --- /dev/null +++ b/src/test/java/com/mercadopago/resources/mocks/response/disbursementrefund/disbursementrefund_base.json @@ -0,0 +1,8 @@ +{ + "id": 78901234, + "advanced_payment_id": 20458724, + "disbursement_id": 123456, + "amount": 50.00, + "status": "approved", + "date_created": "2022-06-02T09:00:00.000-00:00" +} diff --git a/src/test/java/com/mercadopago/resources/mocks/response/invoice/invoice_base.json b/src/test/java/com/mercadopago/resources/mocks/response/invoice/invoice_base.json new file mode 100644 index 00000000..2eec1d1b --- /dev/null +++ b/src/test/java/com/mercadopago/resources/mocks/response/invoice/invoice_base.json @@ -0,0 +1,20 @@ +{ + "id": 6114264375, + "type": "scheduled", + "date_created": "2022-01-01T11:12:25.892-00:00", + "last_modified": "2022-01-01T11:12:25.892-00:00", + "preapproval_id": "2c938084726fca480172750000000000", + "reason": "Yoga classes", + "external_reference": "YG-23546246234", + "currency_id": "ARS", + "transaction_amount": 10.00, + "debit_date": "2022-01-01T11:12:25.892-00:00", + "retry_attempt": 4, + "status": "scheduled", + "summarized": "pending", + "payment": { + "id": 19951521071, + "status": "approved", + "status_detail": "accredited" + } +} diff --git a/src/test/java/com/mercadopago/resources/mocks/response/invoice/invoice_list.json b/src/test/java/com/mercadopago/resources/mocks/response/invoice/invoice_list.json new file mode 100644 index 00000000..369a1b5d --- /dev/null +++ b/src/test/java/com/mercadopago/resources/mocks/response/invoice/invoice_list.json @@ -0,0 +1,11 @@ +{ + "paging": { "total": 1, "limit": 30, "offset": 0 }, + "results": [ + { + "id": 6114264375, + "type": "scheduled", + "status": "scheduled", + "preapproval_id": "2c938084726fca480172750000000000" + } + ] +} diff --git a/src/test/java/com/mercadopago/resources/mocks/response/preapprovalplan/preapprovalplan_base.json b/src/test/java/com/mercadopago/resources/mocks/response/preapprovalplan/preapprovalplan_base.json new file mode 100644 index 00000000..e75c624f --- /dev/null +++ b/src/test/java/com/mercadopago/resources/mocks/response/preapprovalplan/preapprovalplan_base.json @@ -0,0 +1,18 @@ +{ + "id": "plan-abc-123", + "reason": "Monthly yoga subscription", + "external_reference": "PLAN-REF-001", + "status": "active", + "back_url": "https://example.com/back", + "collector_id": 823549964, + "application_id": "6245132082630004", + "date_created": "2022-01-10T10:10:10.000-00:00", + "last_modified": "2022-01-10T10:10:10.000-00:00", + "init_point": "https://www.mercadopago.com.br/subscriptions/checkout?preapproval_plan_id=plan-abc-123", + "auto_recurring": { + "frequency": 1, + "frequency_type": "months", + "currency_id": "BRL", + "transaction_amount": 49.90 + } +} diff --git a/src/test/java/com/mercadopago/resources/mocks/response/preapprovalplan/preapprovalplan_list.json b/src/test/java/com/mercadopago/resources/mocks/response/preapprovalplan/preapprovalplan_list.json new file mode 100644 index 00000000..fdeab656 --- /dev/null +++ b/src/test/java/com/mercadopago/resources/mocks/response/preapprovalplan/preapprovalplan_list.json @@ -0,0 +1,10 @@ +{ + "paging": { "total": 1, "limit": 30, "offset": 0 }, + "results": [ + { + "id": "plan-abc-123", + "reason": "Monthly yoga subscription", + "status": "active" + } + ] +}