diff --git a/payments/payment_gateways/doctype/paypal_settings/paypal_settings.py b/payments/payment_gateways/doctype/paypal_settings/paypal_settings.py index 2702cb7..42d77d7 100644 --- a/payments/payment_gateways/doctype/paypal_settings/paypal_settings.py +++ b/payments/payment_gateways/doctype/paypal_settings/paypal_settings.py @@ -68,7 +68,13 @@ class PayPalSettings(IntegrationService): supported_currencies = ["AUD", "BRL", "CAD", "CZK", "DKK", "EUR", "HKD", "HUF", "ILS", "JPY", "MYR", "MXN", "TWD", "NZD", "NOK", "PHP", "PLN", "GBP", "RUB", "SGD", "SEK", "CHF", "THB", "TRY", "USD"] - + + def __setup__(self): + setattr(self, "use_sandbox", 0) + if hasattr(self, "token"): + data = json.loads(frappe.db.get_value("Integration Request", self.token, "data")) + setattr(self, "use_sandbox", frappe._dict(data).use_sandbox or 0) + def validate(self): if not self.flags.ignore_mandatory: self.validate_paypal_credentails() @@ -94,7 +100,14 @@ class PayPalSettings(IntegrationService): "METHOD": "GetPalDetails" } - api_url = "https://api-3t.sandbox.paypal.com/nvp" if self.paypal_sandbox else "https://api-3t.paypal.com/nvp" + if hasattr(self, "use_sandbox") and self.use_sandbox: + params.update({ + "USER": frappe.conf.sandbox_api_username, + "PWD": frappe.conf.sandbox_api_password, + "SIGNATURE": frappe.conf.sandbox_signature + }) + + api_url = "https://api-3t.sandbox.paypal.com/nvp" if (self.paypal_sandbox or self.use_sandbox) else "https://api-3t.paypal.com/nvp" return params, api_url @@ -112,9 +125,11 @@ class PayPalSettings(IntegrationService): frappe.throw(_("Invalid payment gateway credentials")) def get_payment_url(self, **kwargs): + setattr(self, "use_sandbox", kwargs.get("use_sandbox", 0)) + response = self.execute_set_express_checkout(kwargs["amount"], kwargs["currency"]) - if self.paypal_sandbox: + 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}" @@ -186,78 +201,87 @@ def get_service_details(): @frappe.whitelist(allow_guest=True, xss_safe=True) def get_express_checkout_details(token): - doc = frappe.get_doc("PayPal Settings") - params, url = doc.get_paypal_params_and_url() - params.update({ - "METHOD": "GetExpressCheckoutDetails", - "TOKEN": token - }) + try: + doc = frappe.get_doc({"doctype": "PayPal Settings", "token": token}) + params, url = doc.get_paypal_params_and_url() + params.update({ + "METHOD": "GetExpressCheckoutDetails", + "TOKEN": token + }) - response = doc.post_request(url, data=params) + response = doc.post_request(url, data=params) - if response.get("ACK")[0] != "Success": - frappe.respond_as_web_page(_("Something went wrong"), - _("Looks like something went wrong during the transaction. Since we haven't confirmed the payment, Paypal will automatically refund you this amount. If it doesn't, please send us an email and mention the Correlation ID: {0}.").format(response.get("CORRELATIONID", [None])[0]), - success=False, - http_status_code=frappe.ValidationError.http_status_code) + if response.get("ACK")[0] != "Success": + frappe.respond_as_web_page(_("Something went wrong"), + _("Looks like something went wrong during the transaction. Since we haven't confirmed the payment, Paypal will automatically refund you this amount. If it doesn't, please send us an email and mention the Correlation ID: {0}.").format(response.get("CORRELATIONID", [None])[0]), + success=False, + http_status_code=frappe.ValidationError.http_status_code) + + return - return + update_integration_request_status(token, { + "payerid": response.get("PAYERID")[0], + "payer_email": response.get("EMAIL")[0] + }, "Authorized") - update_integration_request_status(token, { - "payerid": response.get("PAYERID")[0], - "payer_email": response.get("EMAIL")[0] - }, "Authorized") + frappe.local.response["type"] = "redirect" + frappe.local.response["location"] = get_url( \ + "/api/method/frappe.integrations.doctype.paypal_settings.paypal_settings.confirm_payment?token={0}".format(token)) - frappe.local.response["type"] = "redirect" - frappe.local.response["location"] = get_url( \ - "/api/method/frappe.integrations.doctype.paypal_settings.paypal_settings.confirm_payment?token={0}".format(token)) + except Exception: + frappe.log_error(frappe.get_traceback()) @frappe.whitelist(allow_guest=True, xss_safe=True) def confirm_payment(token): - redirect = True - status_changed_to, redirect_to = None, None - doc = frappe.get_doc("PayPal Settings") - integration_request = frappe.get_doc("Integration Request", token) - data = json.loads(integration_request.data) - - redirect_to = data.get('redirect_to') or None - redirect_message = data.get('redirect_message') or None - - params, url = doc.get_paypal_params_and_url() - params.update({ - "METHOD": "DoExpressCheckoutPayment", - "PAYERID": data.get("payerid"), - "TOKEN": token, - "PAYMENTREQUEST_0_PAYMENTACTION": "SALE", - "PAYMENTREQUEST_0_AMT": data.get("amount"), - "PAYMENTREQUEST_0_CURRENCYCODE": data.get("currency").upper() - }) - - response = doc.post_request(url, data=params) - - if response.get("ACK")[0] == "Success": - update_integration_request_status(token, { - "transaction_id": response.get("PAYMENTINFO_0_TRANSACTIONID")[0], - "correlation_id": response.get("CORRELATIONID")[0] - }, "Completed") + try: + redirect = True + status_changed_to, redirect_to = None, None + doc = frappe.get_doc({"doctype": "PayPal Settings", "token": token}) + integration_request = frappe.get_doc("Integration Request", token) + data = json.loads(integration_request.data) - if data.get("reference_doctype") and data.get("reference_docname"): - redirect_url = frappe.get_doc(data.get("reference_doctype"), data.get("reference_docname")).run_method("on_payment_authorized", "Completed") + redirect_to = data.get('redirect_to') or None + redirect_message = data.get('redirect_message') or None - if not redirect_url: - redirect_url = '/integrations/payment-success' - else: - redirect_url = "/integrations/payment-failed" + params, url = doc.get_paypal_params_and_url() + params.update({ + "METHOD": "DoExpressCheckoutPayment", + "PAYERID": data.get("payerid"), + "TOKEN": token, + "PAYMENTREQUEST_0_PAYMENTACTION": "SALE", + "PAYMENTREQUEST_0_AMT": data.get("amount"), + "PAYMENTREQUEST_0_CURRENCYCODE": data.get("currency").upper() + }) - if redirect_to: - redirect_url += '?' + urllib.urlencode({'redirect_to': redirect_to}) - if redirect_message: - redirect_url += '&' + urllib.urlencode({'redirect_message': redirect_message}) + response = doc.post_request(url, data=params) - # this is done so that functions called via hooks can update flags.redirect_to - if redirect: - frappe.local.response["type"] = "redirect" - frappe.local.response["location"] = get_url(redirect_to) + if response.get("ACK")[0] == "Success": + update_integration_request_status(token, { + "transaction_id": response.get("PAYMENTINFO_0_TRANSACTIONID")[0], + "correlation_id": response.get("CORRELATIONID")[0] + }, "Completed") + + if data.get("reference_doctype") and data.get("reference_docname"): + redirect_url = frappe.get_doc(data.get("reference_doctype"), data.get("reference_docname")).run_method("on_payment_authorized", "Completed") + frappe.db.commit() + + if not redirect_url: + redirect_url = '/integrations/payment-success' + else: + redirect_url = "/integrations/payment-failed" + + if redirect_to: + redirect_url += '?' + urllib.urlencode({'redirect_to': redirect_to}) + if redirect_message: + redirect_url += '&' + urllib.urlencode({'redirect_message': redirect_message}) + + # this is done so that functions called via hooks can update flags.redirect_to + if redirect: + frappe.local.response["type"] = "redirect" + frappe.local.response["location"] = get_url(redirect_url) + + except Exception: + frappe.log_error(frappe.get_traceback()) def update_integration_request_status(token, data, status, error=False): frappe.get_doc("Integration Request", token).update_status(data, status) diff --git a/payments/payment_gateways/doctype/razorpay_settings/razorpay_settings.py b/payments/payment_gateways/doctype/razorpay_settings/razorpay_settings.py index 5437bcf..51a843a 100644 --- a/payments/payment_gateways/doctype/razorpay_settings/razorpay_settings.py +++ b/payments/payment_gateways/doctype/razorpay_settings/razorpay_settings.py @@ -117,8 +117,9 @@ class RazorpaySettings(IntegrationService): The money is deducted from the customer’s account, but will not be transferred to the merchant’s account until it is explicitly captured by merchant. """ - settings = self.get_settings() data = json.loads(self.integration_request.data) + + settings = self.get_settings(data) redirect_to = data.get('notes', {}).get('redirect_to') or None redirect_message = data.get('notes', {}).get('redirect_message') or None @@ -167,12 +168,20 @@ class RazorpaySettings(IntegrationService): "status": status } - def get_settings(self): - return frappe._dict({ + def get_settings(self, data): + settings = frappe._dict({ "api_key": self.api_key, "api_secret": self.get_password(fieldname="api_secret", raise_exception=False) }) + if data.get('notes', {}).get('use_sandbox'): + settings.update({ + "api_key": frappe.conf.sandbox_api_key, + "api_secret": frappe.conf.sandbox_api_secret, + }) + + return settings + def capture_payment(is_sandbox=False, sanbox_response=None): """ Verifies the purchase as complete by the merchant. @@ -190,8 +199,10 @@ def capture_payment(is_sandbox=False, sanbox_response=None): resp = sanbox_response else: data = json.loads(doc.data) + settings = controller.get_settings(data) + resp = controller.post_request("https://api.razorpay.com/v1/payments/{0}/capture".format(data.get("razorpay_payment_id")), - auth=(controller.api_key, controller.get_password("api_secret")), data={"amount": data.get("amount")}) + auth=(settings.api_key, settings.api_secret), data={"amount": data.get("amount")}) if resp.get("status") == "captured": frappe.db.set_value("Integration Request", doc.name, "status", "Completed") @@ -212,7 +223,6 @@ def get_checkout_url(**kwargs): success=False, http_status_code=frappe.ValidationError.http_status_code) - @frappe.whitelist() def get_service_details(): return """ diff --git a/payments/templates/pages/razorpay_checkout.py b/payments/templates/pages/razorpay_checkout.py index 1c76f1f..68bed32 100644 --- a/payments/templates/pages/razorpay_checkout.py +++ b/payments/templates/pages/razorpay_checkout.py @@ -14,7 +14,7 @@ expected_keys = ('amount', 'title', 'description', 'reference_doctype', 'referen def get_context(context): context.no_cache = 1 - context.api_key = frappe.db.get_value("Razorpay Settings", None, "api_key") + context.api_key = get_api_key() # all these keys exist in form_dict if not (set(expected_keys) - set(frappe.form_dict.keys())): @@ -28,6 +28,14 @@ def get_context(context): frappe.local.flags.redirect_location = frappe.local.response.location raise frappe.Redirect +def get_api_key(): + api_key = frappe.db.get_value("Razorpay Settings", None, "api_key") + + if frappe.form_dict.get("use_sandbox"): + api_key = frappe.conf.sandbox_api_key + + return api_key + @frappe.whitelist(allow_guest=True) def make_payment(razorpay_payment_id, options, reference_doctype, reference_docname): data = {}