def c2b_validation_url(request, organization_id=None, reference=None): try: logger.debug(request.body) data = json.loads(request.body) logger.debug(data) form = forms.APIC2BForm(data) status = 200 if form.is_valid(): return process_request(request, mpesa.process_c2b_validation_request, organization_id=organization_id, reference=reference) else: status = 400 response = { "message": "Error in values passed", "success": False, "errors": form.errors } except (ObjectDoesNotExist, Http404) as e: logger.exception(e) status = 404 response = {"message": "Item not found", "success": False} except Exception as e: logger.exception(e) response = {"message": "Internal error", "success": False} status = 400 return JsonResponse(response, status=status)
def process_loan_repayment_request(event, context): """ The Loan's Module makes a loan repayment request, we analyze the Loan account for any credit dues then makes a request to mpesa for repayment. AWS specific """ for message in event["Records"]: message_body = message['body'] logger.debug(message_body) try: try: transaction_details = json.loads(message_body) except Exception as e: transaction_details = {} logger.exception(e) logger.debug('transaction_details') logger.debug(transaction_details) # process loan api.process_loan_repayment_request(**transaction_details) logger.debug(f"finished process_loan_repayment_request({message})") except Exception as e: logger.exception(e) logger.debug(f"failed process_loan_repayment_request({message})")
def process_request(request, processor, *args, **kwargs): logger.info("Processing request: %s" % processor) try: data = json.loads(request.body) logger.debug(data) result_code = processor(data, *args, **kwargs) if result_code == enums.ResultCode.success: logger.debug("Result processed successfully") response = { "ResultCode": enums.ResultCode.success, "ResultDesc": "Accepted" } else: logger.debug(f"Result not processed successfully {result_code}") response = {"ResultCode": result_code, "ResultDesc": "Rejected"} status = 200 except Exception as e: logger.exception("Error processing request") status = 500 response = { "ResultCode": enums.ResultCode.internal_failure, "ResultDesc": "Rejected" } logger.info("Finished processing request: %s" % processor) return JsonResponse(response, status=status)
def process_loan_application(event, context): """ We analyze the loan request, and send """ for message in event["Records"]: message_body = message['body'] logger.debug(message_body) try: try: transaction_details = json.loads(message_body) except Exception as e: transaction_details = {} logger.exception(e) logger.debug('transaction_details') logger.debug(transaction_details) if not transaction_details: raise RuntimeError("Cannot process this transaction") api.process_loan_application(**transaction_details) logger.debug("finished running process_loan_application()") except Exception as e: logger.exception(e) logger.debug(f"failed process_loan_repayment_request({message})")
def extract_body(request, *args, **kwargs): try: data = json.loads(request.body) except Exception: data = {} logger.error(json.dumps( dict(message="Error decoding data submitted.", args=args, kwargs=kwargs)), exc_info=True) return data
def test_get_user_is_accessible_via_token_successfully(self): response = self.client.get(reverse( 'users:get_user', kwargs={'user_account_id': self.user.user_account.account_id}), HTTP_AUTHORIZATION=self.HTTP_AUTHORIZATION) self.assertTrue(response.status_code, HTTPStatus.OK.value) self.assertEqual( response.json(), json.loads( json.dumps({ 'success': True, 'user_account': self.user_account.as_dict() })))
def action(request): try: logger.debug(request.body) data = json.loads(request.body) logger.debug(data) response = api.reversal_queue_timeout_url( data, organization_id=organization_id, reference=reference) status = 200 except Exception as e: logger.exception(e) response = {"message": "Internal error", "success": False} status = 400 return JsonResponse(response, status=status)
def process_loan_transaction(event, context): for message in event["Records"]: logger.debug("Processing loan transaction") message_body = message['body'] try: transaction_details = json.loads(message_body) except Exception as e: transaction_details = {} logger.debug(message) logger.debug(message_body) logger.exception(e) logger.debug(transaction_details) if not transaction_details: logger.debug("transaction_details has invalid value, exiting...") raise RuntimeError("Cannot process this transaction") amount = 0 fee = 0 repayment_amount = 0 if transaction_type == LoanTransactionType.LOAN_DISBURSAL: amount = transaction_details['transaction']['amount'] fee = transaction_details['transaction']['payment_platform']['fee'] elif transaction_type == LoanTransactionType.LOAN_REPAYMENT: repayment_amount = transaction_details['transaction'][ 'repayment_amount'] loan_account_id = transaction_details['loan_account_id'] transaction_type = transaction_details['transaction'][ 'transaction_type'] api.process_loan_transaction(loan_account_id, transaction_type, amount=amount, fee=fee, repayment_amount=repayment_amount)
def action(request): logger.info("Processing B2C Request result for %s transaction id %s" % (organization_id, reference)) try: logger.debug(request.body) data = json.loads(request.body) logger.debug(data) response = api.b2c_result_url(data, organization_id=organization_id, reference=reference) status = 200 except Exception as e: logger.exception(e) response = {"message": "Internal error", "success": False} status = 400 return JsonResponse(response, status=status)
def process_mpesa_b2c_transaction(event, context): logger.info("calling process_mpesa_b2c_transaction()") for message in event["Records"]: message_body = message['body'] logger.debug(message_body) try: try: transaction_details = json.loads(message_body) except Exception as e: transaction_details = {} logger.exception(e) logger.debug('transaction_details') logger.debug(transaction_details) api.process_mpesa_b2c_transaction(**transaction_details) except Exception as e: logger.exception(e) logger.debug(f"failed process_mpesa_b2c_transaction({message})")
def get_encrypted_text(plain_text, function_name=None): c = boto3.client( 'lambda', aws_access_key_id=settings.ENCRYPTION_INVOKER_ACCESS_KEY_ID, aws_secret_access_key=settings.ENCRYPTION_INVOKER_SECRET_ACCESS_KEY, region_name="us-east-1") logger.info("Boto client %s prepared" % c) try: logger.debug("Invoking lambda with access key id %s" % settings.ENCRYPTION_INVOKER_ACCESS_KEY_ID) response = c.invoke(FunctionName=function_name, InvocationType='RequestResponse', Payload=json.dumps({"text": plain_text})) logger.info("Response returned %s" % response) payload = json.loads(response['Payload'].read()) return payload['encrypted'] except (TypeError, KeyError) as e: logger.exception(e) return
def fund_loan_book(request): response = {} data = json.loads(request.body) form = FundLoanBookForm(data=data) if form.is_valid(): balance = api.fund_loan_book(**data) if balance: response['success'] = True response['data'] = dict(balance_id=balance.entry_id, balance_as_at=balance.balance_as_at) else: response['success'] = False response['message'] = "Could not complete transaction" else: response['success'] = False response['errors'] = dict(form.errors.items()) return json.JsonResponse(response)
def balance_check_queue_timeout_url(request, organization_id=None, reference=None): try: with db_transaction.atomic(): mpesa_transaction = get_object_or_404( MpesaTransaction.objects.filter( command_id=enums.CommandID.UTILITY_ACCOUNT_BALANCE, sender_account__organization__organization_id= organization_id, transaction_id=reference, transaction_time__isnull=True, transaction_amount__isnull=True, response_payload__isnull=True)) logger.debug(request.body) data = json.loads(request.body) logger.debug(data) mpesa_transaction.response_payload = data mpesa_transaction.save() response = {"message": "Received successfully.", "success": True} status = 200 except (ObjectDoesNotExist, Http404) as e: logger.exception(e) status = 404 response = {"message": "Item not found", "success": False} except Exception as e: logger.exception(e) response = {"message": "Internal error", "success": False} status = 400 return JsonResponse(response, status=status)
def test_mpesa_user_can_register_and_borrow(self, b2c_transact, authenticate, get_encrypted_text, mpesa_express_stk_push): b2c_transact.return_value = { "ConversationID": "AG_20180326_00005ca7f7c21d608166", "OriginatorConversationID": "12363-1328499-6", "ResponseCode": "0", "ResponseDescription": "Accept the service request successfully." } authenticate.return_value = { "access_token": "JZIAHHsd43435jjKSu238007K98SO", "expires_in": "3599" } get_encrypted_text.return_value = { "encrypted": "%s==" % ("ahh2iza7823kasksa" * 7) } mpesa_express_stk_push.return_value = { "MerchantRequestID": "21605-295434-4", "CheckoutRequestID": "ws_CO_04112017184930742", "ResponseCode": "0", "ResponseDescription": "Success. Request accepted for processing", "CustomerMessage": "Success. Request accepted for processing" } #------------- Setup # 3. Now, borrow the amount response = self.client.post(reverse_lazy( 'mpesa:mpesa_express_c2b_push', kwargs={'organization_id': self.organization.organization_id}), data={ 'short_code': '263801', 'phone_number': self.user.username, 'amount': 320, 'notes': 'My notes' }, HTTP_AUTHORIZATION=self.HTTP_AUTHORIZATION) transaction = MpesaTransaction.objects.last() self.assertEqual( response.json(), json.loads( json.dumps({ 'success': True, 'transaction': transaction.as_dict() }))) # 3. Simulate callback from M-Pesa response = self.client.post(reverse_lazy( 'mpesa:mpesa_c2b_stk_push_callback_url', kwargs={ 'organization_id': self.organization.organization_id, 'reference': transaction.third_party_transaction_id }), json.dumps(C2B_STK_MPESA_EXPRESS_RESPONSE), content_type="application/json") self.assertEqual(response.json(), { 'ResultCode': 0, 'ResultDesc': 'Accepted' })
def loan_repayment(request, loan_account_id=None): response = {} try: loan_account = api\ .get_active_loan_account(request.user, loan_account_id=loan_account_id) if loan_account.status in (enums.LoanStatus.PAID_OFF, enums.LoanStatus.WRITTEN_OFF, enums.LoanStatus.CLOSED): response.update({ 'loan_balance': 0, 'success': False, 'message': "Loan repayment unsuccessful. Your loan has already been closed." }) status = HTTPStatus.PRECONDITION_REQUIRED elif loan_account.status in (enums.LoanStatus.ACTIVE, enums.LoanStatus.DISBURSED, enums.LoanStatus.IN_ARREARS): logger.debug(f"checking request.body = {request.body}") data = loads(request.body) repayment_amount = D( data.get('repayment_amount') or loan_account.outstanding_balance or 0) loan_transaction = queue.notify_loan_repayment_request( loan_account, repayment_amount) response.update({ 'success': True, 'transaction': dict(transaction_id=loan_transaction.transaction_id, loan_account_id=loan_transaction.loan_account.account_id, amount=loan_transaction.amount), 'message': "Loan repayment request successful. Kindly input the M-Pesa password to continue" }) status = HTTPStatus.OK else: response.update({ 'success': False, 'message': "Loan repayment request unsuccessful. Invalid Loan state." }) status = HTTPStatus.EXPECTATION_FAILED except (ObjectDoesNotExist, Http404) as e: logger.exception(e) response.update({ "message": "Please complete system setup first", "success": False }) status = HTTPStatus.NOT_FOUND except Exception as e: logger.exception(e) response.update({"message": "Internal Error", "success": False}) status = HTTPStatus.INTERNAL_SERVER_ERROR return JsonResponse(response, status=status)
def loan_application(request, loan_profile_id=None): logger.info("Request for borrow by %s" % request.user.username) response = {} try: loan_profile = api.get_loan_profile(loan_profile_id=loan_profile_id) if (loan_profile.loan_accounts.filter(status__in=( enums.LoanStatus.ACTIVE, enums.LoanStatus.DISBURSED)).exists() or loan_profile.status in (enums.LoanProfileStatus.DEFAULT, enums.LoanProfileStatus.BLACKLISTED, enums.LoanProfileStatus.SUSPENDED)): response.update({ 'loan_balance': 0, 'success': False, 'message': 'Loan application unsuccessful; You currently do not meet the requirements for a new Loan.' }) status = HTTPStatus.PRECONDITION_REQUIRED elif (loan_profile.loan_accounts.filter(status__in=( enums.LoanStatus.CLEAN, enums.LoanStatus.PENDING_DISBURSEMENT, enums.LoanStatus.PAID_OFF)).exists() and loan_profile.status not in (enums.LoanProfileStatus.DEFAULT, enums.LoanProfileStatus.BLACKLISTED, enums.LoanProfileStatus.SUSPENDED)): try: logger.debug(f"checking request.body = {request.body}") data = loads(request.body) loan_amount = data.get('loan_amount', loan_profile.loan_limit) if loan_amount: loan_application = queue.notify_loan_application( loan_profile, loan_amount) if loan_application: status = HTTPStatus.OK logger.info("Request for borrow by %s successful" % request.user.username) response.update({ 'application': loan_application.as_dict(), 'success': True, 'message': 'Loan application successful; Wait for an M-Pesa confirmation or rejection notice.' }) else: response.update({ 'success': False, 'message': "Invalid Loan amount." }) status = HTTPStatus.EXPECTATION_FAILED except Exception as e: logger.exception(e) response.update({ 'success': False, 'message': "Invalid Loan state." }) status = HTTPStatus.EXPECTATION_FAILED else: response.update({ 'success': False, 'message': "Invalid Loan state." }) status = HTTPStatus.EXPECTATION_FAILED except (ObjectDoesNotExist, Http404) as e: logger.exception(e) response.update({ "message": "Please complete system setup first", "success": False }) status = HTTPStatus.NOT_FOUND except Exception as e: logger.exception(e) response.update({"message": "Internal Error", "success": False}) status = HTTPStatus.INTERNAL_SERVER_ERROR return JsonResponse(response, status=status)