diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml new file mode 100644 index 0000000..9f72a15 --- /dev/null +++ b/.pre-commit-config.yaml @@ -0,0 +1,16 @@ +repos: + - repo: https://github.com/melisource/fury_websec-git-hooks + rev: v2.0.0 + hooks: + - id: pre_commit_hook + stages: [commit] + - id: post_commit_hook + stages: [post-commit] + + - repo: https://github.com/melisource/fury_datasec-git-hooks + rev: 1.2.2 + hooks: + - id: pre_commit_hook + stages: [commit] + - id: post_commit_hook + stages: [post-commit] diff --git a/mercadopago/examples/order/cancel_order.py b/mercadopago/examples/order/cancel_order.py new file mode 100644 index 0000000..23cb2e5 --- /dev/null +++ b/mercadopago/examples/order/cancel_order.py @@ -0,0 +1,67 @@ +import os +import time + +from mercadopago import SDK + +def main(): + # Define the authentication token + access_token = "" + + # Define the authentication token + sdk = SDK(access_token) + + # Create a test card token + def create_test_card(): + card_token_object = { + "card_number": "5031433215406351", + "security_code": "123", + "expiration_year": "2030", + "expiration_month": "11", + "cardholder": {"name": "APRO"} + } + card_token_created = sdk.card_token().create(card_token_object) + return card_token_created["response"]["id"] + + # Create an order object + card_token_id = create_test_card() + order_object = { + "type": "online", + "capture_mode": "manual", + "processing_mode": "automatic", + "total_amount": "880.00", + "external_reference": "ext_ref_1234", + "transactions": { + "payments": [ + { + "amount": "880.00", + "payment_method": { + "id": "master", + "type": "credit_card", + "token": card_token_id, + "installments": 2 + } + } + ] + }, + "payer": { + "email": "" + } + } + + try: + # Call the method to create the order + response = sdk.order().create(order_object) + print("Order created successfully") + + # Get the order ID from the response + order_id = response["response"]["id"] + + time.sleep(5) + # Call the method to PROCESS the order created in Manual Mode + order_details = sdk.order().cancel(order_id) + print("Order details:", order_details["response"]) + except Exception as e: + print("Error:", e) + +if __name__ == "__main__": + main() \ No newline at end of file diff --git a/mercadopago/examples/order/capture_order.py b/mercadopago/examples/order/capture_order.py new file mode 100644 index 0000000..ebd207e --- /dev/null +++ b/mercadopago/examples/order/capture_order.py @@ -0,0 +1,64 @@ +import os +from mercadopago import SDK + +def main(): + # Define the authentication token + access_token = "" + + # Define the authentication token + sdk = SDK(access_token) + + # Create a test card token + def create_test_card(): + card_token_object = { + "card_number": "5031433215406351", + "security_code": "123", + "expiration_year": "2030", + "expiration_month": "11", + "cardholder": {"name": "APRO"} + } + card_token_created = sdk.card_token().create(card_token_object) + return card_token_created["response"]["id"] + + # Create an order object + card_token_id = create_test_card() + order_object = { + "type": "online", + "capture_mode": "manual", # Mode need to be Manual to use Capture Method. + "processing_mode": "automatic", + "total_amount": "880.00", + "external_reference": "ext_ref_1234", + "transactions": { + "payments": [ + { + "amount": "880.00", + "payment_method": { + "id": "master", + "type": "credit_card", + "token": card_token_id, + "installments": 2 + } + } + ] + }, + "payer": { + "email": "" + } + } + + try: + # Call the method to create the order + response = sdk.order().create(order_object) + print("Order created successfully") + + # Get the order ID from the response + order_id = response["response"]["id"] + + # Call the method to PROCESS the order created in Manual Mode + order_details = sdk.order().capture(order_id) + print("Order details:", order_details["response"]) + except Exception as e: + print("Error:", e) + +if __name__ == "__main__": + main() \ No newline at end of file diff --git a/mercadopago/examples/order/create_order.py b/mercadopago/examples/order/create_order.py new file mode 100644 index 0000000..9d45386 --- /dev/null +++ b/mercadopago/examples/order/create_order.py @@ -0,0 +1,56 @@ +from mercadopago import SDK + + +def main(): + # Define the authentication token + access_token = "" + + # Define the authentication token + sdk = SDK(access_token) + + # Create a test card token + def create_test_card(): + card_token_object = { + "card_number": "5031433215406351", + "security_code": "123", + "expiration_year": "2030", + "expiration_month": "11", + "cardholder": {"name": "APRO"} + } + card_token_created = sdk.card_token().create(card_token_object) + return card_token_created["response"]["id"] + + # Create an order object + card_token_id = create_test_card() + order_object = { + "type": "online", + "total_amount": "880.00", + "external_reference": "ext_ref_1234", + "transactions": { + "payments": [ + { + "amount": "880.00", + "payment_method": { + "id": "master", + "type": "credit_card", + "token": card_token_id, + "installments": 2 + } + } + ] + }, + "payer": { + "email": "" + } + } + + try: + # Call the method to create the order + response = sdk.order().create(order_object) + print("Order created successfully:", response["response"]) + except Exception as e: + print("Error:", e) + + +if __name__ == "__main__": + main() \ No newline at end of file diff --git a/mercadopago/examples/order/create_transaction.py b/mercadopago/examples/order/create_transaction.py new file mode 100644 index 0000000..85b2166 --- /dev/null +++ b/mercadopago/examples/order/create_transaction.py @@ -0,0 +1,65 @@ +import os +import time + +from mercadopago import SDK + +def main(): + # Define the authentication token + access_token = "" + + # Define the authentication token + sdk = SDK(access_token) + + # Create a test card token + def create_test_card(): + card_token_object = { + "card_number": "5031433215406351", + "security_code": "123", + "expiration_year": "2030", + "expiration_month": "11", + "cardholder": {"name": "APRO"} + } + card_token_created = sdk.card_token().create(card_token_object) + return card_token_created["response"]["id"] + + # Create an order object + card_token_id = create_test_card() + order_object = { + "type": "online", + "processing_mode": "manual", + "total_amount": "200.00", + "external_reference": "ext_ref_1234", + "payer": { + "email": "" + } + } + + try: + # Call the method to create the order + response = sdk.order().create(order_object) + print("Order created successfully") + + # Get the order ID from the response + order_id = response["response"]["id"] + + transaction_object = { + "payments": [ + { + "amount": "200.00", + "payment_method": { + "id": "master", + "type": "credit_card", + "token": card_token_id, + "installments": 12 + } + } + ] + } + # Call the method to PROCESS the order created in Manual Mode + transaction_created = sdk.order().create_transaction(order_id, transaction_object) + print("Transaction created:", transaction_created["response"]) + except Exception as e: + print("Error:", e) + +if __name__ == "__main__": + main() \ No newline at end of file diff --git a/mercadopago/examples/order/delete_transaction.py b/mercadopago/examples/order/delete_transaction.py new file mode 100644 index 0000000..b3243da --- /dev/null +++ b/mercadopago/examples/order/delete_transaction.py @@ -0,0 +1,66 @@ +import os +import time + +from mercadopago import SDK + +def main(): + # Define the authentication token + access_token = "" + + # Define the authentication token + sdk = SDK(access_token) + + # Create a test card token + def create_test_card(): + card_token_object = { + "card_number": "5031433215406351", + "security_code": "123", + "expiration_year": "2030", + "expiration_month": "11", + "cardholder": {"name": "APRO"} + } + card_token_created = sdk.card_token().create(card_token_object) + return card_token_created["response"]["id"] + + # Create an order object + card_token_id = create_test_card() + order_object = { + "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": card_token_id, + "installments": 12 + } + } + ] + }, + "payer": { + "email": "" + } + } + + try: + # Call the method to create the order + response = sdk.order().create(order_object) + print("Order created successfully") + + # Get the order ID from the response + order_id = response["response"]["id"] + transaction_id = response["response"]["transactions"]["payments"][0]["id"] + + # Call the method to PROCESS the order created in Manual Mode + transaction_deleted = sdk.order().delete_transaction(order_id, transaction_id) + print("Transaction Successful Deleted.", transaction_deleted["response"]) + except Exception as e: + print("Error:", e) + +if __name__ == "__main__": + main() \ No newline at end of file diff --git a/mercadopago/examples/order/get_order.py b/mercadopago/examples/order/get_order.py new file mode 100644 index 0000000..e2d056b --- /dev/null +++ b/mercadopago/examples/order/get_order.py @@ -0,0 +1,62 @@ +import os +from mercadopago import SDK + +def main(): + # Define the authentication token + access_token = "" + + # Define the authentication token + sdk = SDK(access_token) + + # Create a test card token + def create_test_card(): + card_token_object = { + "card_number": "5031433215406351", + "security_code": "123", + "expiration_year": "2030", + "expiration_month": "11", + "cardholder": {"name": "APRO"} + } + card_token_created = sdk.card_token().create(card_token_object) + return card_token_created["response"]["id"] + + # Create an order object + card_token_id = create_test_card() + order_object = { + "type": "online", + "total_amount": "880.00", + "external_reference": "ext_ref_1234", + "transactions": { + "payments": [ + { + "amount": "880.00", + "payment_method": { + "id": "master", + "type": "credit_card", + "token": card_token_id, + "installments": 2 + } + } + ] + }, + "payer": { + "email": "" + } + } + + try: + # Call the method to create the order + response = sdk.order().create(order_object) + print("Order created successfully!") + + # Get the order ID from the response + order_id = response["response"]["id"] + + # Call the method to get the order details + order_details = sdk.order().get(order_id) + print("Order details:", order_details["response"]) + except Exception as e: + print("Error:", e) + +if __name__ == "__main__": + main() \ No newline at end of file diff --git a/mercadopago/examples/order/process_order.py b/mercadopago/examples/order/process_order.py new file mode 100644 index 0000000..1815f7a --- /dev/null +++ b/mercadopago/examples/order/process_order.py @@ -0,0 +1,64 @@ +import os +from mercadopago import SDK + +def main(): + # Define the authentication token + access_token = "" + + # Define the authentication token + sdk = SDK(access_token) + + # Create a test card token + def create_test_card(): + card_token_object = { + "card_number": "5031433215406351", + "security_code": "123", + "expiration_year": "2030", + "expiration_month": "11", + "cardholder": {"name": "APRO"} + } + card_token_created = sdk.card_token().create(card_token_object) + return card_token_created["response"]["id"] + + # Create an order object + card_token_id = create_test_card() + order_object = { + "type": "online", + "processing_mode": "manual", # Mode need to be Manual to use Process Method. + "total_amount": "880.00", + "external_reference": "ext_ref_1234", + "transactions": { + "payments": [ + { + "amount": "880.00", + "payment_method": { + "id": "master", + "type": "credit_card", + "token": card_token_id, + "installments": 2 + } + } + ] + }, + "payer": { + "email": "" + } + } + + try: + # Call the method to create the order + response = sdk.order().create(order_object) + print("Order created successfully!") + + # Get the order ID from the response + order_id = response["response"]["id"] + print("Order ID:", order_id) + + # Call the method to PROCESS the order created in Manual Mode + order_details = sdk.order().process(order_id) + print("Order details:", order_details["response"]) + except Exception as e: + print("Error:", e) + +if __name__ == "__main__": + main() \ No newline at end of file diff --git a/mercadopago/examples/order/refund_partial.py b/mercadopago/examples/order/refund_partial.py new file mode 100644 index 0000000..c382748 --- /dev/null +++ b/mercadopago/examples/order/refund_partial.py @@ -0,0 +1,74 @@ +import os +import time + +from mercadopago import SDK + +def main(): + # Define the authentication token + access_token = "" + + # Define the authentication token + sdk = SDK(access_token) + + # Create a test card token + def create_test_card(): + card_token_object = { + "card_number": "5031433215406351", + "security_code": "123", + "expiration_year": "2030", + "expiration_month": "11", + "cardholder": {"name": "APRO"} + } + card_token_created = sdk.card_token().create(card_token_object) + return card_token_created["response"]["id"] + + # Create an order object + card_token_id = create_test_card() + order_object = { + "type": "online", + "processing_mode": "automatic", + "total_amount": "500.00", + "external_reference": "ext_ref_1234", + "transactions": { + "payments": [ + { + "amount": "500.00", + "payment_method": { + "id": "master", + "type": "credit_card", + "token": card_token_id, + "installments": 2 + } + } + ] + }, + "payer": { + "email": "" + } + } + + try: + # Call the method to create the order + response = sdk.order().create(order_object) + print("Order created successfully.") + + # Get the order ID from the response + order_id = response["response"]["id"] + + refund = { + "transactions": [ + { + "id": response["response"]["transactions"]["payments"][0]["id"], + "amount": "25.00" + } + ] + } + + # Call the method to PROCESS the order created in Manual Mode + transaction_refund = sdk.order().refund_transaction(order_id, refund) + print("Transaction Partially Refunded:", transaction_refund["response"]) + except Exception as e: + print("Error:", e) + +if __name__ == "__main__": + main() \ No newline at end of file diff --git a/mercadopago/examples/order/refund_total.py b/mercadopago/examples/order/refund_total.py new file mode 100644 index 0000000..3a58a6c --- /dev/null +++ b/mercadopago/examples/order/refund_total.py @@ -0,0 +1,65 @@ +import os +import time + +from mercadopago import SDK + +def main(): + # Define the authentication token + access_token = "" + + # Define the authentication token + sdk = SDK(access_token) + + # Create a test card token + def create_test_card(): + card_token_object = { + "card_number": "5031433215406351", + "security_code": "123", + "expiration_year": "2030", + "expiration_month": "11", + "cardholder": {"name": "APRO"} + } + card_token_created = sdk.card_token().create(card_token_object) + return card_token_created["response"]["id"] + + # Create an order object + card_token_id = create_test_card() + order_object = { + "type": "online", + "processing_mode": "automatic", + "total_amount": "500.00", + "external_reference": "ext_ref_1234", + "transactions": { + "payments": [ + { + "amount": "500.00", + "payment_method": { + "id": "master", + "type": "credit_card", + "token": card_token_id, + "installments": 2 + } + } + ] + }, + "payer": { + "email": "" + } + } + + try: + # Call the method to create the order + response = sdk.order().create(order_object) + print("Order created successfully.") + + # Get the order ID from the response + order_id = response["response"]["id"] + + # Call the method to PROCESS the order created in Manual Mode + transaction_refund = sdk.order().refund_transaction(order_id) + print("Transaction Total Refunded:", transaction_refund["response"]) + except Exception as e: + print("Error:", e) + +if __name__ == "__main__": + main() \ No newline at end of file diff --git a/mercadopago/examples/order/update_transaction.py b/mercadopago/examples/order/update_transaction.py new file mode 100644 index 0000000..2e653c9 --- /dev/null +++ b/mercadopago/examples/order/update_transaction.py @@ -0,0 +1,73 @@ +import os +import time + +from mercadopago import SDK + +def main(): + # Define the authentication token + access_token = "" + + # Define the authentication token + sdk = SDK(access_token) + + # Create a test card token + def create_test_card(): + card_token_object = { + "card_number": "5031433215406351", + "security_code": "123", + "expiration_year": "2030", + "expiration_month": "11", + "cardholder": {"name": "APRO"} + } + card_token_created = sdk.card_token().create(card_token_object) + return card_token_created["response"]["id"] + + # Create an order object + card_token_id = create_test_card() + order_object = { + "type": "online", + "processing_mode": "manual", + "total_amount": "500.00", + "external_reference": "ext_ref_1234", + "transactions": { + "payments": [ + { + "amount": "500.00", + "payment_method": { + "id": "master", + "type": "credit_card", + "token": card_token_id, + "installments": 2 + } + } + ] + }, + "payer": { + "email": "" + } + } + + try: + # Call the method to create the order + response = sdk.order().create(order_object) + print("Order created successfully") + + # Get the order ID from the response + order_id = response["response"]["id"] + transaction_id = response["response"]["transactions"]["payments"][0]["id"] + + transaction_update = { + "payment_method": { + "type": "credit_card", + "installments": 5 + } + } + + # Call the method to PROCESS the order created in Manual Mode + update = sdk.order().update_transaction(order_id, transaction_id, transaction_update) + print("Transaction Updated:", update["response"]) + except Exception as e: + print("Error:", e) + +if __name__ == "__main__": + main() \ No newline at end of file diff --git a/mercadopago/http/http_client.py b/mercadopago/http/http_client.py index 81d7040..6fe628f 100644 --- a/mercadopago/http/http_client.py +++ b/mercadopago/http/http_client.py @@ -24,12 +24,16 @@ def request(self, method, url, maxretries=None, **kwargs): http.mount("https://", HTTPAdapter(max_retries=retry_strategy)) with http as session: api_result = session.request(method, url, **kwargs) - response = { - "status": api_result.status_code, - "response": api_result.json() - } + response = {"status": api_result.status_code, "response": None} - return response + if api_result.status_code != 204 and api_result.content: + try: + response["response"] = api_result.json() + except ValueError as e: + print(f"Failed to parse JSON: {str(e)}") + response["response"] = None + + return response def get(self, url, headers, params=None, timeout=None, maxretries=None): # pylint: disable=too-many-arguments """Makes a GET request to the API""" diff --git a/mercadopago/resources/__init__.py b/mercadopago/resources/__init__.py index ac555f8..407b471 100644 --- a/mercadopago/resources/__init__.py +++ b/mercadopago/resources/__init__.py @@ -11,6 +11,7 @@ from mercadopago.resources.disbursement_refund import DisbursementRefund from mercadopago.resources.identification_type import IdentificationType from mercadopago.resources.merchant_order import MerchantOrder +from mercadopago.resources.order import Order from mercadopago.resources.payment import Payment from mercadopago.resources.payment_methods import PaymentMethods from mercadopago.resources.plan import Plan @@ -31,6 +32,7 @@ 'HttpClient', 'IdentificationType', 'MerchantOrder', + 'Order', 'Payment', 'PaymentMethods', 'Plan', diff --git a/mercadopago/resources/order.py b/mercadopago/resources/order.py new file mode 100644 index 0000000..d21c4b4 --- /dev/null +++ b/mercadopago/resources/order.py @@ -0,0 +1,207 @@ +""" + Module: order +""" +from mercadopago.core import MPBase + +class Order(MPBase): + """ + This class provides the methods to access the API that will allow you to create + your own order experience on your website. + + From basic to advanced configurations, you control the whole experience. + + [Click here for more info](https://www.mercadopago.com/developers/en/guides/online-payments/checkout-api/introduction/) # pylint: disable=line-too-long + """ + + def create(self, order_object, request_options=None): + """[Click here for more info](https://www.mercadopago.com/developers/en/reference/order/online-payments/create/post/) # pylint: disable=line-too-long + + Args: + order_object (dict): Order to be created + request_options (mercadopago.config.request_options, optional): An instance of + RequestOptions can be pass changing or adding custom options to the REST call. + Defaults to None. + + Raises: + ValueError: Param order_object must be a Dictionary + + Returns: + dict: Order creation response + """ + if not isinstance(order_object, dict): + raise ValueError("Param order_object must be a Dictionary") + + return self._post(uri="/v1/orders", data=order_object, request_options=request_options) + + def get(self, order_id, request_options=None): + """[Click here for more info](https://www.mercadopago.com/developers/en/reference/order/online-payments/get-order/get ) # pylint: disable=line-too-long + + Args: + order_id (str): The Order ID + request_options (mercadopago.config.request_options, optional): An instance of + RequestOptions can be pass changing or adding custom options to the REST call. + Defaults to None. + + Raises: + ValueError: Param order_id must be a string + + Returns: + dict: Order returned in the response to the request made for its creation. + """ + + if not isinstance(order_id, str): + raise ValueError("Param order_id must be a string") + + return self._get(uri="/v1/orders/" + str(order_id), request_options=request_options) + + def process(self, order_id, request_options=None): + """[Click here for more info](https://www.mercadopago.com/developers/en/reference/order/online/process-order/post) # pylint: disable=line-too-long + Args: + order_id (str): ID of the order to be processed. This value is returned in the response to the Create order request. + request_options (mercadopago.config.request_options, optional): An instance of + RequestOptions can be pass changing or adding custom options to the REST call. + Defaults to None. + + Raises: + ValueError: Param order_id must be a string + Returns: + dict: Order returned in the response to the request made for its creation. + """ + + if not isinstance(order_id, str): + raise ValueError("Param order_id must be a string") + + return self._post(uri="/v1/orders/" + str(order_id) + "/process", request_options=request_options) + + def cancel(self, order_id, request_options=None): + """[Click here for more info](https://www.mercadopago.com/developers/en/reference/order/online-payments/cancel-order/post) # pylint: disable=line-too-long + Args: + order_id (str): Order ID + request_options (mercadopago.config.request_options, optional): An instance of + RequestOptions can be pass changing or adding custom options to the REST call. + Defaults to None. + + Raises: + ValueError: Param order_id must be a string + + Returns: + dict: Order cancellation response + """ + if not isinstance(order_id, str): + raise ValueError("Param order_id must be a string") + + return self._post(uri="/v1/orders/" + str(order_id) + "/cancel", request_options=request_options) + + def capture(self, order_id, request_options=None): + """[Click here for more info](https://www.mercadopago.com/developers/en/reference/order/online-payments/capture/post) # pylint: disable=line-too-long + Args: + order_id (str): ID of the order to be captured. This value is returned in the response to the Create order request. + request_options (mercadopago.config.request_options, optional): An instance of + RequestOptions can be pass changing or adding custom options to the REST call. + Defaults to None. + Raises: + ValueError: Param order_id must be a string + Returns: + dict: Order returned in the response to the request made for its creation. + """ + + if not isinstance(order_id, str): + raise ValueError("Param order_id must be a string") + + return self._post(uri="/v1/orders/" + str(order_id) + "/capture", request_options=request_options) + + def create_transaction(self, order_id, transaction_object, request_options=None): + """[Click here for more info](https://www.mercadopago.com/developers/en/reference/order/online-payments/add-transaction/post) # pylint: disable=line-too-long + + Args: + order_id (str): The ID of the order to which the transaction will be added + transaction_object (dict): Transaction to be added + request_options (mercadopago.config.request_options, optional): An instance of + RequestOptions can be pass changing or adding custom options to the REST call. + Defaults to None. + + Raises: + ValueError: Param transaction_object must be a Dictionary + + Returns: + dict: Transaction created response + """ + if not isinstance(transaction_object, dict): + raise ValueError("Param transaction_object must be a Dictionary") + + response = self._post(uri=f"/v1/orders/{order_id}/transactions", data=transaction_object, + request_options=request_options) + if response.get("status") != 201: + raise Exception(f"Failed to add transaction: {response}") + return response + + def update_transaction(self, order_id, transaction_id, transaction_object, request_options=None): + """[Click here for more info](https://www.mercadopago.com/developers/en/reference/order/online-payments/update-transaction/put) # pylint: disable=line-too-long + + Args: + order_id (str): The ID of the order to which the transaction belongs + transaction_id (str): The ID of the transaction to be updated + transaction_object (dict): Transaction details to be updated + request_options (mercadopago.config.request_options, optional): An instance of + RequestOptions can be pass changing or adding custom options to the REST call. + Defaults to None. + + Raises: + ValueError: Param transaction_object must be a Dictionary + + Returns: + dict: Transaction update response + """ + if not isinstance(transaction_object, dict): + raise ValueError("Param transaction_object must be a Dictionary") + + response = self._put(uri=f"/v1/orders/{order_id}/transactions/{transaction_id}", data=transaction_object, + request_options=request_options) + if response.get("status") != 200: + raise Exception(f"Failed to update transaction: {response}") + return response + + def refund_transaction(self, order_id, transaction_object=None, request_options=None): + """[Click here for more info](https://www.mercadopago.com/developers/en/reference/order/online-payments/refund/post) # pylint: disable=line-too-long + Args: + order_id (str): The ID of the order to which the transaction belongs + transaction_object (dict, optional): Transaction details to be updated + request_options (mercadopago.config.request_options, optional): An instance of + RequestOptions can be pass changing or adding custom options to the REST call. + Defaults to None. + Raises: + ValueError: Param transaction_object must be a Dictionary + Returns: + dict: Order refunded response + """ + if transaction_object is not None and not isinstance(transaction_object, dict): + raise ValueError("Param transaction_object must be a Dictionary") + + response = self._post(uri=f"/v1/orders/{order_id}/refund", data=transaction_object, + request_options=request_options) + if response.get("status") != 201: + raise Exception(f"Failed to refund transaction: {response}") + return response + + def delete_transaction(self, order_id, transaction_id, request_options=None): + """[Click here for more info](https://www.mercadopago.com/developers/en/reference/order/online-payments/delete-transaction/delete) # pylint: disable=line-too-long + Args: + order_id (str): The ID of the order to which the transaction belongs + transaction_id (str): The ID of the transaction to be deleted + request_options (mercadopago.config.request_options, optional): An instance of + RequestOptions can be pass changing or adding custom options to the REST call. + Defaults to None. + Raises: + ValueError: Params order_id and transaction_id must be strings + Returns: + Status 204 - No Content - if deleted successfully + """ + if not isinstance(order_id, str) or not isinstance(transaction_id, str): + raise ValueError("Params order_id and transaction_id must be strings") + + response = self._delete(uri=f"/v1/orders/{order_id}/transactions/{transaction_id}", + request_options=request_options) + + if response.get("status") != 204: + raise Exception(f"Failed to delete transaction: {response}") + return response \ No newline at end of file diff --git a/mercadopago/sdk.py b/mercadopago/sdk.py index 0536b58..13afaeb 100644 --- a/mercadopago/sdk.py +++ b/mercadopago/sdk.py @@ -12,6 +12,7 @@ DisbursementRefund, IdentificationType, MerchantOrder, + Order, Payment, PaymentMethods, Plan, @@ -33,15 +34,16 @@ class SDK: 5. Disbursement Refund 6. Identification Type 7. Merchant Order - 8. Payment Methods - 9. Payment - 10. Preapproval - 11. Preference - 12. Refund - 13. User - 14. Chargeback - 15. Subscription - 16. Plan + 8. Order + 9. Payment Methods + 10. Payment + 11. Preapproval + 12. Preference + 13. Refund + 14. User + 15. Chargeback + 16. Subscription + 17. Plan """ def __init__( @@ -120,6 +122,13 @@ def merchant_order(self, request_options=None): """ return MerchantOrder(request_options is not None and request_options or self.request_options, self.http_client) + + def order(self, request_options=None): + """ + Returns the attribute value of the function + """ + return Order(request_options is not None and request_options + or self.request_options, self.http_client) def payment(self, request_options=None): """ diff --git a/tests/test_order.py b/tests/test_order.py new file mode 100644 index 0000000..d4bcd6e --- /dev/null +++ b/tests/test_order.py @@ -0,0 +1,305 @@ +""" + Module: test_order +""" +import json +import os +import time +import unittest +import random +from time import sleep + +import mercadopago + + +class TestOrder(unittest.TestCase): + """ + Test Module: Order + """ + sdk = mercadopago.SDK(os.environ['ACCESS_TOKEN']) + + def create_test_card(self, status="APRO"): + card_token_object = { + "card_number": "5031433215406351", + "security_code": "123", + "expiration_year": "2030", + "expiration_month": "11", + "cardholder": {"name": status} + } + card_token_created = self.sdk.card_token().create(card_token_object) + return card_token_created["response"]["id"] + + def create_order_canceled_or_captured(self, card_token_id): + random_email_id = random.randint(100000, 999999) + order_object_cc = { + "type": "online", + "processing_mode": "automatic", + "total_amount": "200.00", + "external_reference": "ext_ref_1234", + "payer": { + "email": f"test_payer_{random_email_id}@testuser.com" + }, + "capture_mode": "manual", + "transactions": { + "payments": [ + { + "amount": "200.00", + "payment_method": { + "id": "master", + "type": "credit_card", + "token": card_token_id, + "installments": 1 + } + } + ] + } + } + order_created = self.sdk.order().create(order_object_cc) + if order_created.get("status") != 201 or not order_created.get("response"): + self.fail(f"Failed to create order: {order_created}") + return order_created["response"]["id"] + + def create_order_builder_mode(self, card_token_id): + random_email_id = random.randint(100000, 999999) + order_object_cc = { + "type": "online", + "processing_mode": "manual", + "total_amount": "200.00", + "external_reference": "ext_ref_1234", + "payer": { + "email": f"test_payer_{random_email_id}@testuser.com" + }, + } + order_created = self.sdk.order().create(order_object_cc) + if order_created.get("status") != 201 or not order_created.get("response"): + self.fail(f"Failed to create order: {order_created}") + return order_created["response"]["id"] + + def create_order_oneshot_mode_complete(self, card_token_id): + random_email_id = random.randint(100000, 999999) + order_mode_oneshot_complete = { + "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": card_token_id, + "installments": 1 + } + } + ] + }, + "payer": { + "email": f"test_payer_{random_email_id}@testuser.com" + } + } + + order_created = self.sdk.order().create(order_mode_oneshot_complete) + + + if order_created.get("status") != 201 or not order_created.get("response"): + self.fail(f"Failed to create order: {order_created}") + return order_created["response"] + + def create_order_builder_mode_complete(self, card_token_id): + random_email_id = random.randint(100000, 999999) + order_mode_builder_complete = { + "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": card_token_id, + "installments": 12 + } + } + ] + }, + "payer": { + "email": f"test_payer_{random_email_id}@testuser.com" + } + } + + order_created = self.sdk.order().create(order_mode_builder_complete) + + + if order_created.get("status") != 201 or not order_created.get("response"): + self.fail(f"Failed to create order: {order_created}") + return order_created["response"] + + def test_create_order_and_get_by_id(self): + """ + Test Function: Create an Order and Get an Order by ID + """ + card_token_id = self.create_test_card() + random_email_id = random.randint(100000, 999999) + order_object = { + "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_id, + "installments": 12 + } + } + ] + }, + "payer": { + "email": f"test_payer_{random_email_id}@testuser.com" + } + } + + order_created = self.sdk.order().create(order_object) + self.assertEqual(order_created["status"], 201) + self.assertEqual(order_created["response"]["status"], "processed") + + order_get = self.sdk.order().get(order_created["response"]["id"]) + self.assertEqual(order_get["status"], 200) + + def test_process_order(self): + card_token_id = self.create_test_card() + random_email_id = random.randint(100000, 999999) + order_object = { + "type": "online", + "processing_mode": "manual", + "external_reference": "ext_ref_1234", + "total_amount": "200.00", + "transactions": { + "payments": [ + { + "amount": "200.00", + "payment_method": { + "id": "master", + "type": "credit_card", + "token": card_token_id, + "installments": 1 + } + } + ] + }, + "payer": { + "email": f"test_payer_{random_email_id}@testuser.com" + } + } + + order_created = self.sdk.order().create(order_object) + order_id = order_created["response"]["id"] + process_response = self.sdk.order().process(order_id) + if process_response.get("status") != 200 or not process_response.get("response"): + self.fail(f"Failed to create an order: {process_response}") + self.assertEqual(process_response["status"], 200, "Invalid HTTP status when processing the order") + + def test_cancel_order(self): + card_token_id = self.create_test_card() + order_id = self.create_order_canceled_or_captured(card_token_id) + time.sleep(4) + order_canceled = self.sdk.order().cancel(order_id) + self.assertEqual(order_canceled["status"], 200) + self.assertEqual(order_canceled["response"]["status"], "canceled") + + def test_capture_order(self): + card_token_id = self.create_test_card() + order_id = self.create_order_canceled_or_captured(card_token_id) + order_captured = self.sdk.order().capture(order_id) + self.assertEqual(order_captured["status"], 200) + self.assertEqual(order_captured["response"]["status"], "processed") + + def test_create_transaction(self): + card_token_id = self.create_test_card() + order_id = self.create_order_builder_mode(card_token_id) + transaction_object = { + "payments": [ + { + "amount": "200.00", + "payment_method": { + "id": "master", + "type": "credit_card", + "token": card_token_id, + "installments": 12 + } + } + ] + } + + transaction_created = self.sdk.order().create_transaction(order_id, transaction_object) + self.assertEqual(transaction_created["status"], 201) + + def test_update_transaction(self): + card_token_id = self.create_test_card() + order_created = self.create_order_builder_mode_complete(card_token_id) + order_id = order_created["id"] + transaction_id = order_created["transactions"]["payments"][0]["id"] + + transaction_update = { + "payment_method": { + "type": "credit_card", + "installments": 5 + } + } + + transaction_updated = self.sdk.order().update_transaction(order_id, transaction_id, transaction_update) + self.assertEqual(transaction_updated["status"], 200) + + def test_partial_refund_transaction(self): + card_token_id = self.create_test_card() + order_created = self.create_order_oneshot_mode_complete(card_token_id) + order_id = order_created["id"] + transaction_id = order_created["transactions"]["payments"][0]["id"] + + transaction_refund = { + "transactions": [ + { + "id": transaction_id, + "amount": "25.00" + } + ] + } + + sleep(3) + + transaction_refunded = self.sdk.order().refund_transaction(order_id, transaction_refund) + print("Refund Transaction Response:", transaction_refunded) + self.assertIn(transaction_refunded["status"], [ 201], + f"Unexpected status code for refund: {transaction_refunded['status']}. Response: {transaction_refunded}") + + def test_refund_transaction(self): + card_token_id = self.create_test_card() + order_created = self.create_order_oneshot_mode_complete(card_token_id) + order_id = order_created["id"] + sleep(3) + transaction_refunded = self.sdk.order().refund_transaction(order_id) + print("Refund Transaction Response:", transaction_refunded) + self.assertIn(transaction_refunded["status"], [ 201], + f"Unexpected status code for refund: {transaction_refunded['status']}. Response: {transaction_refunded}") + + def test_delete_transaction(self): + card_token_id = self.create_test_card() + order_created = self.create_order_builder_mode_complete(card_token_id) + order_id = order_created["id"] + transaction_id = order_created["transactions"]["payments"][0]["id"] + sleep(3) + + transaction_deleted = self.sdk.order().delete_transaction(order_id, transaction_id) + print("Transaction Deleted:", transaction_deleted) + self.assertEqual(transaction_deleted["status"], 204) + + +if __name__ == "__main__": + unittest.main() \ No newline at end of file