<?php

/**
 * Class d3_oxorder_heidelpay
 */
class d3_oxorder_heidelpay extends d3_oxorder_heidelpay_parent
{

    /**
     * {@inheritdoc}
     */
    protected function _setOrderStatus($sStatus)
    {
        if (false == d3_cfg_mod::get('d3heidelpay')->isActive()) {
            return parent::_setOrderStatus($sStatus);
        }

        $oDB = oxDb::getDb();

        $sOldStatus = $oDB->getOne('select oxtransstatus from oxorder where oxid="' . $this->getId() . '"');
        $sPaid      = $oDB->getOne('select oxpaid from oxorder where oxid="' . $this->getId() . '"');
        $sPaymentId = $this->getFieldData('oxpaymenttype');

        /** @var d3_d3heidelpay_models_settings_heidelpay $oSettings */
        $oSettings = oxNew('d3_d3heidelpay_models_settings_heidelpay', d3_cfg_mod::get('d3heidelpay'));

        /** @var oxPayment $oPayment */
        $oPayment = oxNew('oxPayment');
        $oPayment->load($sPaymentId);

        if (false == $oSettings->isAssignedToHeidelPayment($oPayment)) {
            return parent::_setOrderStatus($sStatus);
        }

        $blIsPrepayment = $oSettings->getPayment($oPayment) instanceof d3_d3heidelpay_models_payment_prepayment;
        $blIsWaiting    = $sOldStatus == 'WAITING' && $sPaid == '0000-00-00 00:00:00';
        if ($blIsPrepayment && $blIsWaiting) {
            $sStatus = "WAITING";
        }

        return parent::_setOrderStatus($sStatus);
    }

    /**
     * Returns bank transfer data if available
     *
     * @return stdClass|null
     */
    public function getHeidelpayBankTransferData()
    {
        if (false == d3_cfg_mod::get('d3heidelpay')->isActive()) {
            return null;
        }

        /** @var d3hpprepaymentdata $oPrePaymentData */
        $oPrePaymentData = oxNew("d3hpprepaymentdata");

        /** @var d3_d3heidelpay_models_settings_heidelpay $oSettings */
        /** @var oxPayment $oPayment */
        $oSettings = oxNew('d3_d3heidelpay_models_settings_heidelpay', d3_cfg_mod::get('d3heidelpay'));
        $oPayment  = oxNew('oxPayment');
        $oPayment->load($this->getFieldData('oxpaymenttype'));
        if (false == $oSettings->isAssignedToHeidelPayment($oPayment)) {
            return null;
        }

        $oHeidelpayment = $oSettings->getPayment($oPayment);

        if ($oHeidelpayment instanceof d3_d3heidelpay_models_payment_prepayment || $oHeidelpayment instanceof d3_d3heidelpay_models_payment_billsafe) {
            return $oPrePaymentData->getBankTransferData($this);
        }

        return null;
    }

    /**
     * @param oxBasket $oBasket
     * @param oxUser   $oUser
     *
     * @return int|null
     */
    public function d3CreateTemporaryOrder(oxBasket $oBasket, oxUser $oUser)
    {
        /* D3 START disabled - 03.03.2016 - KH <!--
        We can't use the session challenge for this break up.
        We need every "hotfix"- payment->toOrder a new order

        $sGetChallenge = oxRegistry::getSession()->getVariable('sess_challenge');
        if ($this->_checkOrderExist($sGetChallenge)) {
            oxRegistry::getUtils()->logger('BLOCKER');

            // we might use this later, this means that somebody klicked like mad on order button
            return self::ORDER_STATE_ORDEREXISTS;
        }

        // if not recalculating order, use sess_challenge id, else leave old order id

        // use this ID
        $this->setId($sGetChallenge);
        --> */

        $this->setId(oxRegistry::get('oxUtilsObject')->generateUId());

        // validating various order/basket parameters before finalizing
        $iOrderState = $this->validateOrder($oBasket, $oUser);
        if ($iOrderState) {
            return $iOrderState;
        }

        /* D3 START added - HotFix - 08.03.2016 - KH */
        if (false == d3_cfg_mod::get('d3heidelpay')->getValue('blD3HpHFSetZeroOrderNumber') && false == $this->oxorder__oxordernr->value) {
            $this->_setNumber();
        }
        /* D3 END   added - HotFix - 08.03.2016 - KH */

        // copies user info
        $this->_setUser($oUser);

        // copies basket info
        $this->_loadFromBasket($oBasket);

        // payment information
        $this->_setPayment($oBasket->getPaymentId());

        // set folder information, if order is new
        // #M575 in recalculating order case folder must be the same as it was

        $this->_setFolder();

        //#4005: Order creation time is not updated when order processing is complete
        $this->_updateOrderDate();

        // marking as not finished
        $this->_setOrderStatus('PENDING');

        /* D3 START added - #4998 - 29.04.2016 - KH */
        $aVouchers = $oBasket->getVouchers();
        if (count($aVouchers)) {
            $aVoucherIds  = array();
            $moduleConfig = d3_cfg_mod::get('d3heidelpay');
            $pendingLimit = $moduleConfig->getValue('sD3HpHFOrderPendingTime');
            foreach ($aVouchers as $sVoucherId => $oStdVoucher) {
                $oVoucher = oxNew('oxvoucher');
                if ($oVoucher->load($oStdVoucher->sVoucherId)) {
                    $aVoucherIds[$oStdVoucher->sVoucherId] = $oStdVoucher->sVoucherId;
                    $oVoucher->assign(array('oxreserved' => time() + $pendingLimit * 3600));
                    $oVoucher->save();
                }
            }
            $this->assign(array('d3heidelpayvouchers' => implode('|', $aVoucherIds)));
        }
        /* D3 END   added - #4998 - 29.04.2016 - KH */

        //saving all order data to DB
        $this->save();

        /* D3 START added - Hotfix - 10.03.2016 - KH */
        // set order ID for thankyou
        $oBasket->setOrderId($this->getId());
        oxRegistry::getSession()->setVariable('sess_challenge', $this->getId());

        /* D3 END   added - Hotfix - 10.03.2016 - KH */

        return null;
    }

    /**
     * @param oxBasket $oBasket
     * @param oxUser   $oUser
     *
     * @return bool|int|void
     */
    public function d3FinalizeTemporaryOrder(oxBasket $oBasket, oxUser $oUser)
    {
        $oUserPayment = $this->_setPayment($oBasket->getPaymentId());
        // executing payment (on failure deletes order and returns error code)
        // in case when recalculating order, payment execution is skipped

        $blRet = $this->_executePayment($oBasket, $oUserPayment);
        if ($blRet !== true) {
            return $blRet;
        }

        if (!$this->oxorder__oxordernr->value) {
            $this->_setNumber();
        } else {
            oxNew('oxCounter')->update($this->_getCounterIdent(), $this->oxorder__oxordernr->value);
        }

        // executing TS protection
        if ($oBasket->getTsProductId()) {
            $blRet = $this->_executeTsProtection($oBasket);
            if ($blRet !== true) {
                return $blRet;
            }
        }

        // deleting remark info only when order is finished
        oxRegistry::getSession()->deleteVariable('ordrem');
        oxRegistry::getSession()->deleteVariable('stsprotection');

        //#4005: Order creation time is not updated when order processing is complete
        //$this->_updateOrderDate();

        // updating order trans status (success status)
        $this->_setOrderStatus('OK');

        // store orderid
        $oBasket->setOrderId($this->getId());

        // updating wish lists
        $this->_updateWishlist($oBasket->getContents(), $oUser);

        // updating users notice list
        $this->_updateNoticeList($oBasket->getContents(), $oUser);

        // marking vouchers as used and sets them to $this->_aVoucherList (will be used in order email)
        // skipping this action in case of order recalculation
        $this->_markVouchers($oBasket, $oUser);

        // send order by email to shop owner and current user
        // skipping this action in case of order recalculation
        $iRet = $this->_sendOrderByEmail($oUser, $oBasket, $oUserPayment);

        return $iRet;
    }

    /**
     * @return oxBasket
     * @throws oxArticleException
     * @throws oxArticleInputException
     * @throws oxNoArticleException
     */
    public function d3GetOrderBasket()
    {
        $this->reloadDelivery(false);
        $this->reloadDiscount(false);
        $oBasket = $this->_getOrderBasket(false);

        foreach ($this->getOrderArticles() as $oOrderArticle) {
            $oBasket->addOrderArticleToBasket($oOrderArticle);
        }

        /* D3 START added - #4998 - 29.04.2016 - KH */
        $aVouchers = explode('|', $this->getFieldData('d3heidelpayvouchers'));
        if (count($aVouchers)) {
            $oBasket->setSkipVouchersChecking(true);
            foreach ($aVouchers as $sVoucherId) {
                $oVoucher = oxNew('oxvoucher');
                if ($oVoucher->load($sVoucherId)) {
                    $oBasket->addVoucher($sVoucherId);
                }
            }
        }
        /* D3 END   added - #4998 - 29.04.2016 - KH */

        //$oBasket->setVoucherDiscount($this->oxorder__oxvoucherdiscount->value);
        $oBasket->calculateBasket();

        foreach ($oBasket->getContents() as $oBasketItem) {
            /** @var d3_oxbasketitem_heidelpay $oBasketItem */
            $oArticle = oxNew('oxarticle');
            $oArticle->loadInLang($this->oxorder__oxlang->value, $oBasketItem->getArticle()->getProductId());
            $oBasketItem->d3SetArticle($oArticle);
        }

        return $oBasket;
    }

    public function finalizeOrder(oxBasket $oxBasket, $oxUser, $blRecalculatingOrder = false)
    {
        $return = parent::finalizeOrder($oxBasket, $oxUser, $blRecalculatingOrder);

        $registry           = oxRegistry::get('oxRegistry');
        $modulConfiguration = d3_cfg_mod::get('d3heidelpay');

        if (false == $modulConfiguration->isActive() || $registry->getConfig()->isAdmin()) {

            return $return;
        }

        /** @var oxPayment $oPayment */
        $oPayment = oxNew('oxPayment');
        $oPayment->load($oxBasket->getPaymentId());

        /** @var d3_d3heidelpay_models_factory $factory */
        $factory = oxNew('d3_d3heidelpay_models_factory', $modulConfiguration);

        try {
            /** @var d3_d3heidelpay_models_payment_abstract $heidelPayment */
            $heidelPayment = $factory->getSettings()->getPayment($oPayment);
        } catch (d3_d3heidelpay_models_payment_exception_PaymentNotReferencedToHeidelpayException $oEx) {
            return $return;
        }

        if (false == $heidelPayment instanceof d3_d3heidelpay_models_payment_abstract) {
            return $return;
        }

        $transaction = $factory->getLatestTransactionByReference($factory->getReferenceNumber());

        if (false == $transaction) {
            return $return;
        }

        /** @var d3_d3heidelpay_models_transactionlog_reader_heidelpay $reader */
        $reader       = $transaction->getTransactiondata();
        $basketAmount = $oxBasket->getPrice()->getBruttoPrice();

        $basketAmount = number_format($basketAmount, '2', '.', '');
        if ($basketAmount !== $reader->getAmount()) {

            $transStatusError = $modulConfiguration->getValue('d3heidelpay_oxtransstatuserror');
            if (empty($transStatusError)) {
                $transStatusError = 'ERROR';
            }
            $aAssignment                  = array();
            $aAssignment['oxtransstatus'] = $transStatusError;
            $aAssignment['oxpaid']        = '0000-00-00 00:00:00';
            $this->assign($aAssignment);
            $this->save();

            $text    = $registry->getLang()->translateString('D3HEIDELPAY_DIFFERENCE_IN_ORDER_ERRRORMESSAGE', null, true);
            $message = sprintf($text, $this->getFieldData('oxordernr'), $reader->getUniqueid());

            $subject = $registry->getLang()->translateString('D3HEIDELPAY_DIFFERENCE_IN_ORDER_SUBJECT', null, true);
            $subject .= $this->getFieldData('oxordernr');

            $recipient = $modulConfiguration->getValue('d3heidelpay_oxtransstatuserrormail');
            if (empty($recipient)) {
                $recipient = $this->getConfig()->getActiveShop()->getFieldData('oxowneremail');
            }

            $email = oxNew('oxEMail');
            $email->d3SendNotificationToShopOwner($subject, $message, $recipient);

            $modulConfiguration->d3getLog()->log(
                d3log::ERROR,
                __CLASS__,
                __FUNCTION__,
                __LINE__,
                $subject,
                $message
            );
        }

        return $return;
    }
}
