Skip to content

feat: Add paypal #2223

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Aug 23, 2019
Merged

feat: Add paypal #2223

merged 1 commit into from
Aug 23, 2019

Conversation

anhanh11001
Copy link
Contributor

@anhanh11001 anhanh11001 commented Aug 1, 2019

Fixes #333
Fixes #1813

Screenshots

Additional Context
Waiting for fossasia/open-event-server#6297 to be merged, another PR will be made and open to send verification to the server before confirming orders

@liveHarshit
Copy link
Member

PR is the same as #1813 What about the server-side confirmation?

@anhanh11001 anhanh11001 changed the title WIP - feat: Add paypal configuration WIP - feat: Add paypal Aug 1, 2019
@anhanh11001
Copy link
Contributor Author

anhanh11001 commented Aug 1, 2019

@liveHarshit still looking for documentation, this is an example for server-side integration but it is not fully enough for me: https://gist.github.com/tomwhipple/62075b4eb9abca1129cf

Gist
Verify a PayPal immediate payment in sandbox. GitHub Gist: instantly share code, notes, and snippets.

@liveHarshit
Copy link
Member

liveHarshit commented Aug 1, 2019

@liveHarshit still looking for documentation, this is an example for server-side integration but it is not fully enough for me: https://gist.github.com/tomwhipple/62075b4eb9abca1129cf

Gist**Verify a PayPal immediate payment in sandbox**Verify a PayPal immediate payment in sandbox. GitHub Gist: instantly share code, notes, and snippets.

Here I can see that -

"payer": {
        "payment_method": "paypal", 
        "status": "VERIFIED", 
        "payer_info": {
            "first_name": "tom", 
            "last_name": "whipple", 
            "email": "twhipple-consumer@paypal.com", 
            "payer_id": "CBQG8NAHWQ3GE"
        }
    }, 

payer id is from server side response. But we want is to charge the payment according to our server implementation.

Gist
Verify a PayPal immediate payment in sandbox. GitHub Gist: instantly share code, notes, and snippets.

@anhanh11001
Copy link
Contributor Author

anhanh11001 commented Aug 1, 2019

Actually I just found a better documentation. We'll handle all the payment in the client side by the SDK and then only send the payment confirmation to the server, the server will check whether payment is confirmed or not like here: https://github.com/paypal/PayPal-Python-SDK/tree/master/samples/mobile_backend

GitHub
Python SDK for PayPal RESTful APIs. Contribute to paypal/PayPal-Python-SDK development by creating an account on GitHub.

@liveHarshit
Copy link
Member

send the payment confirmation to the server,

What information do we need to send on the server?

@anhanh11001
Copy link
Contributor Author

only the payment id and then the server will search for that payment based on the payment ID. After that, server will check whether payment is already successful, if it is then it will send OK response to the Android so that Android app can proceed finishing order

@anhanh11001
Copy link
Contributor Author

anhanh11001 commented Aug 1, 2019

I think verify_payment function in here https://github.com/paypal/PayPal-Python-SDK/blob/master/samples/mobile_backend/paypal_client.py#L37 is what I have been looking for

GitHub
Python SDK for PayPal RESTful APIs. Contribute to paypal/PayPal-Python-SDK development by creating an account on GitHub.

@liveHarshit
Copy link
Member

only the payment id and then the server will search for that payment based on the payment ID. After that, server will check whether payment is already successful, if it is then it will send OK response to the Android so that Android app can proceed finishing order

Oh, that's nice. So for this server-side configuration is required. ✌️

@liveHarshit
Copy link
Member

liveHarshit commented Aug 2, 2019

I think verify_payment function in here https://github.com/paypal/PayPal-Python-SDK/blob/master/samples/mobile_backend/paypal_client.py#L37 is what I have been looking for

GitHub**paypal/PayPal-Python-SDK**Python SDK for PayPal RESTful APIs. Contribute to paypal/PayPal-Python-SDK development by creating an account on GitHub.

Okay, so this configuration is required for issue fossasia/open-event-server#5961

GitHub
Python SDK for PayPal RESTful APIs. Contribute to paypal/PayPal-Python-SDK development by creating an account on GitHub.

@liveHarshit liveHarshit added feature on hold: server side Needs to solve on the server first labels Aug 10, 2019
@anhanh11001 anhanh11001 changed the title WIP - feat: Add paypal feat: Add paypal Aug 11, 2019
@anhanh11001 anhanh11001 removed the on hold: server side Needs to solve on the server first label Aug 11, 2019
@liveHarshit
Copy link
Member

Let's wait for the server PR to be merged, so that I can also test it.

@liveHarshit
Copy link
Member

Screenshots

Is it with the sandbox or live?

@anhanh11001
Copy link
Contributor Author

anhanh11001 commented Aug 11, 2019

sandbox @liveHarshit

@liveHarshit
Copy link
Member

@iamareebjamal Can I get PayPal live client id to test it?

@iamareebjamal
Copy link
Member

Test with sandbox first.

@iamareebjamal
Copy link
Member

Live won't even work as it is not gone to production

@liveHarshit
Copy link
Member

liveHarshit commented Aug 18, 2019

Test with sandbox first.

Then it needs to enable on dev instance with the same sandbox client id as stripe.
@anhanh11001 Please share the working sandbox client id and registered sandbox account with the client id.

@anhanh11001
Copy link
Contributor Author

anhanh11001 commented Aug 18, 2019

@iamareebjamal I got 404 HTTP error for https://open-event-api-dev.herokuapp.com/v1/orders/e185e6d1-0d63-4a03-8dad-440fe6b8063d/verify-mobile-paypal-payment . Before that, the server PR was working fine locally for me on Postman. It is already in the debug server right?

@anhanh11001
Copy link
Contributor Author

@liveHarshit You can try client ID: "AXrRge-gN1E5WHMYsu0FsftPOWBjTu3Sqj0pKfpq7mPKwv6w_ikiqWrka_06lAWZW5_WxL9CwaMiTVsc"

and Paypal email is letrananhduc0311-facilitator@gmail.com

@liveHarshit
Copy link
Member

liveHarshit commented Aug 18, 2019

@iamareebjamal I got 404 HTTP error for https://open-event-api-dev.herokuapp.com/v1/orders/e185e6d1-0d63-4a03-8dad-440fe6b8063d/verify-mobile-paypal-payment . Before that, the server PR was working fine locally for me on Postman. It is already in the debug server right?

404 Not Found

But it needs to unable on the server with the same client id, i think.

@iamareebjamal
Copy link
Member

Try now @anhanh11001

@anhanh11001
Copy link
Contributor Author

@iamareebjamal Got this error
paypalrestsdk.exceptions.MissingConfig: Required PAYPAL_CLIENT_ID and PAYPAL_CLIENT_SECRET. Please enable paypal client ID and secret in debug server

@iamareebjamal
Copy link
Member

iamareebjamal commented Aug 18, 2019

Give the keys to me in private channel or you want keys from FOSSASIA sandbox?

@liveHarshit
Copy link
Member

Give the keys to me in private channel or you want keys from FOSSASIA sandbox?

We can use

AXrRge-gN1E5WHMYsu0FsftPOWBjTu3Sqj0pKfpq7mPKwv6w_ikiqWrka_06lAWZW5_WxL9CwaMiTVsc

@iamareebjamal
Copy link
Member

Give me the client secret for that in private chat

@liveHarshit
Copy link
Member

Paypal email is letrananhduc0311-facilitator@gmail.com

Also please share its password with me.

@liveHarshit
Copy link
Member

Give me the client secret for that in private chat

Please enable PayPal for debug instance

@iamareebjamal
Copy link
Member

I asked a question to Duc about sandbox or live 2 days ago. Got the reply today

@iamareebjamal
Copy link
Member

Added

@anhanh11001
Copy link
Contributor Author

I still have the same problem of paypalrestsdk.exceptions.MissingConfig: Required PAYPAL_CLIENT_ID and PAYPAL_CLIENT_SECRET. Can you check whether it is deployed or not ?

@iamareebjamal
Copy link
Member

Yes, it is set up in sandbox mode. If you want, I can change it to live mode but I doubt it'll work

@anhanh11001
Copy link
Contributor Author

Here is the log

D/OkHttp: <-- 500 INTERNAL SERVER ERROR https://open-event-api-dev.herokuapp.com/v1/orders/ebb8edff-e67b-4dc6-b377-9ec33e2bcc65/verify-mobile-paypal-payment (322ms)
    Connection: close
    Content-Type: text/html; charset=utf-8
    X-Xss-Protection: 0
    Server: Werkzeug/0.15.4 Python/3.6.5
    Date: Wed, 21 Aug 2019 05:03:21 GMT
    Via: 1.1 vegur
paypalrestsdk.exceptions.MissingConfig
paypalrestsdk.exceptions.MissingConfig: Required PAYPAL_CLIENT_ID and PAYPAL_CLIENT_SECRET. Refer https://github.com/paypal/rest-api-sdk-python#configuration

Traceback (most recent call last)
File "/app/.heroku/python/lib/python3.6/os.py", line 666, in __getitem__
        self.unsetenv = unsetenv
        self._data = data
 
    def __getitem__(self, key):
        try:
            value = self._data[self.encodekey(key)]
        except KeyError:
            # raise KeyError with the original key value
            raise KeyError(key) from None
        return self.decodevalue(value)
 
During handling of the above exception, another exception occurred:
File "/app/.heroku/python/lib/python3.6/site-packages/paypalrestsdk/api.py", line 314, in default
    By default points to developer sandbox
    """
    global __api__
    if __api__ is None:
        try:
            client_id = os.environ["PAYPAL_CLIENT_ID"]
            client_secret = os.environ["PAYPAL_CLIENT_SECRET"]
        except KeyError:
            raise exceptions.MissingConfig("Required PAYPAL_CLIENT_ID and PAYPAL_CLIENT_SECRET. \
                Refer https://github.com/paypal/rest-api-sdk-python#configuration")
 
D/OkHttp:
File "/app/.heroku/python/lib/python3.6/os.py", line 669, in __getitem__
    def __getitem__(self, key):
        try:
            value = self._data[self.encodekey(key)]
        except KeyError:
            # raise KeyError with the original key value
            raise KeyError(key) from None
        return self.decodevalue(value)
 
    def __setitem__(self, key, value):
        key = self.encodekey(key)
        value = self.encodevalue(value)
During handling of the above exception, another exception occurred:
File "/app/.heroku/python/lib/python3.6/site-packages/sentry_sdk/integrations/flask.py", line 69, in sentry_patched_wsgi_app
            # type: (Any, Dict[str, str], Callable) -> _ScopedResponse
            if Hub.current.get_integration(FlaskIntegration) is None:
                return old_app(self, environ, start_response)
 
            return SentryWsgiMiddleware(lambda *a, **kw: old_app(self, *a, **kw))(
                environ, start_response
            )
 
        Flask.__call__ = sentry_patched_wsgi_app  # type: ignore
 
 
File "/app/.heroku/python/lib/python3.6/site-packages/sentry_sdk/integrations/wsgi.py", line 106, in __call__
                    rv = self.app(
                        environ,
                        functools.partial(_sentry_start_response, start_response, span),
                    )
                except BaseException:
                    reraise(*_capture_exception(hub))
 
        return _ScopedResponse(hub, rv)
 
 
def _sentry_start_response(
File "/app/.heroku/python/lib/python3.6/site-packages/sentry_sdk/_compat.py", D/OkHttp: line 54, in reraise
    def reraise(tp, value, tb=None):
        # type: (Optional[Type[BaseException]], Optional[BaseException], Optional[Any]) -> None
        assert value is not None
        if value.__traceback__ is not tb:
            raise value.with_traceback(tb)
        raise value
 
 
def with_metaclass(meta, *bases):
    class metaclass(type):
        def __new__(cls, name, this_bases, d):
File "/app/.heroku/python/lib/python3.6/site-packages/sentry_sdk/integrations/wsgi.py", line 103, in __call__
 
            with hub.start_span(span) as span:
                try:
                    rv = self.app(
                        environ,
                        functools.partial(_sentry_start_response, start_response, span),
                    )
                except BaseException:
                    reraise(*_capture_exception(hub))
 
        return _ScopedResponse(hub, rv)
File "/app/.heroku/python/lib/python3.6/site-packages/sentry_sdk/integrations/flask.py", line 68, in <lambda>
        def sentry_patched_wsgi_app(self, environ, start_response):
            # type: (Any, Dict[str, str], Callable) -> _ScopedResponse
            if Hub.current.get_integration(FlaskIntegration) is None:
                return old_app(self, environ, start_response)
 
            return SentryWsgiMiddleware(lambda *a, **kw: old_app(self, *a, **kw))(
                environ, start_response
            )
 
        Flask.__call__ = sentry_patched_wsgi_app  # type: ignore
 
File "/app/.heroku/python/lib/python3.6/site-packages/flask/app.py", line 2463, D/OkHttp: in __call__
 
    def __call__(self, environ, start_response):
        """The WSGI server calls the Flask application object as the
        WSGI application. This calls :meth:`wsgi_app` which can be
        wrapped to applying middleware."""
        return self.wsgi_app(environ, start_response)
 
    def __repr__(self):
        return "<%s %r>" % (self.__class__.__name__, self.name)
File "/app/app/__init__.py", line 72, in __call__
        scheme = environ.get('HTTP_X_FORWARDED_PROTO')
        if scheme:
            environ['wsgi.url_scheme'] = scheme
        if os.getenv('FORCE_SSL', 'no') == 'yes':
            environ['wsgi.url_scheme'] = 'https'
        return self.app(environ, start_response)
 
 
app.wsgi_app = ReverseProxied(app.wsgi_app)
 
app_created = False
File "/app/.heroku/python/lib/python3.6/site-packages/flask/app.py", line 2449, in wsgi_app
            try:
                ctx.push()
                response = self.full_dispatch_request()
            except Exception as e:
                error = e
                response = self.handle_exception(e)
            except:  # noqa: B001
                error = sys.exc_info()[1]
                raise
            return response(environ, start_response)
        finally:
File "/app/.heroku/python/lib/python3.6/site-packages/flask_cors/extension.py", line 161, in wrapped_function
        # Wrap exception handlers with cross_origin
        # These error handlers will still respect the behavior of the route
        if options.get('intercept_exceptions', True):
            def _after_request_decorator(f):
                def wrapped_function(*args, **kwargs):
D/OkHttp:
                    return cors_after_request(app.make_response(f(*args, **kwargs)))
                return wrapped_function
 
            if hasattr(app, 'handle_exception'):
                app.handle_exception = _after_request_decorator(
                    app.handle_exception)
File "/app/.heroku/python/lib/python3.6/site-packages/flask_cors/extension.py", line 161, in wrapped_function
        # Wrap exception handlers with cross_origin
        # These error handlers will still respect the behavior of the route
        if options.get('intercept_exceptions', True):
            def _after_request_decorator(f):
                def wrapped_function(*args, **kwargs):
                    return cors_after_request(app.make_response(f(*args, **kwargs)))
                return wrapped_function
 
            if hasattr(app, 'handle_exception'):
                app.handle_exception = _after_request_decorator(
                    app.handle_exception)
File "/app/.heroku/python/lib/python3.6/site-packages/flask/app.py", line 1866, in handle_exception
            # if we want to repropagate the exception, we can attempt to
            # raise it with the whole traceback in case we can do that
            # (the function was actually called from the except part)
            # otherwise, we just raise the error again
            if exc_value is e:
                reraise(exc_type, exc_value, tb)
            else:
                raise e
 
        self.log_exception((exc_type, exc_value, tb))
        server_error = InternalServerError()
File "/app/.heroku/python/lib/python3.6/site-packages/flask/_compat.py", line 39, in reraise
    import collections.abc as collections_abc
 
    def reraise(tp, value, tb=None):
D/OkHttp:
 
D/OkHttp:
        return self.view_functions[rule.endpoint](**req.view_args)
 
    def full_dispatch_request(self):
        """Dispatches the request and on top of that performs request
        pre and postprocessing as well as HTTP exception catching and
        error handling.
    @wraps(fn)
        verify_jwt_in_request()
        current_user.last_accessed_at = datetime.utcnow()
        save_to_db(current_user)
        return fn(*args, **kwargs)
D/OkHttp:
File "/app/app/api/helpers/payment.py", line 213, in verify_payment
    def verify_payment(payment_id, order):
KeyError: 'PAYPAL_CLIENT_ID'
    During handling of the above exception, another exception occurred:
    Traceback (most recent call last):
      File "/app/.heroku/python/lib/python3.6/site-packages/sentry_sdk/integrations/flask.py", line 69, in sentry_patched_wsgi_app
        environ, start_response
      File "/app/.heroku/python/lib/python3.6/site-packages/sentry_sdk/integrations/wsgi.py", line 106, in __call__
        reraise(*_capture_exception(hub))
      File "/app/.heroku/python/lib/python3.6/site-packages/sentry_sdk/_compat.py", line 54, in reraise
        raise value
      File "/app/.heroku/python/lib/python3.6/site-packages/sentry_sdk/integrations/wsgi.py", line 103, in __call__
        functools.partial(_sentry_start_response, start_response, span),
      File "/app/.heroku/python/lib/python3.6/site-packages/sentry_sdk/integrations/flask.py", line 68, in <lambda>
        return SentryWsgiMiddleware(lambda *a, **kw: old_app(self, *a, **kw))(
      File "/app/.heroku/python/lib/python3.6/site-packages/flask/app.py", line 2463, in __call__
        return self.wsgi_app(environ, start_response)
      File "/app/app/__init__.py", line 72, in __call__
        return self.app(environ, start_response)
      File "/app/.heroku/python/lib/python3.6/site-packages/flask/app.py", line 2449, in wsgi_app
        response = self.handle_exception(e)
      File "/app/.heroku/python/lib/python3.6/site-packages/flask_cors/extension.py", line 161, in wrapped_function
        return cors_after_request(app.make_response(f(*args, **kwargs)))

@iamareebjamal
Copy link
Member

I have changed it to live credentials. Test now. If not working, please raise issue on server

@anhanh11001
Copy link
Contributor Author

Yes, it is not working as well and doesn't provide any logs. What should be the problem raised in the server?

@iamareebjamal
Copy link
Member

#2223 (comment)

@iamareebjamal
Copy link
Member

Does not give any log? What's the response?

@iamareebjamal
Copy link
Member

I have restarted the server. Try one time more

@anhanh11001
Copy link
Contributor Author

anhanh11001 commented Aug 21, 2019

oh I think I got the problem, I didn't put the function to configPaypal() in the verifyPayment() method. But when I test, I didn't know where to put the CLIENT_ID and SECRET so I put it directly to the path where the path logs direct me, that's probably why.

Opening server issue and solving now. Sorry

@liveHarshit
Copy link
Member

Is it working now?

@anhanh11001
Copy link
Contributor Author

@liveHarshit still having some small mistake, sorry, it is so annoying, I forgot to push the change

@anhanh11001
Copy link
Contributor Author

In Order, when formatting to Json, isBillingEnabled turn into "billing_enabled", not "is_billing_enabled". How should I fix this?

@iamareebjamal
Copy link
Member

iamareebjamal commented Aug 23, 2019

Add @JsonProperty annotation

@liveHarshit
Copy link
Member

liveHarshit commented Aug 23, 2019

In Order, when formatting to Json, isBillingEnabled turn into "billing_enabled", not "is_billing_enabled". How should I fix this?

Use @get:JsonProperty("is-billing-enabled")

@anhanh11001
Copy link
Contributor Author

tested and working for normal payment. This is just a general implementation, I will open more issues on different currency problems like billing address in US requires state location or Japanese,.. currency should not contain fractional part

@iamareebjamal iamareebjamal merged commit 968eda8 into fossasia:development Aug 23, 2019
@anhanh11001 anhanh11001 deleted the 333_paypal branch August 24, 2019 00:18
@aggarwalpulkit596
Copy link
Contributor

@anhanh11001 how to check PayPal integration in debug mode?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

Successfully merging this pull request may close these issues.

add paypal
4 participants