<p>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 <a href="http://squarebit.co.uk/" rel="nofollow">Joel over at Square Bit</a> for any details. If this is a crucial feature, you can hire a Craft developer over at <a href="http://straightupcraft.com/professionals" rel="nofollow">Straight Up Craft</a>.</p>

CC BY-SA 3.0
2014-10-08T10:48:55.683Z
2014-10-08T10:48:55.683Z
Bryan Redeagle
<p>We did something similar with Charge when we were accepting payments for a <a href="http://buildwithcraft.com/training">Craft Virtual Training</a> 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.</p>

<p>Start off by creating a primary plugin class (see <a href="http://buildwithcraft.com/docs/plugins/setting-things-up">Setting Things Up</a> in the Craft plugin docs), and then giving your plugin a <a href="http://buildwithcraft.com/docs/plugins/controllers">controller</a> with the following code:</p>

<pre class="lang-php prettyprint-override"><code>&lt;?php
namespace Craft;

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

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

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

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

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

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

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

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

        $charge-&gt;planAmount    = 10000; // In cents

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

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

            craft()-&gt;entries-&gt;saveEntry($entry);

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

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

<p>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.</p>

<p>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 <code>foo/createBooking</code> action:</p>

<pre class="lang-html prettyprint-override"><code>&lt;form method="post" accept-charset="UTF-8"&gt;
    {{ getCsrfInput() }}
    &lt;input type="hidden" name="action" value="foo/createBooking"&gt;

    &lt;!-- ... --&gt;
&lt;/form&gt;
</code></pre>

CC BY-SA 3.0
2014-10-09T10:24:07.703Z
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!
darylknight
CC BY-SA 3.0
2014-10-09T13:40:58.460Z
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).
Joel Bradbury
CC BY-SA 3.0
2014-10-30T14:17:08.080Z
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?
darylknight
CC BY-SA 3.0
2014-10-30T16:40:02.003Z
@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.
Joel Bradbury
CC BY-SA 3.0
2014-10-30T16:53:59.180Z
No problem, thanks for getting back to me!
darylknight
CC BY-SA 3.0
2015-04-29T12:20:26.450Z
Just to update this comment above about {hash} not being properly parsed out, it's just a case of making sure you pass the object to the redirectToPostedUrl() method, so, in this case that'd be : $this->redirectToPostedUrl($charge)
Joel Bradbury
CC BY-SA 3.0
2014-10-08T15:36:31.000Z
2014-10-08T18:38:39.317Z
2014-10-08T18:38:39.317Z
Brandon Kelly
<p>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:</p>

<p>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:</p>

<pre><code>action=saveEntry
</code></pre>

<p>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 <a href="http://squarebit.co.uk/plugins/charge">Charge</a> 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:</p>

<pre><code>action=charge/charge
</code></pre>

<p>The issue I have is that I want to submit a single form which takes a payment and creates a booking (action=saveEntry) <strong>without writing a plugin</strong>. 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.</p>

<p>Is there any way to take a payment and create a booking using template code?</p>

<plugin-development><events><booking>
Booking paid-for events: How?
# Booking paid-for events: How?

(Asked by: username_0 on 2014-10-08)

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?

**Tags:** plugin-development, events, booking


---

## 2 answers

### Answer by username_2 on 2014-10-08. Score: 11 | Accepted answer

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:
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:

    {{ getCsrfInput() }}

> **Comments:**
> **username_0**: 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!  
> **username_3**: 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).  
> **username_0**: 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?  
> **username_3**: @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.  
> **username_0**: No problem, thanks for getting back to me!  
> **username_3**: Just to update this comment above about {hash} not being properly parsed out, it's just a case of making sure you pass the object to the redirectToPostedUrl() method, so, in this case that'd be : $this->redirectToPostedUrl($charge)  

---

### Answer by username_1 on 2014-10-08. Score: 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](http://squarebit.co.uk/) for any details. If this is a crucial feature, you can hire a Craft developer over at [Straight Up Craft](http://straightupcraft.com/professionals).


---

