def create_polling_request(self, kwargs): """ Creates a request for the reception of payments from MPESA users. Returns a request response object < class, 'requests.models.Response'> :param kwargs: The values constitute all user input. :type kwargs: dict :return: requests.models.Response """ if 'access_token' not in kwargs: raise exceptions.InvalidArgumentError('Access Token not given.') if 'scope' not in kwargs or \ 'scope_reference' not in kwargs or \ 'from_time' not in kwargs or \ 'to_time' not in kwargs or \ 'callback_url' not in kwargs: raise exceptions.InvalidArgumentError( 'Invalid arguments for creating Polling Request.') # iterate through kwargs if 'access_token' in kwargs: bearer_token = kwargs['access_token'] if 'scope' in kwargs: scope = kwargs['scope'] if 'scope_reference' in kwargs: scope_reference = kwargs['scope_reference'] if 'from_time' in kwargs: from_time = kwargs['from_time'] if 'to_time' in kwargs: to_time = kwargs['to_time'] if 'callback_url' in kwargs: callback_url = kwargs['callback_url'] # define headers headers = dict(self._headers) # validate bearer_token validation.validate_string_arguments(bearer_token) # add bearer token headers['Authorization'] = 'Bearer ' + bearer_token + '' # build polling request url polling_request_url = self._build_url(POLLING_PATH) # define links JSON object polling_request_links = json_builder.links(callback_url=callback_url) # define MPESA payment request JSON object polling_request_payload = json_builder.polling( scope=scope, scope_reference=scope_reference, from_time=from_time, to_time=to_time, polling_links=polling_request_links) return self._make_requests(headers=headers, method='POST', url=polling_request_url, payload=polling_request_payload)
def send_pay(self, bearer_token, callback_url, destination, value, currency='KES', **kwargs): """ Creates an outgoing pay to a third party. The result of the pay is provided asynchronously and posted to the callback_url provided. Returns a request response object < class, 'requests.models.Response'> :param bearer_token: Access token to be used to make calls to the Kopo Kopo API :type bearer_token: str :param callback_url: :type callback_url: str :param destination: ID of the destination of funds. :type destination: str :param value: Value of money to be sent (child of amount JSON str) :type value: str :param currency: Currency of amount being transacted :type currency: str :param kwargs: Provision for optional metadata with maximum of 5 key value pairs. :type kwargs: dict :return:requests.models.Response """ # build send_pay url send_pay_url = self._build_url(SEND_PAY_PATH) # define headers headers = dict(self.headers) # check bearer token validation.validate_string_arguments(bearer_token) # add authorization to headers headers['Authorization'] = 'Bearer ' + bearer_token + '' # create amount json object pay_amount = json_builder.amount(currency=currency, value=value) # create metadata json object pay_metadata = json_builder.metadata(', '.join( ['{}={}'.format(k, v) for k, v in kwargs.items()])) # create links json object pay_links = json_builder.links(callback_url=callback_url) # create payment json object pay_json = json_builder.pay(destination, pay_amount, pay_metadata, pay_links) return self._make_requests(url=send_pay_url, method='POST', payload=pay_json, headers=headers)
def test_pay_method_with_non_str_required_arguments_fails(self): with self.assertRaises(exceptions.InvalidArgumentError): payment_amount = json_builder.amount(currency=12457, value=12457) payment_metadata = json_builder.metadata(**{12457: 12457}) payment_links = json_builder.links(callback_url=12457) json_builder.pay(12457, payment_amount, payment_metadata, payment_links)
def test_successful_blind_transfer_request(self): response = requests.post( headers=TransferTestCase.header, json=json_builder.transfers( json_builder.links( 'https://webhook.site/52fd1913-778e-4ee1-bdc4-74517abb758d' ), json_builder.amount('KES', "3300")), data=None, url=TransferTestCase.settlement_transfer_obj._build_url( transfers.TRANSFER_PATH)) self.assertEqual(response.status_code, 201)
def test_successful_create_incoming_payment_request(self): response = requests.post( headers=ReceivePaymentTestCase.header, json=json_builder.mpesa_payment( json_builder.links( "https://webhook.site/52fd1913-778e-4ee1-bdc4-74517abb758d" ), json_builder.amount('KES', 'python_sdk_value'), json_builder.subscriber('first_name', 'last_name', "+254712345678", 'Null'), 'payment_channel', 'K112233'), data=None, url=ReceivePaymentTestCase.incoming_payments_obj._build_url( receive_payments.CREATE_RECEIVE_MPESA_PAYMENT_PATH)) self.assertEqual(response.status_code, 201)
def test_successful_targeted_transfer_to_merchant_wallet_request(self): response = requests.post( headers=TransferTestCase.header, json=json_builder.transfers( json_builder.links( 'https://webhook.site/52fd1913-778e-4ee1-bdc4-74517abb758d' ), json_builder.amount('KES', "3300"), **{ "destination_type": "merchant_wallet", "destination_reference": "eba238ae-e03f-46f6-aed5-db357fb00f9c" }), data=None, url=TransferTestCase.settlement_transfer_obj._build_url( transfers.TRANSFER_PATH)) self.assertEqual(response.status_code, 201)
def test_mpesa_payment_method_without_required_arguments_fails(self): with self.assertRaises(exceptions.InvalidArgumentError): mpesa_payment_amount = json_builder.amount(currency=None, value=None) mpesa_links = json_builder.links(callback_url=None) mpesa_payment_metadata = json_builder.metadata(**{None: None}) mpesa_payment_subscriber = json_builder.subscriber(first_name=None, last_name=None, phone=None, email=None) json_builder.mpesa_payment(mpesa_links, mpesa_payment_amount, mpesa_payment_subscriber, None, None)
def test_mpesa_payment_method_with_non_str_required_arguments_fails(self): with self.assertRaises(exceptions.InvalidArgumentError): mpesa_payment_amount = json_builder.amount(currency=15462, value=15462) mpesa_links = json_builder.links(callback_url=15462) mpesa_payment_metadata = json_builder.metadata(**{15462: 15462}) mpesa_payment_subscriber = json_builder.subscriber(first_name=15462, last_name=15462, phone=15462, email=15462) json_builder.mpesa_payment(mpesa_links, mpesa_payment_amount, mpesa_payment_subscriber, 15462, 15462)
def test_successful_targeted_transfer_to_merchant_bank_account_request( self): response = requests.post( headers=TransferTestCase.header, json=json_builder.transfers( json_builder.links( 'https://webhook.site/52fd1913-778e-4ee1-bdc4-74517abb758d' ), json_builder.amount('KES', "3300"), **{ "destination_type": "merchant_bank_account", "destination_reference": "87bbfdcf-fb59-4d8e-b039-b85b97015a7e" }), data=None, url=TransferTestCase.settlement_transfer_obj._build_url( transfers.TRANSFER_PATH)) self.assertEqual(response.status_code, 201)
def test_successful_create_pay_request_to_mobile_wallet(self): response = requests.post( headers=PayTestCase.header, json=json_builder.pay( "9764ef5f-fcd6-42c1-bbff-de280becc64b", "mobile_wallet", json_builder.amount('KES', 'python_sdk_value'), "test", json_builder.links( "https://webhook.site/52fd1913-778e-4ee1-bdc4-74517abb758d" ), json_builder.metadata({ "cId": '8_675_309', "notes": 'Salary payment May 2018' })), data=None, url=PayTestCase.pay_obj._build_url(pay.SEND_PAY_PATH)) self.assertEqual(response.status_code, 201)
def test_successful_create_pay_request_to_bank_account(self): response = requests.post( headers=PayTestCase.header, json=json_builder.pay( "c533cb60-8501-440d-8150-7eaaff84616a", "bank_account", json_builder.amount('KES', 'python_sdk_value'), "test", json_builder.links( "https://webhook.site/52fd1913-778e-4ee1-bdc4-74517abb758d" ), json_builder.metadata({ "cId": '8_675_309', "notes": 'Salary payment May 2018' })), data=None, url=PayTestCase.pay_obj._build_url(pay.SEND_PAY_PATH)) self.assertEqual(response.status_code, 201)
def send_transaction_sms_notification(self, kwargs): """ Creates a transaction sms notification. Returns a request response object < class, 'requests.models.Response'> :return: requests.models.Response """ if 'access_token' not in kwargs: raise exceptions.InvalidArgumentError('Access Token not given.') if 'webhook_event_reference' not in kwargs or \ 'message' not in kwargs or \ 'callback_url' not in kwargs: raise exceptions.InvalidArgumentError('Invalid arguments for creating Transaction SMS Notification.') # iterate through kwargs if 'access_token' in kwargs: bearer_token = kwargs['access_token'] if 'webhook_event_reference' in kwargs: webhook_event_reference = kwargs['webhook_event_reference'] if 'message' in kwargs: message = kwargs['message'] if 'callback_url' in kwargs: callback_url = kwargs['callback_url'] # build url create_transaction_sms_notification_url = self._build_url(TRANSACTION_NOTIFICATIONS_PATH) # define headers headers = dict(self._headers) # validate string arguments validation.validate_string_arguments(bearer_token, webhook_event_reference, message, callback_url) notification_links = json_builder.links(callback_url=callback_url) # add authorization to headers headers['Authorization'] = 'Bearer ' + bearer_token + '' # define create bank settlement account payload create_transaction_sms_notification_payload = json_builder.transaction_sms_notification(webhook_event_reference=webhook_event_reference, message=message, notification_links=notification_links) return self._make_requests(headers=headers, method='POST', url=create_transaction_sms_notification_url, payload=create_transaction_sms_notification_payload)
def test_link_method_with_non_str_argument_fails(self): with self.assertRaises(exceptions.InvalidArgumentError): json_builder.links(callback_url={'Igret': 'You know nothing Jon Snow'})
def test_link_method_with_empty_string_argument_fails(self): with self.assertRaises(exceptions.InvalidArgumentError): json_builder.links(callback_url='')
def test_link_method_without_callback_url_argument_fails(self): with self.assertRaises(exceptions.InvalidArgumentError): json_builder.links(callback_url=None)
def test_link_method_with_callback_url_argument_succeeds(self): links_json = json_builder.links(callback_url='https://some-westoros-url.got') self.assertIsNotNone(links_json)
def test_transfers_method_with_non_str_required_arguments_fails(self): with self.assertRaises(exceptions.InvalidArgumentError): transfers_amount = json_builder.amount(currency=145524, value=145524) transfer_links = json_builder.links(callback_url=145524) json_builder.transfers(transfer_links, transfers_amount)
def create_payment_request(self, bearer_token, callback_url, first_name, last_name, payment_channel, phone, till_number, value, currency='KES', **kwargs): """ Creates a request for the reception of payments from MPESA users. Returns a request response object < class, 'requests.models.Response'> :param bearer_token: Access token to be used to make calls to the Kopo Kopo API. :type bearer_token: str :param callback_url: Callback URL where the result of the MPESA payment request will be posted. :type callback_url: str :param currency: Currency of amount being transacted :type currency: str :param first_name: First name of the subscriber. :type first_name: str :param last_name: Last name of the subscriber. :type last_name: str :param phone: Phone number of the subscriber from which the payment will be made. :type phone: str :param payment_channel: Payment channel to be used eg. MPESA. :type payment_channel: str :param till_number: Till to which the payment will be made. :type till_number: str :param value: Value of money to be received :type value: str :param kwargs: :type kwargs: dict :return: requests.models.Response """ # validate phone number if validation.validate_phone_number(phone) is False: pass # validate email address if present if 'email' in kwargs: validation.validate_email(str(kwargs['email'])) email = kwargs['email'] else: email = 'Null' # define headers headers = dict(self.headers) # validate bearer_token validation.validate_string_arguments(bearer_token) # add bearer token headers['Authorization'] = 'Bearer ' + bearer_token + '' # build create mpesa payment request url mpesa_payment_request_url = self._build_url( CREATE_RECEIVE_MPESA_PAYMENT_PATH) # define amount JSON object mpesa_payment_request_amount = json_builder.amount(currency=currency, value=value) # define links JSON object mpesa_payment_request_links = json_builder.links( callback_url=callback_url) # define metadata JSON object mpesa_payment_metadata = json_builder.metadata(', '.join( ['{}={}'.format(k, v) for k, v in kwargs.items()])) # define subscriber JSON object mpesa_payment_subscriber = json_builder.subscriber( first_name=first_name, last_name=last_name, phone=phone, email=email) # define MPESA payment request JSON object mpesa_payment_request_payload = json_builder.mpesa_payment( mpesa_links=mpesa_payment_request_links, mpesa_payment_amount=mpesa_payment_request_amount, mpesa_payment_subscriber=mpesa_payment_subscriber, metadata=mpesa_payment_metadata, payment_channel=payment_channel, till_number=till_number) return self._make_requests(headers=headers, method='POST', url=mpesa_payment_request_url, payload=mpesa_payment_request_payload)
def settle_funds(self, kwargs): """ Creates a transfer from merchant account to a different settlement account. Returns a request response object < class, 'requests.models.Response'> :param kwargs: The values constitute all user input. :type kwargs: dict :return: requests.models.Response """ if 'access_token' not in kwargs: raise exceptions.InvalidArgumentError('Access Token not given.') if 'currency' not in kwargs: currency = 'KES' if 'destination_reference' not in kwargs: destination_reference = '' if 'destination_type' not in kwargs: destination_type = '' if 'callback_url' not in kwargs or \ 'value' not in kwargs: raise exceptions.InvalidArgumentError( 'Invalid arguments for creating Outgoing Pay.') # iterate through kwargs if 'access_token' in kwargs: bearer_token = kwargs['access_token'] if 'callback_url' in kwargs: callback_url = kwargs['callback_url'] if 'destination_type' in kwargs: destination_type = kwargs['destination_type'] if 'destination_reference' in kwargs: destination_reference = kwargs['destination_reference'] if 'value' in kwargs: value = kwargs['value'] # build settle funds url settle_funds_url = self._build_url(TRANSFER_PATH) # define headers headers = dict(self._headers) # check bearer token validation.validate_string_arguments(bearer_token, currency, value) # add authorization to headers headers['Authorization'] = 'Bearer ' + bearer_token + '' # define amount transfer_amount = json_builder.amount(currency=currency, value=value) # create links json object transfer_links = json_builder.links(callback_url=callback_url) if destination_reference is None and destination_type is None: settle_funds_payload = json_builder.transfers( transfer_links=transfer_links, transfers_amount=transfer_amount) else: settle_funds_payload = json_builder.transfers( transfer_links=transfer_links, transfers_amount=transfer_amount, destination_type=destination_type, destination_reference=destination_reference) return self._make_requests(headers=headers, method='POST', url=settle_funds_url, payload=settle_funds_payload)
def send_pay(self, kwargs): """ Creates an outgoing pay to a third party. The result of the pay is provided asynchronously and posted to the callback_url provided. Returns a request response object < class, 'requests.models.Response'> :param kwargs: Provision for optional metadata with maximum of 5 key value pairs. :type kwargs: dict :return:requests.models.Response """ if 'access_token' not in kwargs: raise exceptions.InvalidArgumentError('Access Token not given.') if 'destination_reference' not in kwargs or \ 'destination_type' not in kwargs or \ 'callback_url' not in kwargs or \ 'description' not in kwargs or \ 'amount' not in kwargs: raise exceptions.InvalidArgumentError( 'Invalid arguments for creating Outgoing Pay.') if 'currency' not in kwargs: currency = 'KES' if 'metadata' not in kwargs: pay_metadata = '' # iterate through kwargs if 'access_token' in kwargs: bearer_token = kwargs['access_token'] if 'callback_url' in kwargs: callback_url = kwargs['callback_url'] if 'description' in kwargs: description = kwargs['description'] if 'currency' in kwargs: currency = 'KES' if 'metadata' in kwargs: pay_metadata = json_builder.metadata(kwargs['metadata']) # build send_pay url send_pay_url = self._build_url(SEND_PAY_PATH) # define headers headers = dict(self._headers) # check bearer token validation.validate_string_arguments(bearer_token) # add authorization to headers headers['Authorization'] = 'Bearer ' + bearer_token + '' # create amount json object pay_amount = json_builder.amount(currency=currency, value=kwargs['amount']) # create links json object pay_links = json_builder.links(callback_url=callback_url) # create payment json object pay_json = json_builder.pay(kwargs['destination_reference'], kwargs['destination_type'], pay_amount, description, pay_links, pay_metadata) return self._make_requests(url=send_pay_url, method='POST', payload=pay_json, headers=headers)
def create_payment_request(self, kwargs): """ Creates a request for the reception of payments from MPESA users. Returns a request response object < class, 'requests.models.Response'> :param kwargs: The values constitute all user input. :type kwargs: dict :return: requests.models.Response """ if 'access_token' not in kwargs: raise exceptions.InvalidArgumentError('Access Token not given.') if 'first_name' not in kwargs or \ 'last_name' not in kwargs or \ 'callback_url' not in kwargs or \ 'payment_channel' not in kwargs or \ 'phone_number' not in kwargs or \ 'till_number' not in kwargs or \ 'email' not in kwargs or \ 'amount' not in kwargs: raise exceptions.InvalidArgumentError('Invalid arguments for creating Incoming Payment Request.') if 'currency' not in kwargs: currency = 'KES' if 'metadata' not in kwargs: mpesa_payment_metadata = '' # iterate through kwargs if 'access_token' in kwargs: bearer_token = kwargs['access_token'] if 'phone_number' in kwargs: phone_number = kwargs['phone_number'] if validation.validate_phone_number(phone_number) is False: pass if 'email' in kwargs: email = kwargs['email'] validation.validate_email(email) if 'currency' in kwargs: currency = 'KES' if 'metadata' in kwargs: mpesa_payment_metadata = json_builder.metadata(kwargs['pay_metadata']) # define headers headers = dict(self._headers) # validate bearer_token validation.validate_string_arguments(bearer_token) # add bearer token headers['Authorization'] = 'Bearer ' + bearer_token + '' # build create mpesa payment request url mpesa_payment_request_url = self._build_url(CREATE_RECEIVE_MPESA_PAYMENT_PATH) # define amount JSON object mpesa_payment_request_amount = json_builder.amount(currency=currency, value=kwargs['amount']) # define links JSON object mpesa_payment_request_links = json_builder.links(callback_url=kwargs['callback_url']) # define subscriber JSON object mpesa_payment_subscriber = json_builder.subscriber(first_name=kwargs['first_name'], last_name=kwargs['last_name'], phone_number=phone_number, email=email) # define MPESA payment request JSON object mpesa_payment_request_payload = json_builder.mpesa_payment(mpesa_links=mpesa_payment_request_links, mpesa_payment_amount=mpesa_payment_request_amount, mpesa_payment_subscriber=mpesa_payment_subscriber, metadata=mpesa_payment_metadata, payment_channel=kwargs['payment_channel'], till_number=kwargs['till_number']) return self._make_requests(headers=headers, method='POST', url=mpesa_payment_request_url, payload=mpesa_payment_request_payload)