From e4f5edcb7be28e656520500ecd6a776518339422 Mon Sep 17 00:00:00 2001 From: andreagostinho-meli Date: Tue, 12 Nov 2024 17:53:03 -0300 Subject: [PATCH 01/15] feat: map create order request --- src/clients/order/create/types.ts | 134 ++++++++++++++++++++++++++++++ 1 file changed, 134 insertions(+) create mode 100644 src/clients/order/create/types.ts diff --git a/src/clients/order/create/types.ts b/src/clients/order/create/types.ts new file mode 100644 index 0000000..68ecf2d --- /dev/null +++ b/src/clients/order/create/types.ts @@ -0,0 +1,134 @@ +import { Address, Phone } from '@src/clients/commonTypes'; +import { Options } from '@src/types'; + +export declare type CreateOrderData = { + body: CreateOrderRequest; + requestOptions?: Options; +} + +export declare type CreateOrderRequest = { + type?: string; + total_amount?: string; + external_reference?: string; + type_config?: TypeConfig; + transactions?: Transactions; + currency?: string; + processing_mode?: string; + description?: string; + payer?: Payer; + marketplace?: string; + marketplace_fee?: string; + campaign_id?: string; + items?: Item[]; + coupon?: Coupon; + splits?: Split[]; + shipment?: Shipment; + expiration_time?: string; +} + +export declare type TypeConfig = { + capture_mode?: string; + ip_address?: string; + callback_url?: string; +} + +export declare type Transactions = { + payments?: Payment[]; +} + +export declare type Payment = { + amount?: string; + currency?: string; + payment_method?: PaymentMethod; +} + +export declare type PaymentMethod = { + id?: string; + type?: string; + token?: string; + installments?: number; + issuer_id?: string; + statement_descriptor?: string; +} + +export declare type Payer = { + email?: string; + first_name?: string; + last_name?: string; + identification?: Identification; + phone?: Phone; + address?: Address; + authentication_type?: string; + registration_date?: string; + last_purchase?: string; + is_prime_user?: boolean; + is_first_purchase_online?: boolean; + entity_type?: string; +} + +export declare type Identification = { + type?: string; + number?: string; +} + +export declare type Item = { + title?: string; + unit_price?: string; + quantity?: number; + description?: string; + code?: string; + type?: string; + picture_url?: string; + warranty?: boolean; + category_descriptor?: CategoryDescriptor; +} + +export declare type CategoryDescriptor = { + event_date?: string; + passenger?: Passenger; + route?: Route; +} + +export declare type Passenger = { + first_name?: string; + last_name?: string; + identification_type?: string; + identification_number?: string; +} + +export declare type Route = { + departure?: string; + destination?: string; + departure_date_time?: string; + arrival_date_time?: string; + company?: string; +} + +export declare type Coupon = { + code?: string; + amount?: string; +} + +export declare type Split = { + oauth_token?: string; + type?: string; + value?: string; +} + +export declare type Shipment = { + receiver_address?: ReceiverAddress; + width?: number; + height?: number; + express_shipment?: boolean; + pick_up_on_seller?: boolean; +} + +export declare type ReceiverAddress = { + street_name?: string; + street_number?: string; + zip_code?: string; + city_name?: string; + state_name?: string; + floor?: string; + apartment?: string; +} From 6f9734f0e0646a2894416cd0ac974e8120a9a51e Mon Sep 17 00:00:00 2001 From: andreagostinho-meli Date: Wed, 13 Nov 2024 16:24:07 -0300 Subject: [PATCH 02/15] refactor: update Order request fields based on new swagger --- src/clients/order/create/types.ts | 96 +++++++++++-------------------- 1 file changed, 35 insertions(+), 61 deletions(-) diff --git a/src/clients/order/create/types.ts b/src/clients/order/create/types.ts index 68ecf2d..0407de1 100644 --- a/src/clients/order/create/types.ts +++ b/src/clients/order/create/types.ts @@ -1,4 +1,4 @@ -import { Address, Phone } from '@src/clients/commonTypes'; +import { Phone } from '@src/clients/commonTypes'; import { Options } from '@src/types'; export declare type CreateOrderData = { @@ -8,28 +8,21 @@ export declare type CreateOrderData = { export declare type CreateOrderRequest = { type?: string; - total_amount?: string; external_reference?: string; - type_config?: TypeConfig; transactions?: Transactions; - currency?: string; + payer?: Payer; + total_amount?: string; + type_config?: TypeConfig; processing_mode?: string; description?: string; - payer?: Payer; marketplace?: string; marketplace_fee?: string; - campaign_id?: string; items?: Item[]; - coupon?: Coupon; - splits?: Split[]; - shipment?: Shipment; expiration_time?: string; } export declare type TypeConfig = { capture_mode?: string; - ip_address?: string; - callback_url?: string; } export declare type Transactions = { @@ -38,8 +31,10 @@ export declare type Transactions = { export declare type Payment = { amount?: string; - currency?: string; + automatic_payments?: AutomaticPayments; payment_method?: PaymentMethod; + stored_credential?: StoredCredential; + subscription_data?: SubscriptionData; } export declare type PaymentMethod = { @@ -52,18 +47,13 @@ export declare type PaymentMethod = { } export declare type Payer = { + customer_id?: string; email?: string; first_name?: string; last_name?: string; identification?: Identification; phone?: Phone; address?: Address; - authentication_type?: string; - registration_date?: string; - last_purchase?: string; - is_prime_user?: boolean; - is_first_purchase_online?: boolean; - entity_type?: string; } export declare type Identification = { @@ -71,64 +61,48 @@ export declare type Identification = { number?: string; } +export declare type Address = { + street_name?: string; + street_number?: string; +} + export declare type Item = { title?: string; unit_price?: string; quantity?: number; + id?: string; + category_id?: string; description?: string; - code?: string; - type?: string; picture_url?: string; - warranty?: boolean; - category_descriptor?: CategoryDescriptor; } -export declare type CategoryDescriptor = { - event_date?: string; - passenger?: Passenger; - route?: Route; +export declare type AutomaticPayments = { + payment_profile_id?: string; + retries?: number; + schedule_date?: string; + due_date?: string; } -export declare type Passenger = { - first_name?: string; - last_name?: string; - identification_type?: string; - identification_number?: string; +export declare type StoredCredential = { + payment_initiator?: string; + reason?: string; + store_payment_method?: boolean; + first_payment?: boolean; } -export declare type Route = { - departure?: string; - destination?: string; - departure_date_time?: string; - arrival_date_time?: string; - company?: string; +export declare type SubscriptionData = { + subscription_sequence?: SubscriptionSequence; + invoice_id?: string; + invoice_period?: InvoicePeriod; + billing_date?: string; } -export declare type Coupon = { - code?: string; - amount?: string; +export declare type SubscriptionSequence = { + number?: number; + total?: number; } -export declare type Split = { - oauth_token?: string; +export declare type InvoicePeriod = { type?: string; - value?: string; -} - -export declare type Shipment = { - receiver_address?: ReceiverAddress; - width?: number; - height?: number; - express_shipment?: boolean; - pick_up_on_seller?: boolean; -} - -export declare type ReceiverAddress = { - street_name?: string; - street_number?: string; - zip_code?: string; - city_name?: string; - state_name?: string; - floor?: string; - apartment?: string; + period?: number; } From 353728fb72fc4ecf18d2de70f25fc5b0284176b9 Mon Sep 17 00:00:00 2001 From: andreagostinho-meli Date: Wed, 13 Nov 2024 17:47:10 -0300 Subject: [PATCH 03/15] feat: map order response --- src/clients/order/create/types.ts | 84 +++++++++++++++++++++++++++---- 1 file changed, 75 insertions(+), 9 deletions(-) diff --git a/src/clients/order/create/types.ts b/src/clients/order/create/types.ts index 0407de1..59ca4d7 100644 --- a/src/clients/order/create/types.ts +++ b/src/clients/order/create/types.ts @@ -1,5 +1,7 @@ +// API version: 5d077b6f-61b2-4b3a-8333-7a64ee547448 + import { Phone } from '@src/clients/commonTypes'; -import { Options } from '@src/types'; +import { ApiResponse, Options } from '@src/types'; export declare type CreateOrderData = { body: CreateOrderRequest; @@ -9,8 +11,8 @@ export declare type CreateOrderData = { export declare type CreateOrderRequest = { type?: string; external_reference?: string; - transactions?: Transactions; - payer?: Payer; + transactions?: TransactionsRequest; + payer?: PayerRequest; total_amount?: string; type_config?: TypeConfig; processing_mode?: string; @@ -21,32 +23,87 @@ export declare type CreateOrderRequest = { expiration_time?: string; } +export declare interface OrderResponse extends ApiResponse { + id?: string; + type?: string; + external_reference?: string; + site_id?: string; + status?: string; + status_detail?: string; + transactions?: TransactionsResponse; + payer?: PayerResponse; + type_config?: TypeConfig; + total_amount?: string; + processing_mode?: string; + description?: string; + marketplace?: string; + marketplace_fee?: string; + items?: Item[]; + expiration_time?: string; +} + export declare type TypeConfig = { capture_mode?: string; } -export declare type Transactions = { - payments?: Payment[]; +export declare type TransactionsRequest = { + payments?: PaymentRequest[]; +} + +export declare type TransactionsResponse = { + payments?: PaymentResponse[]; + refunds?: Refund[]; } -export declare type Payment = { +export declare type PaymentRequest = { amount?: string; automatic_payments?: AutomaticPayments; - payment_method?: PaymentMethod; + payment_method?: PaymentMethodRequest; stored_credential?: StoredCredential; subscription_data?: SubscriptionData; } -export declare type PaymentMethod = { +export declare type PaymentResponse = { + id?: string; + reference_id?: string; + amount?: string; + status?: string; + payment_method?: PaymentMethodResponse; +} + +export declare type Refund = { + id?: string; + transaction_id?: string; + reference_id?: string; + amount?: string; + status?: string; +} + +export declare type PaymentMethodRequest = { + id?: string; + type?: string; + token?: string; + installments?: number; + issuer_id?: string; + statement_descriptor?: string; +} + +export declare type PaymentMethodResponse = { id?: string; type?: string; + card_id?: string; token?: string; installments?: number; issuer_id?: string; statement_descriptor?: string; + external_resource_url?: string; + barcode_content?: string; + reference?: string; + verification_code?: string; + financial_institution?: string; } -export declare type Payer = { +export declare type PayerRequest = { customer_id?: string; email?: string; first_name?: string; @@ -56,6 +113,15 @@ export declare type Payer = { address?: Address; } +export declare type PayerResponse = { + email?: string; + first_name?: string; + last_name?: string; + identification?: Identification; + phone?: Phone; + address?: Address; +} + export declare type Identification = { type?: string; number?: string; From 64cf3e82b865c93d1afa0bb0a61a9b5bd516be6e Mon Sep 17 00:00:00 2001 From: andreagostinho-meli Date: Thu, 14 Nov 2024 09:17:14 -0300 Subject: [PATCH 04/15] enhancement: add missing fields from response --- src/clients/order/create/types.ts | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/clients/order/create/types.ts b/src/clients/order/create/types.ts index 59ca4d7..a8ab57f 100644 --- a/src/clients/order/create/types.ts +++ b/src/clients/order/create/types.ts @@ -28,6 +28,8 @@ export declare interface OrderResponse extends ApiResponse { type?: string; external_reference?: string; site_id?: string; + created_date?: string; + last_updated_date?: string; status?: string; status_detail?: string; transactions?: TransactionsResponse; @@ -68,6 +70,7 @@ export declare type PaymentResponse = { reference_id?: string; amount?: string; status?: string; + status_detail?: string; payment_method?: PaymentMethodResponse; } From 4a6adec04dcf44b7ab1dbdf5b7070ac00d43f1f1 Mon Sep 17 00:00:00 2001 From: andreagostinho-meli Date: Thu, 14 Nov 2024 14:45:43 -0300 Subject: [PATCH 05/15] feat: add call to create Order --- src/clients/order/create/create.spec.ts | 52 +++++++++++++++++++++++++ src/clients/order/create/index.ts | 16 ++++++++ src/clients/order/create/types.ts | 6 +++ 3 files changed, 74 insertions(+) create mode 100644 src/clients/order/create/create.spec.ts create mode 100644 src/clients/order/create/index.ts diff --git a/src/clients/order/create/create.spec.ts b/src/clients/order/create/create.spec.ts new file mode 100644 index 0000000..41be97b --- /dev/null +++ b/src/clients/order/create/create.spec.ts @@ -0,0 +1,52 @@ +import { RestClient } from '@utils/restClient'; +import { MercadoPagoConfig } from '@src/mercadoPagoConfig'; + +import type { CreateOrderClient, CreateOrderRequest } from './types'; +import create from '.'; + +jest.mock('@utils/restClient'); + +describe('Create Order', () => { + test('should create Order', async () => { + const config = new MercadoPagoConfig({ accessToken: 'access_token', options: { timeout: 5000 } }); + const mockBody: CreateOrderRequest = { + type: 'online', + total_amount: '1000.00', + external_reference: 'ext_ref_1234', + transactions: { + payments: [ + { + amount: '1000.00', + payment_method: { + id: 'master', + type: 'credit_card', + token: 'card_token', + installments: 1, + }, + }, + ], + }, + payer: { + email: 'test_1731350184@testuser.com', + }, + }; + const mockCreate: CreateOrderClient = { + body: mockBody, + config + }; + const spyFetch = jest.spyOn(RestClient, 'fetch'); + + await create(mockCreate); + + expect(spyFetch).toHaveBeenCalledWith('/v1/orders', + { + body: JSON.stringify(mockBody), + headers: { + Authorization: 'Bearer access_token' + }, + method: 'POST', + timeout: 5000 + } + ); + }); +}); diff --git a/src/clients/order/create/index.ts b/src/clients/order/create/index.ts new file mode 100644 index 0000000..6da5eb5 --- /dev/null +++ b/src/clients/order/create/index.ts @@ -0,0 +1,16 @@ +import { RestClient } from '@src/utils/restClient'; +import { CreateOrderClient, OrderResponse } from './types'; + +export default function create({ body, config }: CreateOrderClient): Promise { + return RestClient.fetch( + '/v1/orders', + { + method: 'POST', + headers: { + 'Authorization': `Bearer ${config.accessToken}` + }, + body: JSON.stringify(body), + ...config.options + } + ); +} diff --git a/src/clients/order/create/types.ts b/src/clients/order/create/types.ts index a8ab57f..b48c158 100644 --- a/src/clients/order/create/types.ts +++ b/src/clients/order/create/types.ts @@ -1,8 +1,14 @@ // API version: 5d077b6f-61b2-4b3a-8333-7a64ee547448 import { Phone } from '@src/clients/commonTypes'; +import { MercadoPagoConfig } from '@src/mercadoPagoConfig'; import { ApiResponse, Options } from '@src/types'; +export declare type CreateOrderClient = { + body: CreateOrderRequest, + config: MercadoPagoConfig +}; + export declare type CreateOrderData = { body: CreateOrderRequest; requestOptions?: Options; From b2838215cbeb5978270db95d277fc34ba8207c92 Mon Sep 17 00:00:00 2001 From: andreagostinho-meli Date: Thu, 14 Nov 2024 14:58:12 -0300 Subject: [PATCH 06/15] enhancement: use function to generate test user email --- src/clients/order/create/create.spec.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/clients/order/create/create.spec.ts b/src/clients/order/create/create.spec.ts index 41be97b..f317259 100644 --- a/src/clients/order/create/create.spec.ts +++ b/src/clients/order/create/create.spec.ts @@ -3,6 +3,7 @@ import { MercadoPagoConfig } from '@src/mercadoPagoConfig'; import type { CreateOrderClient, CreateOrderRequest } from './types'; import create from '.'; +import { createEmailTestUser } from '@src/mocks/createEmailTestUser'; jest.mock('@utils/restClient'); @@ -27,7 +28,7 @@ describe('Create Order', () => { ], }, payer: { - email: 'test_1731350184@testuser.com', + email: createEmailTestUser(), }, }; const mockCreate: CreateOrderClient = { From 664da41a5a54b32cc5ac3780f8c0bdd25241b6ea Mon Sep 17 00:00:00 2001 From: andreagostinho-meli Date: Thu, 14 Nov 2024 15:30:27 -0300 Subject: [PATCH 07/15] feat: create Order client --- e2e/order/create.spec.ts | 41 ++++++++++++++++++++++++++++++++++++++ src/clients/order/index.ts | 27 +++++++++++++++++++++++++ 2 files changed, 68 insertions(+) create mode 100644 e2e/order/create.spec.ts create mode 100644 src/clients/order/index.ts diff --git a/e2e/order/create.spec.ts b/e2e/order/create.spec.ts new file mode 100644 index 0000000..95622fd --- /dev/null +++ b/e2e/order/create.spec.ts @@ -0,0 +1,41 @@ +import MercadoPago from '@src/index'; +import { config } from '../e2e.config'; +import { Order } from '@src/clients/order'; +import { CreateOrderData } from '@src/clients/order/create/types'; + +describe('Create Order integration test', () => { + test('should create Order', async () => { + const mercadoPagoConfig = new MercadoPago({ accessToken: config.access_token }); + const order = new Order(mercadoPagoConfig); + const body: CreateOrderData = { + body: { + type: 'online', + total_amount: '1000.00', + external_reference: 'ext_ref_1234', + transactions: { + payments: [ + { + amount: '1000.00', + payment_method: { + id: 'pix', + type: 'bank_transfer', + }, + }, + ], + }, + payer: { + email: 'test_1731350184@testuser.com', + }, + }, + }; + + const response = await order.create(body); + + expect(response.id).toBeTruthy(); + expect(response.type).toBe('online'); + expect(response.total_amount).toBe('1000.00'); + expect(response.external_reference).toBe('ext_ref_1234'); + expect(response.transactions.payments[0].amount).toBe('1000.00'); + expect(response.transactions.payments[0].payment_method.id).toBe('pix'); + }); +}); diff --git a/src/clients/order/index.ts b/src/clients/order/index.ts new file mode 100644 index 0000000..20fc28d --- /dev/null +++ b/src/clients/order/index.ts @@ -0,0 +1,27 @@ +import create from './create'; + +import type { MercadoPagoConfig } from '@src/mercadoPagoConfig'; +import { CreateOrderData, OrderResponse } from './create/types'; + +/** + * Mercado Pago Order. + * + * @see {@link https://www.mercadopago.com/developers/en/reference Documentation }. + */ +export class Order { + private config: MercadoPagoConfig; + + constructor(mercadoPagoConfig: MercadoPagoConfig) { + this.config = mercadoPagoConfig; + } + + /** + * Create Order. + * + * @see {@link https://github.com/mercadopago/sdk-nodejs/blob/master/src/examples/order/create.ts Usage Example }. + */ + create({ body, requestOptions }: CreateOrderData): Promise { + this.config.options = { ...this.config.options, ...requestOptions }; + return create({ body, config: this.config }); + } +} From 6314ddf69c37fce3ff2e78729e8ed194dc80581c Mon Sep 17 00:00:00 2001 From: andreagostinho-meli Date: Thu, 14 Nov 2024 16:23:29 -0300 Subject: [PATCH 08/15] feat: add create Order example --- src/examples/order/create.ts | 74 ++++++++++++++++++++++++++++++++++++ 1 file changed, 74 insertions(+) create mode 100644 src/examples/order/create.ts diff --git a/src/examples/order/create.ts b/src/examples/order/create.ts new file mode 100644 index 0000000..8b33ce5 --- /dev/null +++ b/src/examples/order/create.ts @@ -0,0 +1,74 @@ +/** + * Mercado Pago Create Order. + * + * @see {@link [TODO: insert Order documentation URL] Documentation }. + */ + +import { Order } from '@src/clients/order'; +import MercadoPago from '@src/index'; + +const mercadoPagoConfig = new MercadoPago({ accessToken: '', options: { timeout: 5000 } }); + +const order = new Order(mercadoPagoConfig); + +// full order example +order.create({ + body: { + type: 'online', + total_amount: '1000.00', + external_reference: 'ext_ref_1234', + type_config: { + capture_mode: 'automatic' + }, + transactions: { + payments: [ + { + amount: '1000.00', + payment_method: { + id: 'master', + type: 'credit_card', + token: '', + installments: 1, + statement_descriptor: 'Store name' + } + } + ] + }, + processing_mode: 'automatic', + description: 'some description', + payer: { + email: '', + first_name: 'John', + last_name: 'Doe', + identification: { + type: 'CPF', + number: '00000000000' + }, + phone: { + area_code: '55', + number: '99999999999' + }, + address: { + street_name: 'Av. das Nações Unidas', + street_number: '99' + } + }, + marketplace: 'NONE', + marketplace_fee: '10.00', + items: [ + { + title: 'Some item title', + unit_price: '1000.00', + quantity: 1, + description: 'Some item description', + id: 'item_id', + category_id: 'category_id', + picture_url: 'https://mysite.com/img/item.jpg' + } + ], + expiration_time: 'P3D' + }, + requestOptions: { + idempotencyKey: '' + } +}).then(console.log).catch(console.error); From 2dba3d7faadae7b0166e27f5c406a6fe425aebd5 Mon Sep 17 00:00:00 2001 From: andreagostinho-meli Date: Tue, 19 Nov 2024 15:20:36 -0300 Subject: [PATCH 09/15] enhancement: move response structs to common types --- src/clients/order/commonTypes.ts | 93 ++++++++++++++++++++++++++ src/clients/order/create/index.ts | 3 +- src/clients/order/create/types.ts | 106 +++--------------------------- 3 files changed, 103 insertions(+), 99 deletions(-) create mode 100644 src/clients/order/commonTypes.ts diff --git a/src/clients/order/commonTypes.ts b/src/clients/order/commonTypes.ts new file mode 100644 index 0000000..9b0bafc --- /dev/null +++ b/src/clients/order/commonTypes.ts @@ -0,0 +1,93 @@ +import { ApiResponse } from '@src/types'; +import { Phone } from '../commonTypes'; + +export declare interface OrderResponse extends ApiResponse { + id?: string; + type?: string; + external_reference?: string; + site_id?: string; + created_date?: string; + last_updated_date?: string; + status?: string; + status_detail?: string; + transactions?: TransactionsResponse; + payer?: PayerResponse; + type_config?: TypeConfig; + total_amount?: string; + processing_mode?: string; + description?: string; + marketplace?: string; + marketplace_fee?: string; + items?: Item[]; + expiration_time?: string; +} + +export declare type TransactionsResponse = { + payments?: PaymentResponse[]; + refunds?: RefundResponse[]; +} + +export declare type PaymentResponse = { + id?: string; + reference_id?: string; + amount?: string; + status?: string; + status_detail?: string; + payment_method?: PaymentMethodResponse; +} + +export declare type PaymentMethodResponse = { + id?: string; + type?: string; + card_id?: string; + token?: string; + installments?: number; + issuer_id?: string; + statement_descriptor?: string; + external_resource_url?: string; + barcode_content?: string; + reference?: string; + verification_code?: string; + financial_institution?: string; +} + +export declare type RefundResponse = { + id?: string; + transaction_id?: string; + reference_id?: string; + amount?: string; + status?: string; +} + +export declare type PayerResponse = { + email?: string; + first_name?: string; + last_name?: string; + identification?: Identification; + phone?: Phone; + address?: Address; +} + +export declare type Identification = { + type?: string; + number?: string; +} + +export declare type Address = { + street_name?: string; + street_number?: string; +} + +export declare type TypeConfig = { + capture_mode?: string; +} + +export declare type Item = { + id?: string; + title?: string; + unit_price?: string; + quantity?: number; + category_id?: string; + description?: string; + picture_url?: string; +} diff --git a/src/clients/order/create/index.ts b/src/clients/order/create/index.ts index 6da5eb5..fed04ab 100644 --- a/src/clients/order/create/index.ts +++ b/src/clients/order/create/index.ts @@ -1,5 +1,6 @@ import { RestClient } from '@src/utils/restClient'; -import { CreateOrderClient, OrderResponse } from './types'; +import { CreateOrderClient } from './types'; +import { OrderResponse } from '../commonTypes'; export default function create({ body, config }: CreateOrderClient): Promise { return RestClient.fetch( diff --git a/src/clients/order/create/types.ts b/src/clients/order/create/types.ts index b48c158..e9e6b52 100644 --- a/src/clients/order/create/types.ts +++ b/src/clients/order/create/types.ts @@ -2,7 +2,8 @@ import { Phone } from '@src/clients/commonTypes'; import { MercadoPagoConfig } from '@src/mercadoPagoConfig'; -import { ApiResponse, Options } from '@src/types'; +import { Options } from '@src/types'; +import { Address, Identification, Item, TypeConfig } from '../commonTypes'; export declare type CreateOrderClient = { body: CreateOrderRequest, @@ -29,63 +30,16 @@ export declare type CreateOrderRequest = { expiration_time?: string; } -export declare interface OrderResponse extends ApiResponse { - id?: string; - type?: string; - external_reference?: string; - site_id?: string; - created_date?: string; - last_updated_date?: string; - status?: string; - status_detail?: string; - transactions?: TransactionsResponse; - payer?: PayerResponse; - type_config?: TypeConfig; - total_amount?: string; - processing_mode?: string; - description?: string; - marketplace?: string; - marketplace_fee?: string; - items?: Item[]; - expiration_time?: string; -} - -export declare type TypeConfig = { - capture_mode?: string; -} - export declare type TransactionsRequest = { payments?: PaymentRequest[]; } -export declare type TransactionsResponse = { - payments?: PaymentResponse[]; - refunds?: Refund[]; -} - export declare type PaymentRequest = { amount?: string; - automatic_payments?: AutomaticPayments; + automatic_payments?: AutomaticPaymentsRequest; payment_method?: PaymentMethodRequest; - stored_credential?: StoredCredential; - subscription_data?: SubscriptionData; -} - -export declare type PaymentResponse = { - id?: string; - reference_id?: string; - amount?: string; - status?: string; - status_detail?: string; - payment_method?: PaymentMethodResponse; -} - -export declare type Refund = { - id?: string; - transaction_id?: string; - reference_id?: string; - amount?: string; - status?: string; + stored_credential?: StoredCredentialRequest; + subscription_data?: SubscriptionDataRequest; } export declare type PaymentMethodRequest = { @@ -97,21 +51,6 @@ export declare type PaymentMethodRequest = { statement_descriptor?: string; } -export declare type PaymentMethodResponse = { - id?: string; - type?: string; - card_id?: string; - token?: string; - installments?: number; - issuer_id?: string; - statement_descriptor?: string; - external_resource_url?: string; - barcode_content?: string; - reference?: string; - verification_code?: string; - financial_institution?: string; -} - export declare type PayerRequest = { customer_id?: string; email?: string; @@ -122,50 +61,21 @@ export declare type PayerRequest = { address?: Address; } -export declare type PayerResponse = { - email?: string; - first_name?: string; - last_name?: string; - identification?: Identification; - phone?: Phone; - address?: Address; -} - -export declare type Identification = { - type?: string; - number?: string; -} - -export declare type Address = { - street_name?: string; - street_number?: string; -} - -export declare type Item = { - title?: string; - unit_price?: string; - quantity?: number; - id?: string; - category_id?: string; - description?: string; - picture_url?: string; -} - -export declare type AutomaticPayments = { +export declare type AutomaticPaymentsRequest = { payment_profile_id?: string; retries?: number; schedule_date?: string; due_date?: string; } -export declare type StoredCredential = { +export declare type StoredCredentialRequest = { payment_initiator?: string; reason?: string; store_payment_method?: boolean; first_payment?: boolean; } -export declare type SubscriptionData = { +export declare type SubscriptionDataRequest = { subscription_sequence?: SubscriptionSequence; invoice_id?: string; invoice_period?: InvoicePeriod; From 1580209609d18f7f2f083a12e3c758462ad741b9 Mon Sep 17 00:00:00 2001 From: andreagostinho-meli Date: Thu, 28 Nov 2024 13:59:10 -0300 Subject: [PATCH 10/15] fix: import OrderResponse correctly --- src/clients/order/commonTypes.ts | 2 ++ src/clients/order/index.ts | 21 +++++++++++---------- 2 files changed, 13 insertions(+), 10 deletions(-) diff --git a/src/clients/order/commonTypes.ts b/src/clients/order/commonTypes.ts index 9b0bafc..2712300 100644 --- a/src/clients/order/commonTypes.ts +++ b/src/clients/order/commonTypes.ts @@ -1,3 +1,5 @@ +// API version: 5d077b6f-61b2-4b3a-8333-7a64ee547448 + import { ApiResponse } from '@src/types'; import { Phone } from '../commonTypes'; diff --git a/src/clients/order/index.ts b/src/clients/order/index.ts index 20fc28d..484d01d 100644 --- a/src/clients/order/index.ts +++ b/src/clients/order/index.ts @@ -1,7 +1,8 @@ import create from './create'; import type { MercadoPagoConfig } from '@src/mercadoPagoConfig'; -import { CreateOrderData, OrderResponse } from './create/types'; +import { CreateOrderData } from './create/types'; +import { OrderResponse } from './commonTypes'; /** * Mercado Pago Order. @@ -9,19 +10,19 @@ import { CreateOrderData, OrderResponse } from './create/types'; * @see {@link https://www.mercadopago.com/developers/en/reference Documentation }. */ export class Order { - private config: MercadoPagoConfig; + private config: MercadoPagoConfig; - constructor(mercadoPagoConfig: MercadoPagoConfig) { - this.config = mercadoPagoConfig; - } + constructor(mercadoPagoConfig: MercadoPagoConfig) { + this.config = mercadoPagoConfig; + } - /** + /** * Create Order. * * @see {@link https://github.com/mercadopago/sdk-nodejs/blob/master/src/examples/order/create.ts Usage Example }. */ - create({ body, requestOptions }: CreateOrderData): Promise { - this.config.options = { ...this.config.options, ...requestOptions }; - return create({ body, config: this.config }); - } + create({ body, requestOptions }: CreateOrderData): Promise { + this.config.options = { ...this.config.options, ...requestOptions }; + return create({ body, config: this.config }); + } } From 789cd4650480bfb748c777f4459ddbe07cc7718a Mon Sep 17 00:00:00 2001 From: andreagostinho-meli Date: Thu, 28 Nov 2024 18:11:37 -0300 Subject: [PATCH 11/15] fix: use tab as indent style --- .editorconfig | 4 ++-- src/clients/order/index.ts | 18 +++++++++--------- 2 files changed, 11 insertions(+), 11 deletions(-) diff --git a/.editorconfig b/.editorconfig index da0310f..903f280 100644 --- a/.editorconfig +++ b/.editorconfig @@ -2,7 +2,7 @@ root = true [*] -indent_style = space +indent_style = tab indent_size = 2 end_of_line = lf charset = utf-8 @@ -10,4 +10,4 @@ trim_trailing_whitespace = true insert_final_newline = true [*.md] -trim_trailing_whitespace = false \ No newline at end of file +trim_trailing_whitespace = false diff --git a/src/clients/order/index.ts b/src/clients/order/index.ts index 484d01d..b8f9516 100644 --- a/src/clients/order/index.ts +++ b/src/clients/order/index.ts @@ -10,19 +10,19 @@ import { OrderResponse } from './commonTypes'; * @see {@link https://www.mercadopago.com/developers/en/reference Documentation }. */ export class Order { - private config: MercadoPagoConfig; + private config: MercadoPagoConfig; - constructor(mercadoPagoConfig: MercadoPagoConfig) { - this.config = mercadoPagoConfig; - } + constructor(mercadoPagoConfig: MercadoPagoConfig) { + this.config = mercadoPagoConfig; + } - /** + /** * Create Order. * * @see {@link https://github.com/mercadopago/sdk-nodejs/blob/master/src/examples/order/create.ts Usage Example }. */ - create({ body, requestOptions }: CreateOrderData): Promise { - this.config.options = { ...this.config.options, ...requestOptions }; - return create({ body, config: this.config }); - } + create({ body, requestOptions }: CreateOrderData): Promise { + this.config.options = { ...this.config.options, ...requestOptions }; + return create({ body, config: this.config }); + } } From a9bb7ae1e3c0a1a19e954afe20dea35c27765c21 Mon Sep 17 00:00:00 2001 From: Danielen Cestari Nunes Date: Mon, 2 Dec 2024 11:34:09 -0300 Subject: [PATCH 12/15] [Feature] Endpoint Get Order By Id (#2) * endpoint get * include integration test * example get * remove X-sandbox header * merge master --- .pre-commit-config.yaml | 4 +-- e2e/order/get.spec.ts | 44 +++++++++++++++++++++++++++++++ src/clients/order/get/get.spec.ts | 37 ++++++++++++++++++++++++++ src/clients/order/get/index.ts | 17 ++++++++++++ src/clients/order/get/types.ts | 11 ++++++++ src/clients/order/index.ts | 20 +++++++++++--- src/examples/order/get.ts | 21 +++++++++++++++ 7 files changed, 148 insertions(+), 6 deletions(-) create mode 100644 e2e/order/get.spec.ts create mode 100644 src/clients/order/get/get.spec.ts create mode 100644 src/clients/order/get/index.ts create mode 100644 src/clients/order/get/types.ts create mode 100644 src/examples/order/get.ts diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 3e7cb71..9cd7d2f 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -1,7 +1,7 @@ repos: # Websec hook is MANDATORY, DO NOT comment it. - - repo: https://github.com/mercadolibre/fury_websec-git-hooks - rev: v1.0.5 + - repo: https://github.com/melisource/fury_websec-git-hooks + rev: v2.0.0 hooks: - id: pre_commit_hook stages: [commit] diff --git a/e2e/order/get.spec.ts b/e2e/order/get.spec.ts new file mode 100644 index 0000000..b12be4a --- /dev/null +++ b/e2e/order/get.spec.ts @@ -0,0 +1,44 @@ +import MercadoPago from '@src/index'; +import { config } from '../e2e.config'; +import { Order } from '@src/clients/order'; +import { CreateOrderData } from '@src/clients/order/create/types'; + +describe('Get Order integration test', () => { + test('should get an Order by Id', async () => { + const mercadoPagoConfig = new MercadoPago({ accessToken: config.access_token }); + const orderClient = new Order(mercadoPagoConfig); + const body: CreateOrderData = { + body: { + type: 'online', + total_amount: '1000.00', + external_reference: 'ext_ref_1234', + transactions: { + payments: [ + { + amount: '1000.00', + payment_method: { + id: 'pix', + type: 'bank_transfer', + }, + }, + ], + }, + payer: { + email: 'test_1731350184@testuser.com', + }, + }, + }; + + const order = await orderClient.create(body); + const orderId = order.id; + const getOrder = await orderClient.get({ id: orderId }); + + expect(getOrder.id).toBeTruthy(); + expect(getOrder.id).toBe(orderId); + expect(getOrder.type).toBe('online'); + expect(getOrder.total_amount).toBe('1000.00'); + expect(getOrder.external_reference).toBe('ext_ref_1234'); + expect(getOrder.transactions.payments[0].amount).toBe('1000.00'); + expect(getOrder.transactions.payments[0].payment_method.id).toBe('pix'); + }); +}); diff --git a/src/clients/order/get/get.spec.ts b/src/clients/order/get/get.spec.ts new file mode 100644 index 0000000..a054442 --- /dev/null +++ b/src/clients/order/get/get.spec.ts @@ -0,0 +1,37 @@ +import { RestClient } from '@utils/restClient'; +import { MercadoPagoConfig } from '@src/mercadoPagoConfig'; +import get from './index'; +import { OrderResponse } from '../commonTypes'; + +jest.mock('@utils/restClient'); + +describe('Get Order', () => { + test('should get Order', async () => { + const config = new MercadoPagoConfig({ accessToken: 'access_token' }); + const orderId = '01JDMS5325ZDWMESRB5G2541BD'; + const mockOrderResponse: OrderResponse = { + api_response: { + status: 200, + headers: [ + 'Content-Type', ['application/json'] + ] + }, + id: orderId, + status: '200', + total_amount: '200.00', + }; + const spyFetch = jest.spyOn(RestClient, 'fetch').mockResolvedValue(mockOrderResponse); + + const result = await get({ id: orderId, config }); + + expect(spyFetch).toHaveBeenCalledWith('/v1/orders/01JDMS5325ZDWMESRB5G2541BD', + { + method: 'GET', + headers: { + Authorization: 'Bearer access_token', + } + } + ); + expect(result).toEqual(mockOrderResponse); + }); +}); \ No newline at end of file diff --git a/src/clients/order/get/index.ts b/src/clients/order/get/index.ts new file mode 100644 index 0000000..435d857 --- /dev/null +++ b/src/clients/order/get/index.ts @@ -0,0 +1,17 @@ +import { RestClient } from '@src/utils/restClient'; +import { GetOrderClient } from './types'; +import { OrderResponse } from '../commonTypes'; + +export default function get({ id, config }: + GetOrderClient): Promise { + return RestClient.fetch( + `/v1/orders/${id}`, + { + method: 'GET', + headers: { + 'Authorization': `Bearer ${config.accessToken}`, + }, + ...config.options + } + ); +} \ No newline at end of file diff --git a/src/clients/order/get/types.ts b/src/clients/order/get/types.ts new file mode 100644 index 0000000..fe384f2 --- /dev/null +++ b/src/clients/order/get/types.ts @@ -0,0 +1,11 @@ +import { MercadoPagoConfig } from '@src/mercadoPagoConfig'; +import type { Options } from '@src/types'; + +export declare type GetOrderData = { + id: string; + requestOptions?: Options; +} + +export declare type GetOrderClient = GetOrderData & { + config: MercadoPagoConfig +} \ No newline at end of file diff --git a/src/clients/order/index.ts b/src/clients/order/index.ts index b8f9516..52c7c82 100644 --- a/src/clients/order/index.ts +++ b/src/clients/order/index.ts @@ -1,8 +1,10 @@ import create from './create'; +import get from './get'; import type { MercadoPagoConfig } from '@src/mercadoPagoConfig'; import { CreateOrderData } from './create/types'; import { OrderResponse } from './commonTypes'; +import { GetOrderData } from './get/types'; /** * Mercado Pago Order. @@ -17,12 +19,22 @@ export class Order { } /** - * Create Order. - * - * @see {@link https://github.com/mercadopago/sdk-nodejs/blob/master/src/examples/order/create.ts Usage Example }. - */ + * Create Order. + * + * @see {@link https://github.com/mercadopago/sdk-nodejs/blob/master/src/examples/order/create.ts Usage Example }. + */ create({ body, requestOptions }: CreateOrderData): Promise { this.config.options = { ...this.config.options, ...requestOptions }; return create({ body, config: this.config }); } + + /** + * Get Order. + * + * @see {@link https://github.com/mercadopago/sdk-nodejs/blob/master/src/examples/order/get.ts Usage Example }. + */ + get({ id, requestOptions }: GetOrderData): Promise { + this.config.options = { ...this.config.options, ...requestOptions }; + return get({ id, config: this.config }); + } } diff --git a/src/examples/order/get.ts b/src/examples/order/get.ts new file mode 100644 index 0000000..5b1c1be --- /dev/null +++ b/src/examples/order/get.ts @@ -0,0 +1,21 @@ +/** + * Mercado Pago Get Order. + * + * @see {@link [TODO: insert Order documentation URL] Documentation }. + */ + +import { Order } from '@src/clients/order'; +import MercadoPago from '@src/index'; + +const mercadoPagoConfig = new MercadoPago({ accessToken: '', options: { timeout: 5000 } }); + +const order = new Order(mercadoPagoConfig); + +const orderId = ''; + +order.get({ + id: orderId, + requestOptions: { + idempotencyKey: '' + } +}).then(console.log).catch(console.error); From 19fd0b40603d01407ad4adb02dbdd08f3321e6ac Mon Sep 17 00:00:00 2001 From: Danielen Cestari Nunes Date: Mon, 2 Dec 2024 14:33:08 -0300 Subject: [PATCH 13/15] [Feature] Process Endpoint (#5) * save progress * include tests * comments * fix test --- e2e/order/process.spec.ts | 57 +++++++++++++++++++++++ package.json | 2 +- src/clients/order/index.ts | 12 +++++ src/clients/order/process/index.ts | 17 +++++++ src/clients/order/process/process.spec.ts | 40 ++++++++++++++++ src/clients/order/process/types.ts | 11 +++++ src/examples/order/process.ts | 21 +++++++++ 7 files changed, 159 insertions(+), 1 deletion(-) create mode 100644 e2e/order/process.spec.ts create mode 100644 src/clients/order/process/index.ts create mode 100644 src/clients/order/process/process.spec.ts create mode 100644 src/clients/order/process/types.ts create mode 100644 src/examples/order/process.ts diff --git a/e2e/order/process.spec.ts b/e2e/order/process.spec.ts new file mode 100644 index 0000000..ecad2d3 --- /dev/null +++ b/e2e/order/process.spec.ts @@ -0,0 +1,57 @@ +import MercadoPago from '@src/index'; +import { config } from '../e2e.config'; +import { Order } from '@src/clients/order'; +import { CreateOrderData } from '@src/clients/order/create/types'; +import { createCardToken } from '@src/mocks/createCardToken'; + +const mercadoPagoConfig = new MercadoPago({ accessToken: config.access_token }); + +function createBodyOrder(token: string): CreateOrderData { + return { + body: { + type: 'online', + processing_mode: 'manual', + total_amount: '200.00', + external_reference: 'ext_ref_1234', + transactions: { + payments: [ + { + amount: '200.00', + payment_method: { + id: 'master', + type: 'credit_card', + token: token, + installments: 1 + } + } + ] + }, + payer: { + email: 'test_1731350184@testuser.com' + } + } + }; +} + +describe('Process Order integration test', () => { + test('should process an Order successfully', async () => { + const cardTokenResponse = await createCardToken(config.access_token); + const token = cardTokenResponse.id; + const orderClient = new Order(mercadoPagoConfig); + const body = createBodyOrder(token); + + const order = await orderClient.create(body); + const orderId = order.id; + const processOrder = await orderClient.process({ id: orderId }); + + expect(processOrder.id).toBeTruthy(); + expect(processOrder.id).toBe(orderId); + expect(processOrder.type).toBe('online'); + expect(processOrder.total_amount).toBe('200.00'); + expect(processOrder.status).toBe('processed'); + expect(processOrder.status_detail).toBe('accredited'); + expect(processOrder.external_reference).toBe('ext_ref_1234'); + expect(processOrder.transactions.payments[0].amount).toBe('200.00'); + expect(processOrder.transactions.payments[0].payment_method.id).toBe('master'); + }); +}); \ No newline at end of file diff --git a/package.json b/package.json index beb3ec9..58c60e8 100644 --- a/package.json +++ b/package.json @@ -51,7 +51,7 @@ "dist" ], "dependencies": { - "node-fetch": "^2.6.12", + "node-fetch": "^2.7.0", "uuid": "^9.0.0" } } diff --git a/src/clients/order/index.ts b/src/clients/order/index.ts index 52c7c82..c7ee610 100644 --- a/src/clients/order/index.ts +++ b/src/clients/order/index.ts @@ -5,6 +5,8 @@ import type { MercadoPagoConfig } from '@src/mercadoPagoConfig'; import { CreateOrderData } from './create/types'; import { OrderResponse } from './commonTypes'; import { GetOrderData } from './get/types'; +import { ProcessOrderData } from './process/types'; +import process from './process'; /** * Mercado Pago Order. @@ -37,4 +39,14 @@ export class Order { this.config.options = { ...this.config.options, ...requestOptions }; return get({ id, config: this.config }); } + + /** + * Process Order. + * + * @see {@link https://github.com/mercadopago/sdk-nodejs/blob/master/src/examples/order/process.ts Usage Example }. + */ + process({ id, requestOptions }: ProcessOrderData): Promise { + this.config.options = { ...this.config.options, ...requestOptions }; + return process({ id, config: this.config }); + } } diff --git a/src/clients/order/process/index.ts b/src/clients/order/process/index.ts new file mode 100644 index 0000000..bf36674 --- /dev/null +++ b/src/clients/order/process/index.ts @@ -0,0 +1,17 @@ +import { RestClient } from '@src/utils/restClient'; +import { ProcessOrderClient } from './types'; +import { OrderResponse } from '../commonTypes'; + +export default function process({ id, config }: + ProcessOrderClient): Promise { + return RestClient.fetch( + `/v1/orders/${id}/process`, + { + method: 'POST', + headers: { + 'Authorization': `Bearer ${config.accessToken}`, + }, + ...config.options + } + ); +} \ No newline at end of file diff --git a/src/clients/order/process/process.spec.ts b/src/clients/order/process/process.spec.ts new file mode 100644 index 0000000..384b5da --- /dev/null +++ b/src/clients/order/process/process.spec.ts @@ -0,0 +1,40 @@ +import { RestClient } from '@utils/restClient'; +import { MercadoPagoConfig } from '@src/mercadoPagoConfig'; +import process from './index'; +import { OrderResponse } from '../commonTypes'; + +jest.mock('@utils/restClient'); + +describe('Process Order', () => { + test('should process Order', async () => { + const config = new MercadoPagoConfig({ accessToken: 'access_token' }); + const orderId = '01JDWFFTAJ5S3G6JDNQ4T66FBN'; + const mockOrderResponse: OrderResponse = { + api_response: { + status: 200, + headers: [ + 'Content-Type', ['application/json'] + ] + }, + id: orderId, + type: 'online', + processing_mode: 'manual', + status: 'processed', + status_detail: 'accredited', + total_amount: '200.00', + }; + const spyFetch = jest.spyOn(RestClient, 'fetch').mockResolvedValue(mockOrderResponse); + + const result = await process({ id: orderId, config }); + + expect(spyFetch).toHaveBeenCalledWith('/v1/orders/01JDWFFTAJ5S3G6JDNQ4T66FBN/process', + { + method: 'POST', + headers: { + Authorization: 'Bearer access_token', + } + } + ); + expect(result).toEqual(mockOrderResponse); + }); +}); \ No newline at end of file diff --git a/src/clients/order/process/types.ts b/src/clients/order/process/types.ts new file mode 100644 index 0000000..a46be84 --- /dev/null +++ b/src/clients/order/process/types.ts @@ -0,0 +1,11 @@ +import { MercadoPagoConfig } from '@src/mercadoPagoConfig'; +import type { Options } from '@src/types'; + +export declare type ProcessOrderData = { + id: string; + requestOptions?: Options; +} + +export declare type ProcessOrderClient = ProcessOrderData & { + config: MercadoPagoConfig; +} \ No newline at end of file diff --git a/src/examples/order/process.ts b/src/examples/order/process.ts new file mode 100644 index 0000000..d38f260 --- /dev/null +++ b/src/examples/order/process.ts @@ -0,0 +1,21 @@ +/** + * Mercado Pago Process Order. + * + * @see {@link [TODO: insert Order documentation URL] Documentation }. + */ + +import { Order } from '@src/clients/order'; +import MercadoPago from '@src/index'; + +const mercadoPagoConfig = new MercadoPago({ accessToken: '', options: { timeout: 5000 } }); + +const order = new Order(mercadoPagoConfig); + +const orderId = ''; + +order.process({ + id: orderId, + requestOptions: { + idempotencyKey: '' + } +}).then(console.log).catch(console.error); \ No newline at end of file From 2e40739fff1e19f9829bdc864939d4c1076581ab Mon Sep 17 00:00:00 2001 From: Danielen Cestari Nunes Date: Mon, 2 Dec 2024 15:16:07 -0300 Subject: [PATCH 14/15] cancel endpoint --- e2e/order/cancel.spec.ts | 58 +++++++++++++++++++++++++ src/clients/order/cancel/cancel.spec.ts | 48 ++++++++++++++++++++ src/clients/order/cancel/index.ts | 17 ++++++++ src/clients/order/cancel/types.ts | 11 +++++ src/clients/order/index.ts | 17 +++++++- 5 files changed, 149 insertions(+), 2 deletions(-) create mode 100644 e2e/order/cancel.spec.ts create mode 100644 src/clients/order/cancel/cancel.spec.ts create mode 100644 src/clients/order/cancel/index.ts create mode 100644 src/clients/order/cancel/types.ts diff --git a/e2e/order/cancel.spec.ts b/e2e/order/cancel.spec.ts new file mode 100644 index 0000000..268c5e6 --- /dev/null +++ b/e2e/order/cancel.spec.ts @@ -0,0 +1,58 @@ +import MercadoPago from '@src/index'; +import { config } from '../e2e.config'; +import { Order } from '@src/clients/order'; +import { CreateOrderData } from '@src/clients/order/create/types'; +import { createCardToken } from '@src/mocks/createCardToken'; + +const mercadoPagoConfig = new MercadoPago({ accessToken: config.access_token }); + +function createBodyOrder(token: string): CreateOrderData { + return { + body: { + type: 'online', + processing_mode: 'automatic', + total_amount: '200.00', + external_reference: 'ext_ref_1234', + transactions: { + payments: [ + { + amount: '200.00', + payment_method: { + id: 'master', + type: 'credit_card', + token: token, + installments: 1 + } + } + ] + }, + payer: { + email: 'test_1731350184@testuser.com' + }, + type_config:{ + capture_mode: 'manual' + } + } + }; +} + +describe('Cancel Order integration test', () => { + test('should cancel an Order successfully', async () => { + const cardTokenResponse = await createCardToken(config.access_token); + const token = cardTokenResponse.id; + const orderClient = new Order(mercadoPagoConfig); + const body = createBodyOrder(token); + + const order = await orderClient.create(body); + const orderId = order.id; + const processOrder = await orderClient.cancel({ id: orderId }); + + expect(processOrder.id).toBeTruthy(); + expect(processOrder.id).toBe(orderId); + expect(processOrder.status).toBe('cancelled'); + expect(processOrder.status_detail).toBe('cancelled'); + expect(processOrder.transactions.payments[0].amount).toBe('200.00'); + expect(processOrder.transactions.payments[0].status).toBe('cancelled'); + expect(processOrder.transactions.payments[0].status_detail).toBe('cancelled_transaction'); + }); +}); \ No newline at end of file diff --git a/src/clients/order/cancel/cancel.spec.ts b/src/clients/order/cancel/cancel.spec.ts new file mode 100644 index 0000000..ce0afc6 --- /dev/null +++ b/src/clients/order/cancel/cancel.spec.ts @@ -0,0 +1,48 @@ +import { RestClient } from '@utils/restClient'; +import { MercadoPagoConfig } from '@src/mercadoPagoConfig'; +import cancel from './index'; +import { OrderResponse } from '../commonTypes'; + +jest.mock('@utils/restClient'); + +describe('Cancel Order', () => { + test('should cancel an Order', async () => { + const config = new MercadoPagoConfig({ accessToken: 'access_token' }); + const orderId = '01JE48XZBYRK6W22V7DFQRABEV'; + const mockOrderResponse: OrderResponse = { + api_response: { + status: 200, + headers: [ + 'Content-Type', ['application/json'] + ] + }, + id: orderId, + type: 'online', + processing_mode: 'manual', + status: 'cancelled', + status_detail: 'cancelled', + total_amount: '200.00', + transactions: { + payments: [ + { + status: 'cancelled', + status_detail: 'cancelled_transaction' + } + ] + } + }; + const spyFetch = jest.spyOn(RestClient, 'fetch').mockResolvedValue(mockOrderResponse); + + const result = await cancel({ id: orderId, config }); + + expect(spyFetch).toHaveBeenCalledWith('/v1/orders/01JE48XZBYRK6W22V7DFQRABEV/cancel', + { + method: 'POST', + headers: { + Authorization: 'Bearer access_token', + } + } + ); + expect(result).toEqual(mockOrderResponse); + }); +}); \ No newline at end of file diff --git a/src/clients/order/cancel/index.ts b/src/clients/order/cancel/index.ts new file mode 100644 index 0000000..c17fe46 --- /dev/null +++ b/src/clients/order/cancel/index.ts @@ -0,0 +1,17 @@ +import { RestClient } from '@src/utils/restClient'; +import { CancelOrderClient } from './types'; +import { OrderResponse } from '../commonTypes'; + +export default function cancel({ id, config }: + CancelOrderClient): Promise { + return RestClient.fetch( + `/v1/orders/${id}/cancel`, + { + method: 'POST', + headers: { + 'Authorization': `Bearer ${config.accessToken}`, + }, + ...config.options + } + ); +} \ No newline at end of file diff --git a/src/clients/order/cancel/types.ts b/src/clients/order/cancel/types.ts new file mode 100644 index 0000000..29e0704 --- /dev/null +++ b/src/clients/order/cancel/types.ts @@ -0,0 +1,11 @@ +import { MercadoPagoConfig } from '@src/mercadoPagoConfig'; +import type { Options } from '@src/types'; + +export declare type CancelOrderData = { + id: string; + requestOptions?: Options; +} + +export declare type CancelOrderClient = CancelOrderData & { + config: MercadoPagoConfig; +} \ No newline at end of file diff --git a/src/clients/order/index.ts b/src/clients/order/index.ts index c7ee610..eb5f996 100644 --- a/src/clients/order/index.ts +++ b/src/clients/order/index.ts @@ -1,12 +1,15 @@ import create from './create'; import get from './get'; +import process from './process'; +import cancel from './cancel'; import type { MercadoPagoConfig } from '@src/mercadoPagoConfig'; -import { CreateOrderData } from './create/types'; import { OrderResponse } from './commonTypes'; +import { CreateOrderData } from './create/types'; import { GetOrderData } from './get/types'; import { ProcessOrderData } from './process/types'; -import process from './process'; +import { CancelOrderData } from './cancel/types'; + /** * Mercado Pago Order. @@ -49,4 +52,14 @@ export class Order { this.config.options = { ...this.config.options, ...requestOptions }; return process({ id, config: this.config }); } + + /** + * Cancel Order. + * + * @see {@link https://github.com/mercadopago/sdk-nodejs/blob/master/src/examples/order/cancel.ts Usage Example }. + */ + cancel({ id, requestOptions }: CancelOrderData): Promise { + this.config.options = { ...this.config.options, ...requestOptions }; + return cancel({ id, config: this.config }); + } } From a0dda765238406067031e0ab319c1dcff2c51ce2 Mon Sep 17 00:00:00 2001 From: Danielen Cestari Nunes Date: Mon, 2 Dec 2024 15:26:02 -0300 Subject: [PATCH 15/15] example --- e2e/order/cancel.spec.ts | 2 +- src/examples/order/cancel.ts | 21 +++++++++++++++++++++ 2 files changed, 22 insertions(+), 1 deletion(-) create mode 100644 src/examples/order/cancel.ts diff --git a/e2e/order/cancel.spec.ts b/e2e/order/cancel.spec.ts index 268c5e6..951447f 100644 --- a/e2e/order/cancel.spec.ts +++ b/e2e/order/cancel.spec.ts @@ -29,7 +29,7 @@ function createBodyOrder(token: string): CreateOrderData { payer: { email: 'test_1731350184@testuser.com' }, - type_config:{ + type_config: { capture_mode: 'manual' } } diff --git a/src/examples/order/cancel.ts b/src/examples/order/cancel.ts new file mode 100644 index 0000000..3696194 --- /dev/null +++ b/src/examples/order/cancel.ts @@ -0,0 +1,21 @@ +/** + * Mercado Pago Process Order. + * + * @see {@link [TODO: insert Order documentation URL] Documentation }. + */ + +import { Order } from '@src/clients/order'; +import MercadoPago from '@src/index'; + +const mercadoPagoConfig = new MercadoPago({ accessToken: '', options: { timeout: 5000 } }); + +const order = new Order(mercadoPagoConfig); + +const orderId = ''; + +order.cancel({ + id: orderId, + requestOptions: { + idempotencyKey: '' + } +}).then(console.log).catch(console.error); \ No newline at end of file