10

First off, I appreciate this is open ended and SE isn't the best place for it. For a lack of a better place to ask though, here we are:

I've just built a system for a client where users could sign up an book places on events. None of the bookings on this system require payment, so it's just a case of submitting a form which creates an entry in a channel called "bookings" using:

action=saveEntry

I now have a client who needs to take bookings for events which require payment, and to list those bookings in a front end page. I'm trying to use Charge for payments (only because it seems easy to use, and my client doesn't want to pay monthly for something), which requires the form action:

action=charge/charge

The issue I have is that I want to submit a single form which takes a payment and creates a booking (action=saveEntry) without writing a plugin. I'm not a backend developer, I don't know how to write plugins (despite trying). None of the eCommerce addons available for Craft are out of beta yet.

Is there any way to take a payment and create a booking using template code?

0

2 Answers 2

11

We did something similar with Charge when we were accepting payments for a Craft Virtual Training course. It does involve writing a plugin, but thankfully all of the heavy lifting for saving entries and charging credit cards is handled by the services provided by Craft and Charge, so the only thing the plugin has to worry about is collecting post data and passing it to some APIs.

Start off by creating a primary plugin class (see Setting Things Up in the Craft plugin docs), and then giving your plugin a controller with the following code:

<?php
namespace Craft;

class FooController extends BaseController
{
    public $allowAnonymous = array('actionCreateBooking');

    public function actionCreateBooking()
    {
        // Require this to be a POST request
        $this->requirePostRequest();

        // Require that the user is logged in
        craft()->userSession->requireLogin();

        // Get the user
        $user = craft()->userSession->getUser();

        // Do any custom validation here
        // ...

        // Charge the card
        $charge = new ChargeModel();

        $charge->cardToken     = craft()->request->getRequiredPost('cardToken');
        $charge->cardLast4     = craft()->request->getPost('cardLast4');
        $charge->cardType      = craft()->request->getPost('cardType');
        $charge->cardName      = craft()->request->getPost('cardName');
        $charge->cardExpMonth  = craft()->request->getPost('cardExpMonth');
        $charge->cardExpYear   = craft()->request->getPost('cardExpYear');

        $charge->customerName  = craft()->request->getPost('customerName');
        $charge->customerEmail = craft()->request->getPost('customerEmail');

        $charge->planAmount    = 10000; // In cents

        if ($charge->validate() && craft()->charge->handlePayment($charge))
        {
            // Save the booking entry
            $entry = new EntryModel();
            $entry->sectionId = craft()->request->getPost('sectionId');
            $entry->typeId    = craft()->request->getPost('typeId'); // Not necessary if there's only one entry type
            $entry->authorId  = $user->id;
            $entry->enabled   = true;

            $entry->getContent()->title = 'New Booking: '.$user->username;
            $entry->getContent()->chargeId = $charge->id; // Custom number field
            $entry->getContent()->someOtherCustomField = 'xyz';

            craft()->entries->saveEntry($entry);

            // Redirect the request based on the 'redirect' param
            craft()->userSession->setNotice('Booking saved.');
            $this->redirectToPostedUrl();
        }
        else
        {
            craft()->userSession->setError('Couldn’t charge the card.');

            // Send the charge model to the template
            craft()->urlManager->setRouteVariables(array(
                'charge' => $charge
            ));
        }
    }
}

You might want to hard-code the sectionId and typeId rather than leaving it up to the POST data, and there might be other slight changes you want to make, but that’s the gist.

With the plugin in place, you would just need to create a form that captures all of the info the controller is looking for, and posts it to the foo/createBooking action:

<form method="post" accept-charset="UTF-8">
    {{ getCsrfInput() }}
    <input type="hidden" name="action" value="foo/createBooking">

    <!-- ... -->
</form>
6
  • Thank you so much Brandon - saved me time and money posting that. And I've got a better idea of how the plugin stuff works together after seeing a live example. I did hardcode the section ID after all, and I see how the custom fields work. Brilliant! Commented Oct 9, 2014 at 10:24
  • Exactly what Brandon said. I've implemented that same solution a number of times for projects (and while it's semi-obvious when you know what's going on it's not always clear this approach can work for basically any similar setup). Commented Oct 9, 2014 at 13:40
  • Hi Joel/Brandon - just revisiting this now and I've realised that the {hash} from the payment form (charge/success/{hash}) doesn't work when using the plugin as an action instead of charge/charge - it sends the user to /charge/success/%7Bhash%7D. Is there a way to get the plugin to pull in the hash from Charge? Commented Oct 30, 2014 at 14:17
  • @DarylKnight If you're running your own controller infront of the charge payment you can adjust the redirect directly after the craft()->charge->handlePayment returns. I couldn't say exactly why the {hash} isn't automatically parsing in your case, that specific variable replacement is inherited from Craft's internal request controllers not something Charge is doing specially. Commented Oct 30, 2014 at 16:40
  • No problem, thanks for getting back to me! Commented Oct 30, 2014 at 16:53
1

Currently, you will have to either use a plugin, or dump all your content into a notes field given by Charge (this would require JS coding). There are new features coming up in 2.0, but you would need to talk to Joel over at Square Bit for any details. If this is a crucial feature, you can hire a Craft developer over at Straight Up Craft.

0

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.