<?php
/**
 * This Software is the property of OXID eSales and is protected
 * by copyright law - it is NOT Freeware.
 *
 * Any unauthorized use of this software without a valid license key
 * is a violation of the license agreement and will be prosecuted by
 * civil and criminal law.
 *
 * @link      http://www.oxid-esales.com
 * @copyright (C) OXID eSales AG 2003-2017
 * @version   OXID eShop EE
 */

/**
 * Voucher manager.
 * Performs deletion, generating, assigning to group and other voucher
 * managing functions.
 *
 */
class oxps_patches_oxvoucher extends oxps_patches_oxvoucher_parent
{
    /**
     * Gets voucher from db by given number.
     *
     * @param string $sVoucherNr         Voucher number
     * @param array  $aVouchers          Array of available vouchers (default array())
     * @param bool   $blCheckavalability check if voucher is still reserver od not
     *
     * @throws oxVoucherException exception
     *
     * @return mixed
     */
    public function getVoucherByNr($sVoucherNr, $aVouchers = array(), $blCheckavalability = false)
    {
        $oRet = null;
        if (!is_null($sVoucherNr)) {

            $sViewName = $this->getViewName();
            $sSeriesViewName = getViewName('oxvoucherseries');
            $oDb = oxDb::getDb();

            $sQ = "select {$sViewName}.* from {$sViewName}, {$sSeriesViewName} where
                        {$sSeriesViewName}.oxid = {$sViewName}.oxvoucherserieid and
                        {$sViewName}.oxvouchernr = " . $oDb->quote($sVoucherNr) . " and ";

            if (is_array($aVouchers)) {
                foreach ($aVouchers as $sVoucherId => $sSkipVoucherNr) {
                    $sQ .= "{$sViewName}.oxid != " . $oDb->quote($sVoucherId) . " and ";
                }
            }
            $sQ .= "( {$sViewName}.oxorderid is NULL || {$sViewName}.oxorderid = '' ) ";
            $sQ .= " and ( {$sViewName}.oxdateused is NULL || {$sViewName}.oxdateused = 0 ) ";

            // Validate end date of voucher (To prevent issue in case same voucher number been used for multiple voucherseries)
            $sQ .= " and {$sSeriesViewName}.oxenddate >= NOW()";

            //voucher timeout for 3 hours
            if ($blCheckavalability) {
                $iTime = time() - $this->_getVoucherTimeout();
                $sQ .= " and {$sViewName}.oxreserved < '{$iTime}' ";
            }

            $sQ .= " limit 1";

            if (!($oRet = $this->assignRecord($sQ))) {
                $oEx = oxNew('oxVoucherException');
                $oEx->setMessage('ERROR_MESSAGE_VOUCHER_NOVOUCHER');
                $oEx->setVoucherNr($sVoucherNr);
                throw $oEx;
            }
        }

        return $oRet;
    }

    /**
     * Checks if calculation with vouchers of the same series possible. Returns
     * true on success.
     *
     * @param array $aVouchers array of vouchers
     *
     * @throws oxVoucherException exception
     *
     * @return bool
     *
     */
    protected function _isAvailableWithSameSeries($aVouchers)
    {
        if (is_array($aVouchers)) {
            $sId = $this->getId();
            if (isset($aVouchers[$sId])) {
                unset($aVouchers[$sId]);
            }
            $oSeries = $this->getSerie();
            if (!$oSeries->oxvoucherseries__oxallowsameseries->value) {
                $oBasket = $this->getSession()->getBasket();
                foreach ($aVouchers as $voucherId => $voucherNr) {
                    $oVoucher = oxNew('oxVoucher');
                    $oVoucher->load($voucherId);
                    if ($this->oxvouchers__oxvoucherserieid->value == $oVoucher->oxvouchers__oxvoucherserieid->value) {
                        // removing voucher on error
                        $oBasket->removeVoucher($voucherId);

                        $oEx = oxNew('oxVoucherException');
                        $oEx->setMessage('ERROR_MESSAGE_VOUCHER_NOTALLOWEDSAMESERIES');
                        $oEx->setVoucherNr($this->oxvouchers__oxvouchernr->value);
                        throw $oEx;
                    }
                }
            }
        }

        return true;
    }

    /**
     * Checks if calculation with vouchers from the other series possible.
     * Returns true on success.
     *
     * @param array $aVouchers array of vouchers
     *
     * @throws oxVoucherException exception
     *
     * @return bool
     */
    protected function _isAvailableWithOtherSeries($aVouchers)
    {
        if (is_array($aVouchers) && count($aVouchers)) {
            $oSeries = $this->getSerie();
            $sIds = implode(',', oxDb::getInstance()->quoteArray(array_keys($aVouchers)));
            $blAvailable = true;
            $oDb = oxDb::getDb();
            if (!$oSeries->oxvoucherseries__oxallowotherseries->value) {
                // just search for vouchers with different series
                $sSql = "select 1 from oxvouchers where oxvouchers.oxid in ($sIds) and ";
                $sSql .= "oxvouchers.oxvoucherserieid != " . $oDb->quote($this->oxvouchers__oxvoucherserieid->value);
                $blAvailable &= !$oDb->getOne($sSql);
            } else {
                // search for vouchers with different series and those vouchers do not allow other series
                $sSql = "select 1 from oxvouchers left join oxvoucherseries on oxvouchers.oxvoucherserieid=oxvoucherseries.oxid ";
                $sSql .= "where oxvouchers.oxid in ($sIds) and oxvouchers.oxvoucherserieid != " . $oDb->quote($this->oxvouchers__oxvoucherserieid->value);
                $sSql .= "and not oxvoucherseries.oxallowotherseries";
                $blAvailable &= !$oDb->getOne($sSql);
            }
            if (!$blAvailable) {
                // removing voucher on error
                if (is_array($aVouchers)) {
                    $oBasket = $this->getSession()->getBasket();
                    foreach ($aVouchers as $key => $value) {
                        $oBasket->removeVoucher($key);
                    }
                }

                $oEx = oxNew('oxVoucherException');
                $oEx->setMessage('ERROR_MESSAGE_VOUCHER_NOTALLOWEDOTHERSERIES');
                $oEx->setVoucherNr($this->oxvouchers__oxvouchernr->value);
                throw $oEx;
            }
        }

        return true;
    }
}
