Great write-up Jeremy, thanks a lot for sharing that.

The art rebellion site looks great too!


On Wed, Apr 16, 2014 at 10:27 AM, Jeremy Epstein <[email protected]>wrote:

> I've published a more detailed write-up of the process I went through,
> you can find it here:
>
>
> http://greenash.net.au/thoughts/2014/03/using-paypal-wps-with-cartridge-mezzanine-django/
>
> Luc, looking forward to reading more details about how you went about
> it too. And I'm sure other devs would also appreciate it - then
> they'll have several options to choose from, for implementing PayPal
> WPS with Cartridge.
>
> I think that both approaches have their disadvantages. With mine,
> there's code repetition - I copied the code from Cartridge's order
> complete method and modified it. With yours, Luc, there's a fake
> request object being used.
>
> Ideally, the architecture of Cartridge's order completion system will
> be modified for the better, such that (a) it can be called easily from
> an external code snippet like a PayPal IPN callback, and (b) it's
> de-coupled from the request, and there's no need to use a fake request
> object. That way, both of our hacks / solutions will become
> unnecessary.
>
> Cheers,
> Jeremy.
>
> On Mon, Jan 27, 2014 at 6:49 PM, Luc Milland <[email protected]> wrote:
> > Hello,
> > awesome, I eventually ended with something *very* similar.
> > I was planning to expose my solution after the shop I am working on is
> > finished (I am very late on this project).
> > I made a lot of other changes and will have some suggestion to improve
> > Cartridge.
> >
> > Regarding, the external payment stuff, we basically made the *same
> > thing* : using signal in my_app/models.py, retrieve order through ipn
> > stuff (I used order_uuid alone since I don't really now if it's a good
> > idea to let session keys travel through requests) and close the order.
> > to close the order, I did not mimic order.complete() code, but I call
> > the original code through a fake request. It's something like :
> >
> > fake_request = HttpRequest()
> > fake_request.session = session
> > fake_request.cart = cart
> > order.complete(fake_request)
> > session.save()
> >
> > I tried to implement some kind of IPN order status handling to complete
> > order only when status == "Completed" and not "Pending", and to trap
> > error to (for now, any other IPN status than completed or pending leads
> > to cancel the order).
> >
> > E-mails are sent on order complete or cancel.
> >
> > Besides, I use signals on order status transitions to have mail sent
> > automatically.
> >
> > Finally, I wrote a little app to handle shipping services but I will
> > expose this later, since it's a whole subject and would require some
> > more code to be really usefull (basically, I would need another checkout
> > step to handle shipping service choice).
> > This is called ponyexpress and it allows to define shipping services
> > through admin. Each shipping service is associated to destination zones
> > (countries, for now) which are bound to price ranges depending on
> > weight.
> > Adding a weight field to ProductVariation then allow to calculate
> > shipping cost automatically for the chosen service, depending on
> > customer country.
> > While no order is made, the customer country is guessed from IP so an
> > estimated shipping cost can be provided in the shopping cart.
> > I find this pretty cool :)
> >
> > I will publish this code and discuss it as soon as I have finish the
> > shop I am working on.
> >
> > hope that will help too !
> >
> > Luc
> >
> > Le dimanche 26 janvier 2014 à 19:04 -0800, Jeremy Epstein a écrit :
> >> Hi,
> >>
> >> I've just finished building a site powered by Mezzanine / Cartridge, and
> >> I've managed to integrate it with PayPal WPS (i.e. after completing
> >> checkout, user is redirected to PayPal for payment, no SSL cert needed
> on
> >> the site).
> >>
> >> I'm going to do a more detailed write-up when I get the chance - but for
> >> now, here's roughly what I did to cover the all-import "final missing
> step"
> >> that's being discussed in this thread:
> >>
> >> 1. Install cartridge-payments and django-paypal, make sure they're
> enabled:
> >>
> >> INSTALLED_APPS = [
> >>     # ...
> >>     "payments.multipayments",
> >>     "paypal.standard.ipn",
> >>     # ...
> >> ]
> >>
> >> (follow other steps in the install instructions for these apps, I'm not
> >> going to go through it all here).
> >>
> >> 2. Make sure you set PAYPAL_IPN_URL as follows:
> >>
> >> PAYPAL_IPN_URL = lambda cart, uuid, order_form:
> >> ('paypal.standard.ipn.views.ipn', None, {})
> >>
> >> 3. Place the following code somewhere in your codebase (per the
> >> django-paypal docs, I placed it in the models.py file for one of my
> apps):
> >>
> >> # ...
> >>
> >> from importlib import import_module
> >>
> >> from mezzanine.conf import settings
> >>
> >> from cartridge.shop.models import Cart, Order, ProductVariation,
> >> DiscountCode
> >> from paypal.standard.ipn.signals import payment_was_successful
> >>
> >> # ...
> >>
> >>
> >> def payment_complete(sender, **kwargs):
> >>     """Performs the same logic as the code in
> >> cartridge.shop.models.Order.complete(), but fetches the session, order,
> and
> >> cart objects from storage, rather than relying on the request object
> being
> >> passed in (which it isn't, since this is triggered on PayPal IPN
> >> callback)."""
> >>
> >>     ipn_obj = sender
> >>
> >>     if ipn_obj.custom and ipn_obj.invoice:
> >>         s_key, cart_pk = ipn_obj.custom.split(',')
> >>         SessionStore =
> import_module(settings.SESSION_ENGINE).SessionStore
> >>         session = SessionStore(s_key)
> >>
> >>         try:
> >>             cart = Cart.objects.get(id=cart_pk)
> >>             try:
> >>                 order =
> Order.objects.get(transaction_id=ipn_obj.invoice)
> >>                 for field in order.session_fields:
> >>                     if field in session:
> >>                         del session[field]
> >>                 try:
> >>                     del session["order"]
> >>                 except KeyError:
> >>                     pass
> >>
> >>                 # Since we're manually changing session data outside of
> >>                 # a normal request, need to force the session object to
> >>                 # save after modifying its data.
> >>                 session.save()
> >>
> >>                 for item in cart:
> >>                     try:
> >>                         variation =
> >> ProductVariation.objects.get(sku=item.sku)
> >>                     except ProductVariation.DoesNotExist:
> >>                         pass
> >>                     else:
> >>                         variation.update_stock(item.quantity * -1)
> >>                         variation.product.actions.purchased()
> >>
> >>                 code = session.get('discount_code')
> >>                 if code:
> >>
> DiscountCode.objects.active().filter(code=code).update(
> >>                         uses_remaining=F('uses_remaining') - 1)
> >>                 cart.delete()
> >>             except Order.DoesNotExist:
> >>                 pass
> >>         except Cart.DoesNotExist:
> >>             pass
> >>
> >> payment_was_successful.connect(payment_complete)
> >>
> >> 4. Apply some hacks to cartridge-payments and django-paypal:
> >>
> >> a) lib/python2.7/site-packages/payments/multipayments/forms/paypal.py
> >> modify per diff at:
> >>
> >>
> https://github.com/django-mezzanine-paypal/cartridge-payments/commit/6446f09832135e10ebae5cf10c573cafd3607b9b
> >>
> >> b) src/django-paypal/paypal/standard/forms.py modify per:
> >>
> >> http://stackoverflow.com/a/16804992/2066849
> >>
> >> I think that's about it - will test more thoroughly and will re-create
> when
> >> I do a better write-up. But basically, with this, the PayPal IPN
> callback
> >> does everything that cartridge.shop.models.Order.complete() would
> usually
> >> do, if it got called (which it doesn't if you're using PayPal WPS, and I
> >> believe also PayPal EC).
> >>
> >> Hope that helps you guys for now.
> >>
> >> Jeremy.
> >>
> >> On Thursday, November 14, 2013 2:08:30 AM UTC+11, Luc Milland wrote:
> >> >
> >> > Hello,
> >> > I am trying to make a shop with cartridge but I don't want to deal
> with
> >> > credit cards.
> >> > That's why I want to use cartridge-payment with Paypal express
> checkout
> >> > (payment part only, if I understand well).
> >> > Using sandbox paypals accounts and cartridge-payment readme, I can
> make
> >> > an order, pay it and be sent back to the shop at
> >> > shop/checkout/complete .
> >> > But there is my problem : the order is registred, but not completed. I
> >> > mean that it looks as the final checkout step did not apply (I guess
> it
> >> > is because the checkout form is sent to paypal and to our good old
> >> > checkout_step view, right ?) and as order.complete(request) was never
> >> > called.
> >> > As a result, cart is not empty, etc...
> >> > Does anybody had already been there ? Did I miss something ? Is there
> a
> >> > way to jump back in the checkout workflow, maybe with Paypal IPN ?
> >> >
> >> > thanks for your ideas and many thanks to all who build this awesome
> >> > piece of code that mezzanine/cartridge is.
> >> >
> >> > Luc
> >> >
> >> >
> >> On Thursday, November 14, 2013 2:08:30 AM UTC+11, Luc Milland wrote:
> >> >
> >> > Hello,
> >> > I am trying to make a shop with cartridge but I don't want to deal
> with
> >> > credit cards.
> >> > That's why I want to use cartridge-payment with Paypal express
> checkout
> >> > (payment part only, if I understand well).
> >> > Using sandbox paypals accounts and cartridge-payment readme, I can
> make
> >> > an order, pay it and be sent back to the shop at
> >> > shop/checkout/complete .
> >> > But there is my problem : the order is registred, but not completed. I
> >> > mean that it looks as the final checkout step did not apply (I guess
> it
> >> > is because the checkout form is sent to paypal and to our good old
> >> > checkout_step view, right ?) and as order.complete(request) was never
> >> > called.
> >> > As a result, cart is not empty, etc...
> >> > Does anybody had already been there ? Did I miss something ? Is there
> a
> >> > way to jump back in the checkout workflow, maybe with Paypal IPN ?
> >> >
> >> > thanks for your ideas and many thanks to all who build this awesome
> >> > piece of code that mezzanine/cartridge is.
> >> >
> >> > Luc
> >> >
> >> >
> >>
> >
> >
> > --
> > You received this message because you are subscribed to a topic in the
> Google Groups "Mezzanine Users" group.
> > To unsubscribe from this topic, visit
> https://groups.google.com/d/topic/mezzanine-users/n2d6SODIF1o/unsubscribe.
> > To unsubscribe from this group and all its topics, send an email to
> [email protected].
> > For more options, visit https://groups.google.com/groups/opt_out.
>
> --
> You received this message because you are subscribed to the Google Groups
> "Mezzanine Users" group.
> To unsubscribe from this group and stop receiving emails from it, send an
> email to [email protected].
> For more options, visit https://groups.google.com/d/optout.
>



-- 
Stephen McDonald
http://jupo.org

-- 
You received this message because you are subscribed to the Google Groups 
"Mezzanine Users" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to [email protected].
For more options, visit https://groups.google.com/d/optout.

Reply via email to