OXID eShop CE  4.9.7
 All Classes Files Functions Variables Pages
oxvoucher.php
Go to the documentation of this file.
1 <?php
2 
9 class oxVoucher extends oxBase
10 {
11 
12  protected $_oSerie = null;
13 
20  protected $_blDisableShopCheck = true;
21 
25  protected $_sClassName = 'oxvoucher';
26 
30  public function __construct()
31  {
33  $this->init('oxvouchers');
34  }
35 
47  public function getVoucherByNr($sVoucherNr, $aVouchers = array(), $blCheckavalability = false)
48  {
49  $oRet = null;
50  if (!is_null($sVoucherNr)) {
51 
52  $sViewName = $this->getViewName();
53  $sSeriesViewName = getViewName('oxvoucherseries');
54  $oDb = oxDb::getDb();
55 
56  $sQ = "select {$sViewName}.* from {$sViewName}, {$sSeriesViewName} where
57  {$sSeriesViewName}.oxid = {$sViewName}.oxvoucherserieid and
58  {$sViewName}.oxvouchernr = " . $oDb->quote($sVoucherNr) . " and ";
59 
60  if (is_array($aVouchers)) {
61  foreach ($aVouchers as $sVoucherId => $sSkipVoucherNr) {
62  $sQ .= "{$sViewName}.oxid != " . $oDb->quote($sVoucherId) . " and ";
63  }
64  }
65  $sQ .= "( {$sViewName}.oxorderid is NULL || {$sViewName}.oxorderid = '' ) ";
66  $sQ .= " and ( {$sViewName}.oxdateused is NULL || {$sViewName}.oxdateused = 0 ) ";
67 
68  //voucher timeout for 3 hours
69  if ($blCheckavalability) {
70  $iTime = time() - $this->_getVoucherTimeout();
71  $sQ .= " and {$sViewName}.oxreserved < '{$iTime}' ";
72  }
73 
74  $sQ .= " limit 1";
75 
76  if (!($oRet = $this->assignRecord($sQ))) {
77  $oEx = oxNew('oxVoucherException');
78  $oEx->setMessage('ERROR_MESSAGE_VOUCHER_NOVOUCHER');
79  $oEx->setVoucherNr($sVoucherNr);
80  throw $oEx;
81  }
82  }
83 
84  return $oRet;
85  }
86 
94  public function markAsUsed($sOrderId, $sUserId, $dDiscount)
95  {
96  //saving oxreserved field
97  if ($this->oxvouchers__oxid->value) {
98  $this->oxvouchers__oxorderid->setValue($sOrderId);
99  $this->oxvouchers__oxuserid->setValue($sUserId);
100  $this->oxvouchers__oxdiscount->setValue($dDiscount);
101  $this->oxvouchers__oxdateused->setValue(date("Y-m-d", oxRegistry::get("oxUtilsDate")->getTime()));
102  $this->save();
103  }
104  }
105 
109  public function markAsReserved()
110  {
111  //saving oxreserved field
112  $sVoucherID = $this->oxvouchers__oxid->value;
113 
114  if ($sVoucherID) {
115  $oDb = oxDb::getDb();
116  $sQ = "update oxvouchers set oxreserved = " . time() . " where oxid = " . $oDb->quote($sVoucherID);
117  $oDb->Execute($sQ);
118  }
119  }
120 
124  public function unMarkAsReserved()
125  {
126  //saving oxreserved field
127  $sVoucherID = $this->oxvouchers__oxid->value;
128 
129  if ($sVoucherID) {
130  $oDb = oxDb::getDb();
131  $sQ = "update oxvouchers set oxreserved = 0 where oxid = " . $oDb->quote($sVoucherID);
132  $oDb->Execute($sQ);
133  }
134  }
135 
145  public function getDiscountValue($dPrice)
146  {
147  if ($this->_isProductVoucher()) {
148  return $this->_getProductDiscoutValue((double) $dPrice);
149  } elseif ($this->_isCategoryVoucher()) {
150  return $this->_getCategoryDiscoutValue((double) $dPrice);
151  } else {
152  return $this->_getGenericDiscoutValue((double) $dPrice);
153  }
154  }
155 
156  // Checking General Availability
167  public function checkVoucherAvailability($aVouchers, $dPrice)
168  {
169  $this->_isAvailableWithSameSeries($aVouchers);
170  $this->_isAvailableWithOtherSeries($aVouchers);
171  $this->_isValidDate();
172  $this->_isAvailablePrice($dPrice);
173  $this->_isNotReserved();
174 
175  // returning true - no exception was thrown
176  return true;
177  }
178 
190  public function checkBasketVoucherAvailability($aVouchers, $dPrice)
191  {
192  $this->_isAvailableWithSameSeries($aVouchers);
193  $this->_isAvailableWithOtherSeries($aVouchers);
194  $this->_isValidDate();
195  $this->_isAvailablePrice($dPrice);
196 
197  // returning true - no exception was thrown
198  return true;
199  }
200 
210  protected function _isAvailablePrice($dPrice)
211  {
212  $oSeries = $this->getSerie();
213  $oCur = $this->getConfig()->getActShopCurrencyObject();
214  if ($oSeries->oxvoucherseries__oxminimumvalue->value && $dPrice < ($oSeries->oxvoucherseries__oxminimumvalue->value * $oCur->rate)) {
215  $oEx = oxNew('oxVoucherException');
216  $oEx->setMessage('ERROR_MESSAGE_VOUCHER_INCORRECTPRICE');
217  $oEx->setVoucherNr($this->oxvouchers__oxvouchernr->value);
218  throw $oEx;
219  }
220 
221  return true;
222  }
223 
235  protected function _isAvailableWithSameSeries($aVouchers)
236  {
237  if (is_array($aVouchers)) {
238  $sId = $this->getId();
239  if (isset($aVouchers[$sId])) {
240  unset($aVouchers[$sId]);
241  }
242  $oSeries = $this->getSerie();
243  if (!$oSeries->oxvoucherseries__oxallowsameseries->value) {
244  foreach ($aVouchers as $voucherId => $voucherNr) {
245  $oVoucher = oxNew('oxVoucher');
246  $oVoucher->load($voucherId);
247  if ($this->oxvouchers__oxvoucherserieid->value == $oVoucher->oxvouchers__oxvoucherserieid->value) {
248  $oEx = oxNew('oxVoucherException');
249  $oEx->setMessage('ERROR_MESSAGE_VOUCHER_NOTALLOWEDSAMESERIES');
250  $oEx->setVoucherNr($this->oxvouchers__oxvouchernr->value);
251  throw $oEx;
252  }
253  }
254  }
255  }
256 
257  return true;
258  }
259 
270  protected function _isAvailableWithOtherSeries($aVouchers)
271  {
272  if (is_array($aVouchers) && count($aVouchers)) {
273  $oSeries = $this->getSerie();
274  $sIds = implode(',', oxDb::getInstance()->quoteArray(array_keys($aVouchers)));
275  $blAvailable = true;
276  $oDb = oxDb::getDb();
277  if (!$oSeries->oxvoucherseries__oxallowotherseries->value) {
278  // just search for vouchers with different series
279  $sSql = "select 1 from oxvouchers where oxvouchers.oxid in ($sIds) and ";
280  $sSql .= "oxvouchers.oxvoucherserieid != " . $oDb->quote($this->oxvouchers__oxvoucherserieid->value);
281  $blAvailable &= !$oDb->getOne($sSql);
282  } else {
283  // search for vouchers with different series and those vouchers do not allow other series
284  $sSql = "select 1 from oxvouchers left join oxvoucherseries on oxvouchers.oxvoucherserieid=oxvoucherseries.oxid ";
285  $sSql .= "where oxvouchers.oxid in ($sIds) and oxvouchers.oxvoucherserieid != " . $oDb->quote($this->oxvouchers__oxvoucherserieid->value);
286  $sSql .= "and not oxvoucherseries.oxallowotherseries";
287  $blAvailable &= !$oDb->getOne($sSql);
288  }
289  if (!$blAvailable) {
290  $oEx = oxNew('oxVoucherException');
291  $oEx->setMessage('ERROR_MESSAGE_VOUCHER_NOTALLOWEDOTHERSERIES');
292  $oEx->setVoucherNr($this->oxvouchers__oxvouchernr->value);
293  throw $oEx;
294  }
295  }
296 
297  return true;
298  }
299 
307  protected function _isValidDate()
308  {
309  $oSeries = $this->getSerie();
310  $iTime = time();
311 
312  // If date is not set will add day before and day after to check if voucher valid today.
313  $iTomorrow = mktime(0, 0, 0, date("m"), date("d") + 1, date("Y"));
314  $iYesterday = mktime(0, 0, 0, date("m"), date("d") - 1, date("Y"));
315 
316  // Checks if beginning date is set, if not set $iFrom to yesterday so it will be valid.
317  $iFrom = ((int) $oSeries->oxvoucherseries__oxbegindate->value) ?
318  strtotime($oSeries->oxvoucherseries__oxbegindate->value) : $iYesterday;
319 
320  // Checks if end date is set, if no set $iTo to tomorrow so it will be valid.
321  $iTo = ((int) $oSeries->oxvoucherseries__oxenddate->value) ?
322  strtotime($oSeries->oxvoucherseries__oxenddate->value) : $iTomorrow;
323 
324  if ($iFrom < $iTime && $iTo > $iTime) {
325  return true;
326  }
327 
328  $oEx = oxNew('oxVoucherException');
329  $oEx->setMessage('MESSAGE_COUPON_EXPIRED');
330  if ($iFrom > $iTime && $iTo > $iTime) {
331  $oEx->setMessage('ERROR_MESSAGE_VOUCHER_NOVOUCHER');
332  }
333  $oEx->setVoucherNr($this->oxvouchers__oxvouchernr->value);
334  throw $oEx;
335  }
336 
344  protected function _isNotReserved()
345  {
346 
347  if ($this->oxvouchers__oxreserved->value < time() - $this->_getVoucherTimeout()) {
348  return true;
349  }
350 
351  $oEx = oxNew('oxVoucherException');
352  $oEx->setMessage('EXCEPTION_VOUCHER_ISRESERVED');
353  $oEx->setVoucherNr($this->oxvouchers__oxvouchernr->value);
354  throw $oEx;
355  }
356 
357  // Checking User Availability
367  public function checkUserAvailability($oUser)
368  {
369 
370  $this->_isAvailableInOtherOrder($oUser);
371  $this->_isValidUserGroup($oUser);
372 
373  // returning true if no exception was thrown
374  return true;
375  }
376 
386  protected function _isAvailableInOtherOrder($oUser)
387  {
388  $oSeries = $this->getSerie();
389  if (!$oSeries->oxvoucherseries__oxallowuseanother->value) {
390 
391  $oDb = oxDb::getDb();
392  $sSelect = 'select count(*) from ' . $this->getViewName() . ' where oxuserid = ' . $oDb->quote($oUser->oxuser__oxid->value) . ' and ';
393  $sSelect .= 'oxvoucherserieid = ' . $oDb->quote($this->oxvouchers__oxvoucherserieid->value) . ' and ';
394  $sSelect .= '((oxorderid is not NULL and oxorderid != "") or (oxdateused is not NULL and oxdateused != 0)) ';
395 
396  if ($oDb->getOne($sSelect)) {
397  $oEx = oxNew('oxVoucherException');
398  $oEx->setMessage('ERROR_MESSAGE_VOUCHER_NOTALLOWEDSAMESERIES');
399  $oEx->setVoucherNr($this->oxvouchers__oxvouchernr->value);
400  throw $oEx;
401  }
402  }
403 
404  return true;
405  }
406 
416  protected function _isValidUserGroup($oUser)
417  {
418  $oVoucherSeries = $this->getSerie();
419  $oUserGroups = $oVoucherSeries->setUserGroups();
420 
421  if (!$oUserGroups->count()) {
422  return true;
423  }
424 
425  if ($oUser) {
426  foreach ($oUserGroups as $oGroup) {
427  if ($oUser->inGroup($oGroup->getId())) {
428  return true;
429  }
430  }
431  }
432 
433  $oEx = oxNew('oxVoucherException');
434  $oEx->setMessage('ERROR_MESSAGE_VOUCHER_NOTVALIDUSERGROUP');
435  $oEx->setVoucherNr($this->oxvouchers__oxvouchernr->value);
436  throw $oEx;
437  }
438 
444  public function getSimpleVoucher()
445  {
446  $oVoucher = new stdClass();
447  $oVoucher->sVoucherId = $this->getId();
448  $oVoucher->sVoucherNr = $this->oxvouchers__oxvouchernr->value;
449 
450  // R. set in oxBasket : $oVoucher->fVoucherdiscount = oxRegistry::getLang()->formatCurrency( $this->oxvouchers__oxdiscount->value );
451 
452  return $oVoucher;
453  }
454 
460  public function getSerie()
461  {
462  if ($this->_oSerie !== null) {
463  return $this->_oSerie;
464  }
465  $oSeries = oxNew('oxVoucherSerie');
466  if (!$oSeries->load($this->oxvouchers__oxvoucherserieid->value)) {
467  throw oxNew("oxObjectException");
468  }
469  $this->_oSerie = $oSeries;
470 
471  return $oSeries;
472  }
473 
479  protected function _isProductVoucher()
480  {
481  $oDb = oxDb::getDb();
482  $oSeries = $this->getSerie();
483  $sSelect = "select 1 from oxobject2discount where oxdiscountid = " . $oDb->quote($oSeries->getId()) . " and oxtype = 'oxarticles'";
484  $blOk = ( bool ) $oDb->getOne($sSelect);
485 
486  return $blOk;
487  }
488 
494  protected function _isCategoryVoucher()
495  {
496  $oDb = oxDb::getDb();
497  $oSeries = $this->getSerie();
498  $sSelect = "select 1 from oxobject2discount where oxdiscountid = " . $oDb->quote($oSeries->getId()) . " and oxtype = 'oxcategories'";
499  $blOk = ( bool ) $oDb->getOne($sSelect);
500 
501  return $blOk;
502  }
503 
509  protected function _getSerieDiscount()
510  {
511  $oSeries = $this->getSerie();
512  $oDiscount = oxNew('oxDiscount');
513 
514  $oDiscount->setId($oSeries->getId());
515  $oDiscount->oxdiscount__oxshopid = new oxField($oSeries->oxvoucherseries__oxshopid->value);
516  $oDiscount->oxdiscount__oxactive = new oxField(true);
517  $oDiscount->oxdiscount__oxactivefrom = new oxField($oSeries->oxvoucherseries__oxbegindate->value);
518  $oDiscount->oxdiscount__oxactiveto = new oxField($oSeries->oxvoucherseries__oxenddate->value);
519  $oDiscount->oxdiscount__oxtitle = new oxField($oSeries->oxvoucherseries__oxserienr->value);
520  $oDiscount->oxdiscount__oxamount = new oxField(1);
521  $oDiscount->oxdiscount__oxamountto = new oxField(MAX_64BIT_INTEGER);
522  $oDiscount->oxdiscount__oxprice = new oxField(0);
523  $oDiscount->oxdiscount__oxpriceto = new oxField(MAX_64BIT_INTEGER);
524  $oDiscount->oxdiscount__oxaddsumtype = new oxField($oSeries->oxvoucherseries__oxdiscounttype->value == 'percent' ? '%' : 'abs');
525  $oDiscount->oxdiscount__oxaddsum = new oxField($oSeries->oxvoucherseries__oxdiscount->value);
526  $oDiscount->oxdiscount__oxitmartid = new oxField();
527  $oDiscount->oxdiscount__oxitmamount = new oxField();
528  $oDiscount->oxdiscount__oxitmmultiple = new oxField();
529 
530  return $oDiscount;
531  }
532 
540  protected function _getBasketItems($oDiscount = null)
541  {
542  if ($this->oxvouchers__oxorderid->value) {
543  return $this->_getOrderBasketItems($oDiscount);
544  } elseif ($this->getSession()->getBasket()) {
545  return $this->_getSessionBasketItems($oDiscount);
546  } else {
547  return array();
548  }
549  }
550 
558  protected function _getOrderBasketItems($oDiscount = null)
559  {
560  if (is_null($oDiscount)) {
561  $oDiscount = $this->_getSerieDiscount();
562  }
563 
564  $oOrder = oxNew('oxOrder');
565  $oOrder->load($this->oxvouchers__oxorderid->value);
566 
567  $aItems = array();
568  $iCount = 0;
569 
570  foreach ($oOrder->getOrderArticles(true) as $oOrderArticle) {
571  if (!$oOrderArticle->skipDiscounts() && $oDiscount->isForBasketItem($oOrderArticle)) {
572  $aItems[$iCount] = array(
573  'oxid' => $oOrderArticle->getProductId(),
574  'price' => $oOrderArticle->oxorderarticles__oxbprice->value,
575  'discount' => $oDiscount->getAbsValue($oOrderArticle->oxorderarticles__oxbprice->value),
576  'amount' => $oOrderArticle->oxorderarticles__oxamount->value,
577  );
578  $iCount++;
579  }
580  }
581 
582  return $aItems;
583  }
584 
592  protected function _getSessionBasketItems($oDiscount = null)
593  {
594  if (is_null($oDiscount)) {
595  $oDiscount = $this->_getSerieDiscount();
596  }
597 
598  $oBasket = $this->getSession()->getBasket();
599  $aItems = array();
600  $iCount = 0;
601 
602  foreach ($oBasket->getContents() as $oBasketItem) {
603  if (!$oBasketItem->isDiscountArticle() && ($oArticle = $oBasketItem->getArticle()) && !$oArticle->skipDiscounts() && $oDiscount->isForBasketItem($oArticle)) {
604 
605  $aItems[$iCount] = array(
606  'oxid' => $oArticle->getId(),
607  'price' => $oArticle->getBasketPrice($oBasketItem->getAmount(), $oBasketItem->getSelList(), $oBasket)->getPrice(),
608  'discount' => $oDiscount->getAbsValue($oArticle->getBasketPrice($oBasketItem->getAmount(), $oBasketItem->getSelList(), $oBasket)->getPrice()),
609  'amount' => $oBasketItem->getAmount(),
610  );
611 
612  $iCount++;
613  }
614  }
615 
616  return $aItems;
617  }
618 
628  protected function _getGenericDiscoutValue($dPrice)
629  {
630  $oSeries = $this->getSerie();
631  if ($oSeries->oxvoucherseries__oxdiscounttype->value == 'absolute') {
632  $oCur = $this->getConfig()->getActShopCurrencyObject();
633  $dDiscount = $oSeries->oxvoucherseries__oxdiscount->value * $oCur->rate;
634  } else {
635  $dDiscount = $oSeries->oxvoucherseries__oxdiscount->value / 100 * $dPrice;
636  }
637 
638  if ($dDiscount > $dPrice) {
639  $dDiscount = $dPrice;
640  }
641 
642  return $dDiscount;
643  }
644 
645 
651  public function getDiscount()
652  {
653  $oSeries = $this->getSerie();
654 
655  return $oSeries->oxvoucherseries__oxdiscount->value;
656  }
657 
663  public function getDiscountType()
664  {
665  $oSeries = $this->getSerie();
666 
667  return $oSeries->oxvoucherseries__oxdiscounttype->value;
668  }
669 
670 
680  protected function _getProductDiscoutValue($dPrice)
681  {
682  $oDiscount = $this->_getSerieDiscount();
683  $aBasketItems = $this->_getBasketItems($oDiscount);
684 
685  // Basket Item Count and isAdmin check (unble to access property $oOrder->_getOrderBasket()->_blSkipVouchersAvailabilityChecking)
686  if (!count($aBasketItems) && !$this->isAdmin()) {
687  $oEx = oxNew('oxVoucherException');
688  $oEx->setMessage('ERROR_MESSAGE_VOUCHER_NOVOUCHER');
689  $oEx->setVoucherNr($this->oxvouchers__oxvouchernr->value);
690  throw $oEx;
691  }
692 
693  $oSeries = $this->getSerie();
694 
695  $oVoucherPrice = oxNew('oxPrice');
696  $oDiscountPrice = oxNew('oxPrice');
697  $oProductPrice = oxNew('oxPrice');
698  $oProductTotal = oxNew('oxPrice');
699 
700  // Is the voucher discount applied to at least one basket item
701  $blDiscountApplied = false;
702 
703  foreach ($aBasketItems as $aBasketItem) {
704 
705  // If discount was already applied for the voucher to at least one basket items, then break
706  if ($blDiscountApplied and !empty($oSeries->oxvoucherseries__oxcalculateonce->value)) {
707  break;
708  }
709 
710  $oDiscountPrice->setPrice($aBasketItem['discount']);
711  $oProductPrice->setPrice($aBasketItem['price']);
712 
713  // Individual voucher is not multiplied by article amount
714  if (!$oSeries->oxvoucherseries__oxcalculateonce->value) {
715  $oDiscountPrice->multiply($aBasketItem['amount']);
716  $oProductPrice->multiply($aBasketItem['amount']);
717  }
718 
719  $oVoucherPrice->add($oDiscountPrice->getBruttoPrice());
720  $oProductTotal->add($oProductPrice->getBruttoPrice());
721 
722  if (!empty($aBasketItem['discount'])) {
723  $blDiscountApplied = true;
724  }
725  }
726 
727  $dVoucher = $oVoucherPrice->getBruttoPrice();
728  $dProduct = $oProductTotal->getBruttoPrice();
729 
730  if ($dVoucher > $dProduct) {
731  return $dProduct;
732  }
733 
734  return $dVoucher;
735  }
736 
746  protected function _getCategoryDiscoutValue($dPrice)
747  {
748  $oDiscount = $this->_getSerieDiscount();
749  $aBasketItems = $this->_getBasketItems($oDiscount);
750 
751  // Basket Item Count and isAdmin check (unable to access property $oOrder->_getOrderBasket()->_blSkipVouchersAvailabilityChecking)
752  if (!count($aBasketItems) && !$this->isAdmin()) {
753  $oEx = oxNew('oxVoucherException');
754  $oEx->setMessage('ERROR_MESSAGE_VOUCHER_NOVOUCHER');
755  $oEx->setVoucherNr($this->oxvouchers__oxvouchernr->value);
756  throw $oEx;
757  }
758 
759  $oProductPrice = oxNew('oxPrice');
760  $oProductTotal = oxNew('oxPrice');
761 
762  foreach ($aBasketItems as $aBasketItem) {
763  $oProductPrice->setPrice($aBasketItem['price']);
764  $oProductPrice->multiply($aBasketItem['amount']);
765  $oProductTotal->add($oProductPrice->getBruttoPrice());
766  }
767 
768  $dProduct = $oProductTotal->getBruttoPrice();
769  $dVoucher = $oDiscount->getAbsValue($dProduct);
770 
771  return ($dVoucher > $dProduct) ? $dProduct : $dVoucher;
772  }
773 
781  public function __get($sName)
782  {
783  switch ($sName) {
784 
785  // simple voucher mapping
786  case 'sVoucherId':
787  return $this->getId();
788  break;
789  case 'sVoucherNr':
790  return $this->oxvouchers__oxvouchernr;
791  break;
792  case 'fVoucherdiscount':
793  return $this->oxvouchers__oxdiscount;
794  break;
795  }
796  return parent::__get($sName);
797  }
798 
805  protected function _getVoucherTimeout()
806  {
807  $iVoucherTimeout = intval(oxRegistry::getConfig()->getConfigParam('iVoucherTimeout')) ?
808  intval(oxRegistry::getConfig()->getConfigParam('iVoucherTimeout')) :
809  3 * 3600;
810 
811  return $iVoucherTimeout;
812  }
813 }