development

Prompt PayPal payment processing, part 1

I use two payment processors for Dejal: Kagi and PayPal. The Dejal Store powered by Kagi has been fully automated for years, so when a customer buys one of my products, Kagi queries my server, which generates a serial number and passes it back to Kagi's server, and the customer receives it automatically as part of Kagi's "Thanks for your purchase" message. This is very convenient for both me and the customer. (My products also include a Kagi-based store right within the app, which avoids the need to even enter the serial number.)

For the Dejal Store powered by PayPal, on the other hand, it has been a manual process. When someone purchased via PayPal, I received a notification of the payment in my email, which I copied to my home-grown license management app, which parsed it to generate the license, including creating an email message in Mail ready to send. This wasn't much work, but required manual processing on my part, which of course meant the customer had to wait for me before they got their license. I was usually very prompt, but if they bought while I was asleep or otherwise away from my machine, they had to wait. That's just not great service.

So this week I've spent the time to automate the PayPal processing. Now, if you buy from my PayPal store, PayPal will send my server a notification with the shopping cart contents. My server will then automatically add licenses and generate and send out email messages for each product purchased. So now purchasing from either store (or within the app) will give you your license details virtually immediately, with no need for waiting for me. Which of course means less work for me, too, so I can spend more time answering support questions or writing code.

Getting technical

Implementing the PayPal automation wasn't too difficult, though it took some research to find the best solutions. For the standard PayPal business accounts, they offer two automated payment notification services: Payment Data Transfer (PDT) and Instant Payment Notification (IPN). My initial research showed people using PDT, for example that's what the AquaticPrime framework uses. However, further research showed that this might not be the best choice. The way it works is to send the transaction information to your server when the customer is redirected back to your website after the purchase. But if they close their browser window or click away before they return to your site, your server doesn't get the transaction info. Also, you have to deal with pending transactions (e.g. eChecks), form reloads, and other issues.

So then I switched to using IPN. This is a more robust mechanism, but still quite simple to implement. In this case, the payment notification occurs in the background, whether or not the customer actually returns to your site. I believe that pending transactions aren't received until they clear, too. So this is more reliable and efficient.

Both services include fraud protections, in the form of posting the received data back to PayPal and getting a response. If they originated the data, they'll reply saying that it was confirmed, otherwise it's suspicious.

To make things more interesting, my store pages offer multiple products for sale, so I need a shopping cart. Most existing examples assumed a single buy button, but fortunately the PayPal data copes with shopping cart transactions in a fairly simple way, appending digits to the variables.

Continue reading part 2, with a discussion of the PHP code to implement this.

Product positioning ponderings

As as been mentioned before, I'm working on Time Out version 2 (in between other projects), to be released once Leopard is publicly available.

At present Time Out is freeware. It probably shouldn't be, as it's a great, very popular product, but it started that way and has remained so thus far. That will change with version 2, which will include pretty much all of the most popular features people have been asking for over the last few years, many of which I've been keen to do but couldn't justify in a free version.

So version 2 and beyond will be shareware, and require a minimum of Leopard. However, I plan to keep version 1.5 (to be released soon) around for people who haven't yet upgraded to Leopard. Version 1.5 will remain free, and for 10.3.9 and later. That could also serve as an alternative for people who don't want the improvements in version 2 (or don't want to pay for Time Out)... but I'm also considering other options.

The latest such option to ponder is having a "Lite" edition of version 2. So there would be the standard Time Out 2, a shareware product, plus Time Out Lite 2, a freeware product. The Lite edition would have basically the same feature set as version 1.5, plus a few enhancements. The standard edition would have lots more new features. If the basic features were enough for you, you could use Time Out Lite at no cost, like you can use current versions. If you want the extra features, you install the standard Time Out and buy a license. Like my other products, you could install Time Out and try the full features for a while before deciding to buy.

A previous option that I thought of was to have just one Time Out 2 app, but two or three license levels, like for Simon. Under this approach, there would be a cheap Basic license with limited features, a Standard license with advanced features, and perhaps an Enterprise or Site license with the same features but allowing company-wide installation. This is different than the above approach in that there is no separate free edition; the differentiation is all in license levels. I do like the idea of keeping a free edition, though.

Another idea was similar to that one, having more of a "seat"-based approach. One license, the same features for everyone, but quantity discounts for multiple users. This is more like the Individual/Household/Site license model that I use for Caboodle and other apps. A seat-based approach could perhaps be combined with the latest approach (of standard and Lite editions).

What do you all think? Any preferences, or other ideas? Feedback would be appreciated, via the comments, the Time Out forum, or privately.

Dejal Developer pages: free Cocoa code

I've been developing for the Mac since about 1988, initially in Pascal, and since 2002 in ObjC/Cocoa. I've benefited from advice and comments on mailing lists like CocoaDev, and like to give back to the community. In the past I released some of my Classic Pascal code, and now I'm doing the same for some of my Cocoa code.

I am a chronic generic code writer, which I know many people frown on, but with six applications to maintain, shared code is very useful and efficient. An important part of this shared code is my Cocoa categories, that extend Apple's classes with convenience methods and new functionality.

These categories are now available to other Cocoa developers to use in your own products, if desired. The code was written over the last several years, so some of it could be replaced with more modern techniques, but hopefully a lot of it will remain useful. They are certainly used a lot in my products.

The main Developer page is at www.dejal.com/developer. The categories are organized by Foundation and AppKit, plus some utilities. You can view the code online and copy select snippets if you wish, or download .zip archives for each, or a single archive with all.

This code is generously licensed; you are welcome to use it in your own products, including commercial; all I ask is a mention in your credits or website, and that you tell me you're using it. Use as little or as much as you wish.

If you find any bugs or have some suggestions, or want to roll in improvements, please let me know. The code should all be pretty bug-free, though, being in active use. And depending on feedback, I'll probably add more code over time; I have several subclasses and new classes that are shared by all my apps that (with a little tidying up) could also be made available in the future.

I hope it's helpful for you!

Leopard delayed till October

I guess I spoke too soon. Apple shocked everyone today by announcing that Leopard is being pushed back from June to October.

Well, maybe "shocked" is too strong a word... I don't think any developers are too surprised, but some developers are more concerned than others... particularly ones with apps requiring Leopard waiting for release.

Personally, I'm not concerned. I applaud Apple for taking the extra time to get it right. And although I have plans for Leopard updates of Dejal apps, the next versions will still be Tiger-compatible. Time Out 2, which I'm working on now, will require Tiger, and Simon 2.3 will remain for Panther (10.3.9) and later, as will the other apps for now.

Looking forward to WWDC 2007

I've just purchased the conference ticket, and booked the hotel and airfare for Apple's Worldwide Developers Conference, coming in June.

Last year was my first attendance, though I'd been meaning to go for years. I enjoyed it, met a bunch of interesting people, and learned useful things about Leopard etc at the sessions, so I wanted to go again this year.

This year's conference should be very interesting again, with Leopard likely being released either shortly before or (more likely) at the Stevenote.

I look forward to meeting more Mac developers at WWDC this year. I'll probably wear Dejal logo shirts, so if you're there and see me, come up and say hi!

Cocoa topics: the case of the modal WebView

I want to include the occasional programming topic in the Dejal blog, when I encounter something that may be of interest to other Mac developers. Here's my first one.

A while back, I added a Check for Updates... window that displays a WebView of release notes, much like on my site. It works rather well. However, if a beta release has expired, I wanted it to display it modally. But for some strange reason the WebView didn't load when the window was run modally. I couldn't find a solution at the time, so I just had it redirect to the website.

I came across this issue again tonight, while adding Services support to BlogAssist. I'm introducing a handy new feature where you can just hit < in any app to display a modal panel like the existing floating window. It includes a WebView to preview how the marked-up HTML will appear. I really didn't want to have to sacrifice that.

So I found a solution: tickle the runloop! It turns out that the WebView will only work on the main loop. So rather than just call -runModalForWindow:, I use the more verbose -beginModalSessionForWindow: / -runModalSession: / -endModalSession: loop. And the key to keeping the WebView happy: call -limitDateForMode: each time around the loop, so the main loop keeps on truckin'.

Here's the code:

    NSModalSession session = [NSApp beginModalSessionForWindow:[self window]];
    int result = NSRunContinuesResponse;
   
    // Loop until some result other than continues:
    while (result == NSRunContinuesResponse)
    {
        // Run the window modally until there are no events to process:
        result = [NSApp runModalSession:session];
       
        // Give the main loop some time:
        [[NSRunLoop currentRunLoop] limitDateForMode:NSDefaultRunLoopMode];
    }
   
    [NSApp endModalSession:session];

I hope this helps others with this dilemma.

Syndicate content