Epay payment gateway integration in TYPO3 extbase extension.

The process is, after booking we will create the new booking record containing booked product info like product name, its total price etc.

The booking record creation action will be like this,

public function createAction(\TYPO3\myext\Domain\Model\Packagebooking $newPackagebooking) {

//create package
$this->packagebookingRepository->add($newPackagebooking);

//get created package id
$persistenceManager = GeneralUtility::makeInstance(‘TYPO3\\CMS\\Extbase\\Persistence\\Generic\\PersistenceManager’);
$persistenceManager->persistAll();
$pUidNew = $newPackagebooking->getUid();

/* Redirect to payment */
$this->redirect(‘payment’, ‘Packagebooking’ ,NULL ,array(‘packagebooking’=>$pUidNew));
}

After record creation we will redirect to payment Action.

public function paymentAction($packagebooking) {
/*
* MD5 key: mymd5key
* merchant id: 123456
*
*/

//get the booked record. $packagebooking contains the uid of the last created booking record
$packagebooking = $this->packagebookingRepository->findByUid($packagebooking);

//generate return url
$accepturl = $this->controllerContext
->getUriBuilder()->reset()
->setTargetPageUid($this->settings[‘orderConfirmationPid’])
->setNoCache(1)
->setArguments(array(
‘tx_myext_checkout’ => array(
‘orderid’ => $packagebooking->getUid(),
‘action’ => ‘paymentconfirm’,
‘controller’ => ‘Packagebooking’,
)
))->buildFrontendUri();
$accepturl = GeneralUtility::getIndpEnv(‘TYPO3_SITE_URL’).$accepturl;

//Generate javascript required for payment gateway api
$paymentwindowJs = ”;
$paymentParams = array(
‘merchantnumber’ => “123456”,
‘amount’ => $packagebooking->getTotalprice() * 100,
‘currency’ => “DKK”,
‘windowstate’=> “2”,
‘orderid’ => $packagebooking->getUid(),
‘accepturl’ => $accepturl
);
$paymentwindowJs .='<script type=”text/javascript”>’;
$paymentwindowJs .=’paymentwindow = new PaymentWindow({‘;
foreach ($paymentParams as $key => $value) {
$paymentwindowJs .= “‘” . $key . “‘: \”” . $value . “\”,\n”;
}
$paymentwindowJs .= “‘hash’:”.'”‘.md5(implode(“”, array_values($paymentParams)) . “mymd5key”).'”‘;
$paymentwindowJs .= ‘});’;
$paymentwindowJs .=’paymentwindow.append(“payment-div”);paymentwindow.open();</script>’;

$this->view->assignMultiple(
array(
‘paymentwindowJs’ => $paymentwindowJs
)
);
}

Payment action template will be like this

<f:layout name=”Default” />
<f:section name=”main”>
<h1>Payment</h1>
<div class=”thankyoumessage”>
<div id=”payment-div”></div>
</div>

<script charset=”UTF-8″ src=”https://ssl.ditonlinebetalingssystem.dk/integration/ewindow/paymentwindow.js” type=”text/javascript”></script>
<f:format.raw>{paymentwindowJs}</f:format.raw>

</f:section>

Aftere this we will proceed in payment by Epay api. After the payment has been done, we will redirec to confirmation page having confirmation plugin.

Below is the confirmation action, here we will calculate the MD5 hash from the return url and compare it with the received hash. And update the payment record accordingly.

public function paymentconfirmAction() {
$posted = GeneralUtility::_GET(‘tx_myext_checkout’);
$posted[‘txnid’] = GeneralUtility::_GET(‘txnid’);
$posted[‘ordernumber’] = GeneralUtility::_GET(‘orderid’);
$posted[‘paymenttype’] = GeneralUtility::_GET(‘paymenttype’);
$posted[‘hash’] = GeneralUtility::_GET(‘hash’);

//Check for bad hash
$params = $_GET;
$var = “”;
foreach ($params as $key => $value) {
if(is_array($value)) {
foreach ($_GET[‘tx_myext_checkout’] as $key => $value) {
$var .= $value;
}
} elseif($key != “hash”) {
$var .= $value;
}
}

$genstamp = md5($var . “mymd5key”);

if($genstamp != $_GET[“hash”]) {
$status = ‘Hash is not valid’;
} else {
//Hash is OK
$status = ‘Transaction success’;
}

$this->packagebookingRepository->updateOrderEpay($posted, $status);
$this->view->assign(‘status’, $status);
}

Hope this helps someone!

 

TYPO3 fluid selectbox viewhelper.

In the below example, the selectbox options are coming from locallang.

‘hotelclass’ => array(
‘exclude’ => 1,
‘label’ => ‘LLL:EXT:myext/Resources/Private/Language/locallang_db.xlf:tx_myext_domain_model_hotels.hotelclass’,
‘config’ => array(
‘type’ => ‘select’,
‘items’ => array(
array(‘LLL:EXT:myext/Resources/Private/Language/locallang_db.xlf:tx_myext_domain_model_hotels.hotelclass.2star’, ‘2’),
array(‘LLL:EXT:myext/Resources/Private/Language/locallang_db.xlf:tx_myext_domain_model_hotels.hotelclass.3star’, ‘3’),
array(‘LLL:EXT:myext/Resources/Private/Language/locallang_db.xlf:tx_myext_domain_model_hotels.hotelclass.5star’, ‘5’),
array(‘LLL:EXT:myext/Resources/Private/Language/locallang_db.xlf:tx_myext_domain_model_hotels.hotelclass.7star’, ‘7’),
),
‘size’ => 1,
‘maxitems’ => 1,
‘eval’ => ”
),
)

To display this select box in FE from, we can use the custom view helper.

To use the viewhelpler follow the following steps.

1. Create the file

myext/Classes/viewHelpers/TcaOptionsViewHelper.php

2. Add the below code

<?php
namespace TYPO3\Myext\ViewHelpers;

class TcaOptionsViewHelper extends \TYPO3\CMS\Fluid\Core\ViewHelper\AbstractViewHelper {

/**
* local cache for dataMaps
* @var array
*/
protected $dataMaps = array();

/**
* @var \TYPO3\CMS\Extbase\Persistence\Generic\Mapper\DataMapper
* @inject
*/
protected $dataMapper;

/**
* objectManager
*
* @var \TYPO3\CMS\Extbase\Object\ObjectManager
* @inject
*/
protected $objectManager;

/**
* Is returning select values for a property or propertyPath of a given object or className
* @param mixed $subject The object or className the property belongs to
* @param string $property The property itself
* @return array The select options as array
*/
public function render($subject = NULL, $property = ”) {
if (!is_object($subject) && is_string($subject) && class_exists($subject)) {
$subject= $this->objectManager->get($subject);
}
return self::getSelectOptions($property, $subject);
}

/**
* Is resolving the select values for a property or propertyPath of a given object or className
* @param string $propertyPath The property itself
* @param object $subject The object or className the property belongs to
* @return array The select options as array
*/
private function getSelectOptions($propertyPath, $subject) {
$selectOptions = array();

if (is_object($subject)) {
$propertyPathSegments = \TYPO3\CMS\Core\Utility\GeneralUtility::trimExplode(‘.’, $propertyPath);
$object = clone($subject);
$propertyName = $propertyPath;

// resolve a property path
if (count($propertyPathSegments) > 1) {
foreach($propertyPathSegments as $key => $propertyName) {
$propertyType = $this->dataMapper->getType(get_class($tempObject), $propertyName);
if (strpos($propertyType,’_’)) {
$object = $this->objectManager->create($propertyType);
} else {
break;
}
}
}

$dataMap = self::getDataMap($object);

if ($dataMap == NULL || !$dataMap->isPersistableProperty($propertyName)) {
return $selectOptions;
}

$tableName = $this->dataMapper->convertClassNameToTableName(get_class($object));
$columnName = $dataMap->getColumnMap($propertyName)->getColumnName();

// only convert select items which do not have a DB relation
$columnConfig = $GLOBALS[‘TCA’][$tableName][‘columns’][$columnName][‘config’];
if ($columnConfig[‘type’] == ‘select’ && count($columnConfig[‘items’]) && !$columnConfig[‘foreign_table’]) {
foreach ($columnConfig[‘items’] as $option) {
$selectOptions[$option[1]] = \TYPO3\CMS\Extbase\Utility\LocalizationUtility::translate($option[0], $this->controllerContext->getRequest()->getControllerExtensionName());
}
}
}
return $selectOptions;
}

/**
* Resolve the dataMap for the given object
* @param object $object The domain object to get the dataMap for
* @return Tx_Extbase_Persistence_Mapper_DataMap
*/
private function getDataMap($object) {
$class = is_object($object) ? get_class($object) : $object;
if (!isset($this->dataMaps[$class])) {
$this->dataMaps[$class] = $this->dataMapper->getDataMap($class);
}
return $this->dataMaps[$class];
}
}
?>

3. Add the below lines in fluid template, that is intended to show FE form

{namespace custom=TYPO3\Myext\ViewHelpers}

<f:form.select property=”hotelclass” options=”{custom:TcaOptions(property:’hotelclass’,subject:’TYPO3\\Myext\\Domain\\Model\\Hotels’)}” />

4. The output source will be like this.

<select name=”tx_myext_hotels[hotels][hotelclass]”>
<option value=”2″>2 Star</option>
<option value=”3″>3 Star</option>
<option value=”5″>5 Star</option>
<option value=”7″>7 Star</option>
</select>

Thanks to: https://gist.github.com/anonymous/888297

 

TYPO3 Extbase call action through ajax.

Below are the steps to call controller action from ajax.

1. Add the following typoscript on extension setup.

plugin.tx_extname {}
#After this
actionname = PAGE
actionname {
typeNum = 1234
config {
disableAllHeaderCode = 1
additionalHeaders = Content-type:application/html|Cache-Control:no-cache, must-revalidate, max-age=0|Pragma:no-cache
xhtml_cleaning = 0
admPanel = 0
}

10 < tt_content.list.20.extname_controllername
}

3. In controller

/**
* action actionname
*
* @return void
*/
public function actionnameAction() {
return ‘test ajax content’;
}

2. In fluid template

<f:link.action action=”actionname” additionalParams=”{type:’1234′,no_cache:’1′}” noCacheHash=”1″ class=”test”>
Ajax click
</f:link.action>
<div id=”ajax_content”></div>
<script type=”text/javascript”>
$(document).ready(function(){
$(‘.test’).click(function() {
var href = $(this).attr(‘href’);
$.ajax({
url: href,
cache: false,
success: function(htmldata){
$(“#ajax_content”).html(htmldata);
}
});
return false;
});
});
</script>

If everything is correct, it should work.

Call TYPO3 plugin from typeNum

For example, If our plugin is intended to generate some xml sitemaps and we want to call that plugin like this http://www.mysite.com/?type=1234, We can follow the following steps.

1. In extension setup add the following typoscript

plugin.tx_myext {}
#After this

myext = PAGE
myext {
typeNum = 1234
10 = USER_INT
10 {
userFunc = tx_extbase_core_bootstrap->run
pluginName = MypluginName
extensionName = myExtName
controller = MyControllerName
action = actionName
}
config {
doctype = xhtml_basic
xhtml_cleaning = all
disableAllHeaderCode = 1
additionalHeaders = Content-type:text/xml
xhtml_cleaning = 0
admPanel = 0
debug = 0
}
}

Now, install the extension and if we call http://www.mysite.com/?type=1234, we can see direct xml structure, if everything is correctly written in the extension.