OXID eShop CE  4.8.12
 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 
19  protected $_blDisableShopCheck = true;
20 
24  protected $_sClassName = 'oxvoucher';
25 
29  public function __construct()
30  {
32  $this->init( 'oxvouchers' );
33  }
34 
46  public function getVoucherByNr( $sVoucherNr, $aVouchers = array(), $blCheckavalability = false )
47  {
48  $oRet = null;
49  if ( !is_null( $sVoucherNr ) ) {
50 
51  $sViewName = $this->getViewName();
52  $sSeriesViewName = getViewName( 'oxvoucherseries' );
53  $oDb = oxDb::getDb();
54 
55  $sQ = "select {$sViewName}.* from {$sViewName}, {$sSeriesViewName} where
56  {$sSeriesViewName}.oxid = {$sViewName}.oxvoucherserieid and
57  {$sViewName}.oxvouchernr = " . $oDb->quote( $sVoucherNr ) . " and ";
58 
59  if ( is_array( $aVouchers ) ) {
60  foreach ( $aVouchers as $sVoucherId => $sSkipVoucherNr ) {
61  $sQ .= "{$sViewName}.oxid != " . $oDb->quote( $sVoucherId ) . " and ";
62  }
63  }
64  $sQ .= "( {$sViewName}.oxorderid is NULL || {$sViewName}.oxorderid = '' ) ";
65  $sQ .= " and ( {$sViewName}.oxdateused is NULL || {$sViewName}.oxdateused = 0 ) ";
66 
67  //voucher timeout for 3 hours
68  if ( $blCheckavalability ) {
69  $iTime = time() - $this->_getVoucherTimeout();
70  $sQ .= " and {$sViewName}.oxreserved < '{$iTime}' ";
71  }
72 
73  $sQ .= " limit 1";
74 
75  if ( ! ( $oRet = $this->assignRecord( $sQ ) ) ) {
76  $oEx = oxNew( 'oxVoucherException' );
77  $oEx->setMessage( 'ERROR_MESSAGE_VOUCHER_NOVOUCHER' );
78  $oEx->setVoucherNr( $sVoucherNr );
79  throw $oEx;
80  }
81  }
82 
83  return $oRet;
84  }
85 
95  public function markAsUsed( $sOrderId, $sUserId, $dDiscount )
96  {
97  //saving oxreserved field
98  if ( $this->oxvouchers__oxid->value ) {
99  $this->oxvouchers__oxorderid->setValue($sOrderId);
100  $this->oxvouchers__oxuserid->setValue($sUserId);
101  $this->oxvouchers__oxdiscount->setValue($dDiscount);
102  $this->oxvouchers__oxdateused->setValue(date( "Y-m-d", oxRegistry::get("oxUtilsDate")->getTime() ));
103  $this->save();
104  }
105  }
106 
112  public function markAsReserved()
113  {
114  //saving oxreserved field
115  $sVoucherID = $this->oxvouchers__oxid->value;
116 
117  if ( $sVoucherID ) {
118  $oDb = oxDb::getDb();
119  $sQ = "update oxvouchers set oxreserved = " . time() . " where oxid = " . $oDb->quote( $sVoucherID );
120  $oDb->Execute( $sQ );
121  }
122  }
123 
129  public function unMarkAsReserved()
130  {
131  //saving oxreserved field
132  $sVoucherID = $this->oxvouchers__oxid->value;
133 
134  if ( $sVoucherID ) {
135  $oDb = oxDb::getDb();
136  $sQ = "update oxvouchers set oxreserved = 0 where oxid = " . $oDb->quote( $sVoucherID );
137  $oDb->Execute($sQ);
138  }
139  }
140 
150  public function getDiscountValue( $dPrice )
151  {
152  if ($this->_isProductVoucher()) {
153  return $this->_getProductDiscoutValue( (double) $dPrice );
154  } elseif ($this->_isCategoryVoucher()) {
155  return $this->_getCategoryDiscoutValue( (double) $dPrice );
156  } else {
157  return $this->_getGenericDiscoutValue( (double) $dPrice );
158  }
159  }
160 
161  // Checking General Availability
172  public function checkVoucherAvailability( $aVouchers, $dPrice )
173  {
174  $this->_isAvailableWithSameSeries( $aVouchers );
175  $this->_isAvailableWithOtherSeries( $aVouchers );
176  $this->_isValidDate();
177  $this->_isAvailablePrice( $dPrice );
178  $this->_isNotReserved();
179 
180  // returning true - no exception was thrown
181  return true;
182  }
183 
195  public function checkBasketVoucherAvailability( $aVouchers, $dPrice )
196  {
197  $this->_isAvailableWithSameSeries( $aVouchers );
198  $this->_isAvailableWithOtherSeries( $aVouchers );
199  $this->_isValidDate();
200  $this->_isAvailablePrice( $dPrice );
201 
202  // returning true - no exception was thrown
203  return true;
204  }
205 
215  protected function _isAvailablePrice( $dPrice )
216  {
217  $oSeries = $this->getSerie();
218  $oCur = $this->getConfig()->getActShopCurrencyObject();
219  if ( $oSeries->oxvoucherseries__oxminimumvalue->value && $dPrice < ($oSeries->oxvoucherseries__oxminimumvalue->value*$oCur->rate) ) {
220  $oEx = oxNew( 'oxVoucherException' );
221  $oEx->setMessage('ERROR_MESSAGE_VOUCHER_INCORRECTPRICE');
222  $oEx->setVoucherNr($this->oxvouchers__oxvouchernr->value);
223  throw $oEx;
224  }
225 
226  return true;
227  }
228 
240  protected function _isAvailableWithSameSeries( $aVouchers )
241  {
242  if ( is_array( $aVouchers ) ) {
243  $sId = $this->getId();
244  if (isset($aVouchers[$sId])) {
245  unset($aVouchers[$sId]);
246  }
247  $oSeries = $this->getSerie();
248  if (!$oSeries->oxvoucherseries__oxallowsameseries->value) {
249  foreach ( $aVouchers as $voucherId => $voucherNr ) {
250  $oVoucher = oxNew( 'oxVoucher' );
251  $oVoucher->load($voucherId);
252  if ( $this->oxvouchers__oxvoucherserieid->value == $oVoucher->oxvouchers__oxvoucherserieid->value ) {
253  $oEx = oxNew( 'oxVoucherException' );
254  $oEx->setMessage('ERROR_MESSAGE_VOUCHER_NOTALLOWEDSAMESERIES');
255  $oEx->setVoucherNr( $this->oxvouchers__oxvouchernr->value );
256  throw $oEx;
257  }
258  }
259  }
260  }
261 
262  return true;
263  }
264 
275  protected function _isAvailableWithOtherSeries( $aVouchers )
276  {
277  if ( is_array( $aVouchers ) && count($aVouchers) ) {
278  $oSeries = $this->getSerie();
279  $sIds = implode(',', oxDb::getInstance()->quoteArray( array_keys( $aVouchers ) ) );
280  $blAvailable = true;
281  $oDb = oxDb::getDb();
282  if (!$oSeries->oxvoucherseries__oxallowotherseries->value) {
283  // just search for vouchers with different series
284  $sSql = "select 1 from oxvouchers where oxvouchers.oxid in ($sIds) and ";
285  $sSql .= "oxvouchers.oxvoucherserieid != " . $oDb->quote( $this->oxvouchers__oxvoucherserieid->value ) ;
286  $blAvailable &= !$oDb->getOne($sSql);
287  } else {
288  // search for vouchers with different series and those vouchers do not allow other series
289  $sSql = "select 1 from oxvouchers left join oxvoucherseries on oxvouchers.oxvoucherserieid=oxvoucherseries.oxid ";
290  $sSql .= "where oxvouchers.oxid in ($sIds) and oxvouchers.oxvoucherserieid != " . $oDb->quote( $this->oxvouchers__oxvoucherserieid->value );
291  $sSql .= "and not oxvoucherseries.oxallowotherseries";
292  $blAvailable &= !$oDb->getOne($sSql);
293  }
294  if ( !$blAvailable ) {
295  $oEx = oxNew( 'oxVoucherException' );
296  $oEx->setMessage('ERROR_MESSAGE_VOUCHER_NOTALLOWEDOTHERSERIES');
297  $oEx->setVoucherNr($this->oxvouchers__oxvouchernr->value);
298  throw $oEx;
299  }
300  }
301 
302  return true;
303  }
304 
312  protected function _isValidDate()
313  {
314  $oSeries = $this->getSerie();
315 
316  // If date is not set will add day before and day after to check if voucher valid today.
317  $iTomorrow = mktime( 0, 0, 0, date( "m" ), date( "d" )+1, date( "Y" ) );
318  $iYesterday = mktime( 0, 0, 0, date( "m" ), date( "d" )-1, date( "Y" ) );
319 
320  // Checks if beginning date is set, if not set $iFrom to yesterday so it will be valid.
321  $iFrom = ( (int)$oSeries->oxvoucherseries__oxbegindate->value ) ?
322  strtotime( $oSeries->oxvoucherseries__oxbegindate->value ) : $iYesterday;
323 
324  // Checks if end date is set, if no set $iTo to tomorrow so it will be valid.
325  $iTo = ( (int)$oSeries->oxvoucherseries__oxenddate->value ) ?
326  strtotime( $oSeries->oxvoucherseries__oxenddate->value ) : $iTomorrow;
327 
328  if ( $iFrom < time() && $iTo > time() ) {
329  return true;
330  }
331 
332  $oEx = oxNew( 'oxVoucherException' );
333  $oEx->setMessage('MESSAGE_COUPON_EXPIRED');
334  if ( $iFrom > time() && $iTo > time() ) {
335  $oEx->setMessage('ERROR_MESSAGE_VOUCHER_NOVOUCHER');
336  }
337  $oEx->setVoucherNr( $this->oxvouchers__oxvouchernr->value );
338  throw $oEx;
339  }
340 
348  protected function _isNotReserved()
349  {
350 
351  if ( $this->oxvouchers__oxreserved->value < time() - $this->_getVoucherTimeout() ) {
352  return true;
353  }
354 
355  $oEx = oxNew( 'oxVoucherException' );
356  $oEx->setMessage('EXCEPTION_VOUCHER_ISRESERVED');
357  $oEx->setVoucherNr( $this->oxvouchers__oxvouchernr->value );
358  throw $oEx;
359  }
360 
361  // Checking User Availability
371  public function checkUserAvailability( $oUser )
372  {
373 
374  $this->_isAvailableInOtherOrder( $oUser );
375  $this->_isValidUserGroup( $oUser );
376 
377  // returning true if no exception was thrown
378  return true;
379  }
380 
390  protected function _isAvailableInOtherOrder( $oUser )
391  {
392  $oSeries = $this->getSerie();
393  if ( !$oSeries->oxvoucherseries__oxallowuseanother->value ) {
394 
395  $oDb = oxDb::getDb();
396  $sSelect = 'select count(*) from '.$this->getViewName().' where oxuserid = '. $oDb->quote( $oUser->oxuser__oxid->value ) . ' and ';
397  $sSelect .= 'oxvoucherserieid = ' . $oDb->quote( $this->oxvouchers__oxvoucherserieid->value ) . ' and ';
398  $sSelect .= '((oxorderid is not NULL and oxorderid != "") or (oxdateused is not NULL and oxdateused != 0)) ';
399 
400  if ( $oDb->getOne( $sSelect )) {
401  $oEx = oxNew( 'oxVoucherException' );
402  $oEx->setMessage('ERROR_MESSAGE_VOUCHER_NOTALLOWEDSAMESERIES');
403  $oEx->setVoucherNr($this->oxvouchers__oxvouchernr->value);
404  throw $oEx;
405  }
406  }
407 
408  return true;
409  }
410 
420  protected function _isValidUserGroup( $oUser )
421  {
422  $oVoucherSeries = $this->getSerie();
423  $oUserGroups = $oVoucherSeries->setUserGroups();
424 
425  if ( !$oUserGroups->count() ) {
426  return true;
427  }
428 
429  if ( $oUser ) {
430  foreach ( $oUserGroups as $oGroup ) {
431  if ( $oUser->inGroup( $oGroup->getId() ) ) {
432  return true;
433  }
434  }
435  }
436 
437  $oEx = oxNew( 'oxVoucherException' );
438  $oEx->setMessage( 'ERROR_MESSAGE_VOUCHER_NOTVALIDUSERGROUP' );
439  $oEx->setVoucherNr( $this->oxvouchers__oxvouchernr->value );
440  throw $oEx;
441  }
442 
448  public function getSimpleVoucher()
449  {
450  $oVoucher = new stdClass();
451  $oVoucher->sVoucherId = $this->getId();
452  $oVoucher->sVoucherNr = $this->oxvouchers__oxvouchernr->value;
453  // R. set in oxBasket : $oVoucher->fVoucherdiscount = oxRegistry::getLang()->formatCurrency( $this->oxvouchers__oxdiscount->value );
454 
455  return $oVoucher;
456  }
457 
463  public function getSerie()
464  {
465  if ($this->_oSerie !== null) {
466  return $this->_oSerie;
467  }
468  $oSeries = oxNew('oxVoucherSerie');
469  if (!$oSeries->load($this->oxvouchers__oxvoucherserieid->value)) {
470  throw oxNew( "oxObjectException" );
471  }
472  $this->_oSerie = $oSeries;
473  return $oSeries;
474  }
475 
481  protected function _isProductVoucher()
482  {
483  $oDb = oxDb::getDb();
484  $oSeries = $this->getSerie();
485  $sSelect = "select 1 from oxobject2discount where oxdiscountid = ".$oDb->quote( $oSeries->getId() )." and oxtype = 'oxarticles'";
486  $blOk = ( bool ) $oDb->getOne( $sSelect );
487 
488  return $blOk;
489  }
490 
496  protected function _isCategoryVoucher()
497  {
498  $oDb = oxDb::getDb();
499  $oSeries = $this->getSerie();
500  $sSelect = "select 1 from oxobject2discount where oxdiscountid = ". $oDb->quote( $oSeries->getId() )." and oxtype = 'oxcategories'";
501  $blOk = ( bool ) $oDb->getOne( $sSelect );
502 
503  return $blOk;
504  }
505 
511  protected function _getSerieDiscount( )
512  {
513  $oSeries = $this->getSerie();
514  $oDiscount = oxNew('oxDiscount');
515 
516  $oDiscount->setId($oSeries->getId());
517  $oDiscount->oxdiscount__oxshopid = new oxField($oSeries->oxvoucherseries__oxshopid->value);
518  $oDiscount->oxdiscount__oxactive = new oxField(true);
519  $oDiscount->oxdiscount__oxactivefrom = new oxField($oSeries->oxvoucherseries__oxbegindate->value);
520  $oDiscount->oxdiscount__oxactiveto = new oxField($oSeries->oxvoucherseries__oxenddate->value);
521  $oDiscount->oxdiscount__oxtitle = new oxField($oSeries->oxvoucherseries__oxserienr->value);
522  $oDiscount->oxdiscount__oxamount = new oxField(1);
523  $oDiscount->oxdiscount__oxamountto = new oxField(MAX_64BIT_INTEGER);
524  $oDiscount->oxdiscount__oxprice = new oxField(0);
525  $oDiscount->oxdiscount__oxpriceto = new oxField(MAX_64BIT_INTEGER);
526  $oDiscount->oxdiscount__oxaddsumtype = new oxField($oSeries->oxvoucherseries__oxdiscounttype->value=='percent'?'%':'abs');
527  $oDiscount->oxdiscount__oxaddsum = new oxField($oSeries->oxvoucherseries__oxdiscount->value);
528  $oDiscount->oxdiscount__oxitmartid = new oxField();
529  $oDiscount->oxdiscount__oxitmamount = new oxField();
530  $oDiscount->oxdiscount__oxitmmultiple = new oxField();
531 
532  return $oDiscount;
533  }
534 
542  protected function _getBasketItems($oDiscount = null)
543  {
544  if ($this->oxvouchers__oxorderid->value) {
545  return $this->_getOrderBasketItems($oDiscount);
546  } elseif ( $this->getSession()->getBasket() ) {
547  return $this->_getSessionBasketItems($oDiscount);
548  } else {
549  return array();
550  }
551  }
552 
560  protected function _getOrderBasketItems($oDiscount = null)
561  {
562  if (is_null($oDiscount)) {
563  $oDiscount = $this->_getSerieDiscount();
564  }
565 
566  $oOrder = oxNew('oxOrder');
567  $oOrder->load($this->oxvouchers__oxorderid->value);
568 
569  $aItems = array();
570  $iCount = 0;
571 
572  foreach ( $oOrder->getOrderArticles(true) as $oOrderArticle ) {
573  if (!$oOrderArticle->skipDiscounts() && $oDiscount->isForBasketItem($oOrderArticle)) {
574  $aItems[$iCount] = array(
575  'oxid' => $oOrderArticle->getProductId(),
576  'price' => $oOrderArticle->oxorderarticles__oxbprice->value,
577  'discount' => $oDiscount->getAbsValue($oOrderArticle->oxorderarticles__oxbprice->value),
578  'amount' => $oOrderArticle->oxorderarticles__oxamount->value,
579  );
580  $iCount ++;
581  }
582  }
583 
584  return $aItems;
585  }
586 
594  protected function _getSessionBasketItems($oDiscount = null)
595  {
596  if (is_null($oDiscount)) {
597  $oDiscount = $this->_getSerieDiscount();
598  }
599 
600  $oBasket = $this->getSession()->getBasket();
601  $aItems = array();
602  $iCount = 0;
603 
604  foreach ( $oBasket->getContents() as $oBasketItem ) {
605  if ( !$oBasketItem->isDiscountArticle() && ( $oArticle = $oBasketItem->getArticle() ) && !$oArticle->skipDiscounts() && $oDiscount->isForBasketItem($oArticle) ) {
606 
607  $aItems[$iCount] = array(
608  'oxid' => $oArticle->getId(),
609  'price' => $oArticle->getBasketPrice( $oBasketItem->getAmount(), $oBasketItem->getSelList(), $oBasket )->getPrice(),
610  'discount' => $oDiscount->getAbsValue($oArticle->getBasketPrice( $oBasketItem->getAmount(), $oBasketItem->getSelList(), $oBasket )->getPrice()),
611  'amount' => $oBasketItem->getAmount(),
612  );
613 
614  $iCount ++;
615  }
616  }
617 
618  return $aItems;
619  }
620 
630  protected function _getGenericDiscoutValue( $dPrice )
631  {
632  $oSeries = $this->getSerie();
633  if ( $oSeries->oxvoucherseries__oxdiscounttype->value == 'absolute' ) {
634  $oCur = $this->getConfig()->getActShopCurrencyObject();
635  $dDiscount = $oSeries->oxvoucherseries__oxdiscount->value * $oCur->rate;
636  } else {
637  $dDiscount = $oSeries->oxvoucherseries__oxdiscount->value / 100 * $dPrice;
638  }
639 
640  if ( $dDiscount > $dPrice ) {
641  $dDiscount = $dPrice;
642  }
643 
644  return $dDiscount;
645  }
646 
647 
653  public function getDiscount()
654  {
655  $oSeries = $this->getSerie();
656  return $oSeries->oxvoucherseries__oxdiscount->value;
657  }
658 
664  public function getDiscountType()
665  {
666  $oSeries = $this->getSerie();
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  return ( $dVoucher > $dProduct ) ? $dProduct : $dVoucher;
771  }
772 
780  public function __get( $sName )
781  {
782  switch ( $sName ) {
783 
784  // simple voucher mapping
785  case 'sVoucherId':
786  return $this->getId();
787  break;
788  case 'sVoucherNr':
789  return $this->oxvouchers__oxvouchernr;
790  break;
791  case 'fVoucherdiscount':
792  return $this->oxvouchers__oxdiscount;
793  break;
794  }
795  return parent::__get($sName);
796  }
797 
804  protected function _getVoucherTimeout()
805  {
806  $iVoucherTimeout = intval(oxRegistry::getConfig()->getConfigParam( 'iVoucherTimeout' )) ?
807  intval(oxRegistry::getConfig()->getConfigParam( 'iVoucherTimeout' )) :
808  3 *3600;
809  return $iVoucherTimeout;
810  }
811 }