Index: /changelog
===================================================================
--- /changelog	(revision 7864)
+++ /changelog	(revision 7865)
@@ -427,4 +427,5 @@
 - Feature: Stornieren einer Rechnug Ã€ndert den Bestellstatus der Bestellung auf Storniert
 - Feature: Globale Bilder in globalen Variationen
+- Feature: Gutscheine/Coupons werden optional nur noch auf ausgewÃ€hlte Produkte/Produktgruppen angerechnet
 - Bugfix: Anzeige von Name/Titel in den Passwort Vergessen Mails
 - Bugfix: KundenzusammenfÃŒgen funktioniert wieder
Index: /controller/wpsg_BasketController.class.php
===================================================================
--- /controller/wpsg_BasketController.class.php	(revision 7864)
+++ /controller/wpsg_BasketController.class.php	(revision 7865)
@@ -658,5 +658,5 @@
 								
 							}
-							
+
 							if ($bCheckDiscount) {
 								
@@ -684,4 +684,5 @@
 										
 										// ProduktgÃŒltigkeit prÃŒfen
+										/*
 										$tarr = wpsg_explode(',', $gs_db['products']);
 										if (wpsg_isSizedArray($tarr)) {
@@ -741,4 +742,8 @@
 											
 										}
+										*/
+
+										$this->addFrontendMessage(__('Gutschein wurde der Bestellung erfolgreich hinzugefÃŒgt.', 'wpsg'));
+										$this->shop->basket->addGutscheinToSession($gs_db['value'], $gs_db['calc_typ'], $gs_db['code'], $gs_db['id']);
 										
 									}
Index: /lib/wpsg_basket.class.php
===================================================================
--- /lib/wpsg_basket.class.php	(revision 7864)
+++ /lib/wpsg_basket.class.php	(revision 7865)
@@ -39,4 +39,6 @@
 		
 		public $arCheckout;
+
+		public $oCalculation = null;
 		
 		/**
@@ -196,5 +198,5 @@
 			  
 			if (!isset($_SESSION['wpsg']['gs'])) $_SESSION['wpsg']['gs'] = [];
-			
+
 			$_SESSION['wpsg']['gs'][] = wpsg_xss(array(
 				'value' => $value,
@@ -203,5 +205,5 @@
 				'id' => $gs_id
 			));
-			
+
 		} // public function addGutscheinToSession($value, $calc, $code)
 		
@@ -1494,13 +1496,10 @@
 			}
 			
-			if ($base === WPSG_NETTO)
-			{
+			if ($base === WPSG_NETTO) {
 				
 				wpsg_addSet($arReturn['sum']['preis'], $arReturn['sum']['preis_netto']);
 				wpsg_addSet($arReturn['sum']['preis_gesamt'], $arReturn['sum']['preis_gesamt_netto']);
 				
-			}
-			else
-			{
+			} else {
 				
 				wpsg_addSet($arReturn['sum']['preis'], $arReturn['sum']['preis_brutto']);
@@ -1509,6 +1508,6 @@
 			}
 			
-			if ($backend)
-			{
+			if ($backend) {
+
 				$arReturn['backend'] = $backend;
 				$arReturn['price_frontend'] = @$this->arOrder['price_frontend'];
@@ -1718,18 +1717,22 @@
 				
 			}
-			
-			$oCalculation = new \wpsg\wpsg_calculation();
-			
-			if (!$this->loadFromSession) {
-				
-				$oCalculation->fromDB($this->o_id);
-				
-			} else {
-				
-				$oCalculation->fromSession();
-				
-			}
-			
-			$arCalculation = $oCalculation->getCalculationArray();
+
+			if ($this->oCalculation === null) {
+
+				$this->oCalculation = new \wpsg\wpsg_calculation();
+
+				if (!$this->loadFromSession) {
+
+					$this->oCalculation->fromDB($this->o_id);
+
+				} else {
+
+					$this->oCalculation->fromSession();
+
+				}
+
+			}
+			
+			$arCalculation = $this->oCalculation->getCalculationArray();
 			
 			unset($p); // Wichtig, da oben mit der Referenzt &$p gearbeitet wurde
@@ -1797,5 +1800,5 @@
 						'tax_key' => $tax_key_clear,
 						'sum' => $tax['sum'],
-						'name' => $oCalculation->getTaxLabelArray(true)[$tax_key],
+						'name' => $this->oCalculation->getTaxLabelArray(true)[$tax_key],
 						'value' => $tax['tax_value'],
 						'base_value' => $tax['brutto']
Index: /lib/wpsg_calculation.class.php
===================================================================
--- /lib/wpsg_calculation.class.php	(revision 7864)
+++ /lib/wpsg_calculation.class.php	(revision 7865)
@@ -388,6 +388,9 @@
 
             if ($this->arCountry === null) throw new \Exception(__('Warenkorb kann nicht ohne ein gesetztes Land berechnet werden.', 'wpsg'));
-            
+
             if ($force_rebuild === true || is_null($this->arCalculation)) {
+
+            	//$GLOBALS['t'] = ($GLOBALS['t']??0) + 1;
+            	//if ($GLOBALS['t'] === 2) {debug_print_backtrace();die();}
 
             	$this->arCalculation = [
@@ -446,5 +449,5 @@
                 	$brutto = 0;
                 	$netto = 0;
-                	
+
                 	foreach ($cr['set'] as $set) {
 		
@@ -453,30 +456,7 @@
                 								
 						if (strpos($set, '|') !== false) {
-							
-							/*
-							list($typ, $set) = explode('-', $set);
-							
-							$arKosten = explode('|', $set);
-							$arKosten = array_reverse($arKosten);
-			
-							if ($typ === 'w') $value = (($this->shop->getBackendTaxview() === WPSG_NETTO)?$this->arCalculation['sum']['productsum_netto']:$this->arCalculation['sum']['productsum_brutto']);
-							else if ($typ === 's') $value = $this->arCalculation['sum']['amount']; // Menge
-							else if ($typ === 'g') $value = $this->dWeight; // Gewicht
-							else throw new \Exception(wpsg_translate(__('Typ (#1#) fÃŒr KostenschlÃŒssel nicht definiert.', 'wpsg'), $typ));
-							
-							foreach ($arKosten as $k) {
-				
-								$arP = explode(":", $k);
-				
-								if (sizeof($arP) == 1) $kosten = $arP[0];
-								else if (wpsg_tf($arP[0]) <= $value) $kosten = $arP[1];
-				
-							}
-							
-							$kosten = wpsg_tf($kosten);
-							*/
-				
+
 							$kosten = $this->calculateCostKey($set);
-							
+
 							if ($this->shop->getBackendTaxview() === WPSG_NETTO) {
 								
@@ -490,9 +470,47 @@
 							
 						} else if (strpos($set, '%') !== false) {
-							
+
+							if ($cr['type'] === 'voucher') {
+
+								// Ein Gutschein kann nur fÃŒr bestimmte Produktgruppen/Produkte gelten, das prÃŒfe ich hier und ziehe Produktpreise ab, wenn nicht zulÃ€ssig
+								// Ist partial === true, wurde der Gutschein nicht auf alle Produkte angewendet
+
+								$oVoucher = \wpsg_voucher::getInstance($cr['data']['id']);
+
+								$netto_scope = $this->arCalculation['sum']['netto'];
+								$brutto_scope = $this->arCalculation['sum']['brutto'];
+
+								$cr['data']['partial'] = false;
+
+								foreach ($this->arCalculationRow as $cr2) {
+
+									if ($cr2['type'] === 'product') {
+
+										if (!$oVoucher->isUsabel($cr2['data']['product_id'])) {
+
+											list($set_netto, $set_brutto) = $this->calculateTaxPart($cr2['bruttonetto'], $cr2['set'], $cr2['tax_key']);
+
+											$netto_scope -= $set_netto;
+											$brutto_scope -= $set_brutto;
+
+											$cr['data']['partial'] = true;
+
+										}
+
+									}
+
+								}
+
+							} else {
+
+								$netto_scope = $this->arCalculation['sum']['netto'];
+								$brutto_scope = $this->arCalculation['sum']['brutto'];
+
+							}
+
 							// Prozentualer Wert
-							$set_netto = $this->arCalculation['sum']['netto'] / 100 * wpsg_tf($set);
-							$set_brutto = $this->arCalculation['sum']['brutto'] / 100 * wpsg_tf($set);
-							
+							$set_netto = $netto_scope / 100 * wpsg_tf($set);
+							$set_brutto = $brutto_scope / 100 * wpsg_tf($set);
+
 							if ($this->shop->getBackendTaxview() === WPSG_NETTO) {
 								
@@ -666,14 +684,40 @@
 					
                 	if ($cr['type'] === 'coupon') {
-		
+
+                		// Der Wertgutschein kann nur fÃŒr bestimmte Produkte erlaubt sein
+		                // Ich ermittle daher das Brutto/Netto auf den der Gutschein angewendet werden kann
+		                $scope_brutto = 0;
+		                $scope_netto = 0;
+
+		                $cr['data']['partial'] = false;
+
+		                $oVoucher = \wpsg_voucher::getInstance($cr['data']['id']);
+
+		                foreach ($this->arCalculationRow as $cr2) {
+
+		                	if ($cr2['type'] === 'product') {
+
+		                		if ($oVoucher->isUsabel($cr2['data']['product_id'])) {
+
+		                			list($scope_set_netto, $scope_set_brutto) = $this->calculateTaxPart($cr2['bruttonetto'], $cr2['set'], $cr2['tax_key']);
+
+		                			$scope_netto -= $scope_set_netto;
+		                			$scope_brutto -= $scope_set_brutto;
+
+				                } else $cr['data']['partial'] = true;
+
+			                }
+
+		                }
+
 						// Netto / Brutto berechnen
 						if ($cr['bruttonetto'] === WPSG_NETTO) {
-			
-							$set_netto = wpsg_tf($set);
+
+							$set_netto = $scope_netto; //wpsg_tf($set);
 			 							
 							list($set_netto, $set_brutto) = $this->calculateTaxPart(WPSG_NETTO, $set_netto, $cr['tax_key']);
 			
 						} else {
-			
+
 							if (wpsg_isTrue($cr['data']['targetCountry'])) {
 				
@@ -684,5 +728,6 @@
 				
 								$set_brutto = wpsg_calculatePreis(
-									wpsg_calculatePreis(wpsg_tf($set), WPSG_NETTO, $tax_default),
+									//wpsg_calculatePreis(wpsg_tf($set), WPSG_NETTO, $tax_default),
+									wpsg_calculatePreis(wpsg_tf($scope_brutto), WPSG_NETTO, $tax_default),
 									WPSG_BRUTTO,
 									$tax_target
@@ -691,12 +736,12 @@
 							} else {
 				
-								$set_brutto = wpsg_tf($set);
+								$set_brutto = $scope_brutto; //wpsg_tf($set);
 				
 							}
-							
+
 							if (($this->arCalculation['sum']['brutto'] + $set_brutto) < 0) $set_brutto = -1 * $this->arCalculation['sum']['brutto'];
-							 			
+
 							list($set_netto, $set_brutto) = $this->calculateTaxPart(WPSG_BRUTTO, $set_brutto, $cr['tax_key'], true);
-											
+
 							if ($this->arCalculation['sum']['topay_netto'] + $set_netto < 0) {
 								
@@ -705,5 +750,5 @@
 								
 							} else $this->arCalculation['sum']['topay_netto'] += $set_netto;
-							
+
 							if ($this->arCalculation['sum']['topay_brutto'] + $set_brutto < 0) {
 								
@@ -712,5 +757,5 @@
 								
 							} else $this->arCalculation['sum']['topay_brutto'] += $set_brutto;
-							 							
+
 						}
 		
@@ -1341,5 +1386,5 @@
 				} else {
 					
-					if ($sum <= 0) $this->arCalculation['tax'][$tax_key]['part'] = 0;
+					if ($sum <= 0) $this->arCalculation['tax'][$tax_key]['part'] = 1; //? Hier war mal 0 drin
 					else $this->arCalculation['tax'][$tax_key]['part'] = $tax[$bruttonetto] / $sum;
 					
Index: /mods/mod_gutschein/wpsg_voucher.php
===================================================================
--- /mods/mod_gutschein/wpsg_voucher.php	(revision 7864)
+++ /mods/mod_gutschein/wpsg_voucher.php	(revision 7865)
@@ -5,12 +5,10 @@
 	 * @author Daschmi
 	 */
-	class wpsg_voucher extends wpsg_model
-	{
+	class wpsg_voucher extends wpsg_model {
 
 		/**
 		 * LÃ€dt die Daten des Gutscheins
 		 */
-		public function load($voucher_id)
-		{
+		public function load($voucher_id) {
 
 			parent::load($voucher_id);
@@ -25,5 +23,5 @@
 			");
 
-			if ($this->data['id'] != $voucher_id || !wpsg_isSizedInt($voucher_id)) return false;
+			if (!wpsg_isSizedArray($this->data) || $this->data['id'] != $voucher_id || !wpsg_isSizedInt($voucher_id)) return false;
 
 			return true;
@@ -86,6 +84,34 @@
 		    
         }
-        
-        public function isUsabel() {
+
+        public function getAllowedProductgroup(): array {
+
+			return wpsg_explode(',', $this->__get('productgroups'));
+
+        }
+
+        public function isLimitedProductgroup(): bool {
+
+			$arAllowedProductGroups = wpsg_explode(',', $this->__get('productgroups'));
+
+			return wpsg_isSizedArray($arAllowedProductGroups);
+
+        }
+
+        public function getAllowedProduct(): bool {
+
+			return wpsg_explode(',', $this->__get('products'));
+
+        }
+
+        public function isLimitedProduct(): bool {
+
+			$arAllowedProductGroups = wpsg_explode(',', $this->__get('products'));
+
+			return wpsg_isSizedArray($arAllowedProductGroups);
+
+        }
+
+        public function isUsabel($product_id = null) {
 			
 			if (strtotime($this->start_date) > time()) return false;
@@ -93,5 +119,21 @@
 			if (!$this->isMultiUsable() && $this->getUsed() > 0) return false;
 			if ($this->getFreeAmount() <= 0) return false;
-			
+
+			if ($product_id !== null) {
+
+				if ($this->isLimitedProduct()) {
+
+					if (!in_array($product_id, $this->getAllowedProduct())) return false;
+
+				}
+
+				if ($this->isLimitedProductgroup()) {
+
+					if (!in_array(wpsg_product::getInstance($product_id)->getProductgroup()->getId(), $this->getAllowedProductgroup())) return false;
+
+				}
+
+			}
+
 			return true;
 			
@@ -310,5 +352,45 @@
 		}
 
+        /**
+         * @param int $voucher_id
+         * @param bool $noCache
+         * @return wpsg_voucher
+         */
+		public static function getInstance($voucher_id, $noCache = false) {
+
+			$class_name = get_called_class();
+
+			if (wpsg_isSizedArray($voucher_id)) {
+
+				$arReturn = [];
+
+				foreach ($voucher_id as $_id) {
+
+					$arReturn[$_id] = self::getInstance($_id);
+
+				}
+
+				return $arReturn;
+
+			} else if (is_array($voucher_id)) {
+
+			    return array();
+
+            } else {
+
+				if (!array_key_exists($class_name.'_'.$voucher_id, self::$_objCache) || $noCache === true) {
+
+					$oObject = new $class_name();
+					$oObject->load($voucher_id);
+
+					self::$_objCache[$class_name.'_'.$voucher_id] = $oObject;
+
+				}
+
+				return self::$_objCache[$class_name.'_'.$voucher_id];
+
+			}
+
+		} // public static function getInstance($id, $noCache = false)
+
 	} // class wpsg_voucher
-
-?>
Index: /mods/wpsg_mod_gutschein.class.php
===================================================================
--- /mods/wpsg_mod_gutschein.class.php	(revision 7864)
+++ /mods/wpsg_mod_gutschein.class.php	(revision 7865)
@@ -140,15 +140,15 @@
 		 
 			if ($product_done && $payship_done) {
-				
+
 				if (wpsg_isSizedArray($_SESSION['wpsg']['gs'])) {
 					
 					foreach ($_SESSION['wpsg']['gs'] as $gs) {
-						
+
 						$oVoucher = wpsg_voucher::getInstance($gs['id']);
 						
 						if ($oVoucher->isUsabel()) {
-						
+
 							if ($oVoucher->isCoupon()) {
-								
+
 								$oCalculation->addCoupon($oVoucher->getFreeAmount(), $this->shop->getBackendTaxview(), '0', 1, $gs['code'], $gs['id']);
 								
Index: /views/css/frontend.css
===================================================================
--- /views/css/frontend.css	(revision 7864)
+++ /views/css/frontend.css	(revision 7865)
@@ -53,6 +53,10 @@
 .basket_product_wrap .basket_product_row .product_info .dummyp { flex-grow:1; width:110px; }
 .basket_sum_wrap .basket_sum_row { display:flex; width:100%; justify-content:space-between; align-items:center; }
-.basket_sum_wrap .basket_sum_row .title { width: 60%; display:inline-block; margin-top:0.3em; margin-bottom:0.3em; }
+.basket_sum_wrap .basket_sum_row .title { width: 80%; display:inline-block; margin-top:0.3em; margin-bottom:0.3em; }
 .basket_sum_wrap .basket_sum_row .title2 { width: 80%; display:inline-block; margin-top:0.3em; margin-bottom:0.3em; }
+.basket_sum_wrap .basket_sum_voucher .title,
+.basket_sum_wrap .basket_sum_coupon .title { display:flex; justify-content:flex-start; align-items:center; }
+.basket_sum_wrap .basket_sum_voucher .title a,
+.basket_sum_wrap .basket_sum_coupon .title a { margin-right:0.5rem; }
 .basket_sum_wrap .basket_sum_row .value { width: 20%; display:inline-block; font-weight:normal; text-align:right; }
 .basket_sum_wrap .basket_sum_row .valuel { width: 20%; display:inline-block; font-weight:normal; text-align:left; }
Index: /views/mods/mod_gutschein/add.phtml
===================================================================
--- /views/mods/mod_gutschein/add.phtml	(revision 7864)
+++ /views/mods/mod_gutschein/add.phtml	(revision 7865)
@@ -65,5 +65,5 @@
 			<?php echo wpsg_drawForm_Textarea('wpsg_mod_gutschein_comment', __('Kommentar', 'wpsg'), @$this->view['mod_gutschein']['comment']); ?>
 			<?php if ($this->hasMod('wpsg_mod_productgroups') && wpsg_isSizedArray($this->view['wpsg_mod_gutschein']['arProductGroups'])) { ?>
-			<?php echo wpsg_drawForm_Select('wpsg_mod_gutschein_productgroups', __('BeschrÃ€nkung auf Produktgruppen', 'wpsg'), $this->view['wpsg_mod_gutschein']['arProductGroups'], $this->view['mod_gutschein']['productgroups'], array('multiple' => ((sizeof($this->view['wpsg_mod_gutschein']['arProductGroups']) > 5)?5:sizeof($this->view['wpsg_mod_gutschein']['arProductGroups'])), 'help' => 'wpsg_mod_gutschein_productgroups')); ?>
+			<?php echo wpsg_drawForm_Select('wpsg_mod_gutschein_productgroups', __('BeschrÃ€nkung auf Produktgruppen', 'wpsg'), $this->view['wpsg_mod_gutschein']['arProductGroups'], wpsg_getArray($this->view['mod_gutschein']['productgroups']), array('multiple' => ((sizeof($this->view['wpsg_mod_gutschein']['arProductGroups']) > 5)?5:sizeof($this->view['wpsg_mod_gutschein']['arProductGroups'])), 'help' => 'wpsg_mod_gutschein_productgroups')); ?>
 			<?php } ?>
 			<?php echo wpsg_drawForm_Select('wpsg_mod_gutschein_products', __('BeschrÃ€nkung auf Produkte', 'wpsg'), @$this->view['wpsg_mod_gutschein']['arProducts'], @$this->view['mod_gutschein']['products'], array('multiple' => ((sizeof($this->view['wpsg_mod_gutschein']['arProducts']) > 5)?5:sizeof($this->view['wpsg_mod_gutschein']['arProducts'])), 'help' => 'wpsg_mod_gutschein_products')); ?>
Index: /views/mods/mod_gutschein/basket_row_end_coupon.phtml
===================================================================
--- /views/mods/mod_gutschein/basket_row_end_coupon.phtml	(revision 7864)
+++ /views/mods/mod_gutschein/basket_row_end_coupon.phtml	(revision 7865)
@@ -16,8 +16,17 @@
 <?php foreach ($arCalculation['coupon'] as $gs) { ?>
 	
-	<div class="basket_sum_row">
+	<div class="basket_sum_row basket_sum_coupon">
 		<div class="title">
 			<a class="wpsg_basket_removelink" href="<?php echo str_replace('&', '&amp;', $this->getRemoveLinkURL('voucher_'.$gs['id'])); ?>" title="<?php echo __('Wertgutschein aus dem Warenkorb entfernen', 'wpsg'); ?>" onclick="return confirm('<?php echo __('Sind Sie sich sicher, dass sie den Wertgutschein aus dem Warenkorb entfernen mÃ¶chten?', 'wpsg'); ?>');"><img src="<?php echo WPSG_URL; ?>views/gfx/bin_x.png" alt="<?php echo __('LÃ¶schen', 'wpsg'); ?>" /></a>
-			<?php echo __('Wertgutschein', 'wpsg'); ?> <?php echo ((wpsg_isSizedString($gs['code']))?'('.$gs['code'].')':''); ?>
+			<?php echo __('Wertgutschein', 'wpsg'); ?> <?php
+
+                $arInfo = [];
+
+                if (wpsg_isSizedString($gs['code'])) $arInfo[] = $gs['code'];
+                if (wpsg_isTrue($gs['partial'])) $arInfo[] = __('teilweise angerechnet', 'wpsg');
+
+                if (wpsg_isSizedArray($arInfo)) echo '('.implode(' / ', $arInfo).')';
+
+            ?>
 		</div>
 		<?php if (sizeof($this->view['basket']['mwst']) > 1 || $this->get_option('wpsg_showMwstAlways') == '1') { ?>
@@ -29,5 +38,5 @@
 				
 				if (strpos($gs['set'], '%') !== false) {
-					
+
 					echo '<span class="procent_payship">('.wpsg_ff(wpsg_tf($gs['set']), '%').')</span>';
 					
Index: /views/warenkorb/basket.phtml
===================================================================
--- /views/warenkorb/basket.phtml	(revision 7864)
+++ /views/warenkorb/basket.phtml	(revision 7865)
@@ -153,8 +153,17 @@
 				<?php foreach ($this->view['basket']['arCalculation']['voucher'] as $gs) { ?>
 				
-					<div class="basket_sum_row">
+					<div class="basket_sum_row basket_sum_voucher">
 						<div class="title">
-							<?php echo __('Gutschein', 'wpsg'); ?> <?php echo ((wpsg_isSizedString($gs['code']))?'('.$gs['code'].')':''); ?>
-							<a class="wpsg_basket_removelink" href="<?php echo str_replace('&', '&amp;', $this->getRemoveLinkURL('voucher_'.$gs['id'])); ?>" title="<?php echo __('Gutschein aus dem Warenkorb entfernen', 'wpsg'); ?>" onclick="return confirm('<?php echo __('Sind Sie sich sicher, dass sie den Gutschein aus dem Warenkorb entfernen mÃ¶chten?', 'wpsg'); ?>');"><img src="<?php echo WPSG_URL; ?>views/gfx/bin_x.png" alt="<?php echo __('LÃ¶schen', 'wpsg'); ?>" /></a>
+                            <a class="wpsg_basket_removelink" href="<?php echo str_replace('&', '&amp;', $this->getRemoveLinkURL('voucher_'.$gs['id'])); ?>" title="<?php echo __('Gutschein aus dem Warenkorb entfernen', 'wpsg'); ?>" onclick="return confirm('<?php echo __('Sind Sie sich sicher, dass sie den Gutschein aus dem Warenkorb entfernen mÃ¶chten?', 'wpsg'); ?>');"><img src="<?php echo WPSG_URL; ?>views/gfx/bin_x.png" alt="<?php echo __('LÃ¶schen', 'wpsg'); ?>" /></a>
+							<?php echo __('Gutschein', 'wpsg'); ?> <?php
+
+                                $arInfo = [];
+
+                                if (wpsg_isSizedString($gs['code'])) $arInfo[] = $gs['code'];
+                                if (wpsg_isTrue($gs['partial'])) $arInfo[] = __('teilweise angerechnet', 'wpsg');
+
+                                if (wpsg_isSizedArray($arInfo)) echo '('.implode(' / ', $arInfo).')';
+
+                            ?>
 						</div>
 						<?php if (sizeof($this->view['basket']['mwst']) > 1 || $this->get_option('wpsg_showMwstAlways') == '1') { ?>
