def create_stripe_subscription(gateway_controller, data): stripe_settings = frappe.get_doc("Stripe Settings", gateway_controller) stripe_settings.data = frappe._dict(data) stripe.api_key = stripe_settings.get_password(fieldname="secret_key", raise_exception=False) stripe.default_http_client = stripe.http_client.RequestsClient() try: stripe_settings.integration_request = create_request_log( stripe_settings.data, "Host", "Stripe") stripe_settings.payment_plans = frappe.get_doc( "Payment Request", stripe_settings.data.reference_docname).subscription_plans return create_subscription_on_stripe(stripe_settings) except Exception: frappe.log_error(frappe.get_traceback()) return { "redirect_to": frappe.redirect_to_message( _('Server Error'), _("It seems that there is an issue with the server's stripe configuration. In case of failure, the amount will get refunded to your account." )), "status": 401 }
def handle_api_response(self, global_id, request_dict, response): """Response received from API calls returns a global identifier for each transaction, this code is returned during the callback.""" # check error response if getattr(response, "requestId"): req_name = getattr(response, "requestId") error = response else: # global checkout id used as request name req_name = getattr(response, global_id) error = None if not frappe.db.exists('Integration Request', req_name): create_request_log(request_dict, "Host", "Mpesa", req_name, error) if error: frappe.throw(_(getattr(response, "errorMessage")), title=_("Transaction Error"))
def process_payment_callback(checkout_token, reference_doctype, reference_docname): """' Charge authorization occurs after a user completes the Affirm checkout flow and returns to the merchant site. Authorizing the charge generates a charge ID that will be used to reference it moving forward. You must authorize a charge to fully create it. A charge is not visible in the Read charge response, nor in the merchant dashboard until you authorize it. """ data = { "checkout_token": checkout_token, "reference_doctype": reference_doctype, "reference_docname": reference_docname } integration_request = create_request_log(data, "Host", "Affirm") redirect_url = "/integrations/payment-failed" affirm_settings = get_api_config() authorization_response = requests.post( "{api_url}/charges".format(**affirm_settings), auth=HTTPBasicAuth(affirm_settings.get('public_api_key'), affirm_settings.get('private_api_key')), json={"checkout_token": checkout_token}) affirm_data = authorization_response.json() integration_request = frappe.get_doc("Integration Request", integration_request.name) integration_request.update_status(affirm_data, "Authorized") # frappe.log("Response: {}".format(json.dumps(affirm_data))) if affirm_data: authorize_payment(affirm_data, reference_doctype, reference_docname, integration_request)
def create_order(self, **kwargs): # Creating Orders https://razorpay.com/docs/api/orders/ # convert rupees to paisa kwargs['amount'] *= 100 # Create integration log integration_request = create_request_log(kwargs, "Host", "Razorpay") # Setup payment options payment_options = { "amount": kwargs.get('amount'), "currency": kwargs.get('currency', 'INR'), "receipt": kwargs.get('receipt'), "payment_capture": kwargs.get('payment_capture') } if self.api_key and self.api_secret: try: order = make_post_request("https://api.razorpay.com/v1/orders", auth=(self.api_key, self.get_password( fieldname="api_secret", raise_exception=False)), data=payment_options) order['integration_request'] = integration_request.name return order # Order returned to be consumed by razorpay.js except Exception: frappe.log(frappe.get_traceback()) frappe.throw(_("Could not create razorpay order"))
def create_order(self, **kwargs): # Creating Orders https://midtrans.com/docs/api/orders/ # convert rupees to paisa kwargs['amount'] *= 100 # Create integration log integration_request = create_request_log(kwargs, "Host", "midtrans") # Setup payment options payment_options = { "amount": kwargs.get('amount'), "currency": kwargs.get('currency', 'INR'), "receipt": kwargs.get('receipt'), "payment_capture": kwargs.get('payment_capture') } controller = frappe.get_doc("midtrans Settings") for doc in frappe.get_all("Integration Request", filters={"status": "Authorized", "integration_request_service": "midtrans"}, fields=["name", "data"]): data = json.loads(doc.data) settings = controller.get_settings(data) if self.client_key and self.server_key: try: order = make_post_request(settings.base_url + "/transactions", auth=(self.client_key, self.get_password(fieldname="server_key", raise_exception=False)), data=payment_options) order['integration_request'] = integration_request.name return order # Order returned to be consumed by midtrans.js except Exception: frappe.log(frappe.get_traceback()) frappe.throw(_("Could not create midtrans order"))
def get_payment_url(self, **kwargs): '''Return payment url with several params''' # create unique order id by making it equal to the integration request integration_request = create_request_log(kwargs, "Host", "Paytm") kwargs.update(dict(order_id=integration_request.name)) return get_url("./integrations/paytm_checkout?{0}".format( urlencode(kwargs)))
def create_request(self, data): # simulates a transaction by just submitting a quotation # if there is enough credit available there should be no issues self.process_data = frappe._dict(data) self.billing_info = self.process_data.get("billing_info") self.shipping_info = self.process_data.get("shipping_info") redirect_url = "" redirect_to = data.get("notes", {}).get("redirect_to") or None redirect_message = data.get("notes", {}).get("redirect_message") or None status = "Completed" if not self.process_data.get("unittest"): self.integration_request = create_request_log(self.process_data, "Host", self.service_name) self.integration_request.status = status self.integration_request.save() custom_redirect_to = None try: if not self.process_data.get("unittest"): ref_doc = frappe.get_doc( self.process_data.reference_doctype, self.process_data.reference_docname) ref_doc.flags["skip_payment_request"] = 1 custom_redirect_to = ref_doc.run_method("on_payment_authorized", status) except Exception as ex: log(frappe.get_traceback()) raise ex if custom_redirect_to: redirect_to = custom_redirect_to redirect_url = "/integrations/credit_success" redirect_message = "Continue Shopping" success = True params = [] if redirect_to: params.append(urllib.urlencode({"redirect_to": redirect_to})) if redirect_message: params.append(urllib.urlencode({"redirect_message": redirect_message})) if len(params) > 0: redirect_url += "?" + "&".join(params) self.process_data = {} self.billing_info = {} self.shipping_info = {} return { "redirect_to": redirect_url, "error": redirect_message if status == "Failed" else None, "status": status }
def get_payment_url(self, **kwargs): #create txn, save, return brws url params = { "returnurl": "http://{}/{}/{}".format( get_site_base_path()[2:], "api/method/paynow_gateway.paynow_gateway.doctype.paynow_settings.paynow_settings.check_if_paid?", kwargs.get( "reference_docname")), #api post dynamic for website "resulturl": "http://{}/{}".format( get_site_base_path()[2:], "orders" ), #redirection page after payment. shld be dynamic: fail / success OR API call which checks failure or success of txn based on ref "reference": kwargs.get("reference_docname"), #get from transaction "amount": kwargs.get("amount"), #get from transaction "id": self.paynow_integration_id, #Keep elsewhere "additionalinfo": kwargs.get("description"), "authemail": kwargs.get("payer_email"), "status": "Message" } # concertanate nd hash, request, get response query_string = self.paynow_create_url_query( params, self.paynow_integration_key) paynow_request = Request(self.paynow_init_url) result = urlopen(paynow_request, query_string) result = result.read().decode('utf-8') #checking if request was successful if self.check_initiate_response(result, self.paynow_integration_key): response = {} parts = result.split('&') for part in parts: indparts = part.split("=") response[indparts[0]] = unquote(indparts[1]) #response is a dict of results #save info smewhere payment req?? hidden. bind to transaction #lets c where i need the stuff n hw to retrieve. global pollurl global urlhash pollurl = response['pollurl'] urlhash = response['hash'] #not accessible if func not run in same instance. #dont run in another, duplicate txn integration_request = create_request_log(kwargs, "Host", "Paynow") #data = json.loads(integration_request.data) #data={"pollurl": response['pollurl'], "urlhash": response['hash'] } return response['browserurl']
def create_request(self, data): self.data = frappe._dict(data) try: self.integration_request = create_request_log(self.data, "Host", "Stripe") return self.create_charge_on_stripe() except Exception: frappe.log_error(frappe.get_traceback()) return{ "redirect_to": frappe.redirect_to_message(_('Server Error'), _("Seems issue with server's razorpay config. Don't worry, in case of failure amount will get refunded to your account.")), "status": 401 }
def create_payment_request(self, data): self.data = frappe._dict(data) try: self.integration_request = create_request_log(self.data, "Host", "GoCardless") return self.create_charge_on_gocardless() except Exception: frappe.log_error(frappe.get_traceback()) return{ "redirect_to": frappe.redirect_to_message(_('Server Error'), _("There seems to be an issue with the server's GoCardless configuration. Don't worry, in case of failure, the amount will get refunded to your account.")), "status": 401 }
def create_payment_request(self, data): self.data = frappe._dict(data) try: self.integration_request = create_request_log(self.data, "Host", "Braintree") return self.create_charge_on_braintree() except Exception: frappe.log_error(frappe.get_traceback()) return{ "redirect_to": frappe.redirect_to_message(_('Server Error'), _("There seems to be an issue with the server's braintree configuration. Don't worry, in case of failure, the amount will get refunded to your account.")), "status": 401 }
def get_payment_url(self, **kwargs): snap = midtransclient.Snap(is_production=bool(self.is_production), server_key=self.server_key, client_key=self.client_key) param = {} param.update({ "transaction_details": { "order_id": kwargs['reference_docname'], "gross_amount": kwargs['amount'] }, "credit_card": { "secure": True } }) try: trans = snap.create_transaction(param) payment_url = trans['redirect_url'] doc = frappe.get_doc("Midtrans Settings") md5 = hashlib.md5() md5.update( ("{}-{}".format(doc.merchant_id, kwargs['reference_docname']).encode("utf8"))) token = md5.hexdigest() # kwargs.update({ # "token": token # }) create_request_log(kwargs, "Remote", "Midtrans", token) print("Payment url : {}".format(payment_url)) frappe.msgprint("Payment url : {}".format(payment_url)) return payment_url except Exception as e: # frappe.msgprint(_(str(e)), raise_exception=1, indicator='red') raise frappe.ValidationError(str(e))
def create_subscription(self, data): self.data = frappe._dict(data) try: self.reference_document = frappe.get_doc(self.data.reference_doctype, self.data.reference_docname) self.origin_transaction = frappe.get_doc(self.reference_document.reference_doctype,\ self.reference_document.reference_name) self.integration_request = create_request_log(self.data, "Request", "Stripe") return self.create_new_subscription() except Exception as e: self.change_integration_request_status("Failed", "error", str(e)) return self.error_message(402, _("Stripe request creation failure"))
def create_request(self, data): import stripe self.data = frappe._dict(data) stripe.api_key = self.get_password(fieldname="secret_key", raise_exception=False) stripe.default_http_client = stripe.http_client.RequestsClient() try: self.integration_request = create_request_log(self.data, "Host", "Stripe") return self.create_charge_on_stripe() except Exception: frappe.log_error(frappe.get_traceback()) return{ "redirect_to": frappe.redirect_to_message(_('Server Error'), _("It seems that there is an issue with the server's stripe configuration. In case of failure, the amount will get refunded to your account.")), "status": 401 }
def get_payment_url(self, **kwargs): setattr(self, "use_sandbox", cint(kwargs.get("use_sandbox", 0))) response = self.execute_set_express_checkout(**kwargs) if self.paypal_sandbox or self.use_sandbox: return_url = "https://www.sandbox.paypal.com/cgi-bin/webscr?cmd=_express-checkout&token={0}" else: return_url = "https://www.paypal.com/cgi-bin/webscr?cmd=_express-checkout&token={0}" kwargs.update({ "token": response.get("TOKEN")[0], "correlation_id": response.get("CORRELATIONID")[0] }) self.integration_request = create_request_log(kwargs, "Remote", "PayPal", response.get("TOKEN")[0]) return return_url.format(kwargs["token"])
def create_payment_request(self, data): self.data = frappe._dict(data) try: self.integration_request = create_request_log( self.data, "Request", "GoCardless") self.reference_document = frappe.get_doc( self.data.reference_doctype, self.data.reference_docname) self.create_charge_on_gocardless() return self.finalize_request( self.output.attributes.get("id") if self.output. attributes else None) except Exception as e: self.change_integration_request_status("Failed", "error", str(e)) return self.error_message(402, _("GoCardless payment creation error"))
def create_request(self, data): self.data = frappe._dict(data) try: self.integration_request = create_request_log( self.data, "Host", "Stripe") return self.create_charge_on_stripe() except Exception: frappe.log_error(frappe.get_traceback()) return { "redirect_to": frappe.redirect_to_message( _('Server Error'), _("Seems issue with server's razorpay config. Don't worry, in case of failure amount will get refunded to your account." )), "status": 401 }
def create_stripe_subscription(gateway_controller, data): stripe_settings = frappe.get_doc("Stripe Settings", gateway_controller) stripe_settings.data = frappe._dict(data) stripe.api_key = stripe_settings.get_password(fieldname="secret_key", raise_exception=False) stripe.default_http_client = stripe.http_client.RequestsClient() try: stripe_settings.integration_request = create_request_log(stripe_settings.data, "Host", "Stripe") stripe_settings.payment_plans = frappe.get_doc("Payment Request", stripe_settings.data.reference_docname).subscription_plans return create_subscription_on_stripe(stripe_settings) except Exception: frappe.log_error(frappe.get_traceback()) return{ "redirect_to": frappe.redirect_to_message(_('Server Error'), _("It seems that there is an issue with the server's stripe configuration. In case of failure, the amount will get refunded to your account.")), "status": 401 }
def create_payment_request(self, data): self.data = frappe._dict(data) try: self.integration_request = create_request_log(self.data, "Host", "GoCardless") return self.create_charge_on_gocardless() except Exception: frappe.log_error("Gocardless payment reqeust failed") return { "redirect_to": frappe.redirect_to_message( _("Server Error"), _( "There seems to be an issue with the server's GoCardless configuration. Don't worry, in case of failure, the amount will get refunded to your account." ), ), "status": 401, }
def create_payment_intent(self, data, intent): self.data = frappe._dict(data) self.intent = frappe.parse_json(intent) payment_intent = self.intent.get("paymentIntent") try: self.reference_document = frappe.get_doc(self.data.reference_doctype, self.data.reference_docname) self.origin_transaction = frappe.get_doc(self.reference_document.reference_doctype, self.reference_document.reference_name) self.integration_request = create_request_log(self.data, "Request", "Stripe") self.link_integration_request("PaymentIntent", payment_intent.get("id"), payment_intent.get("status")) self.change_integration_request_status("Pending", "output", str(intent)) self.fetch_charges_after_intent(payment_intent=payment_intent.get("id")) return self.finalize_request(getattr(self, "charge_id")) except Exception as e: self.change_integration_request_status("Failed", "error", str(e)) return self.error_message(402, _("Stripe request creation failure"))
def capture_payment(affirm_id, sales_order): """ Capture the funds of an authorized charge, similar to capturing a credit card transaction. """ affirm_data = {"affirm_id": affirm_id, "sales_order": sales_order} integration_request = create_request_log(affirm_data, "Host", "Affirm") affirm_settings = get_api_config() authorization_response = requests.post( "{0}/charges/{1}/capture".format(affirm_settings.get("api_url"), affirm_id), auth=HTTPBasicAuth(affirm_settings.get('public_api_key'), affirm_settings.get('private_api_key')), ) if authorization_response.status_code == 200: affirm_data = authorization_response.json() #make payment entry agianst Sales Order integration_request.update_status(affirm_data, "Authorized") make_so_payment_entry(affirm_data, sales_order, integration_request) return affirm_data else: integration_request.update_status(affirm_data, "Failed") frappe.throw("Something went wrong.")
def create_request(self, data): import stripe self.data = frappe._dict(data) stripe.api_key = self.get_password(fieldname="secret_key", raise_exception=False) stripe.default_http_client = stripe.http_client.RequestsClient() try: self.integration_request = create_request_log(self.data, "Host", "Stripe") return self.create_charge_on_stripe() except Exception: frappe.log_error(frappe.get_traceback()) return { "redirect_to": frappe.redirect_to_message( _("Server Error"), _( "It seems that there is an issue with the server's stripe configuration. In case of failure, the amount will get refunded to your account." ), ), "status": 401, }
def capture_payment(affirm_id, sales_order): """ Capture the payment from affirm on a customer's sales order. Create a new integration request for the capture. Update the status of the sales order to paid and the integration request to Completed """ affirm_data = {"affirm_id": affirm_id, "sales_order": sales_order} #create a new integration request for capturing the affirm payment integration_request = create_request_log(affirm_data, "Host", "Affirm") affirm_settings = get_api_config() authorization_response = requests.post( "{0}/charges/{1}/capture".format(affirm_settings.get("api_url"), affirm_id), auth=HTTPBasicAuth(affirm_settings.get('public_api_key'), affirm_settings.get('private_api_key')), ) #if the payment capture is authorized, update status of affirm in the sales order and integration_req if authorization_response.status_code == 200: affirm_data = authorization_response.json() integration_request.update_status(affirm_data, "Authorized") frappe.db.set_value("Sales Order", sales_order, "affirm_status", authorization_response.json().get("status")) make_so_payment_entry(affirm_data, sales_order) integration_request.update_status(affirm_data, "Completed") else: #if payment capture fails integration_request.update_status(affirm_data, "Failed") integration_request.error = authorization_response.reason integration_request.save() frappe.throw("Something went wrong.") create_sales_invoice_for_affirm(sales_order) integration_request.save() return affirm_data
def charge_credit_card(data, card_number, expiration_date, card_code): """ Charge a credit card """ data = json.loads(data) data = frappe._dict(data) # Create Integration Request integration_request = create_request_log(data, "Host", "Authorizenet") # Authenticate with Authorizenet merchant_auth = apicontractsv1.merchantAuthenticationType() merchant_auth.name = frappe.db.get_single_value("Authorizenet Settings", "api_login_id") merchant_auth.transactionKey = get_decrypted_password( 'Authorizenet Settings', 'Authorizenet Settings', fieldname='api_transaction_key', raise_exception=False) # Create the payment data for a credit card credit_card = apicontractsv1.creditCardType() credit_card.cardNumber = card_number credit_card.expirationDate = expiration_date credit_card.cardCode = card_code # Add the payment data to a paymentType object payment = apicontractsv1.paymentType() payment.creditCard = credit_card pr = frappe.get_doc(data.reference_doctype, data.reference_docname) reference_doc = frappe.get_doc(pr.reference_doctype, pr.reference_name).as_dict() customer_address = apicontractsv1.customerAddressType() customer_address.firstName = data.payer_name customer_address.email = data.payer_email customer_address.address = reference_doc.customer_address[:60] # Create order information order = apicontractsv1.orderType() order.invoiceNumber = reference_doc.name # build the array of line items line_items = apicontractsv1.ArrayOfLineItem() for item in reference_doc.get("items"): # setup individual line items line_item = apicontractsv1.lineItemType() line_item.itemId = item.item_code line_item.name = item.item_name[:30] line_item.description = item.item_name line_item.quantity = item.qty line_item.unitPrice = cstr(item.rate) line_items.lineItem.append(line_item) # Create a transactionRequestType object and add the previous objects to it. transaction_request = apicontractsv1.transactionRequestType() transaction_request.transactionType = "authCaptureTransaction" transaction_request.amount = data.amount transaction_request.payment = payment transaction_request.order = order transaction_request.billTo = customer_address transaction_request.lineItems = line_items # Assemble the complete transaction request create_transaction_request = apicontractsv1.createTransactionRequest() create_transaction_request.merchantAuthentication = merchant_auth create_transaction_request.transactionRequest = transaction_request # Create the controller createtransactioncontroller = createTransactionController( create_transaction_request) if not frappe.db.get_single_value("Authorizenet Settings", "sandbox_mode"): createtransactioncontroller.setenvironment(constants.PRODUCTION) createtransactioncontroller.execute() response = createtransactioncontroller.getresponse() status = "Failed" if response is not None: # Check to see if the API request was successfully received and acted upon if response.messages.resultCode == "Ok" and hasattr( response.transactionResponse, 'messages') is True: status = "Completed" if status != "Failed": try: pr.run_method("on_payment_authorized", status) except Exception as ex: raise ex response_dict = to_dict(response) integration_request.update_status(data, status) description = "Something went wrong while trying to complete the transaction. Please try again." if status == "Completed": description = response_dict.get("transactionResponse").get( "messages").get("message").get("description") elif status == "Failed": description = error_text = response_dict.get( "transactionResponse").get("errors").get("error").get("errorText") integration_request.error = error_text integration_request.save(ignore_permissions=True) return frappe._dict({"status": status, "description": description})
def charge_credit_card(card, data): """ Charge a credit card """ data = frappe._dict(json.loads(data)) card = frappe._dict(json.loads(card)) # sanity gate keeper. Don't process anything without reference doctypes if not data.reference_doctype or not data.reference_docname: return { "status": "Failed", "description": "Invalid request. Submitted data contains no order reference. This seems to be an internal error. Please contact support." } # fetch previous requests info request_info = get_order_request_info(data.reference_doctype, data.reference_docname) # and document references pr = frappe.get_doc(data.reference_doctype, data.reference_docname) reference_doc = frappe.get_doc(pr.reference_doctype, pr.reference_name) # Sanity check. Make sure to not process card if a previous request was fullfilled status = get_status(data) if status.get("status") != "Failed" and status.get("status") != "NotFound": return status # sanity gate keeper. Don't process anything without reference doctypes if not data.reference_doctype or not data.reference_docname: return { "status": "Failed", "description": "Invalid request. Submitted data contains no order reference. This seems to be an internal error. Please contact support." } # fetch previous requests info request_info = get_order_request_info(data.reference_doctype, data.reference_docname) # and document references pr = frappe.get_doc(data.reference_doctype, data.reference_docname) reference_doc = frappe.get_doc(pr.reference_doctype, pr.reference_name) # Sanity check. Make sure to not process card if a previous request was fullfilled status = get_status(data) if status.get("status") != "Failed" and status.get("status") != "NotFound": return status # Create Integration Request integration_request = create_request_log(data, "Host", "Authorizenet") # Setup Authentication on Authorizenet merchant_auth = apicontractsv1.merchantAuthenticationType() merchant_auth.name = frappe.db.get_single_value("Authorizenet Settings", "api_login_id") merchant_auth.transactionKey = get_decrypted_password('Authorizenet Settings', 'Authorizenet Settings', fieldname='api_transaction_key', raise_exception=False) # create request dict to ease passing around data request = frappe._dict({ "pr": pr, "reference_doc": reference_doc, "data": data, "merchant_auth": merchant_auth, "integration_request": integration_request, "card": card }) # Charge card step def tryChargeCard(i): # ping authnet first to check if transaction was previously made order_transaction = query_successful_authnet_transaction(request) # if transaction was already recorded on authnet side, update integration # request and return success if order_transaction: return frappe._dict({ "status": "Completed" }) # Otherwise, begine charging card response = authnet_charge(request) # translate result to response payload status = "Failed" if response is not None: # Check to see if the API request was successfully received and acted upon if response.messages.resultCode == "Ok" and hasattr(response.transactionResponse, 'messages') is True: status = "Completed" response_dict = to_dict(response) result = frappe._dict({ "status": status }) if status == "Completed": description = response_dict.get( "transactionResponse", {}) \ .get("messages",{}) \ .get("message", {}) \ .get("description", "") if description: result.update({"description": description}) elif status == "Failed": description = response_dict.get( "transactionResponse", {}) \ .get("errors",{}) \ .get("error", {}) \ .get("errorText", "Unknown Error") if description: result.update({"description": description}) integration_request.error = description else: # TODO: Check what errors would trickle here... result.update({ "description": "Something went wrong while trying to complete the transaction. Please try again." }) # update integration request with result integration_request.update_status(data, status) # Finally update PR and order if status != "Failed": try: pr.run_method("on_payment_authorized", status) # now update Payment Entry to store card holder name for record keeping pe_list = frappe.get_all("Payment Entry", filters={"reference_no": pr.name}, limit=1) if len(pe_list) > 0: pe_name = pe_list[0] remarks = frappe.db.get_value("Payment Entry", pe_name, "remarks") remarks = "{}\n---\nCard Holder: {}".format(remarks, card.holder_name) frappe.db.set_value("Payment Entry", pe_name, "remarks", remarks) except Exception as ex: # we have a payment, however an internal process broke # so, log it and add a comment on the reference document. # continue to process the request as if it was succesful traceback = frappe.get_traceback() err_doc = frappe.log_error(message=traceback , title="Error processing credit card") request.reference_doc.add_comment("Comment", text="[INTERNAL ERROR] There was a problem while processing this order's payment.\n"+ "The transaction was record successfully and the card was charged.\n\n" + "However, please contact support to track down this issue and provide the following " + "error id: " + err_doc.name ) # Flag declined transactions as a validation error which the user should correct. if "declined" in (result.get("description") or "").lower(): result.type = "Validation" if "duplicate" in (result.get("description") or "").lower(): result.type = "Duplicate" return result # validate result to trigger a retry or complete calls def chargeResultPredicate(result, i): return result # handle exceptions during card charges def chargeExceptionPredicate(exception, i): result_obj = {} if isinstance(exception, Exception): description = "There was an internal error while processing your payment." + \ "To avoid double charges, please contact us." traceback = frappe.get_traceback() frappe.log_error(message=traceback , title="Error processing credit card") result_obj.update({ "status": "Failed", "description": description, "error": exception.message }) return result_obj result = retry(tryChargeCard, 3, chargeResultPredicate, chargeExceptionPredicate) return result
def build_checkout_data(**kwargs): full_name = kwargs.get("payer_name") # Dirty Hack # Affirm needs Full Name to have atleast 2 words if len(full_name.split()) == 1: full_name = full_name + " ." # Pick up reference doc from payment request. # This is usually the payment request it self. # On awc its the awc transction proxy to the request. ref_doc = frappe.get_doc(kwargs['reference_doctype'], kwargs['reference_docname']) # fetch the actual doctype use for this transaction. Could be Quotation, Sales Order or Invoice order_doc = frappe.get_doc(ref_doc.reference_doctype, kwargs["order_id"]) items = [] discounts = {} billing_address = None shipping_address = None if order_doc.get("customer_address"): billing_address = frappe.get_doc("Address", order_doc.customer_address) if order_doc.get("shipping_address_name"): shipping_address = frappe.get_doc("Address", order_doc.shipping_address_name) if not shipping_address: shipping_address = frappe.get_doc( "Address", frappe.get_value("Affirm Settings", "Affirm Settings", "pickup_address")) # deduce shipping from taxes table shipping_fee = 0 for tax in order_doc.taxes: if 'shipping ' in tax.description.lower(): shipping_fee = tax.tax_amount for idx, item in enumerate(order_doc.items): item_discount = item.price_list_rate - item.rate if item_discount > 0: discount_percent = 100 - (item.rate * 100 / item.price_list_rate) discount_code = "LINE {} | {} | {}% DISCOUNT ($ -{:,.2f})".format( idx, item.item_code, discount_percent, item_discount) discounts[discount_code] = { "discount_amount": convert_to_cents(item_discount), "discount_display_name": discount_code } items.append({ "display_name": item.item_name, "sku": item.item_code, "unit_price": convert_to_cents(item.price_list_rate), "qty": item.qty, "item_image_url": get_url(item.get("image", "")), "item_url": get_url() }) if order_doc.coupon_code: discounts[order_doc.coupon_code] = { "discount_amount": convert_to_cents(order_doc.discount_amount), "discount_display_name": "Coupon Code {}".format(order_doc.coupon_code) } checkout_data = { "merchant": { "user_confirmation_url": get_url(("/api/method/erpnext_affirm.erpnext_affirm_integration" ".doctype.affirm_settings.affirm_settings.affirm_callback" "?reference_doctype={0}&reference_docname={1}").format( ref_doc.doctype, ref_doc.name)), "user_cancel_url": get_url("/cart"), "user_confirmation_url_action": "GET", "name": "JH Audio" }, "items": items, "discounts": discounts, "order_id": order_doc.name, "shipping_amount": convert_to_cents(shipping_fee), "tax_amount": convert_to_cents(order_doc.total_taxes_and_charges - shipping_fee), "total": convert_to_cents(order_doc.grand_total) } if billing_address: checkout_data['billing'] = { "name": { "full": full_name }, "address": { "line1": billing_address.get("address_line1"), "line2": billing_address.get("address_line2"), "city": billing_address.get("city"), "state": billing_address.get("state"), "zipcode": billing_address.get("pincode"), "country": billing_address.get("country") } } if shipping_address: checkout_data['shipping'] = { "name": { "full": full_name }, "address": { "line1": shipping_address.get("address_line1"), "line2": shipping_address.get("address_line2"), "city": shipping_address.get("city"), "state": shipping_address.get("state"), "zipcode": shipping_address.get("pincode"), "country": shipping_address.get("country") } } create_request_log(checkout_data, "Host", "Affirm") return checkout_data
def get_payment_url(self, **kwargs): integration_request = create_request_log(kwargs, "Host", "Razorpay") return get_url("./integrations/razorpay_checkout?token={0}".format(integration_request.name))
def get_payment_url(self, **kwargs): integration_request = create_request_log(kwargs, "Host", "Razorpay") return get_url("./integrations/razorpay_checkout?token={0}".format( integration_request.name))
def create_order(**kwargs): """ Read the checkout data and current checkout status for a specific checkout attempt. """ full_name = kwargs.get("payer_name") # Affirm needs Full Name to have atleast 2 words if len(full_name.split()) == 1: full_name = full_name + " ." ref_doc = frappe.get_doc(kwargs['reference_doctype'], kwargs['reference_docname']) # fetch the actual doctype use for this transaction. Could be Quotation, Sales Order or Invoice order_doc = frappe.get_doc(ref_doc.reference_doctype, ref_doc.reference_name) items = [] discounts = {} billing_address = None shipping_address = None if order_doc.get("customer_address"): billing_address = frappe.get_doc("Address", order_doc.customer_address) if order_doc.get("shipping_address_name"): shipping_address = frappe.get_doc("Address", order_doc.shipping_address_name) if not shipping_address: shipping_address = frappe.get_doc("Address", order_doc.customer_address) # deduce shipping from taxes table shipping_fee = 0 for tax in order_doc.taxes: if 'shipping ' in tax.description.lower(): shipping_fee = tax.tax_amount for idx, item in enumerate(order_doc.items): item_discount = item.price_list_rate - item.rate if item_discount > 0: discount_percent = 100 - (item.rate * 100 / item.price_list_rate) discount_code = _( "LINE {0} | {1} | {2}% DISCOUNT ($ -{3:,.2f})").format( idx, item.item_code, discount_percent, item_discount) discounts[discount_code] = { "discount_amount": convert_to_cents(item_discount), "discount_display_name": discount_code } items.append({ "display_name": item.item_name, "sku": item.item_code, "unit_price": convert_to_cents(item.price_list_rate), "qty": item.qty, "item_image_url": get_url(item.get("image", "")), "item_url": get_url() }) checkout_data = { "merchant": { "user_confirmation_url": get_url(( "/api/method/erpnext.erpnext_integrations" ".doctype.affirm_settings.affirm_settings.process_payment_callback" "?reference_doctype={0}&reference_docname={1}").format( ref_doc.doctype, ref_doc.name)), "user_cancel_url": get_url("/cart"), "user_confirmation_url_action": "GET", "name": frappe.defaults.get_user_default("company") }, "items": items, "discounts": discounts, "order_id": order_doc.name, "shipping_amount": convert_to_cents(shipping_fee), "tax_amount": convert_to_cents(order_doc.total_taxes_and_charges - shipping_fee), "total": convert_to_cents(order_doc.grand_total) } if billing_address: checkout_data['billing'] = { "name": { "full": full_name }, "address": { "line1": billing_address.get("address_line1"), "line2": billing_address.get("address_line2"), "city": billing_address.get("city"), "state": billing_address.get("state"), "zipcode": billing_address.get("pincode"), "country": billing_address.get("country") } } if shipping_address: checkout_data['shipping'] = { "name": { "full": full_name }, "address": { "line1": shipping_address.get("address_line1"), "line2": shipping_address.get("address_line2"), "city": shipping_address.get("city"), "state": shipping_address.get("state"), "zipcode": shipping_address.get("pincode"), "country": shipping_address.get("country") } } create_request_log(checkout_data, "Host", "Affirm") return checkout_data
def create_request(self, data): try: from moneris_payment.MonerisPaymentGateway import Vault,PurchaseWithVault,mpgHttpsPost,CustInfo,BillingInfo,ShippingInfo,Item self.data= json.loads(data) self.integration_request = create_request_log(self.data, "Host", "Moneris") data = json.loads(data) self.reference_doctype="Payment Request" self.reference_docname=data.get('payment_request_id') payment_request=frappe.get_doc("Payment Request", data.get('payment_request_id')) sale_order=frappe.get_doc("Sales Order",payment_request.reference_name) if sale_order: billing_info=frappe.get_doc("Address", sale_order.customer_address) shipping_info=frappe.get_doc("Address", sale_order.shipping_address_name) # customer_info=frappe.get_doc("Customer", sale_order.customer) sale_order_items=frappe.db.get_all("Sales Order Item", fields=['item_code,item_name,rate,qty'], filters={'parent':sale_order.name},limit_page_length=1000) order_id =payment_request.reference_name print(sale_order.rounded_total) amount = str(sale_order.rounded_total) pan =data.get('card_number').replace(' ', '') expiry_date = data.get('card_expire') crypt = data.get('card_cvv') customer=CustInfo() #Customer Billing Info and Shipping Info first_name=sale_order.contact_display last_name=" " company_name="" # Billing Info billing_full_address=billing_info.address_line1 if billing_info.address_line2: billing_full_address=billing_full_address+","+billing_info.address_line2 if len(billing_full_address)>70: billing_full_address=billing_full_address[:70] billing_address=billing_full_address billing_city=billing_info.city billing_state_province=billing_info.state billing_postal_code=billing_info.pincode billing_country=billing_info.country billing_phone_number=billing_info.phone billing_fax="" billing_tax1="" if sale_order.total_taxes_and_charges: billing_tax1=str(sale_order.total_taxes_and_charges) billing_tax2="" billing_tax3="" shipping_cost="0.00" # # Shipping Info shipping_full_address=shipping_info.address_line1 if shipping_info.address_line2: shipping_full_address=shipping_full_address+","+shipping_info.address_line2 if len(shipping_full_address)>70: shipping_full_address=shipping_full_address[:70] shipping_address=shipping_full_address shipping_city=shipping_info.city shipping_state_province=shipping_info.state shipping_postal_code=shipping_info.pincode shipping_country=shipping_info.country shipping_phone_number=shipping_info.phone shipping_fax="" shipping_tax1="" if sale_order.total_taxes_and_charges: shipping_tax1=str(sale_order.total_taxes_and_charges) shipping_tax2="" shipping_tax3="" shipping_cost="0.00" billing_obj=BillingInfo(first_name, last_name, company_name, billing_address, billing_city, billing_state_province, billing_postal_code, billing_country, billing_phone_number, billing_fax, billing_tax1, billing_tax2, billing_tax3, shipping_cost) shpping_obj=ShippingInfo(first_name, last_name, company_name, shipping_address, shipping_city, shipping_state_province, shipping_postal_code, shipping_country, shipping_phone_number, shipping_fax, shipping_tax1, shipping_tax2, shipping_tax3, shipping_cost) customer.setBilling(billing_obj) customer.setShipping(shpping_obj) customer.setEmail(frappe.session.user) customer.setInstruction(" ") # Product Items for item in sale_order_items: customer.addItem(Item(item.item_name[:45],str(item.qty),item.item_code[:45].split(':')[0],str(item.rate))) data_key='' if data.get('data_key'): if data.get('data_key')!='': data_key=data.get('data_key') if data_key=='': vault = Vault(pan, expiry_date ,shipping_info.phone, frappe.session.user,frappe.session.user, "7") VautObject=mpgHttpsPost(vault) VautObject.postRequest() valutResp = VautObject.getResponse() if valutResp.getComplete()=="true": data_key=valutResp.getDataKey() CheckCardExist=frappe.db.get_all("Moneris Vault", fields=['user_id,data_key,pan'], filters={'user_id':frappe.session.user,'pan':valutResp.getResMaskedPan(),'expiry':valutResp.getResExpdate(),},limit_page_length=1000) if len(CheckCardExist)==0: frappe.get_doc({ "doctype":"Moneris Vault", "user_id":frappe.session.user, "data_key":valutResp.getDataKey(), "pan":valutResp.getResMaskedPan(), "expiry":valutResp.getResExpdate(), "card_type":cardType(pan), }).insert(ignore_permissions=True) #Purchase if data_key!='': purchase = PurchaseWithVault(data_key,order_id,amount,'1') purchase.setCustId(frappe.session.user) purchase.setCustInfo(customer) MSGObject=mpgHttpsPost(purchase) print(MSGObject) MSGObject.postRequest() # #Response resp = MSGObject.getResponse() if resp.getComplete()=="true": self.integration_request.db_set('status', 'Completed', update_modified=False) self.flags.status_changed_to = "Completed" return self.finalize_request(data.get('payment_request_id'),str(resp.getTransID()),str(resp.getTransDate())) else: return {"ReceiptId" : resp.getReceiptId(), "ReferenceNum" :resp.getReferenceNum(), "ResponseCod" : resp.getResponseCode(), "AuthCode" : resp.getAuthCode(), "TransTime" : resp.getTransTime(), "TransDate" : resp.getTransDate(), "TransType" : resp.getTransType(), "Complete" : resp.getComplete(), "status" : resp.getComplete(), "Message" : resp.getMessage(), "TransAmount" : resp.getTransAmount(), "CardType" : resp.getCardType(), "TransID" : resp.getTransID(), "TimedOut" : resp.getTimedOut(), "BankTotals" : resp.getBankTotals(), "Ticket" : resp.getTicket()} # purchase = Purchase(order_id, amount , pan, expiry_date, crypt) # purchase.setCustInfo(customer) # MSGObject=mpgHttpsPost(purchase) # MSGObject.postRequest() # #Response # resp = MSGObject.getResponse() # if resp.getComplete()=="true": # self.integration_request.db_set('status', 'Completed', update_modified=False) # self.flags.status_changed_to = "Completed" # return self.finalize_request(data.get('payment_request_id'),str(resp.getTransID()),str(resp.getTransDate())) # else: # return {"ReceiptId" : resp.getReceiptId(), # "ReferenceNum" :resp.getReferenceNum(), # "ResponseCod" : resp.getResponseCode(), # "AuthCode" : resp.getAuthCode(), # "TransTime" : resp.getTransTime(), # "TransDate" : resp.getTransDate(), # "TransType" : resp.getTransType(), # "Complete" : resp.getComplete(), # "status" : resp.getComplete(), # "Message" : resp.getMessage(), # "TransAmount" : resp.getTransAmount(), # "CardType" : resp.getCardType(), # "TransID" : resp.getTransID(), # "TimedOut" : resp.getTimedOut(), # "BankTotals" : resp.getBankTotals(), # "Ticket" : resp.getTicket()} # else: # return { # "redirect_to": "payment-failed", # "status": "failed" # } else: return { "redirect_to": "payment-failed", "status": "failed" } except Exception as e: print(e) return e
def build_checkout_data(**kwargs): full_name = kwargs.get("payer_name") # Dirty Hack # Affirm needs Full Name to have atleast 2 words if len(full_name.split()) == 1: full_name = full_name + " ." # Pick up reference doc from payment request. # This is usually the payment request it self. # On awc its the awc transction proxy to the request. ref_doc = frappe.get_doc(kwargs['reference_doctype'], kwargs['reference_docname']) # fetch the actual doctype use for this transaction. Could be Quotation, Sales Order or Invoice order_doc = frappe.get_doc(ref_doc.reference_doctype, kwargs["order_id"]) items = [] shipping_address = frappe.get_doc("Address", order_doc.shipping_address_name) # deduce shipping from taxes table shipping_fee = 0 for tax in order_doc.taxes: if 'shipping ' in tax.description.lower(): shipping_fee = tax.tax_amount for item in order_doc.items: items.append({ "display_name": item.item_name, "sku": item.item_code, "unit_price": convert_to_cents(item.rate), "qty": item.qty, "item_image_url": get_url(item.get("image", "")), "item_url": get_url() }) checkout_data = { "merchant": { "user_confirmation_url": get_url( ( "/api/method/erpnext_affirm.erpnext_affirm_integration" ".doctype.affirm_settings.affirm_settings.affirm_callback" "?reference_doctype={0}&reference_docname={1}" ).format(ref_doc.doctype, ref_doc.name) ), "user_cancel_url": get_url("/cart"), "user_confirmation_url_action": "GET", "name": "JH Audio" }, "shipping": { "name": { "full": full_name }, "address": { "line1": shipping_address.get("address_line1"), "line2": shipping_address.get("address_line2"), "city": shipping_address.get("city"), "state": shipping_address.get("state"), "zipcode": shipping_address.get("pincode"), "country": shipping_address.get("country") } }, "items": items, "order_id": order_doc.name, "shipping_amount": convert_to_cents(shipping_fee), "tax_amount": convert_to_cents(order_doc.total_taxes_and_charges - shipping_fee), "total": convert_to_cents(order_doc.grand_total) } create_request_log(checkout_data, "Host", "Affirm") return checkout_data
def get_payment_url(self, **kwargs): integration_request = create_request_log(kwargs, "Host", "AFS Payment") return get_url("./afs_payment_checkout?token={0}".format( integration_request.name))
def create_request(self, data): self.process_data = frappe._dict(data) # try: # remove sensitive info from being entered into db self.card_info = self.process_data.get("card_info") self.billing_info = self.process_data.get("billing_info") self.shipping_info = self.process_data.get("shipping_info") redirect_url = "" request, redirect_to, redirect_message, authorizenet_data = self.process_payment( ) if self.process_data.get('creation'): del self.process_data['creation'] if self.process_data.get('modified'): del self.process_data['modified'] if self.process_data.get('log'): del self.process_data['log'] # sanitize card info if self.process_data.get("card_info"): self.process_data.card_info["card_number"] = "%s%s" % ("X" * \ (len(self.process_data.card_info["card_number"]) - 4), self.process_data["card_info"]["card_number"][-4:]) self.process_data.card_info["card_code"] = "X" * \ len(self.process_data.card_info["card_code"]) if not self.process_data.get("unittest"): self.integration_request = create_request_log( self.process_data, "Host", self.service_name) if request.get('status') == "Captured": status = "Completed" elif request.get('status') == "Authorized": status = "Authorized" else: status = "Failed" request.log_action(status, "Info") # prevents unit test from inserting data on db if not self.process_data.get("unittest"): self.integration_request.status = status self.integration_request.save() request.save() custom_redirect_to = None if status != "Failed": try: if not self.process_data.get("unittest"): custom_redirect_to = frappe.get_doc( self.process_data.reference_doctype, self.process_data.reference_docname).run_method( "on_payment_authorized", status) request.log_action( "Custom Redirect To: %s" % custom_redirect_to, "Info") except Exception as ex: log(frappe.get_traceback()) request.log_action(frappe.get_traceback(), "Error") raise ex if custom_redirect_to: redirect_to = custom_redirect_to if request.status == "Captured" or request.status == "Authorized": redirect_url = "/integrations/payment-success" redirect_message = "Continue Shopping" success = True else: redirect_url = "/integrations/payment-failed" if request.error_msg: redirect_message = "Declined due to:\n" + request.error_msg else: redirect_message = "Declined" success = False params = [] if redirect_to: # Fixes issue where system passes a relative url for orders if redirect_to == "orders": redirect_to = "/orders" params.append(urllib.urlencode({"redirect_to": redirect_to})) if redirect_message: params.append( urllib.urlencode({"redirect_message": redirect_message})) if len(params) > 0: redirect_url += "?" + "&".join(params) if not self.process_data.get("unittest"): request.log_action("Redirect To: %s" % redirect_url, "Info") request.save() else: for l in request.log: print(l.get("level") + "----------------") print(l.get("log")) print("") self.process_data = {} self.card_info = {} self.billing_info = {} self.shipping_info = {} return { "redirect_to": redirect_url, "error": redirect_message if status == "Failed" else None, "status": status, "authorizenet_data": authorizenet_data }