/**
  * Finishing Page from Checkout.
  *
  * @param \CommerceTeam\Commerce\Payment\PaymentInterface $paymentObj The payment
  *
  * @return string HTML-Content
  * @throws \Exception If no payment type was configured
  */
 public function finishIt(\CommerceTeam\Commerce\Payment\PaymentInterface $paymentObj = null)
 {
     $database = $this->getDatabaseConnection();
     $orderId = $this->getOrderId();
     if (!is_object($paymentObj)) {
         $paymentType = $this->getPaymentType();
         $config = SettingsFactory::getInstance()->getConfiguration('SYSPRODUCTS.PAYMENT.types.' . strtolower((string) $paymentType));
         if (!isset($config['class']) || !file_exists($config['path'])) {
             throw new \Exception('FINISHING: FATAL! No payment possible because no payment handler is configured!', 1395665876);
         }
         $paymentObj = GeneralUtility::makeInstance($config['class'], $this);
     } else {
         $config = SettingsFactory::getInstance()->getConfiguration('SYSPRODUCTS.PAYMENT.types.' . $paymentObj->getType());
     }
     if ($paymentObj instanceof \CommerceTeam\Commerce\Payment\PaymentInterface) {
         $paymentDone = $paymentObj->checkExternalData($_REQUEST, $this->sessionData);
     } else {
         $paymentDone = false;
     }
     // Check if terms are accepted
     if (!$paymentDone && (empty($this->piVars['terms']) || $this->piVars['terms'] != 'termschecked')) {
         $this->formError['terms'] = $this->pi_getLL('error_terms_not_accepted');
         $content = $this->handlePayment($paymentObj);
         if ($content == false) {
             $this->formError['terms'] = $this->pi_getLL('error_terms_not_accepted');
             $content = $this->getListing();
         }
         return $content;
     }
     // Check stock amount of articles
     if (!$this->checkStock()) {
         $content = $this->pi_getLL('not_all_articles_in_stock') . $this->pi_linkToPage($this->pi_getLL('no_stock_back'), $this->conf['noStockBackPID']);
         return $this->cObj->stdWrap($content, $this->conf['noStockWrap.']);
     }
     // Handle orders
     $feUser = $this->getFrontendUser();
     $basket = $this->getBasket();
     $hooks = HookFactory::getHooks('Controller/CheckoutController', 'finishIt');
     foreach ($hooks as $hookObj) {
         if (method_exists($hookObj, 'prepayment')) {
             $hookObj->prepayment($paymentObj, $basket);
         }
     }
     $this->debug($basket, '$basket', __FILE__ . ' ' . __LINE__);
     // Merge local lang array
     if (is_array($this->LOCAL_LANG) && isset($paymentObj->LOCAL_LANG)) {
         foreach ($this->LOCAL_LANG as $llKey => $llData) {
             $newLlData = array_merge($llData, (array) $paymentObj->LOCAL_LANG[$llKey]);
             $this->LOCAL_LANG[$llKey] = $newLlData;
         }
     }
     if (method_exists($paymentObj, 'hasSpecialFinishingForm') && $paymentObj->hasSpecialFinishingForm($_REQUEST)) {
         return $paymentObj->getSpecialFinishingForm($config, $this->sessionData, $basket);
     } elseif (!$paymentObj->finishingFunction($config, $this->sessionData, $basket)) {
         return $this->handlePayment($paymentObj);
     }
     foreach ($hooks as $hookObj) {
         if (method_exists($hookObj, 'postpayment')) {
             $hookObj->postpayment($paymentObj, $basket, $this);
         }
     }
     /*
      * We implement a new TS - Setting to handle the generating of orders.
      * if you want to use the "generateOrderId" - Hook and need a unique ID
      * this is only possible if you insert an empty order an make an update
      * later.
      */
     if (isset($this->conf['lockOrderIdInGenerateOrderId']) && $this->conf['lockOrderIdInGenerateOrderId'] == 1) {
         $orderData = array();
         $now = time();
         $orderData['crdate'] = $now;
         $orderData['tstamp'] = $now;
         $database->exec_INSERTquery('tx_commerce_orders', $orderData);
         $orderUid = $database->sql_insert_id();
         // make orderUid avaible in hookObjects
         $this->orderUid = $orderUid;
     }
     // Real finishing starts here !
     // Determine sysfolder, where to place all datasests
     // Default (if no hook us used, the Commerce default folder)
     if (isset($this->conf['newOrderPid']) and $this->conf['newOrderPid'] > 0) {
         $orderData['pid'] = $this->conf['newOrderPid'];
     }
     if (empty($orderData['pid']) || $orderData['pid'] < 0) {
         $comPid = array_keys(FolderRepository::getFolders($this->extKey, 0, 'COMMERCE'));
         $ordPid = array_keys(FolderRepository::getFolders($this->extKey, $comPid[0], 'Orders'));
         $incPid = array_keys(FolderRepository::getFolders($this->extKey, $ordPid[0], 'Incoming'));
         $orderData['pid'] = $incPid[0];
     }
     // Save the order, execute the hooks and stock
     $orderData = $this->saveOrder($orderId, $orderData['pid'], $basket, $paymentObj, true, true);
     // Send emails
     $this->userMailOk = $this->sendUserMail($orderId, $orderData);
     $this->adminMailOk = $this->sendAdminMail($orderId, $orderData);
     foreach ($hooks as $hookObj) {
         if (method_exists($hookObj, 'afterMailSend')) {
             $markerArray = $hookObj->afterMailSend($orderData, $this);
         }
     }
     // Start content rendering
     $content = $this->cObj->getSubpart($this->templateCode, '###FINISH###');
     $markerArray['###LISTING_BASKET###'] = $this->makeBasketView($basket, '###BASKET_VIEW###', GeneralUtility::intExplode(',', $this->conf['regularArticleTypes']), array('###LISTING_ARTICLE###', '###LISTING_ARTICLE2###'));
     $markerArray['###MESSAGE###'] = '';
     $markerArray['###LISTING_TITLE###'] = $this->pi_getLL('order_confirmation');
     if (method_exists($paymentObj, 'getSuccessData')) {
         $markerArray['###MESSAGE_PAYMENT_OBJECT###'] = $paymentObj->getSuccessData($this);
     } else {
         $markerArray['###MESSAGE_PAYMENT_OBJECT###'] = '';
     }
     $deliveryAddress = '';
     if ($orderData['cust_deliveryaddress']) {
         $data = $database->exec_SELECTgetSingleRow('*', 'tt_address', 'uid = ' . $orderData['cust_deliveryaddress']);
         if (is_array($data)) {
             $deliveryAddress = $this->makeAdressView($data, '###DELIVERY_ADDRESS###');
         }
     }
     $content = $this->cObj->substituteSubpart($content, '###DELIVERY_ADDRESS###', $deliveryAddress);
     $billingAddress = '';
     if ($orderData['cust_invoice']) {
         $data = $database->exec_SELECTgetSingleRow('*', 'tt_address', 'uid = ' . $orderData['cust_invoice']);
         if (is_array($data)) {
             $billingAddress = $this->makeAdressView($data, '###BILLING_ADDRESS_SUB###');
             $markerArray['###CUST_NAME###'] = $data['NAME'];
         }
     }
     $content = $this->cObj->substituteSubpart($content, '###BILLING_ADDRESS###', $billingAddress);
     $markerArray = $this->finishItRenderGoodBadMarker($markerArray);
     foreach ($hooks as $hookObj) {
         if (method_exists($hookObj, 'processMarker')) {
             $markerArray = $hookObj->processMarker($markerArray, $this);
         }
     }
     $content = $this->cObj->substituteMarkerArray($this->cObj->substituteMarkerArray($content, $markerArray), $this->languageMarker);
     foreach ($hooks as $hookObj) {
         if (method_exists($hookObj, 'postFinish')) {
             $hookObj->postFinish($basket, $this);
         }
     }
     // At last remove some things from the session
     if ($this->clearSessionAfterCheckout == true) {
         $feUser->setKey('ses', \CommerceTeam\Commerce\Utility\GeneralUtility::generateSessionKey('payment'), null);
         $feUser->setKey('ses', \CommerceTeam\Commerce\Utility\GeneralUtility::generateSessionKey('delivery'), null);
         $feUser->setKey('ses', \CommerceTeam\Commerce\Utility\GeneralUtility::generateSessionKey('billing'), null);
     }
     $basket->finishOrder();
     // create new basket to remove all values from old one
     /**
      * Basket.
      *
      * @var \CommerceTeam\Commerce\Domain\Model\Basket $basket
      */
     $basket = GeneralUtility::makeInstance('CommerceTeam\\Commerce\\Domain\\Model\\Basket');
     $basket->setSessionId(md5($feUser->id . ':' . rand(0, PHP_INT_MAX)));
     $basket->loadData();
     $feUser->setKey('ses', 'orderId', null);
     $feUser->setKey('ses', 'commerceBasketId-' . $basket->getBasketStoragePid(), $basket->getSessionId());
     $feUser->tx_commerce_basket = $basket;
     return $content;
 }