Bladeren bron

[fix] paypal sandboxing to test dummy payments (#2281)

* [fix] paypal sandboxing to test dummy payments

* [fix] sandbox testing for razorpay
pull/2/head
Saurabh 8 jaren geleden
committed by Rushabh Mehta
bovenliggende
commit
a388c2597d
3 gewijzigde bestanden met toevoegingen van 111 en 69 verwijderingen
  1. +87
    -63
      payments/payment_gateways/doctype/paypal_settings/paypal_settings.py
  2. +15
    -5
      payments/payment_gateways/doctype/razorpay_settings/razorpay_settings.py
  3. +9
    -1
      payments/templates/pages/razorpay_checkout.py

+ 87
- 63
payments/payment_gateways/doctype/paypal_settings/paypal_settings.py Bestand weergeven

@@ -68,7 +68,13 @@ class PayPalSettings(IntegrationService):
supported_currencies = ["AUD", "BRL", "CAD", "CZK", "DKK", "EUR", "HKD", "HUF", "ILS", "JPY", "MYR", "MXN", 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"] "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): def validate(self):
if not self.flags.ignore_mandatory: if not self.flags.ignore_mandatory:
self.validate_paypal_credentails() self.validate_paypal_credentails()
@@ -94,7 +100,14 @@ class PayPalSettings(IntegrationService):
"METHOD": "GetPalDetails" "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 return params, api_url


@@ -112,9 +125,11 @@ class PayPalSettings(IntegrationService):
frappe.throw(_("Invalid payment gateway credentials")) frappe.throw(_("Invalid payment gateway credentials"))
def get_payment_url(self, **kwargs): 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"]) 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}" return_url = "https://www.sandbox.paypal.com/cgi-bin/webscr?cmd=_express-checkout&token={0}"
else: else:
return_url = "https://www.paypal.com/cgi-bin/webscr?cmd=_express-checkout&token={0}" 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) @frappe.whitelist(allow_guest=True, xss_safe=True)
def get_express_checkout_details(token): 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) @frappe.whitelist(allow_guest=True, xss_safe=True)
def confirm_payment(token): 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): def update_integration_request_status(token, data, status, error=False):
frappe.get_doc("Integration Request", token).update_status(data, status) frappe.get_doc("Integration Request", token).update_status(data, status)


+ 15
- 5
payments/payment_gateways/doctype/razorpay_settings/razorpay_settings.py Bestand weergeven

@@ -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 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. until it is explicitly captured by merchant.
""" """
settings = self.get_settings()
data = json.loads(self.integration_request.data) data = json.loads(self.integration_request.data)

settings = self.get_settings(data)
redirect_to = data.get('notes', {}).get('redirect_to') or None redirect_to = data.get('notes', {}).get('redirect_to') or None
redirect_message = data.get('notes', {}).get('redirect_message') or None redirect_message = data.get('notes', {}).get('redirect_message') or None


@@ -167,12 +168,20 @@ class RazorpaySettings(IntegrationService):
"status": status "status": status
} }


def get_settings(self):
return frappe._dict({
def get_settings(self, data):
settings = frappe._dict({
"api_key": self.api_key, "api_key": self.api_key,
"api_secret": self.get_password(fieldname="api_secret", raise_exception=False) "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): def capture_payment(is_sandbox=False, sanbox_response=None):
""" """
Verifies the purchase as complete by the merchant. Verifies the purchase as complete by the merchant.
@@ -190,8 +199,10 @@ def capture_payment(is_sandbox=False, sanbox_response=None):
resp = sanbox_response resp = sanbox_response
else: else:
data = json.loads(doc.data) 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")), 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": if resp.get("status") == "captured":
frappe.db.set_value("Integration Request", doc.name, "status", "Completed") frappe.db.set_value("Integration Request", doc.name, "status", "Completed")
@@ -212,7 +223,6 @@ def get_checkout_url(**kwargs):
success=False, success=False,
http_status_code=frappe.ValidationError.http_status_code) http_status_code=frappe.ValidationError.http_status_code)



@frappe.whitelist() @frappe.whitelist()
def get_service_details(): def get_service_details():
return """ return """


+ 9
- 1
payments/templates/pages/razorpay_checkout.py Bestand weergeven

@@ -14,7 +14,7 @@ expected_keys = ('amount', 'title', 'description', 'reference_doctype', 'referen


def get_context(context): def get_context(context):
context.no_cache = 1 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 # all these keys exist in form_dict
if not (set(expected_keys) - set(frappe.form_dict.keys())): 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 frappe.local.flags.redirect_location = frappe.local.response.location
raise frappe.Redirect 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) @frappe.whitelist(allow_guest=True)
def make_payment(razorpay_payment_id, options, reference_doctype, reference_docname): def make_payment(razorpay_payment_id, options, reference_doctype, reference_docname):
data = {} data = {}


Laden…
Annuleren
Opslaan