|
View:
New views
8 Messages
—
Rating Filter:
Alert me
|
|
|
overrides, chaos, and multiplepaymentprocessorsAs Michael suggested last week, I have studied how all of the payment processors besides Google Checkout integrate with GetPaid; Michael, it was a great suggestion! And, thanks to guidance which Christopher Johnson provided when we talked on Friday, I have also read through the various branches in GetPaid labeled "multiplepaymentprocessors". (USABILITY PEOPLE: You can skip down to the "Big Questions That I Need Feedback On" section farther down if you want to skip the technical discussion.) As a result, I now have a more complete picture of how the various GetPaid payment processors are designed. To keep things straight, I sketched out this rough diagram in Inkscape this afternoon: http://rhodesmill.org/brandon/static/2009/getpaid-overrides.png Red text in the diagram indicates the presence of a ZCML override of some sort. Note that I have left out extra steps that might be present in the wizard, like shipping options; when present, such steps would sit between the "Address Info" and the "Review & Pay" pages in the diagram. Payment Processors, and How They Work ------------------------------------- Taking the diagram from top to bottom: * Google Checkout: The payment processor provides its own copies of the shopping cart view and shopping cart portlet, so that it can draw a pretty "Google Checkout" button on each of them. The buttons point at a view named "/google-checkout" on the Plone site, which has no associated template but instead redirects directly to Google itself. OPEN QUESTION: It is not clear to me why the checkout buttons do not point at Google directly instead of going through the extra view, but I see Google Analytics parameters being constructed on the way that might have something to do with it. * ClickandBuy / PagSeguro: These both provide their own @@getpaid-checkout-wizard view that removes all of the normal functionality, and shows a big button that, when pushed, sends the user to an off-site checkout process. OPEN QUESTION: This approach competes directly with the Google Checkout approach. Which is better: providing a special checkout button for "Checkout"? Or, letting them visit our normal checkout URL then asking them to click off-site? The former requires one less click from the user; the latter gives them a bit more warning that they are leaving. Should we rewrite all three payment processors to use a common approach, and then provide an admin config option for whether a store owner wants the extra "Click here to checkout" step added or not? * PayPal: This also provides its own @@getpaid-checkout-wizard, but the view simply does an immediate redirect to PayPal. OPEN QUESTION: Like with Google Checkout, the question is, why? Because it was easier than overriding the "Checkout" buttons? Or because the extra step lets a few last variables and parameters be put into place before the customer arrives at PayPal? * Luottokunta / Verkkomaksut: These processors only change the last step of the default checkout wizard. They simply provide an alternate form for the last view, named @@checkout-review-pay, that asks for some fields that their particular payment processors need to operate. * Ogone / PxPay: These payment processors do a good deal more violence than the previous two we looked at. Like them, they let most of the checkout wizard views complete their job, and then just override the final @@checkout-review-pay page. But instead of presenting a slightly adjusted form, they actually redirect the user away from the Plone site altogether, so the customer's credit card information can be entered on the remote site. OPEN QUESTION: Why do I call these two more "violent"? I think it's because of how painfully they abuse the idea of an IPaymentProcessor. Instead of simply dropping the idea altogether and performing their redirects directly - which is what a view is for, right? - these two payment processors have their @@checkout-review-pay views call the authorize() method of a PaymentProcessor object that then - I warned you that this was painful, right? - performs the redirect itself! They put, in other words, view logic inside of an interface that's supposed to process a credit card and return an actual result. * nullpayment / AuthorizeDotNet / PayFlowPro / PaymentTech These are the well-behaved payment processors that actually work as GetPaid intended. Note the happy lack of red text from their area of the diagram! They accept payment information and try to get the payment processed, and leave it up to the PloneGetPaid views to report back to the user whether their purchase worked. So, there you have it! No fewer than six separate techniques are used in GetPaid payment processors for what are really amounts to four separate situations: 1. Off-site processors that provide their own checkout wizards (Google Checkout, ClickandBuy, PagSeguro, PayPal) 2. Off-site processors that let Plone collect the shipping info (Ogone, PxPay) 3. Normal payment processors that need a few payment fields adjusted (Luottokunta, Verkkomaksut) 4. Normal payment processors that can use the default payment page (nullpayment, AuthorizeDotNet, PayFlowPro, PaymentTech) So, what about the "multiplepaymentprocessors" work? Multiple Payment Processors --------------------------- The "multiple payment processors" branches seem focused on processor categories 3 and 4, as given in the above list: the processors that require GetPaid to ask for the credit card number on-site. For these, it introduces a new registration system. Instead of simply registering themselves as providing IPaymentProcessor, these new-style payment processors would have to actually use a custom ZCML registration that looks like: <paymentprocessors:registerProcessor name="..." i18n_name="..." selection_view="..." review_pay_view="..." thank_you_view="..." settings_view="..." /> The basic idea here is that many payment processors can register themselves this way. The store owner will be shown all of them on his Site Setup page, and be asked which he wants to use. If he only selects one, then that is the one that users are sent to directly. But if he selects several, then a new @@checkout-payment-method step is placed before the final @@checkout-review-pay step, and the user is shown a pretty button for each available checkout method (that's what the "selection_view" shown above is for), and has to select one. And the final checkout form, when they get there, can be possibly customized to have extra or different fields from the normal one. That seems to be what the "review_pay_view" means in the registration example above: it's a way, without an override, for a payment processor like Luottokunta or Verkkomaksut to adjust what the final view contains. I am not sure what I think about special ZCML declarations; it seems to me like the same information could be provided much more simply through the adapter-registration mechanism we already use, and that class properties with names like "thank_you_view" and "settings_view" would do a fine job of pointing at the views that the payment processor wanted to provide, without needing any ZCML. But that's probably my Grok background showing through, and maybe there are view configurations done behind the scenes here that I've not studied yet. What does everyone think? If something can be done simply enough in code, should ZCML be used or not? Either way, it looks to me like the "multiplepaymentprocessors" work is a great candidate for getting rid of the overrides required by category 3 payment processors, as given above, and for letting users choose their favorite payment processor when it's okay with the site owner. That, of course, just leaves categories 1 and 2 as problems. Handling Off-Site Checkout Wizards ---------------------------------- Right now, the series of steps that the on-site checkout wizard supports seems kind of hard-coded; in the "CheckoutController" it says (in the new "multiplepaymentprocessors" branch): steps = ['checkout-address-info', 'checkout-select-shipping', 'checkout-payment-method', 'checkout-review-pay'] What if this list was something built dynamically? What if the default was something like a series of views like this: 100 'checkout-address-info' 200 'checkout-select-shipping' 300 'checkout-payment-method' 400 'checkout-review-pay' where plug-ins could provide steps of their own, like: 150 'checkout-shipping-company' Maybe inequality invariants would be better than static numbers; but static numbers work pretty well for the Ubuntu package managers who build all those /etc directories, I'll note. But whichever way we established order among the steps, the act of building the list dynamically could have several advantages. One of them would be that none of the remaining payment processor types would need overrides! "ClickandBuy", for example, could just say: 050 'checkout-clickandbuy-button' and the view that shows the "Check out at ClickandBuy" button would show up in front of the user before anything else in the wizard - and then the button could take them far away and not return them, meaning they wouldn't encounter any of the rest of the wizard. This could handle Google Checkout, ClickandBuy, PagSeguro, *and* PayPal, *if* we were willing to tell the people using Google Checkout and PayPal that they have to use a you're-leaving-the-site splash screen like ClickandBuy and PagSeguro. Actually, maybe that wouldn't be necessary; maybe they could provide a set of "redirect" views that could be dropped in place if the store owner opted not to have a two-click process where one would work: 050 'checkout-paypal-redirect' Processors like Ogone and PxPay would put their redirect (or leaving-this-site click-this-button) page later in the process, after the shipping information has been collected: 350 'checkout-pxpay-redirect' The one thing that such a pluggable-pages scheme would *not* fix is the situation, like the Google Checkout design today, where the "Checkout" buttons on the shopping cart view and shopping cart portlet both need to be re-drawn to "look like" the checkout buttons for the selected payment processor. If we want to support that, then we need to do work "outside" the standard wizard, like the work I announced last week that I did experimentally in my "brandon-no-overrides" buildout: we need those buttons to become views that payment processors can override. Big Questions That I Need Feedback On ------------------------------------- The big outstanding questions I have right now are: * It's neat for users to be able to choose among payment processors like AuthorizeDotNet and PayFlowPro, that both plug in right at the end of the normal checkout wizard. But what about off-site services that provide their own wizards, like Google Checkout? Should users be able to choose between Google Checkout and AuthorizeDotNet? I would *love* for this to be answered as a usability question, *not* a technical one; a good design is possible here either way we answer the question. The usability question that is raised is this: the choice between AuthorizeDotNet and PayFlowPro can be asked right at the end of the wizard, before the credit card information is demanded. But the choice given to the user between using Google Checkout and AuthorizeDotNet would have to be asked immediately, before the first normal page of the wizard was even shown. Should users in a multiple-payment-processors situation (a) *always* be asked which they want to use *before* entering the wizard, or (b) should the question "float" so that it's asked right before it becomes important, but otherwise as late as possible, so that it's asked before the other wizard steps if, say, Google Checkout is one of the options, but late in the process if it's just AuthorizeDotNet and PayFlowPro? I'd love to do (b) because it seems the "real answer" that, if done right, lets store owners give users the maximum amount of choice when it's what's wanted. But I'm open to counter-arguments. * Again, a usability question: do store owners deserve the right to avoid a "click here" screen by having the cart "Checkout" button say "Check out with Google Checkout" and go right there? Conversely: should every off-site processor support, if the store owner wants it, a separate "click here to leave" screen that follows the normal "Checkout" button instead of subverting it? I think this answer should probably be "yes", and I think a reasonable design will result. Let me know if this matches what other people want; you guys have used this a lot more than I have! * I assume that users partway through the checkout process with PayFlowPro should be able to back up and re-start with Google Checkout if they suddenly realize that's what they want to do? IF the above usability questions are answered like I expect, then I might have to rescind the distinction that I tried to draw in my "brandon-no-overrides" experiment between Wizards and Processors, because that would create an ugly situation where users whose store owners had been very liberal would have to *first* choose their Wizard, *then* choose their back-end Payment Processor if they choose the built-in Wizard; or an ugly combined form would have to be created. I would like to avoid either of these situations! If we decide we want true flexibility here, then I think we need to abandon my "Wizard" concept and just talk about "Payment Processors that redirect the user somewhere else" versus "Payment Processors that let GetPaid do most of the work, then just verify the credit card." Apologies For Stuff I've Gotten Wrong ------------------------------------- Today was my first time looking at most of these payment processors, and I've probably gotten a bit mixed up about how some of them work. If you find I've misunderstood anything above, then just reply and point out how this first impression of my differs from the reality. I want to make sure that all reasonable payment processor designs become easy as we re-factor how they are registered and deployed! Next Steps ---------- As usual, given the size of this email and the questions it asks, I'll wait a day or two so that people have time to digest it and respond. Then, unless the responses really surprise me and merit debate and discussion, I think my next step will be to try inventing and documenting - but maybe not implementing until I get feedback on the draft documentation? - a straightforward registration scheme that supports all the kinds of payment processor we've got. I'll call the draft "How to Write a Payment Processor", with the idea that we focus on exactly that: what will payment processors look like to the person who's *writing* them, in a way that's flexible enough to support the whole spectrum of techniques we've listed above. Then it'll be a simple matter of adjusting the GetPaid core, the Plone Product, and the various change processors to match the new standard. :-) -- Brandon Craig Rhodes brandon@... http://rhodesmill.org/brandon --~--~---------~--~----~------------~-------~--~----~ You received this message because you are subscribed to the Google Groups "getpaid-dev" group. To post to this group, send email to getpaid-dev@... To unsubscribe from this group, send email to getpaid-dev+unsubscribe@... For more options, visit this group at http://groups.google.com/group/getpaid-dev?hl=en -~----------~----~----~----~------~----~------~--~--- |
|
|
Re: overrides, chaos, and multiplepaymentprocessorsWow, lots of good info and direction forward. Will try to dive into usability thoughts on processors shortly. For now, just one usability issue that seems like it may be a proper place to address in the refactoring, and that is the use of the name "getpaid" in the URLs of the system. I see you are suggesting a replacement view of the checkout wizard, and it seems like a good opportunity to rename it to just @@checkout-wizard (dropping the getpaid). As some people have mentioned, it's really unnecessary to name the product in the ecommerce functionality...
Thanks for the great work on this! Best, Chris On Wed, Aug 26, 2009 at 3:36 AM, Mikko Ohtamaa <mikko@...> wrote: Chaos - who wouldn't love that? ;) -- Cofounder and CEO ifPeople - Innovation for People www.ifpeople.net t: 678-608-3408 130 Boulevard NE, #6 Atlanta, GA 30312 --~--~---------~--~----~------------~-------~--~----~ You received this message because you are subscribed to the Google Groups "getpaid-dev" group. To post to this group, send email to getpaid-dev@... To unsubscribe from this group, send email to getpaid-dev+unsubscribe@... For more options, visit this group at http://groups.google.com/group/getpaid-dev?hl=en -~----------~----~----~----~------~----~------~--~--- |
|
|
Re: overrides, chaos, and multiplepaymentprocessorsMikko Ohtamaa <mikko@...> writes: >> seems like a good opportunity to rename it to just @@checkout-wizard > > You can also drop @@. ... So you can just have: > > /enter-shipping-address > /choose-payment-method > /final-checkout Which brings up some great questions! :-) First, just to make sure everyone knows the difference, the URL "/Plone/foo" can mean *two* different things. First, it might bring up some item inside of the container "Plone", like a Folder or Page or whatever, that happens to have the ID of "foo". Second, it might find that there is a view registered for "Plone" objects that is named "@@foo", and display that view of the Plone object instead. So the @@-less URLs suggested above will only work if we can *guarantee* that Plone users will not create top-level folders with the same name. Try it on a sample instance of your own: first, observe that "/Plone/empty-cart" shows you the GetPaid empty-cart view, just like the similar URL "/Plone/@@empty-cart". Now, go into "/Plone" and create a Page named "Empty Cart". What happens? The "/Plone/empty-cart" URL now shows the page you've created, and GetPaid, if it was relying on that URL, would be broken. But, of course, even if we can stay out of the way of users, we still have other developers to contend with! What if (I'm being a bit silly, just for illustration) someone writes an Oregon Trail clone for Plone and has an "empty-cart" view for what happens if your supplies get stolen? Then, depending on which view gets registered first (or would a conflict message be generated by the duplicate registration?), only one of the two plugins could work on any given site. I suspect that this is why the best of the GetPaid views have their names start with "getpaid-*"; that way, they're pretty much guaranteed to be unique, and not conflict with other views that other products have registered. And if we do conflict, we can easily blame the other guy, for starting their view with the name of our product. :-) All of this raises a second question besides the question of whether names are likely to collide: does it strike anyone else besides me as extremely strange that the "@@empty-cart" view is *not* merely a view of a Plone site, but a view of *any possible object whatsoever*? Try it! Create a new Plone instance with GetPaid, and try visiting these URLs: "/Plone/@@empty-cart" "/Plone/news/@@empty-cart" "/Plone/events/@@empty-cart" "/Plone/front-page/@@empty-cart" These are *all* aliases for the same view! Why? Because, crazily, the ZCML declaration for "empty-cart" goes like this: <browser:page for="*" template="templates/cart-empty.pt" name="empty-cart" permission="zope2.View" /> In other words, the "empty-cart" view is declared to be an appropriate view for "*": for ANYTHING! This seems to be an utter abuse of the concept of a view. Views are supposed to get data, and display it. Like these views: "/Plone/@@folder_contents" "/Plone/@@manage-content-rules" "/Plone/@@sharing" These are views that are working as they ought! They are taking an object for which they are designed - in this case, the "Plone" container - and render it in some useful fashion that lets it be viewed or modified. Why does "@@empty-cart" need to exist everywhere beneath a site? Why should hundreds of URLs for it be valid? This approach will also get us into trouble if we want to make these views available under other frameworks, like Pylons or Turbogears or Django. Under those systems, when someone wants to provide a plug-in system, they generally just ask for *one* plug-in point beneath which their URLs exist. The integrator gets to select "/getpaid", or "/cart", or "/checkout", or whatever they want, and then all of the plug-in URLs exist under there. The Plone approach - of creating dozens of new views, of "dumping" them into the global URL space and just hoping there will be no collisions, and of registering them for every object under the sun so that they exist beneath every valid URL on the web site - is, if I can use this word politely, just bizarre. :-) What solution might we consider for this chaos? It occurs to me that views can be registered against all objects that happen to offer a certain interface. What if we registered all of our views for="IStore"? All sorts of good results would seem to follow: (a) Only those sites in a Zope instance that have actually installed GetPaid and been marked as IStores will have the GetPaid views activated for them. If "/Plone1" has GetPaid installed but "/Plone2" does not, then only the former will have a shopping-cart view. (b) GetPaid views will only exist at each store's root, rather than being crazily duplicated everywhere. (c) When we go to offer GetPaid as a solution under more conventional web frameworks, all we've got to offer is a way for, say, "/getpaid" under their Django site to return a Zope "IStore" object and start up the Zope traversal logic, and, bingo!, all of our views will be accessible as "/getpaid/checkout", "/getpaid/enter-shipping-address", and so forth. Trust me: no normal web framework will consider us unless we can behave nicely, by placing all of the new URLs we create down beneath a designated name the guarantees we won't conflict with their other URLs. :-) This doesn't seem to solve the problem of keeping our view names from colliding with other site-level views in a Plone site; but, Plone people seem to be living with the current situation without complain, so I'm fine for now if no one else has a problem with "/Plone/@@checkout" being where we put the checkout wizard. Heck, I guess if we document the restriction, we could even have "/Plone/checkout" be what we named it. Maybe Plone people are much more careful and alert about not creating conflicting names than I'm imagining, and it's not something we should worry about? Speak up, Plone folks, and help me understand how you live with all of this. -- Brandon Craig Rhodes brandon@... http://rhodesmill.org/brandon --~--~---------~--~----~------------~-------~--~----~ You received this message because you are subscribed to the Google Groups "getpaid-dev" group. To post to this group, send email to getpaid-dev@... To unsubscribe from this group, send email to getpaid-dev+unsubscribe@... For more options, visit this group at http://groups.google.com/group/getpaid-dev?hl=en -~----------~----~----~----~------~----~------~--~--- |
|
|
Re: overrides, chaos, and multiplepaymentprocessorsMikko Ohtamaa <mikko@...> writes: > Brandon, I like your enthusiasm towards Plone :) Thanks. :-) > My rationale ... > * Web best practices say that friendly URLs are must. > * @@ does not look friendly in URL. > * /getpaid-checkout does not look as friendly as /checkout in URL You're right, "getpaid" does look pretty ugly in a URL. You've convinced me! Let's go with new, simple URLs like "/checkout". I'd still love to give shop owners the *option* to move our views "one level down" in their Plone site, beneath a URL of their own choosing like "/shop" or whatever, which would also prepare us for web frameworks like Turbogears and Django that want products to live beneath their own URL prefix. How would this work, technically? Currently, our code does something like this to figure out where the checkout wizard lives: portal = getToolByName( self.context, 'portal_url').getPortalObject() url = portal.absolute_url() + '/@@getpaid-checkout-wizard' Now, this tells us right off the bat that, as I observed yesterday, the registration for this view is overly broad: <browser:page for="*" name="getpaid-checkout-wizard" class=".checkout.CheckoutWizard" permission="zope2.View" /> Since, as the above code demonstrates, we always expect the checkout wizard to live right beneath the Plone site's main URL, there's no reason not to tighten the view registration up and say this instead: for="IStore" so that every other object in the Plone site doesn't gain a "@@getpaid-checkout-wizard" view that it doesn't need. How could we change the assumption built into the above code - that our views always live on the portal root - so that we also have the option of living beneath another URL instead? I can think of three ways: 1. We currently slap an "IStore" marker interface on the Plone portal itself. If we treated it instead as a utility that was merely registered with the current portal, then it could live anywhere instead. To find the store, you just ask for the "IStore" utility. If the site owner is using the default setting, then the portal itself will have had the "IStore" marker placed on it, and the checkout page will live at "/Plone/checkout". If the site owner instead said to put everything under "/shop", then a simple "shop" object will have been created inside the Plone site and *it* will have been registered as the "IStore" utility. Under other web frameworks, we would just jury-rig a global utility registration pointing at an IStore object that knows where in the Django or Turbogears URL tree GetPaid has been installed. 2. But maybe it would be a Bad Thing to move the "IStore" marker off of the portal, since that would both move all of our configuration views down on to the "/shop" URL instead, if the site owner asked for one? On the one hand, having the configuration URLs move around might be not just nice, but necessary, if we think that a TurboGears integration of GetPaid would re-use our configuration screens, since they can't there live at the site root very comfortably. But, in Plone, it seems plain awkward for site-configuration views to live anywhere else but on the Plone object itself. Plus, a quick search of the source code suggests that "IStore" is used two ways that are incompatible with moving it away from the portal root: it's used as the name for the Store's adapter-and-interface registry where various GetPaid products register themselves, and the installation of the IStore marker interface is used as an event trigger by at least some of the shipping code. So, if all of the above reasons are good ones for leaving "IStore" alone and keeping it as the name of the portal root and Zope 3 registration point, then we would want to create another utility name - maybe "IStoreContext"? - that serves as the base URL off of which our checkout views live. There would be three situations: a. In a default Plone install, the portal root would be both an IStore and an IStoreContext, making it both where you go to see configuration views, and also where you go to find the cart and checkout views. b. In a Plone install where the owner asks us to live beneath "/shop", their portal root remains an IStore, and so all of their Site Setup views would continue to live at places like "/Plone/@@manage-getpaid-content-types" (note that we allow ourselves here both the "@@" eyes looking at us and also the name "getpaid" in the view name, since this URL will be seen, if at all, only by site admins that expect that sort of thing), but the "/Plone/shop" object we create is both marked as an IStoreContext and also registered as the site's IStoreContext utility. That way, URLs that say "/Plone/shop/checkout" would traverse to the IStoreContext and find the "checkout" view waiting beneath it, and checkout code that needs to generate URLs would just ask for the IStoreContext utility, then ask it for its URL, then slap "/cart" or whatever on their end. c. In a non-Zope framework, "/shop" would be configured using the host's URL registration framework as pointing at a special object that is itself marked as both an IStore and an IStoreContext, and that launches Zope traversal when a URL lands on it. Any config views that survive in the other framework, as well as all of our customer-facing views, would live under "/shop" in the web site. We would create a global registry at start-up that advertises our "shop" object as both the registered IStore utility and IStoreContext utility. 3. We abandon the modern idea of utility registration for the older idea we're currently using of merely being able to find our global options and ask it questions. Recall that at the moment we find things out about the current payment processor, when that knowledge is needed, with code like this: portal = self.context.portal_url.getPortalObject() manage_options = IGetPaidManagementOptions( portal ) processor_name = manage_options.payment_processor In other words, instead of asking for a utility, we ask for the portal root and then forcefully adapt it to the Options interface; that is, we pretty much insist, through the way we write our code, that configuration be stored on the site root itself, *not* somewhere else. I would argue against using such code, since, if we're not in Plone, (a) there might not exist a site root, and (b) even if there were, it might not be the best place to put our configuration information. I like the idea of an IStore utility that configures us and an IStoreContext utility where our views live because they are so abstract: they don't insist that we're part of a Plone site at all, they just require that whatever kind of web framework we're in be supplied with the ability to provide us with both of these utilities. Anyway, as I was saying: if we don't want to use utilities, we could hang everything off of the ability to get at the global options object (and, in other web frameworks, somehow fake things so that something that looked like a portal could be found through something like the above code). So instead of asking for where the current IStoreContext is, we could just grab the global options, and ask them what URL our checkout views should live beneath; and the global options would have that information because it's through changing the global options that the store owner expresses their will. Okay, enough options for right now. :-) Now, it might be that I'm creating an artificial distinction here between the "pretty" option of having an IStore and an IStoreContext utility, and the "ugly" option of grabbing the portal root and making it adapt to IGetPaidManagementOptions, because there is a third way between these two extremes: we could register the options themselves as a utility, and demand that utility as the first act we perform when we need to learn where GetPaid lives or where it is wired up. I admit, as I noted in an earlier email, that the idea of starting *every* question about GetPaid with "go get the options" is very pretty, because, that way, everything GetPaid needs to know is stored one place. With my suggestion above that we store *two* different utilities in every Plone site that uses GetPaid, we start the process of scattering our configuration information far and wide, where lots of things (site-wide registrations, for example) have to be changed or cleaned up when GetPaid is reconfigured or uninstalled. So, maybe the way to go it to turn the Options into a utility, so that we can get to it without needing a portal-root to exist, and give *it* an option that knows where in the site GetPaid is supposed to exist? Hmm. That wouldn't completely solve the problem, though, since for the URL "/Plone/shop/checkout" to resolve, there's *got* to be a "shop" object that actually, really exists in the site. So I'm not sure we can get away without having *some* site-wide registrations or object creations going on, unless we give up the idea of Plone users being able to put our URLs beneath some sub-URL. And maybe that's an idea we should give up for now, and just try to nail the two more "obvious" use-cases of Plone with our views living right beneath the root, and of other web frameworks having us live beneath a sub-URL, and in both cases we just ask for our Options and find out from them how to compute our URL? Hmm. I should think about this more. One last option: I think it is *possible*, last I checked, to have views that (gulp!) live inside of other views. So instead of creating an actual "shop" *object* in the "/Plone" container of a site owner that wanted our URLs to live under "/Plone/shop", which would then need to be cleaned up or deleted later (and which the shop owner would see in their table of contents and might delete by hand if they didn't know how it had gotten there), we could register a named view on "IStore" named "shop" that, itself, has views like "checkout" and "cart" registered for it. I think that the "vice" RSS syndication system did something like that to construct interesting multi-part URLs beneath Plone folders (like ".../recent/rss" and ".../all/atom"), but I'd have to go read their code to remember how they worked. -- Brandon Craig Rhodes brandon@... http://rhodesmill.org/brandon --~--~---------~--~----~------------~-------~--~----~ You received this message because you are subscribed to the Google Groups "getpaid-dev" group. To post to this group, send email to getpaid-dev@... To unsubscribe from this group, send email to getpaid-dev+unsubscribe@... For more options, visit this group at http://groups.google.com/group/getpaid-dev?hl=en -~----------~----~----~----~------~----~------~--~--- |
|
|
Re: overrides, chaos, and multiplepaymentprocessorsOn 27 Aug 2009, at 9:26 AM, Brandon Craig Rhodes wrote: > > Mikko Ohtamaa <mikko@...> writes: > >> Brandon, I like your enthusiasm towards Plone :) > > Thanks. :-) > As a lurker, I just wanna say I'm enjoying this immensely, and learning a hell of a lot about both getpaid and about Plone... Thanks, all, and thanks Brandon for your explicit thought process! Eventually, I'll integrate getpaid into my own site. I've also got a "PrintShopOrder" product sketched out in ArgoUML, but that's going to take a few months of 'stimulus money' for me to ever make any progress on it ;-) Cheers Peter Peter Fraterdeus Exquisite Letterpress from Slow Print Studios http://slowprint.com/ --~--~---------~--~----~------------~-------~--~----~ You received this message because you are subscribed to the Google Groups "getpaid-dev" group. To post to this group, send email to getpaid-dev@... To unsubscribe from this group, send email to getpaid-dev+unsubscribe@... For more options, visit this group at http://groups.google.com/group/getpaid-dev?hl=en -~----------~----~----~----~------~----~------~--~--- |
|
|
Re: overrides, chaos, and multiplepaymentprocessorsMikko Ohtamaa <mikko@...> writes: > Multiple payment processor branch also should support off-site > processors. Agreed! > IPaymentProcessor interface should have not references to the > user-inteface or Plone (Products.PloneGetPaid) so that other Zope > frameworks (BFG, Grok) can use it. Agreed; if possible, payment processors should simply *provide* views, they should try very hard to avoid importing and fiddling with views from the existing checkout process. On the other hand, I think that our checkout forms need to be pulled out of Products.PloneGetPaid and put somewhere else - maybe in a new package named "getpaid.checkout"? - so that other frameworks can use them. There's no reason that our forms shouldn't be able to travel to other frameworks, I don't think. > Well... I thought everything in Plone should be configured through > ZCML nowadays... are we redesigning the system *again*? ;) ZCML is teh > shit... Having looked over some Plone documentation to remember exactly how Plone people think about ZCML (as opposed to how pure Zope 3 people think about it, or Grok people think about it), it looks like ZCML is a way to create an ephemeral object that never exists in Python code. To (maybe) make the difference clear, let me try writing a single example registration in two different ways: 1. With a custom ZCML directive: <paymentprocessors:registerProcessor name="Off-site Google Payment Processor" selection_view="google-selection-view" review_pay_view="google-review-pay-view" /> 2. With a utility registration pointing to a class: <utility provides="getpaid.paymentprocessor.interfaces.IPaymentProcessor" factory="getpaid.googlecheckout.processor.GooglePaymentProcessor" /> class GooglePaymentProcessor(PaymentProcessor): name = u"Off-site Google Payment Processor" selection_view = "google-selection-view" review_pay_view = "google-review-pay-view" So, what are the important differences between these two registrations? The most notable feature that I can see is that the first one creates a "ghost" object that you can't actually import anywhere in Python code. Clearly it creates something called a Payment Processor, that's made up of other pieces; but where does this information go? Clearly, into some sort of special registry - that, if I want to introspect, I have to go read about and learn the API of and write special, customized code to interact with. The second registration, by contrast, creates a registration that merely *points* at an existing entity that I've already gone to the trouble of creating in code. This object has a name, "GooglePaymentProcessor"; it's clear where it lives (you could, in another application or in other code, import it and do things with it); and it can be introspected using good old-fashioned Python mechanisms that every experienced-enough Python programmer knows how to use. I have no problem with having GetPaid use ZCML to register payment processors. But I would like us to use approach #2, where the payment processor actually *exists* outside of ZCML, inside of regular Python code, because: (a) This makes our classes available to other frameworks. (b) This means that unit tests can proceed without always having to start up and run the ZCML and create an object registry, since the payment processor object "already exists" and can just be imported. (c) It means that in a distant future, if the Grok methodology ever wins the day, we can just remove the ZCML and have our classes auto-discovered instead - since all the real information, about what views and settings the payment processor needs and so forth, will already be in Python code and not trapped in XML. > multiplepaymentprocessor branch should handle those case as well. I > think it's just matter of having more view hooks available (checkout > button,etc.). Having stared at the use cases for a few hours, I finally think it's safe to agree with you: by providing just a few more plug-in points, I think we can indeed eliminate all special overrides that currently exist in payment processor registrations. > 1. In real-world the payment is done just right before you are leaving the > shop as the last thing of your shopping experience > 2. Thus, the payment method shoul be chosen as the last step of the wizard > because people are familiar with this best practice > > To support my rationale, all major webshops are doing the payment method as > the last choice. If you need to see example, try registering a domain in > GoDaddy. The choice between payment processors can only be made as the last step if both of the payment processors that you are choosing between only send you off-site for the last step. If one of the choices your store owner has enabled is Google Checkout with both the address and shipping info collected off-site, then you have to ask whether they want to use Google Checkout several steps *before* the last step: CHOICE checkout ---> Google Checkout ---> Google Checkout address, shipping, etc button AuthorizeDotNet ---> @@address-info ---> @@review-pay --> ... Having sketched out many scenarios, I am now convinced that, when the store owner has selected more than one possible payment processor for users to choose between, the checkout system needs to: 1. Look at the possible payment processors. 2. Look up the step on which each payment processor sends the user off-site (if any). 3. One step *before* that step - which might put the choice on the cart's Checkout button itself! - ask which payment processor the user wants to use. Essentially, the cart will have to be smart enough to "diff" the available checkout processors, see how "early" in the checkout process the first difference is, and ask right before it hits that step. -- Brandon Craig Rhodes brandon@... http://rhodesmill.org/brandon --~--~---------~--~----~------------~-------~--~----~ You received this message because you are subscribed to the Google Groups "getpaid-dev" group. To post to this group, send email to getpaid-dev@... To unsubscribe from this group, send email to getpaid-dev+unsubscribe@... For more options, visit this group at http://groups.google.com/group/getpaid-dev?hl=en -~----------~----~----~----~------~----~------~--~--- |
|
|
Re: overrides, chaos, and multiplepaymentprocessorsOn Wed, Aug 26, 2009 at 1:04 PM, Brandon Craig Rhodes<brandon@...> wrote: > > As Michael suggested last week, I have studied how all of the payment > processors besides Google Checkout integrate with GetPaid; Michael, it > was a great suggestion! And, thanks to guidance which Christopher > Johnson provided when we talked on Friday, I have also read through the > various branches in GetPaid labeled "multiplepaymentprocessors". > > (USABILITY PEOPLE: You can skip down to the "Big Questions That I > Need Feedback On" section farther down if you want > to skip the technical discussion.) > > As a result, I now have a more complete picture of how the various > GetPaid payment processors are designed. To keep things straight, I > sketched out this rough diagram in Inkscape this afternoon: > > http://rhodesmill.org/brandon/static/2009/getpaid-overrides.png > > Red text in the diagram indicates the presence of a ZCML override of > some sort. Note that I have left out extra steps that might be present > in the wizard, like shipping options; when present, such steps would sit > between the "Address Info" and the "Review & Pay" pages in the diagram. > > Payment Processors, and How They Work > ------------------------------------- > > Taking the diagram from top to bottom: > > * Google Checkout: > > The payment processor provides its own copies of the shopping cart > view and shopping cart portlet, so that it can draw a pretty "Google > Checkout" button on each of them. The buttons point at a view named > "/google-checkout" on the Plone site, which has no associated > template but instead redirects directly to Google itself. > > OPEN QUESTION: It is not clear to me why the checkout buttons do not > point at Google directly instead of going through the extra view, but > I see Google Analytics parameters being constructed on the way that > might have something to do with it. The strongest reason is that the site itself needs to communicate with Google Checkout before redirecting the shopper to Google Checkout. It could be arranged that is communication is done when rendering the checkout button and the result somehow used in that rendering. But that would mean having to communicate with googlecheckout each time the checkout button was rendered for the shopper. > * ClickandBuy / PagSeguro: > > These both provide their own @@getpaid-checkout-wizard view that > removes all of the normal functionality, and shows a big button that, > when pushed, sends the user to an off-site checkout process. > > OPEN QUESTION: This approach competes directly with the Google > Checkout approach. Which is better: providing a special checkout > button for "Checkout"? Or, letting them visit our normal checkout > URL then asking them to click off-site? The former requires one less > click from the user; the latter gives them a bit more warning that > they are leaving. Should we rewrite all three payment processors to > use a common approach, and then provide an admin config option for > whether a store owner wants the extra "Click here to checkout" step > added or not? I think less clicking is for the shopper is good. And I think that these off site processors try to provide strongly branded checkout buttons which gives the shopper just enough warning. So you don't need the intermediate page. > * PayPal: > > This also provides its own @@getpaid-checkout-wizard, but the view > simply does an immediate redirect to PayPal. > > OPEN QUESTION: Like with Google Checkout, the question is, why? > Because it was easier than overriding the "Checkout" buttons? Or > because the extra step lets a few last variables and parameters be > put into place before the customer arrives at PayPal? I don't know. Might be the same reasoning as the Google Checkout. -- Michael Dunstan --~--~---------~--~----~------------~-------~--~----~ You received this message because you are subscribed to the Google Groups "getpaid-dev" group. To post to this group, send email to getpaid-dev@... To unsubscribe from this group, send email to getpaid-dev+unsubscribe@... For more options, visit this group at http://groups.google.com/group/getpaid-dev?hl=en -~----------~----~----~----~------~----~------~--~--- |
|
|
Re: overrides, chaos, and multiplepaymentprocessorsOn Wed, Aug 26, 2009 at 7:36 PM, Mikko Ohtamaa<mikko@...> wrote: >> 1. Off-site processors that provide their own checkout wizards >> (Google Checkout, ClickandBuy, PagSeguro, PayPal) > > PayPal and Google Checkout support also more tightly integration with the > existing web site without 1) taking the user away from the site I don't think that is the case for Google Checkout. I don't think Google offer that kind of service - yet. > 2) managing > the order on the payment processor site. The current plug-ins don't use > them, however. For Google Checkout - correct. (The processor is receiving notifications - just nothing other than timely discarding of shoppers carts is being done with those notifications.) -- Michael Dunstan --~--~---------~--~----~------------~-------~--~----~ You received this message because you are subscribed to the Google Groups "getpaid-dev" group. To post to this group, send email to getpaid-dev@... To unsubscribe from this group, send email to getpaid-dev+unsubscribe@... For more options, visit this group at http://groups.google.com/group/getpaid-dev?hl=en -~----------~----~----~----~------~----~------~--~--- |
| Free embeddable forum powered by Nabble | Forum Help |