aboutsummaryrefslogtreecommitdiffstats
path: root/trunk/etherpad/src/etherpad/control/store/eepnet_checkout_control.js
diff options
context:
space:
mode:
Diffstat (limited to 'trunk/etherpad/src/etherpad/control/store/eepnet_checkout_control.js')
-rw-r--r--trunk/etherpad/src/etherpad/control/store/eepnet_checkout_control.js757
1 files changed, 757 insertions, 0 deletions
diff --git a/trunk/etherpad/src/etherpad/control/store/eepnet_checkout_control.js b/trunk/etherpad/src/etherpad/control/store/eepnet_checkout_control.js
new file mode 100644
index 0000000..ddd4973
--- /dev/null
+++ b/trunk/etherpad/src/etherpad/control/store/eepnet_checkout_control.js
@@ -0,0 +1,757 @@
+/**
+ * Copyright 2009 Google Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS-IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import("email.sendEmail");
+import("fastJSON");
+import("funhtml.*");
+import("jsutils.*");
+import("sqlbase.sqlobj");
+import("stringutils");
+import("sync");
+
+import("etherpad.billing.billing");
+import("etherpad.billing.fields");
+import("etherpad.globals");
+import("etherpad.globals.*");
+import("etherpad.helpers");
+import("etherpad.licensing");
+import("etherpad.pro.pro_utils");
+import("etherpad.sessions.{getSession,getTrackingId,getSessionId}");
+import("etherpad.store.checkout");
+import("etherpad.store.eepnet_checkout");
+import("etherpad.utils.*");
+
+import("static.js.billing_shared.{billing=>billingJS}");
+
+jimport("java.lang.System.out.println");
+
+//----------------------------------------------------------------
+
+var STORE_URL = '/ep/store/eepnet-checkout/';
+
+var _pageSequence = [
+ ['purchase', "Number of Users", true],
+ ['support-contract', "Support Contract", true],
+ ['license-info', "License Information", true],
+ ['billing-info', "Billing Information", true],
+ ['confirmation', "Confirmation", false]
+];
+
+var _specialPages = {
+ 'receipt': ['receipt', "Receipt", false]
+}
+
+//----------------------------------------------------------------
+
+function _cart() {
+ return getSession().eepnetCart;
+}
+
+function _currentPageSegment() {
+ return request.path.split('/')[4];
+}
+
+function _currentPageId() {
+ return _applyToCurrentPageSequenceEntry(function(ps) { return ps[0]; });
+}
+
+function _applyToCurrentPageSequenceEntry(f) {
+ for (var i = 0; i < _pageSequence.length; i++) {
+ if (_pageSequence[i][0] == _currentPageSegment()) {
+ return f(_pageSequence[i], i, true);
+ }
+ }
+ if (_specialPages[_currentPageSegment()]) {
+ return f(_specialPages[_currentPageSegment()], -1, false);
+ }
+ return undefined;
+}
+
+function _currentPageIndex() {
+ return _applyToCurrentPageSequenceEntry(function(ps, i) { return i; });
+}
+
+function _currentPageTitle() {
+ return _applyToCurrentPageSequenceEntry(function(ps) { return ps[1]; });
+}
+
+function _currentPageShowCart() {
+ return _applyToCurrentPageSequenceEntry(function(ps) { return ps[2]; });
+}
+
+function _currentPageInFlow() {
+ return _applyToCurrentPageSequenceEntry(function(ps, i, isSpecial) { return isSpecial });
+}
+
+function _pageId(d) {
+ return _applyToCurrentPageSequenceEntry(function(ps, i) {
+ if (_pageSequence[i+d]) {
+ return _pageSequence[i+d][0];
+ }
+ });
+}
+
+function _nextPageId() { return _pageId(+1); }
+function _prevPageId() { return _pageId(-1); }
+
+function _advancePage() {
+ response.redirect(_pathTo(_nextPageId()));
+}
+
+function _pathTo(id) {
+ return STORE_URL+id;
+}
+
+// anything starting with 'billing' is also ok.
+function _isAutomaticallySetParam(p) {
+ var _automaticallySetParams = arrayToSet([
+ 'numUsers', 'couponCode', 'supportContract',
+ 'email', 'ownerName', 'orgName', 'licenseAgreement'
+ ]);
+
+ return _automaticallySetParams[p] || stringutils.startsWith(p, "billing");
+}
+
+function _lastSubmittedPage() {
+ var cart = _cart();
+ return isNaN(cart.lastSubmittedPage) ? -1 : Number(cart.lastSubmittedPage);
+}
+
+function _shallowSafeCopy(obj) {
+ return billing.clearKeys(obj, [
+ {name: 'billingCCNumber',
+ valueTest: function(s) { return /^\d{15,16}$/.test(s) },
+ valueReplace: billing.replaceWithX },
+ {name: 'billingCSC',
+ valueTest: function(s) { return /^\d{3,4}$/.test(s) },
+ valueReplace: billing.replaceWithX }]);
+}
+
+function onRequest() {
+ billing.log({
+ 'type': "billing-request",
+ 'date': +(new Date),
+ 'method': request.method,
+ 'path': request.path,
+ 'query': request.query,
+ 'host': request.host,
+ 'scheme': request.scheme,
+ 'params': _shallowSafeCopy(request.params),
+ 'cart': _shallowSafeCopy(_cart())
+ });
+ if (request.path == STORE_URL+"paypalnotify") {
+ _handlePaypalNotification();
+ }
+ if (request.path == STORE_URL+"paypalredirect") {
+ _handlePayPalRedirect();
+ }
+ var cart = _cart();
+ if (!cart || request.params.clearcart) {
+ getSession().eepnetCart = {
+ lastSubmittedPage: -1,
+ invoiceId: billing.createInvoice()
+ };
+ if (request.params.clearcart) {
+ response.redirect(request.path);
+ }
+ if (_currentPageId() != 'purchase') {
+ response.redirect(_pathTo('purchase'));
+ }
+ cart = _cart();
+ }
+ if (request.params.invoice) {
+ cart.billingPurchaseType = 'invoice';
+ }
+ if (cart.purchaseComplete && _currentPageId() != 'receipt') {
+ cart.showStartOverMessage = true;
+ response.redirect(_pathTo('receipt'));
+ }
+ // somehow user got too far?
+ if (_currentPageIndex() > _lastSubmittedPage() + 1) {
+ response.redirect(_pathTo(_pageSequence[_lastSubmittedPage()+1][0]));
+ }
+ if (request.isGet) {
+ // see if this is a standard cart-page get
+ if (_currentPageId()) {
+ _renderCartPage();
+ return true;
+ }
+ }
+ if (request.isPost) {
+ // add params to cart
+ eachProperty(request.params, function(k,v) {
+ if (! _isAutomaticallySetParam(k)) { return; }
+ if (k == "billingCCNumber" && v.charAt(0) == 'X') { return; }
+ cart[k] = stringutils.toHTML(v);
+ });
+ if (_currentPageId() == 'license-info' && ! request.params.licenseAgreement) {
+ delete cart.licenseAgreement;
+ }
+ if (_currentPageIndex() > cart.lastSubmittedPage) {
+ cart.lastSubmittedPage = _currentPageIndex();
+ }
+ }
+ if (request.params.backbutton) {
+ _updateCosts();
+ response.redirect(_pathTo(_prevPageId()));
+ }
+ return false; // commence auto-dispatch
+}
+
+function _getCoupon(code) {
+ return sqlobj.selectSingle('checkout_referral', {id: code});
+}
+
+function _supportCost() {
+ var cart = _cart();
+ return Math.max(eepnet_checkout.SUPPORT_MIN_COST, eepnet_checkout.SUPPORT_COST_PCT/100*cart.baseCost);
+}
+
+function _discountedSupportCost() {
+ var cart = _cart();
+ if ('couponSupportPctDiscount' in cart) {
+ return _supportCost() -
+ (cart.couponSupportPctDiscount ?
+ cart.couponSupportPctDiscount/100 * _supportCost() :
+ 0);
+ }
+}
+
+function _updateCosts() {
+ var cart = _cart();
+
+ if (cart.numUsers) {
+ cart.numUsers = Number(cart.numUsers);
+
+ cart.baseCost = cart.numUsers * eepnet_checkout.COST_PER_USER;
+
+ if (cart.supportContract == "true") {
+ cart.supportCost = _supportCost();
+ } else {
+ delete cart.supportCost;
+ }
+
+ var coupon = _getCoupon(cart.couponCode);
+ if (coupon) {
+ for (i in coupon) {
+ cart["coupon"+stringutils.makeTitle(i)] = coupon[i];
+ }
+ cart.coupon = coupon;
+ } else {
+ for (i in cart.coupon) {
+ delete cart["coupon"+stringutils.makeTitle(i)];
+ }
+ delete cart.coupon;
+ }
+
+ if (cart.couponProductPctDiscount) {
+ cart.productReferralDiscount =
+ cart.couponProductPctDiscount/100 * cart.baseCost;
+ } else {
+ delete cart.productReferralDiscount;
+ }
+ if (cart.couponSupportPctDiscount) {
+ cart.supportReferralDiscount =
+ cart.couponSupportPctDiscount/100 * (cart.supportCost || 0);
+ } else {
+ delete cart.supportReferralDiscount;
+ }
+ cart.subTotal =
+ cart.baseCost - (cart.productReferralDiscount || 0) +
+ (cart.supportCost || 0) - (cart.supportReferralDiscount || 0);
+
+ if (cart.couponTotalPctDiscount) {
+ cart.totalReferralDiscount =
+ cart.couponTotalPctDiscount/100 * cart.subTotal;
+ } else {
+ delete cart.totalReferralDiscount;
+ }
+
+ if (cart.couponFreeUsersCount || cart.couponFreeUsersPct) {
+ cart.freeUserCount =
+ Math.round(cart.couponFreeUsersCount +
+ cart.couponFreeUsersPct/100 * cart.numUsers);
+ } else {
+ delete cart.freeUserCount;
+ }
+ cart.userCount = Number(cart.numUsers) + Number(cart.freeUserCount || 0);
+
+ cart.total =
+ cart.subTotal - (cart.totalReferralDiscount || 0);
+ }
+}
+
+//----------------------------------------------------------------
+// template helper functions
+//----------------------------------------------------------------
+
+function _cartDebug() {
+ if (globals.isProduction()) {
+ return '';
+ }
+
+ var d = DIV({style: 'font-family: monospace; font-size: 1em; border: 1px solid #ccc; padding: 1em; margin: 1em;'});
+ d.push(H3({style: "font-size: 1.5em; font-weight: bold;"}, "Debug Info:"));
+ var t = TABLE({border: 1, cellspacing: 0, cellpadding: 4});
+ keys(_cart()).sort().forEach(function(k) {
+ var v = _cart()[k];
+ if (typeof(v) == 'object' && v != null) {
+ v = v.toSource();
+ }
+ t.push(TR(TD({style: 'padding: 2px 6px;', align: 'right'}, k),
+ TD({style: 'padding: 2px 6px;', align: 'left'}, v)));
+ });
+ d.push(t);
+ return d;
+}
+
+var billingButtonName = "Review Order";
+
+function _templateContext(extra) {
+ var cart = _cart();
+
+ var pageId = _currentPageId();
+
+ var ret = {
+ cart: cart,
+ costPerUser: eepnet_checkout.COST_PER_USER,
+ supportCostPct: eepnet_checkout.SUPPORT_COST_PCT,
+ supportMinCost: eepnet_checkout.SUPPORT_MIN_COST,
+ errorIfInvalid: _errorIfInvalid,
+ dollars: checkout.dollars,
+ countryList: fields.countryList,
+ usaStateList: fields.usaStateList,
+ obfuscateCC: checkout.obfuscateCC,
+ helpers: helpers,
+ inFlow: _currentPageInFlow(),
+ displayCart: _displayCart,
+ displaySummary: _displaySummary,
+ pathTo: _pathTo,
+ billing: billingJS,
+ handlePayPalRedirect: _handlePayPalRedirect,
+ supportCost: _supportCost,
+ discountedSupportCost: _discountedSupportCost,
+ billingButtonName: billingButtonName,
+ billingFinalPhrase: "<p>You will not be charged until you review"+
+ " and confirm your order on the next page.</p>",
+ getFullSuperdomainHost: pro_utils.getFullSuperdomainHost,
+ showCouponCode: false
+ };
+ eachProperty(extra, function(k, v) {
+ ret[k] = v;
+ });
+ return ret;
+}
+
+function _displayCart(cartid, editable) {
+ return renderTemplateAsString('store/eepnet-checkout/cart.ejs', _templateContext({
+ shoppingcartid: cartid || "shoppingcart",
+ editable: editable
+ }));
+}
+
+function _displaySummary(editable) {
+ return renderTemplateAsString('store/eepnet-checkout/summary.ejs', _templateContext({
+ editable: editable
+ }));
+}
+
+function _renderCartPage() {
+ var cart = _cart();
+
+ var pageId = _currentPageId();
+ var title = _currentPageTitle();
+
+ function _getContent() {
+ return renderTemplateAsString('store/eepnet-checkout/'+pageId+'.ejs', _templateContext());
+ }
+
+ renderFramed('store/eepnet-checkout/checkout-template.ejs', {
+ cartDebug: _cartDebug,
+ errorDiv: _errorDiv,
+ pageId: pageId,
+ getContent: _getContent,
+ title: title,
+ inFlow: _currentPageInFlow(),
+ displayCart: _displayCart,
+ showCart: _currentPageShowCart(),
+ cart: cart,
+ billingButtonName: billingButtonName
+ });
+
+ // clear errors
+ delete cart.errorMsg;
+ delete cart.errorId;
+}
+
+function _errorDiv() {
+ var m = _cart().errorMsg;
+ if (m) {
+ return DIV({className: 'errormsg', id: 'errormsg'}, m);
+ } else {
+ return '';
+ }
+}
+
+function _errorIfInvalid(id) {
+ var e = _cart().errorId
+ if (e && e[id]) {
+ return 'error';
+ } else {
+ return '';
+ }
+}
+
+function _validationError(id, msg, pageId) {
+ var cart = _cart();
+ cart.errorMsg = msg;
+ cart.errorId = {};
+ if (id instanceof Array) {
+ id.forEach(function(k) {
+ cart.errorId[k] = true;
+ });
+ } else {
+ cart.errorId[id] = true;
+ }
+ if (pageId) {
+ response.redirect(_pathTo(pageId));
+ }
+ response.redirect(request.path);
+}
+
+//--------------------------------------------------------------------------------
+// main
+//--------------------------------------------------------------------------------
+
+function render_main() {
+ response.redirect(STORE_URL+'purchase');
+}
+
+//--------------------------------------------------------------------------------
+// cart
+//--------------------------------------------------------------------------------
+
+function render_purchase_post() {
+ var cart = _cart();
+
+ // validate numUsers and couponCode
+ if (! checkout.isOnlyDigits(cart.numUsers)) {
+ _validationError("numUsers", "Please enter a valid number of users.");
+ }
+ if (Number(cart.numUsers) < 1) {
+ _validationError("numUsers", "Please specify at least one user.");
+ }
+
+ if (cart.couponCode && (cart.couponCode.length != 8 || ! _getCoupon(cart.couponCode))) {
+ _validationError("couponCode", "That coupon code does not appear to be valid.");
+ }
+
+ _updateCosts();
+ _advancePage();
+}
+
+//--------------------------------------------------------------------------------
+// support-contract
+//--------------------------------------------------------------------------------
+
+function render_support_contract_post() {
+ var cart = _cart();
+
+ if (cart.supportContract != "true" && cart.supportContract != "false") {
+ _validationError("supportContract", "Please select one of the options.");
+ }
+
+ _updateCosts();
+ _advancePage();
+}
+
+//--------------------------------------------------------------------------------
+// license-info
+//--------------------------------------------------------------------------------
+
+function render_license_info_post() {
+ var cart = _cart();
+
+ if (!isValidEmail(cart.email)) {
+ _validationError("email", "That email address does not look valid.");
+ }
+ if (!cart.ownerName) {
+ _validationError("ownerName", "Please enter a license owner name.");
+ }
+ if (!cart.orgName) {
+ _validationError("orgName", "Please enter an organization name.");
+ }
+ if (!cart.licenseAgreement) {
+ _validationError("licenseAgreement", "You must agree to the terms of the license to purchase EtherPad PNE.");
+ }
+
+ if ((! cart.billingFirstName) && ! (cart.billingLastName)) {
+ var nameParts = cart.ownerName.split(/\s+/);
+ if (nameParts.length == 1) {
+ cart.billingFirstName = nameParts[0];
+ } else {
+ cart.billingLastName = nameParts[nameParts.length-1];
+ cart.billingFirstName = nameParts.slice(0, nameParts.length-1).join(' ');
+ }
+ }
+
+ _updateCosts();
+ _advancePage();
+}
+
+//--------------------------------------------------------------------------------
+// billing-info
+//--------------------------------------------------------------------------------
+
+function render_billing_info_post() {
+ var cart = _cart();
+
+ checkout.validateBillingCart(_validationError, cart);
+ if (cart.billingPurchaseType == 'paypal') {
+ _beginPaypalPurchase();
+ }
+
+ _updateCosts();
+ _advancePage();
+}
+
+function _absoluteUrl(id) {
+ return request.scheme+"://"+request.host+_pathTo(id);
+}
+
+function _beginPaypalPurchase() {
+ _updateCosts();
+
+ var cart = _cart();
+
+ var purchase = _generatePurchaseRecord();
+ var result =
+ billing.beginExpressPurchase(cart.invoiceId, cart.customerId,
+ "EEPNET", cart.total || 0.01, cart.couponCode || "",
+ _absoluteUrl('paypalredirect?status=ok'),
+ _absoluteUrl('paypalredirect?status=fail'),
+ _absoluteUrl('paypalnotify'));
+ if (result.status != 'success') {
+ _validationError("billingPurchaseType",
+ "PayPal purchase not available at the moment. "+
+ "Please try again later, or try using a different payment option.");
+ }
+ cart.paypalPurchaseInfo = result.purchaseInfo;
+ response.redirect(billing.paypalPurchaseUrl(result.purchaseInfo.token));
+}
+
+//--------------------------------------------------------------------------------
+// confirmation
+//--------------------------------------------------------------------------------
+
+function _handlePaypalNotification() {
+ var ret = billing.handlePaypalNotification();
+ if (ret.status == 'completion') {
+ var purchaseInfo = ret.purchaseInfo;
+ var eepnetPurchase = eepnet_checkout.getPurchaseByInvoiceId(purchaseInfo.invoiceId);
+ var fakeCart = {
+ ownerName: eepnetPurchase.owner,
+ orgName: eepnetPurchase.organization,
+ email: eepnetPurchase.emails,
+ customerId: eepnetPurchase.id,
+ userCount: eepnetPurchase.numUsers,
+ receiptEmail: eepnetPurchase.receiptEmail,
+ }
+ eepnet_checkout.generateLicenseKey(fakeCart);
+ eepnet_checkout.sendReceiptEmail(fakeCart);
+ eepnet_checkout.sendLicenseEmail(fakeCart);
+ billing.log({type: 'purchase-complete', dollars: purchaseInfo.cost});
+ }
+}
+
+function _handlePayPalRedirect() {
+ var cart = _cart();
+
+ if (request.params.status == 'ok' && cart.paypalPurchaseInfo) {
+ var result = billing.continueExpressPurchase(cart.paypalPurchaseInfo);
+ if (result.status == 'success') {
+ cart.paypalPayerInfo = result.payerInfo;
+ response.redirect(_pathTo('confirmation'));
+ } else {
+ _validationError("billingPurchaseType",
+ "There was an error processing your payment through PayPal. "+
+ "Please try again later, or use a different payment option.",
+ 'billing-info');
+ }
+ } else {
+ _validationError("billingPurchaseType",
+ "PayPal payment didn't go through. "+
+ "Please try again later, or use a different payment option.",
+ 'billing-info');
+ }
+}
+
+function _recordPurchase(p) {
+ return sqlobj.insert("checkout_purchase", p);
+}
+
+function _generatePurchaseRecord() {
+ var cart = _cart();
+
+ if (! cart.invoiceId) {
+ throw Error("No invoice id!");
+ }
+
+ var purchase = {
+ invoiceId: cart.invoiceId,
+ email: cart.email,
+ firstName: cart.billingFirstName,
+ lastName: cart.billingLastName,
+ owner: cart.ownerName || "",
+ organization: cart.orgName || "",
+ addressLine1: cart.billingAddressLine1 || "",
+ addressLine2: cart.billingAddressLine2 || "",
+ city: cart.billingCity || "",
+ state: cart.billingState || "",
+ zip: cart.billingZipCode || "",
+ referral: cart.couponCode,
+ cents: cart.total*100, // cents here.
+ numUsers: cart.userCount,
+ purchaseType: cart.billingPurchaseType,
+ }
+ cart.customerId = _recordPurchase(purchase);
+ return purchase;
+}
+
+function _performCreditCardPurchase() {
+ var cart = _cart();
+ var purchase = _generatePurchaseRecord();
+ var payInfo = checkout.generatePayInfo(cart);
+
+ // log everything but the CVV, which we're not allowed to store
+ // any longer than it takes to process this transaction.
+ var savedCvv = payInfo.cardCvv;
+ delete payInfo.cardCvv;
+ checkout.writeToEncryptedLog(fastJSON.stringify({date: String(new Date()), purchase: purchase, customerId: cart.customerId, payInfo: payInfo}));
+ payInfo.cardCvv = savedCvv;
+
+ var result =
+ billing.directPurchase(cart.invoiceId, cart.customerId,
+ "EEPNET", cart.total || 0.01,
+ cart.couponCode || "",
+ payInfo, _absoluteUrl('paypalnotify'));
+
+ if (result.status == 'success') {
+ cart.status = 'success';
+ cart.purchaseComplete = true;
+ eepnet_checkout.generateLicenseKey(cart);
+ eepnet_checkout.sendReceiptEmail(cart);
+ eepnet_checkout.sendLicenseEmail(cart);
+ billing.log({type: 'purchase-complete', dollars: cart.total,
+ email: cart.email, user: cart.ownerName,
+ org: cart.organization});
+ // TODO: generate key and include in receipt page, and add to purchase table.
+ } else if (result.status == 'pending') {
+ cart.status = 'pending';
+ cart.purchaseComplete = true;
+ eepnet_checkout.sendReceiptEmail(cart);
+ // save the receipt email text to resend later.
+ eepnet_checkout.updatePurchaseWithReceipt(cart.customerId,
+ eepnet_checkout.receiptEmailText(cart));
+ } else if (result.status == 'failure') {
+ var paypalResult = result.debug;
+ billing.log({'type': 'FATAL', value: "Direct purchase failed on paypal.", cart: cart, paypal: paypalResult});
+ if (result.errorField.permanentErrors[0] == 'invoiceId') {
+ // repeat invoice id. damnit, this is bad.
+ sendEmail('support@pad.spline.inf.fu-berlin.de', 'urgent@pad.spline.inf.fu-berlin.de', 'DUPLICATE INVOICE WARNING!', {},
+ "Hey,\n\nThis is a billing system error. The EEPNET checkout tried to make a "+
+ "purchase with PayPal and got a duplicate invoice error on invoice ID "+cart.invoiceId+
+ ".\n\nUnless you're expecting this (or recently ran a selenium test, or have reason to "+
+ "believe this isn't an exceptional condition, please look into this "+
+ "and get back to the user ASAP!\n\n"+fastJSON.stringify(cart));
+ _validationError('', "Your payment was processed, but we cannot proceed. "+
+ "You will hear from us shortly via email. (If you don't hear from us "+
+ "within 24 hours, please email <a href='mailto:sales@pad.spline.inf.fu-berlin.de'>"+
+ "sales@pad.spline.inf.fu-berlin.de</a>.)");
+ }
+ checkout.validateErrorFields(function(x, y) { _validationError(x, y, 'billing-info') }, "There seems to be an error in your billing information."+
+ " Please verify and correct your ",
+ result.errorField.userErrors);
+ checkout.validateErrorFields(function(x, y) { _validationError(x, y, 'billing-info') }, "The bank declined your billing information. Please try a different ",
+ result.errorField.permanentErrors);
+ _validationError('', "A temporary error has prevented processing of your payment. Please try again later.");
+ } else {
+ billing.log({'type': 'FATAL', value: "Unknown error: "+result.status+" - debug: "+result.debug});
+ sendEmail('support@pad.spline.inf.fu-berlin.de', 'urgent@pad.spline.inf.fu-berlin.de', 'UNKNOWN ERROR WARNING!', {},
+ "Hey,\n\nThis is a billing system error. Some unknown error occurred. "+
+ "This shouldn't ever happen. Probably good to let J.D. know. <grin>\n\n"+
+ fastJSON.stringify(cart));
+ _validationError('', "An unknown error occurred. We're looking into it!")
+ }
+}
+
+function _completePaypalPurchase() {
+ var cart = _cart();
+ var purchaseInfo = cart.paypalPurchaseInfo;
+ var payerInfo = cart.paypalPayerInfo;
+
+ var result = billing.completeExpressPurchase(purchaseInfo, payerInfo, _absoluteUrl('paypalnotify'));
+ if (result.status == 'success') {
+ cart.status = 'success';
+ cart.purchaseComplete = true;
+ eepnet_checkout.generateLicenseKey(cart);
+ eepnet_checkout.sendReceiptEmail(cart);
+ eepnet_checkout.sendLicenseEmail(cart);
+ billing.log({type: 'purchase-complete', dollars: cart.total,
+ email: cart.email, user: cart.ownerName,
+ org: cart.organization});
+
+ } else if (result.status == 'pending') {
+ cart.status = 'pending';
+ cart.purchaseComplete = true;
+ eepnet_checkout.sendReceiptEmail(cart);
+ // save the receipt email text to resend later.
+ eepnet_checkout.updatePurchaseWithReceipt(cart.customerId,
+ eepnet_checkout.receiptEmailText(cart));
+ } else {
+ billing.log({'type': 'FATAL', value: "Paypal failed.", cart: cart, paypal: paypalResult});
+ _validationError("billingPurchaseType",
+ "There was an error processing your payment through PayPal. "+
+ "Please try again later, or use a different payment option.",
+ 'billing-info');
+ }
+}
+
+function _showReceipt() {
+ response.redirect(_pathTo('receipt'));
+}
+
+function render_confirmation_post() {
+ var cart = _cart();
+
+ _updateCosts(); // no fishy business, please.
+
+ if (cart.billingPurchaseType == 'creditcard') {
+ _performCreditCardPurchase();
+ _showReceipt();
+ } else if (cart.billingPurchaseType == 'paypal') {
+ _completePaypalPurchase();
+ _showReceipt();
+ }
+}
+
+//--------------------------------------------------------------------------------
+// receipt
+//--------------------------------------------------------------------------------
+
+function render_receipt_post() {
+ response.redirect(request.path);
+}