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>