diff --git a/tests/webpay/oneclick/test_mall_bin_info.py b/tests/webpay/oneclick/test_mall_bin_info.py new file mode 100644 index 00000000..c82839bb --- /dev/null +++ b/tests/webpay/oneclick/test_mall_bin_info.py @@ -0,0 +1,46 @@ +import unittest +import json +from unittest.mock import Mock +from unittest.mock import patch +from transbank.error.transbank_error import TransbankError +from transbank.error.mall_bin_info_query_error import MallBinInfoQueryError +from transbank.webpay.oneclick.mall_bin_info import MallBinInfo + + +class MallBinInfoTestCase(unittest.TestCase): + + def setUp(self) -> None: + self.mock_response = Mock() + + @patch('transbank.common.request_service.requests.post') + def test_query_bin(self, mock_post): + response = {'bin_issuer': 'TEST COMMERCE BANK', 'bin_payment_type': 'Credito', 'bin_brand': 'Visa'} + self.mock_response.status_code = 200 + self.mock_response.text = json.dumps(response) + mock_post.return_value = self.mock_response + + mall_bin_info = MallBinInfo.build_for_integration('commerce_code', 'api_key') + result = mall_bin_info.query_bin('tbkUser') + + _, kwargs = mock_post.call_args + body = json.loads(kwargs['data']) + + self.assertEqual(result['bin_issuer'], 'TEST COMMERCE BANK') + self.assertEqual(result['bin_payment_type'], 'Credito') + self.assertEqual(result['bin_brand'], 'Visa') + self.assertEqual(body['tbk_user'], 'tbkUser') + + def test_query_bin_invalid_tbk_user(self): + mall_bin_info = MallBinInfo.build_for_integration('commerce_code', 'api_key') + with self.assertRaises(TransbankError): + mall_bin_info.query_bin('b134e1c5e9eeb134e1c5e9eeb134e1c5e9eeb134e1c5e9eeb134e1c5e9eeb134e1c5e9eeb134e1c5e9eeb134e1c5e9ee') + + @patch('transbank.common.request_service.requests.post') + def test_query_bin_throws_api_exception(self, mock_post): + self.mock_response.status_code = 400 + self.mock_response.text = '{"error": "Bad Request"}' + mock_post.return_value = self.mock_response + mall_bin_info = MallBinInfo.build_for_integration('commerce_code', 'api_key') + + with self.assertRaises(MallBinInfoQueryError): + mall_bin_info.query_bin('tbkUser') diff --git a/transbank/error/mall_bin_info_query_error.py b/transbank/error/mall_bin_info_query_error.py new file mode 100644 index 00000000..b9cc0975 --- /dev/null +++ b/transbank/error/mall_bin_info_query_error.py @@ -0,0 +1,5 @@ +from transbank.error.transbank_error import TransbankError + +class MallBinInfoQueryError(TransbankError): + def __init__(self, message="Mall bin info query could not be performed. Please verify given parameters", code=0): + super().__init__(message, code) diff --git a/transbank/webpay/oneclick/mall_bin_info.py b/transbank/webpay/oneclick/mall_bin_info.py new file mode 100644 index 00000000..e5910a3f --- /dev/null +++ b/transbank/webpay/oneclick/mall_bin_info.py @@ -0,0 +1,36 @@ +from transbank.common.api_constants import ApiConstants +from transbank.common.webpay_transaction import WebpayTransaction +from transbank.common.validation_util import ValidationUtil +from transbank.common.api_constants import ApiConstants +from transbank.common.options import WebpayOptions +from transbank.common.request_service import RequestService +from transbank.error.transbank_error import TransbankError +from transbank.error.mall_bin_info_query_error import MallBinInfoQueryError +from transbank.webpay.oneclick.request import MallBinInfoQueryRequest +from transbank.webpay.oneclick.schema import MallBinInfoQueryRequestSchema + +class MallBinInfo(WebpayTransaction): + INFO_ENDPOINT = ApiConstants.ONECLICK_ENDPOINT + '/bin_info' + + def __init__(self, options: WebpayOptions): + super().__init__(options) + + def query_bin(self, tbk_user: str): + """ + Queries the BIN information for a given `tbk_user`. + + Args: + tbk_user (str): The `tbk_user` for which to query the BIN information. + Returns: + dict: The BIN information for the specified `tbk_user`. + Raises: + MallBinInfoQueryError: If there is an error querying the BIN information. + TransbankError: If `tbk_user` exceeds the max length + """ + ValidationUtil.has_text_with_max_length(tbk_user, ApiConstants.TBK_USER_LENGTH, "tbk_user") + try: + endpoint = MallBinInfo.INFO_ENDPOINT + request = MallBinInfoQueryRequest(tbk_user) + return RequestService.post(endpoint, MallBinInfoQueryRequestSchema().dumps(request), self.options) + except TransbankError as e: + raise MallBinInfoQueryError(e.message, e.code) diff --git a/transbank/webpay/oneclick/request/__init__.py b/transbank/webpay/oneclick/request/__init__.py index 1b9472b8..d50e3b82 100644 --- a/transbank/webpay/oneclick/request/__init__.py +++ b/transbank/webpay/oneclick/request/__init__.py @@ -97,3 +97,10 @@ def __init__(self, self.commerce_code = commerce_code self.detail_buy_order = detail_buy_order self.amount = amount + +class MallBinInfoQueryRequest(object): + def __init__(self, tbk_user: str): + self.tbk_user = tbk_user + + def __repr__(self): + return "MallBinInfoQueryRequest(tbk_user: {})".format(self.tbk_user) diff --git a/transbank/webpay/oneclick/schema.py b/transbank/webpay/oneclick/schema.py index d646aee5..42edb510 100644 --- a/transbank/webpay/oneclick/schema.py +++ b/transbank/webpay/oneclick/schema.py @@ -35,3 +35,6 @@ class MallTransactionRefundRequestSchema(Schema): commerce_code = fields.Str() detail_buy_order = fields.Str() amount = fields.Str() + +class MallBinInfoQueryRequestSchema(Schema): + tbk_user = fields.Str()