diff --git a/_doimport.html b/_doimport.html
index 22a6610..dafebf9 100644
--- a/_doimport.html
+++ b/_doimport.html
@@ -111,8 +111,8 @@
 			}
 			http.open('GET', '{{vtLink: -met="ajax/import_image.html", src="{vtGet:Source}" }}&amp;path=' + encodeURIComponent( thePath ) );
 			document.getElementById('wait').style.display = 'block';
-			document.getElementById('wait_message').innerHTML = 'Importiere Bild #' + imageCount + '<br>' + thePath;
-			addMessage( 'Importiere Bild #' + imageCount + ': ' + thePath );
+			document.getElementById('wait_message').innerHTML = 'Importiere Bild #' + (1+imageCount) + '<br>' + thePath;
+			addMessage( 'Importiere Bild #' + (1+imageCount) + ': ' + thePath );
 			http.onreadystatechange = handleResponse_importImage;
 			http.send(null);
 		}
@@ -234,7 +234,7 @@
 			}
 			document.getElementById( 'messages' ).appendChild( newElm );
 			document.all[ 'msg' + messageCount ].innerHTML = '<a name="msg' + messageCount + '"></a>' + theMessage;
-			window.location.hash = 'msg' + messageCount;
+			window.scrollTo( 0, document.body.scrollHeight ); // scroll to the bottom of the pagse
 			messageCount++;
 		}
 		
diff --git a/actions/update.html b/actions/update.html
index b4d6019..402845b 100644
--- a/actions/update.html
+++ b/actions/update.html
@@ -80,6 +80,21 @@ folder"
 		{{vtDo: -act="delete", -obj="{vtResult}" }}
 	{{vtEndIf}}
 
+	{{vtIf: {vtGlobal:pxtc_version_number} .lt. 55 }}
+		{{vtDbQuery: ALTER TABLE `%table_downloads_log`
+			ADD `id` int(10) unsigned NOT NULL AUTO_INCREMENT PRIMARY KEY FIRST,
+			ADD `image_id` int(10) unsigned DEFAULT NULL,
+			ADD `paid` tinyint(4) NOT NULL DEFAULT '0'
+		}}
+		{{vtDbQuery: UPDATE `%table_downloads_log` d
+			LEFT JOIN `%data_image` i
+			ON i.verzeichnis = REGEXP_REPLACE( d.image_path, '/[^/]+$', '' )
+			AND i.dateiname = SUBSTRING_INDEX( d.image_path, '/', -1 )
+			SET d.image_id = i.vtid
+			WHERE d.image_id IS NULL
+		}}
+	{{vtEndIf}}
+
 	{{vtEndAsAdmin}}
 
 {{vtEndScript}}
diff --git a/ajax/order_dialog.html b/ajax/order_dialog.html
index 7891576..7d08178 100644
--- a/ajax/order_dialog.html
+++ b/ajax/order_dialog.html
@@ -1,22 +1,36 @@
 {{vtInclude: includes/initialize.html}}
 
-<div class="modal-dialog modal-lg" data-type="{{vtPageType}}">
+<div class="modal-dialog modal-dialog-scrollable modal-lg" data-type="{{vtPageType}}">
 	<!-- {{vtPromo}} -->
 	<div class="modal-content">
 		<div class="modal-header">
 			<!--{{vtIf: {vtPageType} .eq. image }}-->
 				<!--{{vtInclude: includes/get_products.html }}-->
 				<img src="{{vtGet:thumbnailUrl}}/{{Verzeichnis}}/{{Dateiname}}?{{Thumb_Timestamp}}" class="img-thumbnail mr-3" style="height:50px" alt="">
-				<h5 class="modal-title text-truncate">
-					<!--{{vtIf: {Name} .neq. }}-->{{Name}}<!--{{vtElse}}-->{{vtName}}<!--{{vtEndIf}}-->
-				</h5>
+				<div class="text-truncate" style="width:100%">
+					<h5 class="modal-title text-truncate">
+						<!--{{vtIf: {Name} .neq. }}-->{{Name}}<!--{{vtElse}}-->{{vtName}}<!--{{vtEndIf}}-->
+					</h5>
+					<div class="d-flex" style="100%">
+					<!--{{vtRepeat: {vtGet:Cart} }}-->
+						<!--{{vtIf: {vtItem:image} .eq. {vtId} }}-->
+							<a href="{{vtLink: {vtGet:ID_Warenkorb} }}">
+								<span class="badge badge-warning text-truncate mr-1" style="font-weight:normal;" title="{{vtItem:quantity}} &times; {{vtItem:title}}">
+									<i class="fas fa-shopping-cart text-white mr-1"></i>
+									{{vtItem:quantity}} &times; {{vtItem:title}}
+								</span>
+							</a>
+						<!--{{vtEndIf}}-->
+					<!--{{vtEndRepeat}}-->
+					</div>
+				</div>
 			<!--{{vtElseIf: {vtPageType} .eq. lightbox }}-->
 				<!--{{vtInclude: includes/get_products_lb.html }}-->
 				<h5 class="modal-title text-truncate">
 					{{vtGet:LightboxCount}} {{vtGet:s_txt_0037}}
 				</h5>
 			<!--{{vtEndIf}}-->
-			<button type="button" class="close" data-dismiss="modal" aria-label="Close">
+			<button type="button" class="close d-none d-sm-block" data-dismiss="modal" aria-label="Close">
 				<span aria-hidden="true">&times;</span>
 			</button>
 		</div>
@@ -53,40 +67,66 @@
 						<!--{{vtSet: ProductsExist = "1" }}-->
 						<tr class="pxtc-product" data-id="{{vtItem:id}}" data-quantity="{{vtItem:cartQuantity}}" data-type="{{vtItem:type}}">
 							<!--{{vtIf: {vtItem:id} .eq. 0 }}-->
-								<td colspan="1" class="table-secondary">
-									<h6>{{vtItem:name}}</h6>
+								<td colspan="1" class="row table-secondary">
+									<h6 class="col-12">{{vtItem:name}}</h6>
 								</td>
-							<!--{{vtElse}}-->
-								<td class="{{vtGet:CellClass}}">
-									<form class="orderform form-inline float-right" action="{{vtLink:-met='ajax/cart_change.html'}}" method="POST">
-										<input type="hidden" name="item" value="{{vtItem:id}}">
-										<input type="hidden" name="q" value="">
-										<div class="btn-group" role="group">
-											<button type="button" class="btn btn-outline-secondary btn-minus" {{vtIf: {vtItem:cartQuantity} .eq. 0}}disabled{{vtEndIf}}><i class="fas fa-minus"></i></button>
-											<button type="button" class="btn btn-outline-secondary quantity" disabled><!--{{vtIf: {vtItem:cartQuantity} .neq.}}-->{{vtItem:cartQuantity}}<!--{{vtElse}}-->0<!--{{vtEndIf}}--></button>
-											<button type="button" class="btn btn-outline-secondary btn-plus" {{vtIf: {vtItem:type} .eq. datei .and. {vtItem:cartQuantity} .gt. 0}}disabled{{vtEndIf}}><i class="fas fa-plus"></i></button>
-										</div>
-									</form>
+							<!--{{vtElseIf: {vtItem:type} .neq. Gruppe .or. {vtItem:options} .neq. [] }}-->
+								<td class="row {{vtGet:CellClass}}">
+									<div class="col-8">
 									<span class="btn-toggle">{{vtItem:name}}</span>
 									<!--{{vtIf: {vtItem:description} .neq. }}-->
 										<i class="fa fa-info-circle text-info btn-prod-info" style="cursor:pointer"></i>
 									<!--{{vtEndIf}}-->
+									<!--{{vtSet: Type = "{vtItem:type}", Price = "{vtItem:price}", VatRate = "{vtItem:vatRate}", Product = "{vtItem:id}", ListInitialized = "" }}-->
+									<!--{{vtIf: {vtItem:options} .neq. }}-->
+										<!--{{vtSet: GroupName = "{vtItem:name}" }}-->
+										&nbsp;&nbsp;
+										<select id="prodSelection{{vtItem:id}}" class="form-control form-control-sm prod-selection" style="display:inline-block; width:auto; vertical-align:middle">
+											<!--{{vtRepeat: {vtItem:options} }}-->
+												<!--{{vtIf: {vtGet:ListInitialized} .eq. }}-->
+													<!--{{vtSet: Type = "{vtItem:type}", Price = "{vtItem:price}", VatRate = "{vtItem:vatRate}", Product = "{vtItem:id}", ListInitialized = "1" }}-->
+												<!--{{vtEndIf}}-->
+												<!--{{vtCalc: (float)'{vtItem:price}' * ( 1 + (float)'{vtItem:vatRate}'/100 ) }}-->
+												<option value="{{vtItem:id}}" data-price="{{vtItem:price|num-en:2}}" data-netprice="{{vtResult|num-en:2}}" data-vatRate="{{vtItem:vatRate}}">
+													<!--{{vtCalc: strpos( '{vtItem:name}', '{vtGet:GroupName}' ) === 0 ? substr( '{vtItem:name}', strlen('{vtGet:GroupName}') ) : '{vtItem:name}' }}-->
+													{{vtResult}}
+												</option>
+											<!--{{vtEndRepeat}}-->
+										</select>
+									<!--{{vtEndIf}}-->
 									<br>
 									<small class="text-muted">
-										<!--{{vtIf: {vtItem:price} .gt. 0 .and. {vtGlobal:pxtcVatAppearance} .eq. 1 .and. {vtGlobal:pxtcVatHandling} .neq. }}-->
+										<!--{{vtIf: {vtGet:Price} .gt. 0 .and. {vtGlobal:pxtcVatAppearance} .eq. 1 .and. {vtGlobal:pxtcVatHandling} .neq. }}-->
 											<!--{{vtIf: {vtGlobal:pxtcVatHandling} .bw. incl }}--> 
-												<span class="price">{{vtItem:price|num-en:2}}</span>&nbsp;{{vtGlobal:pxtcCurrency}}
-												{{vtGet:s_txt_0070}} {{vtItem:vatRate}}% {{vtGet:s_txt_0072}}
+												<span class="price">{{vtGet:Price|num-en:2}}</span>&nbsp;{{vtGlobal:pxtcCurrency}}
+												{{vtGet:s_txt_0070}} <span class="vatrate">{{vtGet:VatRate}}</span>% {{vtGet:s_txt_0072}}
 											<!--{{vtElse}}-->
-												<span class="netprice">{{vtItem:price|num-en:2}}</span>&nbsp;{{vtGlobal:pxtcCurrency}}
-												<!--{{vtCalc: {vtItem:price} * ( 1 + {vtItem:vatRate}/100 ) }}-->
-												{{vtGet:s_txt_0071}} {{vtItem:vatRate}}% {{vtGet:s_txt_0072}} = 
+												<span class="netprice">{{vtGet:Price|num-en:2}}</span>&nbsp;{{vtGlobal:pxtcCurrency}}
+												<!--{{vtCalc: {vtGet:Price} * ( 1 + {vtItem:vatRate}/100 ) }}-->
+												{{vtGet:s_txt_0071}} <span class="vatrate">{{vtGet:VatRate}</span>}% {{vtGet:s_txt_0072}} = 
 												<span class="price">{{vtResult|num-en:2}}</span>&nbsp;{{vtGlobal:pxtcCurrency}}
 											<!--{{vtEndIf}}-->
 										<!--{{vtElse}}-->
-											<span class="price">{{vtItem:price|num-en:2}}</span>&nbsp;{{vtGlobal:pxtcCurrency}}
+											<span class="price">{{vtGet:Price|num-en:2}}</span>&nbsp;{{vtGlobal:pxtcCurrency}}
 										<!--{{vtEndIf}}-->
 									</small>
+									</div>
+									<div class="col-4 text-right">
+										<!--{{vtIf: {vtGet:Type} .eq. print }}-->
+										<div class="btn-group" role="group">
+											<button type="button" class="btn btn-outline-secondary btn-minus" disabled><i class="fas fa-minus"></i></button>
+											<button type="button" class="btn btn-outline-secondary quantity" disabled>1</button>
+											<button type="button" class="btn btn-outline-secondary btn-plus"><i class="fas fa-plus"></i></button>
+										</div>
+										<!--{{vtEndIf}}-->
+										<form class="order-form d-inline-block" action="{{vtIf: {vtPageType} .eq. lightbox }}{{vtLink:-met='addtocart'}}{{vtElse}}{{vtLink:-met='ajax/cart_change.html'}}{{vtEndIf}}">
+											<input type="hidden" name="q" value="1">
+											<input type="hidden" name="item" value="{{vtGet:Product}}">
+											<button type="button" class="btn btn-primary ml-3 btn-buy">
+												<i class="fas fa-cart-plus"></i><!-- {{vtGet:s_btn_into_cart}} -->
+											</button>
+										</form>
+									</div>
 								</td>
 							<!--{{vtEndIf}}-->
 						</tr>
@@ -117,10 +157,12 @@
 				<a id="gotoCart" href="{{vtLink: {vtGet:ID_Warenkorb} }}" class="btn btn-primary mx-auto" style="{{vtIf: {vtGet:ShowCartButton} .neq. 1 }}display:none{{vtEndIf}}">
 					{{vtGet:s_btn_cart}}
 				</a>
-				<button type="button" class="btn btn-primary mx-auto" data-dismiss="modal">
-					{{vtGet:s_btn_continue}}
-				</button>
 			<!--{{vtEndIf}}-->
+			<div class="text-center" style="width:100%">
+				<button type="button" class="btn btn-secondary mr-2 mb-2" data-dismiss="modal">
+					{{vtGet:s_btn_close}}
+				</button>
+			</div>
 		</div>
 	</div>
 </div>
@@ -128,4 +170,68 @@
 <script>
 	var errorDefault = '{{vtGet:s_msg_0059,escaped}}';
 	var errorMaxItems = '{{vtGet:s_msg_0060,escaped}}';
+	$('.prod-selection').change( function(){
+		let row = $(this).parent();
+		let option = $(this).find('option:selected');
+		row.find('.price').text( option.data('price') );
+		row.find('.netprice').text( option.data('netprice') );
+		row.find('.vatrate').text( option.data('vatrate') );
+		$(this).parents('.pxtc-product').find('form.order-form input[name=item]').val( $(this).val() );
+	});
+	$('.btn-plus').click( function(){
+		$(this).blur();
+		let quantity = 1 * $(this).siblings('.quantity').text() + 1;
+		$(this).parents('.pxtc-product').find('form.order-form input[name=q]').val( quantity );
+		$(this).siblings('.quantity').text( quantity );
+		$(this).siblings('.btn-minus').prop( 'disabled', quantity <= 1 );
+	});
+	$('.btn-minus').click( function(){
+		$(this).blur();
+		let quantity = 1 * $(this).siblings('.quantity').text() - 1;
+		$(this).parents('.pxtc-product').find('form.order-form input[name=q]').val( quantity );
+		$(this).siblings('.quantity').text( quantity );
+		$(this).prop( 'disabled', quantity <= 1 );
+	});
+	$('.btn-buy').click( function(){
+		var orderForm = $(this).parents('.pxtc-product').find('form.order-form');
+		// {{vtIf: {vtPageType} .eq. lightbox }}
+			var products = [{ id: orderForm.find('input[name=item]').val(), quantity: orderForm.find('input[name=q]').val() }];
+			$.ajax({
+				type: 'POST',
+				url: orderForm.attr('action'),
+				data: { products: JSON.stringify( products ) },
+				success: function( data ){
+					$('#add-to-cart').modal('hide');
+					window.location.reload();
+				},
+				error: function(data)
+				{
+					console.log('Error when changing cart');
+					console.log( data );
+				}
+			});
+		// {{vtElse}}
+			$.ajax({
+				type: 'GET',
+				url: orderForm.attr('action'),
+				data: orderForm.serialize(),
+				success: function( data ){
+					if ( ! data.productId ){
+						console.log( data );
+						return;
+					}
+					
+					$('#add-to-cart').modal('hide');
+					if ( handle_cart_change ){
+						handle_cart_change( data.imageId, data.inCartStatus != '', data.cartCount );
+					}
+				},
+				error: function(data)
+				{
+					console.log('Error when changing cart');
+					console.log( data );
+				}
+			});
+		// {{vtEndIf}}
+	});
 </script>
diff --git a/assortment.html b/assortment.html
index 2f8ed6c..bea5c67 100644
--- a/assortment.html
+++ b/assortment.html
@@ -31,7 +31,14 @@
 				<!--{{vtElseIf: {vtItem:product_id} .gt. 0 }}-->
 					<!--{{vtUse: {vtItem:product_id} }}-->
 						<!--{{vtIf: {vtContainerId} .eq. {vtGet:ID_Produkte} }}-->
-							<p class="product">{{Bezeichnung}} | {{Preis|num-en:2}} {{vtGlobal:pxtcCurrency}}</p>
+							<p class="product">
+								{{Bezeichnung}} |
+								<!--{{vtIf: {Typ} .eq. Gruppe }}-->
+									 {{vtCountPages}} Produkt(e)
+								<!--{{vtElse}}-->
+									{{Preis|num-en:2}} {{vtGlobal:pxtcCurrency}}
+								<!--{{vtEndIf}}-->
+							</p>
 						<!--{{vtEndIf}}-->
 					<!--{{vtEndUse}}-->
 				<!--{{vtEndIf}}-->
diff --git a/assortment.vtedit.html b/assortment.vtedit.html
index c2d2762..4a5aa8a 100644
--- a/assortment.vtedit.html
+++ b/assortment.vtedit.html
@@ -103,7 +103,14 @@
 										<div class="product" data-prodid="{{vtId}}">
 											<button type="button">&times;</button>
 											<span>&#9776;</span>
-											<p>{{Bezeichnung}} | {{Preis|num-en:2}} {{vtGlobal:pxtcCurrency}}</p>
+											<p>
+												{{Bezeichnung}} |
+												<!--{{vtIf: {Typ} .eq. Gruppe }}-->
+													 {{vtCountPages}} Produkt(e)
+												<!--{{vtElse}}-->
+													{{Preis|num-en:2}} {{vtGlobal:pxtcCurrency}}
+												<!--{{vtEndIf}}-->
+											</p>
 										</div>
 									<!--{{vtEndIf}}-->
 								<!--{{vtEndUse}}-->
@@ -145,7 +152,12 @@
 						</td>
 						<td>
 							<label for="fldProduct_{{vtId}}">
-								{{Bezeichnung}} | {{Preis|num-en:2}}&nbsp;{{vtGlobal:pxtcCurrency}}
+								{{Bezeichnung}} |
+								<!--{{vtIf: {Typ} .eq. Gruppe }}-->
+									 {{vtCountPages}} Produkt(e)
+								<!--{{vtElse}}-->
+									{{Preis|num-en:2}}&nbsp;{{vtGlobal:pxtcCurrency}}
+								<!--{{vtEndIf}}-->
 							</label>
 						</td>
 					</tr>
@@ -199,7 +211,8 @@
 						text: 'Hinzufügen', 
 						click: function(){
 							$(this).find('input:checked').each( function(){
-								$('#prodlist').append( '<div class="product" data-prodid="' + $(this).data('prodid') + '"><button type="button">&times;</button><span>&#9776;</span><p> ' + $(this).data('text') + ' </p></div>' );
+								let label = $(this).parents('tr').find('label').text();
+								$('#prodlist').append( '<div class="product" data-prodid="' + $(this).data('prodid') + '"><button type="button">&times;</button><span>&#9776;</span><p> ' + label + ' </p></div>' );
 							});
 							$(this).dialog('close'); 
 							$('input[name=Liste]').val( serialize_prod_List('#prodlist') );
diff --git a/checkout.html b/checkout.html
index 8002662..65c27fb 100644
--- a/checkout.html
+++ b/checkout.html
@@ -131,7 +131,7 @@
 	{{vtIf: {vtGet:CartValue} .gt. 0 }}
 		{{vtDbQuery: SELECT `vtid` FROM {vtDbTable:data_coupon} d, {vtDbTable:content} c
 							WHERE d.`vtid` = c.`id` AND c.`containerID` = {vtGet:ID_Gutscheine}
-							AND ( `verwendet` IS NULL OR `verwendet` = '0' )
+							AND ( `verwendet` IS NULL OR `verwendet:num` = '0' )
 							AND ( `gueltig_von` = '' OR `gueltig_von:num` <= {vtEcho:time()} )
 							AND ( `gueltig_bis` = '' OR `gueltig_bis:num` >= {vtEcho:strtotime('today')} ) }}
 			{{vtIf: {vtDbCountSelection} .gt. 0 }}
diff --git a/checkout.summary.html b/checkout.summary.html
index f4e2fbb..d2d590c 100644
--- a/checkout.summary.html
+++ b/checkout.summary.html
@@ -655,6 +655,10 @@
 				<form action="{{vtLink: -met='payrexx'}}" method="POST">
 					<button type="submit" class="btn btn-primary btn-lg btn-block payrexx-modal-window" data-href="">{{vtGet:s_btn_pay_now}}</button>
 				</form>
+			<!--{{vtElseIf: {vtSession:Bezahlmethode} .eq. mollie .and. {vtGet:Gesamtpreis} .gt. 0 }}-->
+				<form action="{{vtLink: -met='mollie'}}" method="POST">
+					<button type="submit" class="btn btn-primary btn-lg btn-block" data-href="">{{vtGet:s_btn_pay_now}}</button>
+				</form>
 			<!--{{vtElse}}-->
 				<form action="{{vtLink: -met='finish'}}" method="POST">
 					<button type="submit" class="btn btn-primary btn-lg btn-block">{{vtGet:s_btn_send_order}}</button>
diff --git a/download.single.html b/download.single.html
index 59f303a..a53057f 100644
--- a/download.single.html
+++ b/download.single.html
@@ -31,6 +31,8 @@
 			{{vtSet: File}}
 			{{vtCalc: basename('{vtGet:File,escaped}') }}
 			{{vtSet: FileName }}
+			{{vtSet: LogType = "hires" }}
+			{{vtSet: LogPath="{vtItem:folder}/{vtItem:hires_path}"}}
 
 			{{vtIf: {vtItem:rule} .neq.}}
 				{{vtCalc: substr( '{vtGet:FileName,escaped}', 0, -4 ) . '_' . strtolower('{vtItem:rule}') . '.jpg' }}
@@ -41,6 +43,8 @@
 				{{vtIf: {vtGet:File} .bw. - }}
 					{{vtCode: die( 'Could not generate image [' . v::vtget('File') . ']' ); }}
 				{{vtEndIf}}
+				{{vtSet: LogType = "{vtItem:rule}" }}
+				{{vtSet: LogPath="{vtItem:folder}/{vtGet:FileName}"}}
 			{{vtEndIf}}
 
 			{{vtDeliver: {vtGet:File}, {vtGet:FileName} }}
@@ -49,6 +53,18 @@
 				{{vtReturn}}
 			{{vtEndIf}}
 
+			{{vtDbQuery: INSERT INTO {vtDbTable:table_downloads_log} SET
+				`timestamp` = CURRENT_TIMESTAMP,
+				`ip_address` = '{vtEcho: getenv( 'REMOTE_ADDR' ) }',
+				`session_id` = '{vtSession:id}',
+				`type` = '{vtGet:LogType}',
+				`user` = '{vtUser:name}',
+				`realname` = '{vtUser:realname}',
+				`organization` = '{vtUser:Contact_Company}',
+				`image_path` = '{vtGet:LogPath}',
+				`image_id` = '{vtItem:image}',
+				`paid` = 1
+			}}
 			{{vtIf: {vtGlobal:mailRecipient} .neq. .or. {vtGlobal:pxtcNotifyRecipient} .neq. }}
 				{{vtIf: {vtGlobal:pxtcNotifyHiresDownload} .eq. 1 }}
 					{{vtIf: {vtGlobal:pxtcNotifyRecipient} .neq. }}
@@ -72,4 +88,4 @@
 
 {{vtEndIf}}
 
-{{vtEndScript}}{{vtInclude:download.html}}
\ No newline at end of file
+{{vtEndScript}}{{vtInclude:download.html}}
diff --git a/download.zip.html b/download.zip.html
index c70c9de..d353d4e 100644
--- a/download.zip.html
+++ b/download.zip.html
@@ -39,10 +39,12 @@
 					{{vtElse}}
 						{{vtCalc: substr( '{vtGet:File,escaped}', 0, strrpos( '{vtGet:File,raw}', '.' ) ) . '_' . strtolower('{vtItem:rule}') . '.' . pathinfo( v::vtget('TempFile'), PATHINFO_EXTENSION ) }}
 						{{vtSet: FinalList[] = "{vtResult}|{vtGet:TempFile}" }}
+						{{vtSet: NumberList[] = "{vtItem:image}|{vtResult}|{vtItem:rule}" }}
 						{{vtSet: DeleteList[] = "{vtGet:TempFile}" }}
 					{{vtEndIf}}
 				{{vtElse}}
 					{{vtSet: FinalList[] = "{vtGet:File,raw}" }}
+					{{vtSet: NumberList[] = "{vtItem:image}|{vtResult}|hires" }}
 				{{vtEndIf}}
 			{{vtEndIf}}
 		{{vtEndIf}}
@@ -76,6 +78,27 @@
 			{{vtEndIf}}
 		{{vtEndIf}}
 
+		{{vtRepeat: {vtGet:NumberList} }}
+			{{vtCalc: strtok( '{vtItem:escaped}', '|' ) }}
+			{{vtSet: ImageId }}
+			{{vtCalc: strtok( '|' ) }}
+			{{vtSet: ImagePath }}
+			{{vtCalc: strtok( '|' ) }}
+			{{vtSet: LogType }}
+			{{vtDbQuery: INSERT INTO {vtDbTable:table_downloads_log} SET
+				`timestamp` = CURRENT_TIMESTAMP,
+				`ip_address` = '{vtEcho: getenv( 'REMOTE_ADDR' ) }',
+				`session_id` = '{vtSession:id}',
+				`type` = '{vtGet:LogType}',
+				`user` = '{vtUser:name}',
+				`realname` = '{vtUser:realname}',
+				`organization` = '{vtUser:Contact_Company}',
+				`image_path` = '/{vtGet:ImagePath,raw}',
+				`image_id` = '{vtGet:ImageId}',
+				`paid` = 1
+			}}
+		{{vtEndRepeat}}
+
 		{{vtRepeat: {vtGet:DeleteList} }}
 			{{vtCalc: unlink('{vtItem:escaped}') }}
 		{{vtEndRepeat}}
diff --git a/downloadlog.html b/downloadlog.html
index d8ffe1c..ed86100 100644
--- a/downloadlog.html
+++ b/downloadlog.html
@@ -23,46 +23,109 @@
 		tr:hover {
 			background: #FFF;
 		}
+		form input[type=text] {
+			width: 9em;
+		}
 	</style>
 </head>
-<body>
+<body data-url="{{vtLink:-met='update',-raw='1'}}">
 	<div class="content" style="width:95%">
 		<h1>Download-Protokoll</h1>
 		<!--
+			{{vtIf: {vtGetValue:-limit} .neq. }}
+				{{vtCalc: (int) '{vtGetValue:-limit,escaped}' }}
+				{{vtDo: -act="updateSession", dlflt_limit="{vtResult}" }}
+			{{vtElseIf: {vtSession:dlflt_limit} .eq. }}
+				{{vtDo: -act="updateSession", dlflt_limit="50" }}
+			{{vtEndIf}}
+
+			{{vtIf: {vtPostValue:filter} .neq. }}
+				{{vtDo: -act="updateSession", -postvalues="dlflt_timestamp, dlflt_ip_address, dlflt_user, dlflt_realname, dlflt_organization, dlflt_type, dlflt_image_path, dlflt_paid" }}
+			{{vtEndIf}}
+
+			{{vtSet: Where = "1" }}
+			{{vtIf: {vtSession:dlflt_timestamp} .neq. }}
+				{{vtSet: Where = "{vtGet:Where} AND timestamp LIKE '{vtSession:dlflt_timestamp, escaped}%'" }}
+			{{vtEndIf}}
+			{{vtIf: {vtSession:dlflt_ip_address} .neq. }}
+				{{vtSet: Where = "{vtGet:Where} AND ip_address LIKE '{vtSession:dlflt_ip_address, escaped}%'" }}
+			{{vtEndIf}}
+			{{vtIf: {vtSession:dlflt_user} .neq. }}
+				{{vtSet: Where = "{vtGet:Where} AND user LIKE '{vtSession:dlflt_user, escaped}%'" }}
+			{{vtEndIf}}
+			{{vtIf: {vtSession:dlflt_realname} .neq. }}
+				{{vtSet: Where = "{vtGet:Where} AND realname LIKE '{vtSession:dlflt_realname, escaped}%'" }}
+			{{vtEndIf}}
+			{{vtIf: {vtSession:dlflt_organization} .neq. }}
+				{{vtSet: Where = "{vtGet:Where} AND organization LIKE '{vtSession:dlflt_organization, escaped}%'" }}
+			{{vtEndIf}}
+			{{vtIf: {vtSession:dlflt_type} .neq. }}
+				{{vtSet: Where = "{vtGet:Where} AND type LIKE '{vtSession:dlflt_type, escaped}%'" }}
+			{{vtEndIf}}
+			{{vtIf: {vtSession:dlflt_image_path} .neq. }}
+				{{vtSet: Where = "{vtGet:Where} AND image_path LIKE '%{vtSession:dlflt_image_path, escaped}%'" }}
+			{{vtEndIf}}
+			{{vtIf: {vtSession:dlflt_paid} .eq. 1 }}
+				{{vtSet: Where = "{vtGet:Where} AND paid = 1" }}
+			{{vtEndIf}}
+
+			{{vtIf: {vtSession:dlflt_limit} .gt. 0 }}
+				{{vtSet: Limit = "LIMIT {vtSession:dlflt_limit}" }}
+			{{vtEndIf}}
+
 			{{vtIf: {vtGetValue:del} .eq. 1 }}
-				{{vtDbQuery: DELETE FROM {vtDbTable:table_downloads_log} WHERE 1 }}
+				{{vtDbQuery: DELETE FROM {vtDbTable:table_downloads_log} WHERE {vtGet:Where} {vtGet:Limit} }}
+				{{vtRedirect}}
+				{{vtReturn}}
 			{{vtEndIf}}
 
-			{{vtDbQuery: SELECT * FROM {vtDbTable:table_downloads_log} WHERE 1 ORDER BY `timestamp` DESC }}
+			{{vtDbQuery: SELECT * FROM {vtDbTable:table_downloads_log} WHERE {vtGet:Where}
+				ORDER BY `timestamp` DESC {vtGet:Limit} }}
 			
 			{{vtIf: {vtDbErrno} .gt. 0 }}
-				{{vtDbQuery: CREATE TABLE IF NOT EXISTS {vtDbTable:table_downloads_log} (
-								  `timestamp` datetime NOT NULL default '0000-00-00 00:00:00',
-								  `ip_address` varchar(15) default NULL,
-								  `session_id` varchar(255) default NULL,
-								  `user` varchar(255) default NULL,
-								  `realname` varchar(255) default NULL,
-								  `organization` varchar(255) default NULL,
-								  `type` varchar(255) default NULL,
-								  `image_path` varchar(255) default NULL
-								) ENGINE=MyISAM DEFAULT CHARSET=latin1
+				{{vtDbQuery: CREATE TABLE `pxtc5_table_downloads_log` (
+					`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
+					`timestamp` datetime DEFAULT NULL,
+					`ip_address` varchar(15) DEFAULT NULL,
+					`session_id` varchar(255) DEFAULT NULL,
+					`user` varchar(255) DEFAULT NULL,
+					`realname` varchar(255) DEFAULT NULL,
+					`organization` varchar(255) DEFAULT NULL,
+					`type` varchar(255) DEFAULT NULL,
+					`image_path` varchar(255) DEFAULT NULL,
+					`image_id` int(10) unsigned DEFAULT NULL,
+					`paid` tinyint(4) NOT NULL DEFAULT 0,
+					PRIMARY KEY (`id`)
+					)
 				}}
 			{{vtEndIf}}
-         
-         {{Optionen: checkbox, [ { "text":"Bildpfade als Links darstellen", "value":"linkImages"} ] }}
-         
-         {{vtIf: {Optionen} .cn. linkImages }}
-            {{vtUse: {vtGet:ID_Bilder} }}
-               {{vtSet: Bilder = "/{vtName}" }}
-            {{vtEndUse}}
-         {{vtEndIf}}
 		-->
-		<!--{{vtIf: {vtDbCountSelection} .gt. 0}}-->
 		<p>
-			<a href="{{vtLink:-met='export/download_log.xls',-raw='1'}}">Daten herunterladen</a> |
-			<a href="{{vtLink:-met='{vtGetValue:-met}',del='1'}}" onclick="return confirm('Sind Sie sicher, dass Sie das GESAMTE Protokoll löschen wollen? Dies lässt sich nicht rückgängig machen.')">Daten löschen</a>
+			<!--{{vtIf: {vtDbCountSelection} .gt. 0}}-->
+				<a href="{{vtLink:-met='export/download_log.xls',-raw='1'}}">Daten herunterladen</a> |
+				<a href="{{vtLink:-met='{vtGetValue:-met}',del='1'}}" onclick="return confirm('Sind Sie sicher, dass Sie ALLE sichtbaren Einträge löschen wollen? Dies lässt sich nicht rückgängig machen.')">Daten löschen</a>
+			<!--{{vtEndIf}}-->
+			<!--{{vtIf: {vtGet:Where} .neq. 1 }}-->
+				| <a id="btnResetFilter" href="#">Filter zurücksetzen</a>
+			<!--{{vtEndIf}}-->
 		</p>
-		<table>
+		<form id="formFilter" action="" method="POST" style="margin-bottom:1em">
+			<input type="hidden" name="filter" value="1">
+			<input type="text" name="dlflt_timestamp" value="{{vtSession:dlflt_timestamp}}" placeholder="Datum/Uhrzeit">
+			<input type="text" name="dlflt_ip_address" value="{{vtSession:dlflt_ip_address}}" placeholder="IP-Adresse">
+			<input type="text" name="dlflt_user" value="{{vtSession:dlflt_user}}" placeholder="Anmeldename">
+			<input type="text" name="dlflt_realname" value="{{vtSession:dlflt_realname}}" placeholder="Name">
+			<input type="text" name="dlflt_organization" value="{{vtSession:dlflt_organization}}" placeholder="Organisation">
+			<input type="text" name="dlflt_type" value="{{vtSession:dlflt_type}}" placeholder="Typ">
+			<input type="text" name="dlflt_image_path" value="{{vtSession:dlflt_image_path}}" placeholder="Bildpfad">
+			<input type="hidden" name="dlflt_paid" value="">
+			<input type="checkbox" name="dlflt_paid" value="1" id="fldFilterPaid" {{vtIf: {vtSession:dlflt_paid} .eq. 1 }}checked{{vtEndIf}}>
+			<label for="fldFilterPaid">gekauft</label>
+			&emsp;
+			<input type="submit" name="" value="Liste filtern">
+		</form>
+		<!--{{vtIf: {vtDbCountSelection} .gt. 0}}-->
+		<table style="width:100%">
 			<tr>
 				<th>Datum/Uhrzeit</th>
 				<th>IP-Adresse</th>
@@ -71,6 +134,7 @@
 				<th>Organisation</th>
 				<th>Typ</th>
 				<th>Bildpfad</th>
+				<th>gekauft</th>
 			</tr>
 			<!--{{vtDbLoop}}-->
 			<tr>
@@ -81,20 +145,42 @@
 				<td>{{vtDbRow:organization}}</td>
 				<td>{{vtDbRow:type}}</td>
 				<td>
-               <!--
-                  {{vtIf: {vtGet:Bilder} .neq.}}
-                     {{vtCapture:ImageLink}}{{vtLink: {vtGet:Bilder}{vtDbRow:image_path} }}{{vtEndCapture}}
-                  {{vtEndIf}}
-               -->
-               <!--{{vtIf: {vtGet:ImageLink} .neq. .and. {vtGet:ImageLink} .neq. # }}-->
-                  <a href="{{vtGet:ImageLink}}">{{vtDbRow:image_path}}</a>
+               <!--{{vtIf: {vtDbRow:image_id} .neq. }}-->
+                  <a href="{{vtLink: {vtDbRow:image_id} }}">{{vtDbRow:image_path}}</a>
+						<!--{{vtSet: IdListe = "{vtGet:IdListe},{vtDbRow:image_id}" }}-->
                <!--{{vtElse}}-->
                   {{vtDbRow:image_path}}
                <!--{{vtEndIf}}-->
             </td>
+				<td style="text-align:center">
+               <!--{{vtIf: {vtDbRow:image_id} .neq. }}-->
+						<input data-id="{{vtDbRow:id}}" type="checkbox" value="1" {{vtIf: {vtDbRow:paid} .eq. 1 }}checked{{vtEndIf}}>
+               <!--{{vtElse}}-->
+						<input type="checkbox" disabled>
+               <!--{{vtEndIf}}-->
+				</td>
 			</tr>
 			<!--{{vtEndDbLoop}}-->
 		</table>
+		<p style="text-align:center">
+			<!--{{vtRepeat: 50,100,250 }}-->
+				<!--{{vtIf: {vtItem} .eq. {vtSession:dlflt_limit} }}-->
+					<strong>{{vtItem}}</strong> |
+				<!--{{vtElse}}-->
+					<a href="{{vtLink:-limit='{vtItem}'}}">{{vtItem}}</a> |
+				<!--{{vtEndIf}}-->
+			<!--{{vtEndRepeat}}-->
+			<!--{{vtIf: {vtSession:dlflt_limit} .eq. 0 }}-->
+				<strong>∞</strong>
+			<!--{{vtElse}}-->
+				<a href="{{vtLink:-limit='{vtItem}'}}">∞</a>
+			<!--{{vtEndIf}}-->
+			<!--{{vtIf: {vtGet:IdListe} .neq. }}-->
+				<!--{{vtCalc: encodeNumberList('{vtGet:IdListe}') }}-->
+				&nbsp;&nbsp;&mdash;&nbsp; &nbsp;
+				<a href="{{vtLink: -pg='{vtGet:ID_Lightbox}', lb='{vtResult}', lbx='r' }}">Aufgelistete Bilder in Lightbox legen</a>
+			<!--{{vtEndIf}}-->
+		</p>
 		<!--{{vtElseIf: {vtLicenseType} .eq. a }}-->
 			<p>Diese Funktion ist nur in der Professional-Edition verfügbar.</p>
 			<p><a href="{{vtGet:LinkUpgrade}}" class="text_link" target="_blank">jetzt bestellen</a></p>
@@ -105,9 +191,33 @@
 					Jetzt aktivieren
 				</a>
 			</p>
+		<!--{{vtElseIf: {vtGet:Where} .neq. 1 }}-->
+			<p>Es liegen keine Protokolleinträge vor, die den Filterbedingungen entsprechen.</p>
 		<!--{{vtElse}}-->
 			<p>Es liegen noch keine Protokolleinträge vor.</p>
 		<!--{{vtEndIf}}-->
 	</div>
+	<script>
+		$('input[type=checkbox][data-id]').on( 'click', function( event ){
+			if ( ! confirm('Sind Sie sicher, dass der \'gekauft\'-Status dieses Eintrags umgeschaltet werden soll?') ){
+				return false;
+			}
+			let url = $('body').data('url');
+			let id = $(this).data('id');
+			let paid = $(this).prop('checked') ? 1 : 0;
+			$.get( url + `&id=${id}+&paid=${paid}`, function( data ){
+				console.log( data );
+			});
+		});
+		$('#btnResetFilter').on( 'click', function( event ){
+			event.preventDefault();
+			if ( ! confirm('Sind Sie sicher, dass alle Filter entfernt werden sollen?') ){
+				return false;
+			}
+			$('#formFilter input[type=text]').val('');
+			$('#fldFilterPaid').prop( 'checked', false );
+			$('#formFilter').submit();
+		});
+	</script>
 </body>
 </html>
diff --git a/downloadlog.update.html b/downloadlog.update.html
new file mode 100644
index 0000000..61be84f
--- /dev/null
+++ b/downloadlog.update.html
@@ -0,0 +1,21 @@
+{{vtScript}}
+
+{{vtHeader: ContentType: application/json }}
+
+{{vtIf: {vtUser:admin} .neq. 1 }}
+	{{vtSet: Status = "0", Error = "Fehlende Rechte" }}
+{{vtElseIf: {vtGetValue:id} .eq. .or. {vtGetValue:paid} .eq. }}
+	{{vtSet: Status = "0", Error = "Fehlende Parameter" }}
+{{vtElse}}
+	{{vtCalc: (int) '{vtGetValue:id}' }}
+	{{vtSet: id }}
+	{{vtCalc: '{vtGetValue:paid}' ? 1 : 0 }}
+	{{vtSet: paid }}
+	{{vtDbQuery: UPDATE `%table_downloads_log`
+		SET paid = {vtGet:paid} WHERE id = {vtGet:id}
+	}}
+	{{vtSet: Status = "1", Error = "0" }}
+{{vtEndIf}}
+
+{{vtEndScript}}{ status: {{vtGet:Status}}, error: {{vtGet:Error}} }
+
diff --git a/export/download_log.xls b/export/download_log.xls
index 43cb492..cd1dd38 100644
--- a/export/download_log.xls
+++ b/export/download_log.xls
@@ -1,9 +1,40 @@
 {{vtScript}}
 
 	{{vtIf: workspace .and. {vtUser:admin} .eq. 1 }}
-		{{vtDbQuery: SELECT * FROM {vtDbTable:table_downloads_log} WHERE 1 }}
+		{{vtSet: Where = "1" }}
+		{{vtIf: {vtSession:dlflt_timestamp} .neq. }}
+			{{vtSet: Where = "{vtGet:Where} AND timestamp LIKE '{vtSession:dlflt_timestamp, escaped}%'" }}
+		{{vtEndIf}}
+		{{vtIf: {vtSession:dlflt_ip_address} .neq. }}
+			{{vtSet: Where = "{vtGet:Where} AND ip_address LIKE '{vtSession:dlflt_ip_address, escaped}%'" }}
+		{{vtEndIf}}
+		{{vtIf: {vtSession:dlflt_user} .neq. }}
+			{{vtSet: Where = "{vtGet:Where} AND user LIKE '{vtSession:dlflt_user, escaped}%'" }}
+		{{vtEndIf}}
+		{{vtIf: {vtSession:dlflt_realname} .neq. }}
+			{{vtSet: Where = "{vtGet:Where} AND realname LIKE '{vtSession:dlflt_realname, escaped}%'" }}
+		{{vtEndIf}}
+		{{vtIf: {vtSession:dlflt_organization} .neq. }}
+			{{vtSet: Where = "{vtGet:Where} AND organization LIKE '{vtSession:dlflt_organization, escaped}%'" }}
+		{{vtEndIf}}
+		{{vtIf: {vtSession:dlflt_type} .neq. }}
+			{{vtSet: Where = "{vtGet:Where} AND type LIKE '{vtSession:dlflt_type, escaped}%'" }}
+		{{vtEndIf}}
+		{{vtIf: {vtSession:dlflt_image_path} .neq. }}
+			{{vtSet: Where = "{vtGet:Where} AND image_path LIKE '%{vtSession:dlflt_image_path, escaped}%'" }}
+		{{vtEndIf}}
+		{{vtIf: {vtSession:dlflt_paid} .eq. 1 }}
+			{{vtSet: Where = "{vtGet:Where} AND paid = 1" }}
+		{{vtEndIf}}
+
+		{{vtIf: {vtSession:dlflt_limit} .gt. 0 }}
+			{{vtSet: Limit = "LIMIT {vtSession:dlflt_limit}" }}
+		{{vtEndIf}}
+
+		{{vtDbQuery: SELECT * FROM {vtDbTable:table_downloads_log} WHERE {vtGet:Where}
+			ORDER BY `timestamp` DESC {vtGet:Limit} }}
 	{{vtEndIf}}
 	
-{{vtEndScript}}"Datum/Uhrzeit"	"IP-Adresse"	"Anmeldename"	"Name"	"Organisation"	"Typ"	"Bildpfad"
-{{vtDbLoop}}"{{vtDbRow:timestamp}}"	"{{vtDbRow:ip_address}}"	"{{vtDbRow:user}}"	"{{vtDbRow:realname}}"	"{{vtDbRow:organization}}"	"{{vtDbRow:type}}"	"{{vtDbRow:image_path}}"
-{{vtEndDbLoop}}
\ No newline at end of file
+{{vtEndScript}}"Datum/Uhrzeit"	"IP-Adresse"	"Anmeldename"	"Name"	"Organisation"	"Typ"	"Bildpfad"	"gekauft"
+{{vtDbLoop}}"{{vtDbRow:timestamp}}"	"{{vtDbRow:ip_address}}"	"{{vtDbRow:user}}"	"{{vtDbRow:realname}}"	"{{vtDbRow:organization}}"	"{{vtDbRow:type}}"	"{{vtDbRow:image_path}}"	"{{vtDbRow:paid}}"
+{{vtEndDbLoop}}
diff --git a/image.download.html b/image.download.html
index e7942bb..89f0c07 100644
--- a/image.download.html
+++ b/image.download.html
@@ -107,7 +107,8 @@
 							`user` = '{vtUser:name}',
 							`realname` = '{vtUser:realname}',
 							`organization` = '{vtUser:Contact_Company}',
-							`image_path` = '{vtGet:LogPath}'
+							`image_path` = '{vtGet:LogPath}',
+							`image_id` = '{vtId}'
 			}}
 		{{vtEndIf}}
 		
diff --git a/imagelist.download.html b/imagelist.download.html
index 35d331c..95ee5a7 100644
--- a/imagelist.download.html
+++ b/imagelist.download.html
@@ -126,7 +126,7 @@
 			{{vtElse}}
 				{{vtCalc: substr( '{vtName:escaped}', 0, -4 ) . '_' . strtolower('{vtGetValue:rule}') . '.' . pathinfo( v::vtget('TempFile'), PATHINFO_EXTENSION ) }}
 				{{vtSet: FinalList[] = "{vtGet:Verzeichnis,raw}/{vtResult}|{vtGet:TempFile}" }}
-				{{vtSet: NumberList="{vtGet:NumberList},{vtID}"}}
+				{{vtSet: NumberList="{vtGet:NumberList},{vtID}|{vtGet:Verzeichnis,raw}/{vtResult}"}}
 				{{vtSet: DeleteList[] = "{vtGet:TempFile}" }}
 			{{vtEndIf}}
 		{{vtElseIf: {vtGetValue:v} .eq. }}
@@ -154,7 +154,7 @@
 				{{vtCalc: file_exists( '{vtGet:Directory}/{vtGet:BaseName}{vtItem}' ) ? '1' : '' }}
 				{{vtIf: {vtResult} .eq. 1}}
 					{{vtSet: FinalList[]="{vtGet:BaseName}{vtItem}"}}
-					{{vtSet: NumberList="{vtGet:NumberList},{vtID}"}}
+					{{vtSet: NumberList="{vtGet:NumberList},{vtID}|{vtGet:BaseName}{vtItem}"}}
 					{{vtExit}}
 				{{vtEndIf}}
 			{{vtEndRepeat}}
@@ -213,8 +213,10 @@
 		{{vtEndIf}}
 
 		{{vtIf: {vtGet:LogType} .neq.}}
-			{{vtRepeat: {vtGet:FinalList} }}
-				{{vtCalc: array_shift( explode( '|', '{vtItem:escaped}' ) ) }}
+			{{vtRepeat: {vtGet:NumberList} }}
+				{{vtCalc: strtok( '{vtItem:escaped}', '|' ) }}
+				{{vtSet: ImageId }}
+				{{vtCalc: strtok( '|' ) }}
 				{{vtSet: ImagePath }}
 				{{vtDbQuery: INSERT INTO {vtDbTable:table_downloads_log} SET
 								`timestamp` = CURRENT_TIMESTAMP,
@@ -224,7 +226,8 @@
 								`user` = '{vtUser:name}',
 								`realname` = '{vtUser:realname}',
 								`organization` = '{vtUser:Contact_Company}',
-								`image_path` = '/{vtGet:ImagePath,raw}'
+								`image_path` = '/{vtGet:ImagePath,raw}',
+								`image_id` = '{vtGet:ImageId}'
 				}}
 			{{vtEndRepeat}}
 		{{vtEndIf}}
diff --git a/imagelist.html b/imagelist.html
index 7eeabe4..b8a45e3 100644
--- a/imagelist.html
+++ b/imagelist.html
@@ -275,6 +275,18 @@
 		{{vtInclude: includes/get_payment_methods.html }}
 		{{vtInclude: includes/deliverymethods.html }}
 
+		{{vtLoad: templates/pixtacy/lib/pxtc_products.class.php }}
+		{{vtCalc: Pixtacy_Products::set_options( array ( 
+			'paymentsPossible' => ! empty( v::vtget('Bezahlmethoden') ) || ! empty( v::vtget('DeliveryPayment') ),
+			'deliveryPossible' => ! empty( v::vtget('DeliveryMethods') ),
+			'vatRate1' => v::vtglobal('pxtcVatRate'),
+			'vatRate2' => v::vtglobal('pxtcVatRate2'),
+			'userName' => v::vtuser('name'),
+			'userGroups' => v::vtuser('groups'),
+			'preferEnglish' => v::vtget('Language') != 'de' ? '1' : '' 
+		) ) }}
+		{{vtCalc: Pixtacy_Products::initialize( v::get_db(), v::vtget('ID_Produkte'), v::vtget('ID_Sortimente'), v::vtget('Cart') ) }}
+
 		{{vtIf: {Sortiment} .eq. 0 }}
 			{{vtSet: GalerieSortiment = "" }}
 			{{vtSet: GalerieProdukte = "{Produkte}
@@ -333,16 +345,8 @@
 					{{vtSet: Image[badge] = "{vtGet:s_txt_0018}" }}
 				{{vtEndIf}}
 				
-				{{vtIf: {Sortiment} .eq. .or. {Sortiment} .eq. 0 }}
-					{{vtSet: Sortiment = "{vtGet:GalerieSortiment}" }}
-				{{vtElseIf: {Sortiment} .neq. -1 }}
-					{{vtSet: Sortiment = "{Sortiment}" }}
-				{{vtElse}}
-					{{vtSet: Sortiment = "" }}
-				{{vtEndIf}}
-
-				{{vtCalc: image_is_buyable( '{Verzeichnis:escaped}/{Dateiname:escaped}', '{vtGet:Sortiment}', '{vtGet:GalerieProdukte}
-{Produkte}' ) ? 1 : 0 }}
+				{{vtCalc: Pixtacy_Products::is_image_buyable( '{Verzeichnis:escaped}/{Dateiname:escaped}', '{Sortiment:escaped}',
+					'{Produkte:escaped}', '{vtGet:GalerieSortiment}', '{vtGet:GalerieProdukte}' ) ? 1 : 0 }}
 				{{vtIf: {vtResult} .eq. 1 }}
 					{{vtSet: ShowCartButtons = "1" }}
 					{{vtSet: Image[buyable] = "1" }}
diff --git a/includes/get_payment_methods.html b/includes/get_payment_methods.html
index b040807..5929caa 100644
--- a/includes/get_payment_methods.html
+++ b/includes/get_payment_methods.html
@@ -43,6 +43,12 @@
 			{{vtSet: Methode[label]="{vtGet:s_payment_payrexx}"}}
 			{{vtSet: Bezahlmethoden[]="{vtGet:Methode}"}}
 		{{vtEndIf}}
+		{{vtIf: {vtGlobal:pxtcPaymentMollie} .in. 1|2 .or. {vtGlobal:pxtcPaymentMollie} .in. {vtUser:groups} .and. {vtGet:AdvancedOptions} .eq. 1 }}
+			{{vtSet: Methode[id]="8"}}
+			{{vtSet: Methode[name]="mollie"}}
+			{{vtSet: Methode[label]="{vtGet:s_payment_mollie}"}}
+			{{vtSet: Bezahlmethoden[]="{vtGet:Methode}"}}
+		{{vtEndIf}}
 
 	{{vtElse}}
 
@@ -82,6 +88,12 @@
 			{{vtSet: Methode[label]="{vtGet:s_payment_payrexx}"}}
 			{{vtSet: Bezahlmethoden[]="{vtGet:Methode}"}}
 		{{vtEndIf}}
+		{{vtIf: {vtGet:MollieInitialized} .eq. 1 .and. {vtGlobal:pxtcPaymentMollie} .eq. 2 }}
+			{{vtSet: Methode[id]="8"}}
+			{{vtSet: Methode[name]="mollie"}}
+			{{vtSet: Methode[label]="{vtGet:s_payment_mollie}"}}
+			{{vtSet: Bezahlmethoden[]="{vtGet:Methode}"}}
+		{{vtEndIf}}
 
 	{{vtEndIf}}
 
diff --git a/includes/get_products.html b/includes/get_products.html
index 0bf5485..3666db5 100644
--- a/includes/get_products.html
+++ b/includes/get_products.html
@@ -26,6 +26,7 @@
 		'vatRate2' => v::vtglobal('pxtcVatRate2'),
 		'userName' => v::vtuser('name'),
 		'userGroups' => v::vtuser('groups'),
+		'userPriceFactor' => v::vtuser('Preisfaktor'),
 		'preferEnglish' => v::vtget('Language') != 'de' ? '1' : '' 
 	) ) }}
 	{{vtCalc: Pixtacy_Products::initialize( v::get_db(), v::vtget('ID_Produkte'), v::vtget('ID_Sortimente'), v::vtget('Cart') ) }}
diff --git a/includes/get_products_lb.html b/includes/get_products_lb.html
index d13722c..bb2c663 100644
--- a/includes/get_products_lb.html
+++ b/includes/get_products_lb.html
@@ -4,58 +4,34 @@
 	### In "ProductList" wird die Liste, in "ProductCount" die Anzahl gespeichert
 
 	{{vtInclude: includes/get_payment_methods.html}}
-
-	{{vtSet: ProductCount = "0" }}
-	{{vtSet: ProductList = "" }}
-
-	{{vtAsAdmin}}
-		{{vtUse: {vtGet:ID_Produkte} }}
-			{{vtLoop}}
-		
-				{{vtSet: ShowRow=""}}
-				{{vtIf: {Benutzer} .neq. .and. {Benutzer} .neq. guest .and. {vtUser:groups} .ncn. {Benutzer} .and. {vtUser:admin} .neq. 1 }}
-				{{vtElseIf: {Benutzer} .eq. guest .and. {vtUser:name} .neq. .and. {vtUser:admin} .neq. 1 }}
-				{{vtElseIf: {Preis|num-en} .gt. 0 .and. {vtGet:Bezahlmethoden} .eq.}}
-				{{vtElseIf: {Zuordnung} .eq. 1 .and. {Kennung} .eq.}}
-					{{vtSet: ShowRow="1"}}
-				{{vtEndIf}}
-	
-				{{vtIf: {vtGet:ShowRow} .eq. 1}}
-		
-					{{vtSet: Prod[id] = "{vtID}" }}
-					{{vtSet: Prod[name] = "{Bezeichnung:raw}" }}
-					{{vtSet: Prod[name_en] = "{Bezeichnung_en:raw}" }}
-					{{vtSet: Prod[type] = "{Typ}" }}
-					{{vtSet: Prod[description] = "{Beschreibung:raw}" }}
-
-					{{vtIf: {Steuersatz} .eq. 2 }}
-						{{vtSet: Prod[vatRate] = "{vtGlobal:pxtcVatRate2}" }}
-					{{vtElse}}
-						{{vtSet: Prod[vatRate] = "{vtGlobal:pxtcVatRate}" }}
-					{{vtEndIf}}
-
-					{{vtIf: {Preisanpassung} .eq. 1 .and. {vtUser:Preisfaktor} .gt. 0}}
-						{{vtCalc: {Preis} * {vtUser:Preisfaktor|num:2.} }}
-						{{vtSet: Prod[price] = "{vtResult}" }}
-					{{vtElse}}
-						{{vtSet: Prod[price] = "{Preis}" }}
-					{{vtEndIf}}
-				
-					{{vtCalc: get_cart_price( {vtID} ) }}
-					{{vtIf: {vtResult} .gt. 0 }}
-						{{vtSet: Prod[price] = "{vtResult}" }}
-					{{vtEndIf}}
-
-					{{vtCalc: get_cart_quantity( {vtGet:ID_Current}, {vtID} ) }}
-					{{vtSet: Prod[quantity] = "{vtResult}" }}
-
-					{{vtSet: ProductList[] = "{vtGet:Prod}" }}
-					{{vtCalc: {vtGet:ProductCount} + 1 }}
-					{{vtSet: ProductCount }}
-
-				{{vtEndIf}}
-			{{vtEndLoop}}
-		{{vtEndUse}}
-	{{vtEndAsAdmin}}
+	{{vtInclude: includes/deliverymethods.html }}
+
+	{{vtIf: {vtGet:Bezahlmethoden} .eq. .and. {vtGet:DeliveryPayment} .neq. 1 }}
+		{{vtSet: PaymentPossible = "0" }}
+	{{vtElse}}
+		{{vtSet: PaymentPossible = "1" }}
+	{{vtEndIf}}
+
+	{{vtIf: {vtGet:DeliveryMethods} .eq. }}
+		{{vtSet: DeliveryPossible = "0" }}
+	{{vtElse}}
+		{{vtSet: DeliveryPossible = "1" }}
+	{{vtEndIf}}
+
+	{{vtLoad: templates/pixtacy/lib/pxtc_products.class.php }}
+	{{vtCalc: Pixtacy_Products::set_options( array ( 
+		'paymentsPossible' => v::vtget('PaymentPossible'),
+		'deliveryPossible' => v::vtget('DeliveryPayment'),
+		'vatRate1' => v::vtglobal('pxtcVatRate'),
+		'vatRate2' => v::vtglobal('pxtcVatRate2'),
+		'preferEnglish' => v::vtget('Language') != 'de' ? '1' : '' 
+	) ) }}
+	{{vtCalc: Pixtacy_Products::initialize( v::get_db(), v::vtget('ID_Produkte'), v::vtget('ID_Sortimente') ) }}
+
+	{{vtCalc: Pixtacy_Products::get_global_products() }}
+	{{vtSet: ProductList }}
+
+	{{vtCalc: count( json_decode( v::vtresult() ) ) }}
+	{{vtSet: ProductCount }}
 
 {{vtEndScript}}
diff --git a/includes/header_r.html b/includes/header_r.html
index bfc8b88..0e5cbe3 100644
--- a/includes/header_r.html
+++ b/includes/header_r.html
@@ -67,7 +67,7 @@
 		<nav class="navbar navbar-expand-lg navbar-{{vtGet:NavbarClass}} {{vtGet:NavbarBgClass}}">
 				<!--{{vtIf: {vtGlobal:pxtcNaviBrand} .neq. -1 }}-->
 					<!--{{vtIf: {vtGlobal:pxtcNaviBrandTarget} .neq. -1 }}-->
-						<a class="navbar-brand mr-2 d-none d-lg-flex"
+						<a class="navbar-brand mr-2 d-lg-flex"
 							href="{{vtIf: {vtGlobal:pxtcNaviBrandTarget} .eq. 1}}{{vtGlobal:pxtcLogoLink}}{{vtElse}}{{vtLink: {vtGet:ID_Home} }}{{vtEndIf}}" 
 							target="{{vtIf: {vtGlobal:pxtcNaviBrandTarget} .eq. 1}}{{vtGlobal:pxtcLogoTarget}}{{vtEndIf}}">
 					<!--{{vtElse}}-->
diff --git a/includes/initialize.html b/includes/initialize.html
index 61b0c52..87efa03 100644
--- a/includes/initialize.html
+++ b/includes/initialize.html
@@ -3,7 +3,7 @@
 
 	{{vtLoad: templates/pixtacy/resources/functions.php}}
 	
-	{{vtSet: CurrentVersionNumber="54"}}
+	{{vtSet: CurrentVersionNumber="55"}}
 	{{vtSet: ID_Current="{vtID}"}}
 	{{vtSet: thumbnailUrl="{vtConfig:baseURLData}pixtacy_thumbnails"}}
 	{{vtSet: thumbnailPath="{vtConfig:pathToData}pixtacy_thumbnails"}}
diff --git a/languages/de.txt b/languages/de.txt
index c31880d..e8903db 100644
--- a/languages/de.txt
+++ b/languages/de.txt
@@ -317,6 +317,7 @@ Viele Grüße
 {{vtSet: s_payment_sofortueberweisung = "sofortüberweisung.de"}}
 {{vtSet: s_payment_paypal             = "PayPal"}}
 {{vtSet: s_payment_payrexx            = "Payrexx"}}
+{{vtSet: s_payment_mollie             = "Mollie"}}
 
 {{vtSet: s_invoice_text_vorkasse            = "Bitte überweisen Sie den Rechnungsbetrag auf unser unten angegebenes Konto." }}
 {{vtSet: s_invoice_text_sepa                = "Der Rechnungsbetrag wird wie vereinbart von Ihrem Konto eingezogen." }}
diff --git a/languages/en.txt b/languages/en.txt
index 8cf7e37..0c41617 100644
--- a/languages/en.txt
+++ b/languages/en.txt
@@ -316,6 +316,7 @@ Regards,
 {{vtSet: s_payment_sofortueberweisung = "sofortüberweisung.de"}}
 {{vtSet: s_payment_paypal             = "PayPal"}}
 {{vtSet: s_payment_payrexx            = "Payrexx"}}
+{{vtSet: s_payment_mollie             = "Mollie"}}
 
 {{vtSet: s_invoice_text_vorkasse            = "Please transfer the invoiced amount to our bank account (see below)." }}
 {{vtSet: s_invoice_text_sepa                = "The invoiced amount will be debited from your bank account." }}
diff --git a/lib/pxtc_products.class.php b/lib/pxtc_products.class.php
index 505285d..969f0c6 100644
--- a/lib/pxtc_products.class.php
+++ b/lib/pxtc_products.class.php
@@ -12,6 +12,7 @@ class Pixtacy_Products {
 	private static $options; // Datensatz mit globalen Optionen
 	private static $productQuantities; // Liste der Warenkorbprodukte mit ihren (aufsummierten) Mengen
 	private static $imageQuantities; // Liste der Warenkorbbilder mit ihren Mengen je Produkt
+	private static $productGroups; // Liste der Produktgruppen mit ihren zugeordneten Produkten
 	public static $cart = [];
 	public static $lastProductsCount;
 
@@ -52,12 +53,17 @@ class Pixtacy_Products {
 		}
 
 		// build lists of buyable products and assortments
-		$groups = empty( self::$options['userGroups'] ) ? array () : explode( ',', self::$options['userGroups'] );
-		$sql = "SELECT c.id, p.`benutzer`, p.`kennung`, p.`preis:num`, p.`zuordnung:num`, p.`typ`,
-			p.`bezeichnung`, p.`bezeichnung_en`, p.`beschreibung`, p.`beschreibung_en`, p.`preisanpassung`, p.`steuersatz`
-			FROM `%data_product` p LEFT JOIN `%content` c ON c.id = p.vtid 
-			WHERE c.containerID = {$pageIdProducts}
-			ORDER BY IF( c.sortValue > 0, 0, 1 ), c.sortValue, p.bezeichnung";
+		$userGroups = empty( self::$options['userGroups'] ) ? array () : explode( ',', self::$options['userGroups'] );
+		$sql = "SELECT c.id, IF( c.containerID = {$pageIdProducts}, 0, c.containerID ) AS 'group',
+			p.`benutzer`, p.`kennung`, p.`preis:num`, IF( c.containerID = {$pageIdProducts}, p.`zuordnung:num`, pg.`zuordnung:num` ) AS 'zuordnung:num',
+			p.`typ`, p.`bezeichnung`, p.`bezeichnung_en`, p.`beschreibung`, p.`beschreibung_en`, p.`preisanpassung`, p.`steuersatz`
+			FROM `%data_product` p
+			LEFT JOIN `%content` c ON c.id = p.vtid
+			LEFT JOIN `%data_product` pg ON c.containerID = pg.vtid
+			WHERE c.containerID = {$pageIdProducts} 
+			OR c.path LIKE CONCAT( (SELECT path FROM `%content` WHERE id = {$pageIdProducts}), ',%' )
+			ORDER BY IF( c.containerID = {$pageIdProducts}, 0, 1 ),
+			IF( c.sortValue > 0, 0, 1 ), c.sortValue, p.bezeichnung";
 		$result = $db->query( $sql );
 		//if ( ! $result ){
 		//	die( $db->error );
@@ -66,7 +72,7 @@ class Pixtacy_Products {
 		while ( $result && $result->num_rows && $product = $result->fetch_assoc() ) {
 			if ( ( empty( self::$options['paymentsPossible'] ) && $product['preis:num'] )
 				|| ( empty( self::$options['deliveryPossible'] ) && strtolower( $product['typ'] ) == 'print' )
-				|| ( ! empty( $product['benutzer'] ) && ! in_array( $product['benutzer'], $groups ) 
+				|| ( ! empty( $product['benutzer'] ) && ! in_array( $product['benutzer'], $userGroups ) 
 				&& ! ( $product['benutzer'] == 'guest' && empty( self::$options['userName'] ) )
 				&& ! ( $product['benutzer'] == 'Alle' && ! empty( self::$options['userName'] ) ) ) 
 			) {
@@ -74,7 +80,10 @@ class Pixtacy_Products {
 			}
 			$prodId = (int) $product['id'];
 			self::$globalProducts[ $prodId ] = $product;
-			if ( $product['zuordnung:num'] ) {
+			if ( $product['group'] > 0 ){
+				self::$productGroups[ $product['group'] ][] = self::get_product_record( $prodId );
+			}
+			if ( ! empty( $product['zuordnung:num'] ) ) {
 				// es ist ein automatisch zugeordnetes Produkt
 				self::$autoProducts[] = $prodId;
 				if ( empty( $product['kennung'] ) ) {
@@ -82,8 +91,8 @@ class Pixtacy_Products {
 					self::$allImagesBuyable = TRUE;
 				}
 			}
-			elseif ( ! isset( self::$productAssortments[ $prodId ] ) ) { 
-				// Produkt ist keinem Sortiment zugeordnet
+			elseif ( $product['group'] > 0 || ! isset( self::$productAssortments[ $prodId ] ) ) { 
+				// Produkt ist ein Subprodukt oder keinem Sortiment zugeordnet
 				continue;
 			}
 			elseif ( empty( $product['kennung'] ) ) { 
@@ -94,6 +103,9 @@ class Pixtacy_Products {
 				}
 			}
 		}
+		if ( empty( self::$globalProducts ) ) {
+			self::$noImageBuyable = TRUE;
+		}
 		return array ( 'assortments' => self::$assortments, 'assortmentsAlwaysBuyable' => self::$assortmentsAlwaysBuyable,
 			'globalProducts' => self::$globalProducts, 'autoProducts' => self::$autoProducts );
 	}
@@ -107,7 +119,7 @@ class Pixtacy_Products {
 		}
 		// Galeriesortiment
 		if ( empty( $imageAssortment ) ){
-			if ( $galleryAssortment == 0 ){
+			if ( empty( $galleryAssortment ) ){
 				// Galerie hat kein Sortiment, sondern eigene Produktauswahl
 				$products = array_merge( $products, explode( "\n", $galleryProducts ) );
 			}
@@ -128,22 +140,25 @@ class Pixtacy_Products {
 			return FALSE;
 		}
 		$offerings = self::get_offerings( $imageAssortment, $imageProducts, $galleryAssortment, $galleryProducts );
-		$products = array ();
 		if ( isset( self::$assortments[ $offerings['assortment'] ] ) ){
 			if ( in_array( $offerings['assortment'], self::$assortmentsAlwaysBuyable ) ){
 				return TRUE;
 			}
 			foreach ( self::$assortments[ $offerings['assortment'] ] as $item ){
-				if ( ! empty( $item['product_id'] ) ){
-					$products[] = $item['product_id'];
+				if ( empty( $item['product_id'] ) ){
+					continue;
+				}
+				if ( empty( self::$globalProducts[ $item['product_id'] ]['kennung'] ) 
+					|| hires_file_exists( $imagePath, self::$globalProducts[ $item['product_id'] ]['kennung'] ) 
+				){
+					return TRUE;
 				}
 			}
 		}
-		$products = array_merge( $products, $offerings['products'] );
-		foreach ( $products as $product ) {
-			if ( isset( self::$globalProducts[ $product ] ) 
-				&& ( self::$globalProducts[ $product ]['kennung'] == '' 
-				|| hires_file_exists( $imagePath, self::$globalProducts[ $product ]['kennung'] ) )
+		foreach ( $offerings['products'] as $productId ) {
+			if ( isset( self::$globalProducts[ $productId ] ) 
+				&& ( empty( self::$globalProducts[ $productId ]['kennung'] ) 
+				|| hires_file_exists( $imagePath, self::$globalProducts[ $productId ]['kennung'] ) )
 			) {
 				return TRUE;
 			}
@@ -165,8 +180,12 @@ class Pixtacy_Products {
 				elseif ( empty( self::$globalProducts[ $item['product_id'] ]['kennung'] ) 
 					|| hires_file_exists( $imagePath, self::$globalProducts[ $item['product_id'] ]['kennung'] ) 
 				){
-					$products[] = self::get_product_record( $item['product_id'], $imageId );
-					$productIds[] = $item['product_id'];
+					$record = self::get_product_record( $item['product_id'], $imageId );
+					if ( $record['type'] == 'Gruppe' ){
+						$record['options'] = self::$productGroups[ $record['id'] ] ?? [];
+					}
+					$products[] = $record;
+					$productIds[] = $record['id'];
 				}
 			}
 		}
@@ -177,8 +196,12 @@ class Pixtacy_Products {
 				&& ( empty( self::$globalProducts[ $productId ]['kennung'] )
 				|| hires_file_exists( $imagePath, self::$globalProducts[ $productId ]['kennung'] ) )
 			) {
-				$products[] = self::get_product_record( $productId, $imageId );
-				$productIds[] = $productId;
+				$record = self::get_product_record( $productId );
+				if ( $record['type'] == 'Gruppe' ){
+					$record['options'] = self::$productGroups[ $record['id'] ] ?? [];
+				}
+				$products[] = $record;
+				$productIds[] = $record['id'];
 			}
 		}
 		// liefere Produktliste zurück
@@ -208,9 +231,6 @@ class Pixtacy_Products {
 			: 1;
 		$product = self::$globalProducts[ $prodId ];
 		$price = (float) $product['price'];
-		$factor = empty( self::$options['userPriceFactor'] ) 
-			? 1 
-			: (float) str_replace( ',', '.', self::$options['userPriceFactor'] );
 		if ( ! empty( $product['applyDiscount'] ) && ! empty( $product['discountScale'] ) ){
 			foreach ( $product['discountScale'] as $level ){
 				if ( $quantity >= $level['quantity'] ){
@@ -218,9 +238,6 @@ class Pixtacy_Products {
 				}
 			}
 		}
-		if ( $product['applyUserPriceFactor'] && $factor != 1 ){
-			$price = $price * $factor;
-		}
 		if ( empty( self::$options['vatHandling'] ) || self::$options['vatHandling'] == 'excluded' ){
 			return $price;
 		}
@@ -243,7 +260,7 @@ class Pixtacy_Products {
 	}
 
 
-	private static function get_product_record( $prodId, $imageId ){
+	private static function get_product_record( $prodId, $imageId = NULL ){
 		if ( ! isset( self::$globalProducts[ $prodId ] ) ){
 			return FALSE;
 		}
@@ -254,20 +271,26 @@ class Pixtacy_Products {
 		else {
 			$name = $p['bezeichnung'];
 		}
+		$price = $p['preis:num'];
+		if ( ! empty( $p['preisanpassung'] ) && ! empty( self::$options['userPriceFactor'] ) ){
+			$factor = (float) str_replace( ',', '.', self::$options['userPriceFactor'] );
+			$price = round( $price * $factor, 2 );
+		}
 		return array (
 			'id' => (int) $prodId,
+			'group' => (int) $p['group'],
 			'name' => trim( strtok( $name, '@' ) ),
 			'type' => $p['typ'],
 			'description' => ! empty( self::$options['preferEnglish'] ) && ! empty( $p['beschreibung_en'] ) ? $p['beschreibung_en'] : $p['beschreibung'],
-			'price' => $p['preis:num'],
+			'price' => $price,
 			'applyUserPriceFactor' => ! empty( $p['preisanpassung'] ),
-			'vatRate' => self::$options[ $p['steuersatz'] == 2 ? 'vatRate2' : 'vatRate1' ],
+			'vatRate' => (int) self::$options[ $p['steuersatz'] == 2 ? 'vatRate2' : 'vatRate1' ],
 			'applyDiscount' => ! empty( $p['rabatt_anwenden'] ),
 			'discountScale' => empty( $p['rabattstaffel'] ) 
 				? NULL 
 				: json_decode( $p['rabattstaffel'] ),
-			'cartVatRate' => self::$options[ $p['steuersatz'] == 2 ? 'vatrate2' : 'vatrate1' ],
-			'cartQuantity' => self::get_cart_quantity( $imageId, $prodId ),
+			'cartVatRate' => self::$options[ $p['steuersatz'] == 2 ? 'vatRate2' : 'vatRate1' ],
+			'cartQuantity' => $imageId ? self::get_cart_quantity( $imageId, $prodId ) : 0,
 		);
 	}
 }
diff --git a/lightbox.download.html b/lightbox.download.html
index 9d68a6d..fce6622 100644
--- a/lightbox.download.html
+++ b/lightbox.download.html
@@ -73,7 +73,7 @@
 				{{vtElse}}
 					{{vtCalc: substr( '{vtName:escaped}', 0, -4 ) . '_' . strtolower('{vtGetValue:rule}') . '.' . pathinfo( v::vtget('TempFile'), PATHINFO_EXTENSION ) }}
 					{{vtSet: FinalList[] = "{vtGet:Verzeichnis,raw}/{vtResult}|{vtGet:TempFile}" }}
-					{{vtSet: NumberList="{vtGet:NumberList},{vtID}"}}
+					{{vtSet: NumberList="{vtGet:NumberList},{vtID}|{vtGet:Verzeichnis,raw}/{vtResult}"}}
 					{{vtSet: DeleteList[] = "{vtGet:TempFile}" }}
 				{{vtEndIf}}
 			{{vtElseIf: {vtGetValue:v} .eq. }}
@@ -99,7 +99,7 @@
 					{{vtCalc: file_exists( '{vtConfig:pathToVirthos}{vtGet:Directory}/{vtGet:BaseName}{vtItem}' ) ? '1' : '' }}
 					{{vtIf: {vtResult} .eq. 1}}
 						{{vtSet: FinalList[]="{vtGet:BaseName}{vtItem}"}}
-						{{vtSet: NumberList="{vtGet:NumberList},{vtID}"}}
+						{{vtSet: NumberList="{vtGet:NumberList},{vtID}|{vtGet:Verzeichnis,raw}/{vtResult}"}}
 						{{vtExit}}
 					{{vtEndIf}}
 				{{vtEndRepeat}}
@@ -160,8 +160,10 @@
 		{{vtEndIf}}
 
 		{{vtIf: {vtGet:LogType} .neq.}}
-			{{vtRepeat: {vtGet:FinalList} }}
-				{{vtCalc: array_shift( explode( '|', '{vtItem:escaped}' ) ) }}
+			{{vtRepeat: {vtGet:NumberList} }}
+				{{vtCalc: strtok( '{vtItem:escaped}', '|' ) }}
+				{{vtSet: ImageId }}
+				{{vtCalc: strtok( '|' ) }}
 				{{vtSet: ImagePath }}
 				{{vtDbQuery: INSERT INTO {vtDbTable:table_downloads_log} SET
 								`timestamp` = CURRENT_TIMESTAMP,
@@ -171,7 +173,8 @@
 								`user` = '{vtUser:name}',
 								`realname` = '{vtUser:realname}',
 								`organization` = '{vtUser:Contact_Company}',
-								`image_path` = '/{vtGet:ImagePath,raw}'
+								`image_path` = '/{vtGet:ImagePath,raw}',
+								`image_id` = '{vtGet:ImageId}'
 				}}
 			{{vtEndRepeat}}
 		{{vtEndIf}}
diff --git a/order.html b/order.html
index a8667b0..b202a51 100644
--- a/order.html
+++ b/order.html
@@ -4,7 +4,7 @@
 <html>
 <head>
 	<!--{{vtInclude: includes/initialize.html}}-->
-	<!--{{vtScript}} {{Nummer:short}} {{Rechnungsnummer:short}} {{Token:short}} {{abgeschlossen:checkbox,[{"value":"1","text":"ja"}] }} {{bezahlt:checkbox,[{"value":"1","text":"ja"}] }} {{erledigt:checkbox,[{"value":"1","text":"ja"}] }} {{Datum:short}} {{Uhrzeit:short}} {{Kommentar:styled}} {{Anrede:short}} {{Vorname:short}} {{Name:short}} {{Firma:short}} {{USt_ID:short}} {{Strasse:short}} {{PLZ:short}} {{Ort:short}} {{Land:short}} {{Landesname:short}} {{Bundesland:short}} {{Telefon:short}} {{Email:short}} {{Registrierung:select,["ja","nein"] }} {{Bemerkungen}} {{Lieferanschrift:checkbox,[{"value":"1","text":"ja"}] }} {{Vorname2:short}} {{Name2:short}} {{Firma2:short}} {{Strasse2:short}} {{Plz2:short}} {{Ort2:short}} {{Land2:short}} {{Landesname2:short}} {{Bundesland2:short}} {{Datenlieferung:checkbox,[{"value":"1","text":"ja"}] }} {{Liefermethode:short}} {{Liefermethode_en:short}} {{Bezahlmethode:select,["vorkasse","rechnung","lastschrift","sepa","paypal","payrexx","sofortueberweisung","barzahlung"] }} {{SEPA_IBAN:short}} {{SEPA_BIC:short}} {{SEPA_Inhaber:short}} {{SEPA_Email:short}} {{SEPA_Ref:short}} {{Payment_TAN:short}} {{Payment_Date:short}} {{Payment_Value:short}} {{Payment_Comment:short}} {{Warenkorb}} {{Anzahl_Files:short}} {{Anzahl_Prints:short}} {{Warenwert_netto:short}} {{Warenwert:short}} {{Rabatt_netto:short}} {{Rabatt:short}} {{CD_Versand_netto:short}} {{CD_Versand:short}} {{Auftragspauschale_netto:short}} {{Auftragspauschale:short}} {{Versandkosten_netto:short}} {{Versandkosten:short}} {{Mehrwertsteuer:short}} {{nicht_steuerbar:checkbox,[{"value":"1","text":"ja"}] }} {{Rechnungsbetrag:short}} {{Waehrung:short}} {{pxprint_Order_ID:short}} {{pxprint_Order_TS:short}} {{pxprint_Error:short}} {{Easybill_Number:short}} {{Easybill_ID:short}} {{Easybill_TS:short}} {{Easybill_Error:short}} {{Gutscheincode:short}} {{GutscheinID:short}} {{Language:short}} {{Session:non_editable}} {{Userid:non_editable}} {{Zwischensumme:non_editable}} {{DeliveryNotificationSent:non_editable}} {{vtEndScript}}-->
+	<!--{{vtScript}} {{Nummer:short}} {{Rechnungsnummer:short}} {{Token:short}} {{abgeschlossen:checkbox,[{"value":"1","text":"ja"}] }} {{bezahlt:checkbox,[{"value":"1","text":"ja"}] }} {{erledigt:checkbox,[{"value":"1","text":"ja"}] }} {{Datum:short}} {{Uhrzeit:short}} {{Kommentar:styled}} {{Anrede:short}} {{Vorname:short}} {{Name:short}} {{Firma:short}} {{USt_ID:short}} {{Strasse:short}} {{PLZ:short}} {{Ort:short}} {{Land:short}} {{Landesname:short}} {{Bundesland:short}} {{Telefon:short}} {{Email:short}} {{Registrierung:select,["ja","nein"] }} {{Bemerkungen}} {{Lieferanschrift:checkbox,[{"value":"1","text":"ja"}] }} {{Vorname2:short}} {{Name2:short}} {{Firma2:short}} {{Strasse2:short}} {{Plz2:short}} {{Ort2:short}} {{Land2:short}} {{Landesname2:short}} {{Bundesland2:short}} {{Datenlieferung:checkbox,[{"value":"1","text":"ja"}] }} {{Liefermethode:short}} {{Liefermethode_en:short}} {{Bezahlmethode:select,["vorkasse","rechnung","lastschrift","sepa","paypal","payrexx","mollie","sofortueberweisung","barzahlung"] }} {{SEPA_IBAN:short}} {{SEPA_BIC:short}} {{SEPA_Inhaber:short}} {{SEPA_Email:short}} {{SEPA_Ref:short}} {{Payment_TAN:short}} {{Payment_Date:short}} {{Payment_Value:short}} {{Payment_Comment:short}} {{Warenkorb}} {{Anzahl_Files:short}} {{Anzahl_Prints:short}} {{Warenwert_netto:short}} {{Warenwert:short}} {{Rabatt_netto:short}} {{Rabatt:short}} {{CD_Versand_netto:short}} {{CD_Versand:short}} {{Auftragspauschale_netto:short}} {{Auftragspauschale:short}} {{Versandkosten_netto:short}} {{Versandkosten:short}} {{Mehrwertsteuer:short}} {{nicht_steuerbar:checkbox,[{"value":"1","text":"ja"}] }} {{Rechnungsbetrag:short}} {{Waehrung:short}} {{pxprint_Order_ID:short}} {{pxprint_Order_TS:short}} {{pxprint_Error:short}} {{Easybill_Number:short}} {{Easybill_ID:short}} {{Easybill_TS:short}} {{Easybill_Error:short}} {{Gutscheincode:short}} {{GutscheinID:short}} {{Language:short}} {{Session:non_editable}} {{Userid:non_editable}} {{Zwischensumme:non_editable}} {{DeliveryNotificationSent:non_editable}} {{vtEndScript}}-->
 	<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
 	<title>Bestellung {{Nummer}} | {{vtGlobal:siteName}}</title>
 	{{vtInclude: includes/html_headers_internal.html }}
diff --git a/product.html b/product.html
index a863ef1..a6690c0 100644
--- a/product.html
+++ b/product.html
@@ -1,4 +1,5 @@
-<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
+<!--{{vtIf: {Typ} .eq. Gruppe }}-->{{vtInclude:productlist.html}}<!--{{vtReturn}}-->
+<!--{{vtEndIf}}--><!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
    "http://www.w3.org/TR/html4/loose.dtd">
 
 <html>
@@ -10,7 +11,17 @@
 </head>
 <body>
 	<div class="content">
-		<p style="margin-bottom:2em"><a href="{{vtLink:..}}">&Uuml;bersicht</a></p>
+		<p style="margin-bottom:2em">
+			<!--{{vtUse:..}}-->
+			<a href="{{vtLink}}">
+				<!--{{vtIf: {vtPageType} .eq. productlist }}-->
+					Produktübersicht
+				<!--{{vtElseIf: {vtPageType} .eq. product }}-->
+					{{Bezeichnung}}
+				<!--{{vtEndIf}}-->
+			</a>
+			<!--{{vtEndUse}}-->
+		</p>
 		<h1>{{Bezeichnung}}</h1>
 		<table width="600" border="0" cellpadding="4">
 			<!--{{vtIf: {Bezeichnung_en} .neq. }}-->
diff --git a/product.vtedit.html b/product.vtedit.html
index c5d3d8a..dec45c0 100644
--- a/product.vtedit.html
+++ b/product.vtedit.html
@@ -41,15 +41,10 @@
 			// {{vtEndIf}}
 
 			$( 'input[name="Typ"]' ).change( function(){
-				if ( $( 'input[name="Typ"]' ).first().prop('checked') )
-				{
-					$( '#pxprint_id' ).hide();
-				}
-				else
-				{
-					$( '#pxprint_id' ).show();
-				}
+				$('#pxprint_id').toggle( $('input[name="Typ"][value="Print"]').prop('checked') );
+				$('.product-data').toggle( ! $('input[name="Typ"][value="Gruppe"]').prop('checked') );
 			});
+			$( 'input[name="Typ"]' ).change();
 
 			$( 'input[name="Rabatt_anwenden"]' ).change( function(){
 				if ( $( this ).prop('checked') )
@@ -122,7 +117,7 @@
 				return false;
 			}
 
-			if( f.Preis.value == '' ){
+			if( f.Preis.value == '' && ! f.Typ[0].checked ){
 				f.Preis.focus();
 				alert('Der Preis darf nicht leer bleiben.');
 				return false;
@@ -135,7 +130,7 @@
 				var vat_rate = {{vtIf:{vtGlobal:pxtcVatRate}.neq.}}{{vtGlobal:pxtcVatRate}}{{vtElse}}0.0{{vtEndIf}};
 			}
 			
-			if( ! check_price( price2number( f.Preis.value ), vat_rate ) ){
+			if( ! f.Typ[0].checked && ! check_price( price2number( f.Preis.value ), vat_rate ) ){
 				if( ! confirm( 'Es gibt keinen Nettopreis, der bei ' + vat_rate + '% MwSt. gerundet ' + f.Preis.value + ' EUR ergeben würde. Daher wird es bei der Rechnungsstellung zu Rundungsfehlern kommen. Trotzdem fortfahren?' ) ){
 					f.Preis.focus();
 					f.Preis.select();
@@ -239,7 +234,18 @@
 	<div class="content">
 
 		<form name="formular" action="{{vtLink:-pg='..',-act='update',-obj='{vtID}'}}" method="post">
-		<table width="800" border="0" cellpadding="4"> 
+		<table width="900" border="0" cellpadding="4"> 
+			<!--{{vtUse: .. }}-->
+				<!--{{vtIf: {vtPageType} .eq. product .and. {Typ} .eq. Gruppe }}-->
+					<!--{{vtSet: ProductGroup = "{vtId}" }}-->
+					<tr>
+						<td align="right" class="normal" width="100">Produktgruppe</td>
+						<td class="normal" style="padding-bottom:15px">
+							<a href="{{vtLink}}">{{Bezeichnung}}</a>
+						</td>
+					</tr>
+				<!--{{vtEndIf}}-->
+			<!--{{vtEndUse}}-->
 			<tr>
 				<td align="right" class="normal" width="100">Bezeichnung</td>
 				<td class="normal" style="padding-bottom:15px">
@@ -256,9 +262,14 @@
 				</td>
 			</tr>
 			<!--{{vtEndIf}}-->
-			<tr>
+			<tr style="{{vtIf: {Typ} .eq. Gruppe .and. {vtCountPages} .gt. 0 }}display:none{{vtEndIf}}">
 				<td align="right" class="normal">Typ</td>
 				<td class="normal" style="padding-bottom:15px">
+					<!--{{vtIf: {vtGet:ProductGroup} .eq. }}-->
+					<input id="input_type_group" type="radio" name="Typ" value="Gruppe" {{vtIf:{Typ} .eq. Gruppe}}checked{{vtEndIf}}>
+					<label for="input_type_group">Produktgruppe</label>
+					&nbsp;&nbsp;&nbsp;
+					<!--{{vtEndIf}}-->
 					<input id="input_type_file" type="radio" name="Typ" value="Datei" {{vtIf:{Typ} .eq. Datei}}checked{{vtEndIf}}>
 					<label for="input_type_file">Datei/Nutzungsrecht</label>
 					&nbsp;&nbsp;&nbsp;
@@ -273,7 +284,7 @@
 					</span>
 				</td>
 			</tr>
-			<tr>
+			<tr class="product-data">
 				<td align="right" class="normal">Preis</td>
 				<td class="normal" style="padding-bottom:15px">
 					<input type="text" name="Preis" size="7" value="{{Preis|num-en:2,}}" onchange="make_price(this)"> {{vtGlobal:pxtcCurrency}}
@@ -288,7 +299,7 @@
 					<label for="input_rabatt_anwenden">Rabattstaffel anwenden</label>
 				</td>
 			</tr>
-			<tr id="Rabattstaffel">
+			<tr class="product-data" id="Rabattstaffel">
 				<td align="right" class="normal">Rabattstaffel</td>
 				<td id="rabattstaffel" class="normal" style="padding-bottom:15px">
 					<input type="hidden" name="Rabattstaffel" value="{{Rabattstaffel:rawhtml}}">
@@ -304,7 +315,7 @@
 			</tr>
 			<!--{{vtIf: {vtGlobal:pxtcVatHandling} .neq. }}-->
 			<!--{{vtIf: {vtGlobal:pxtcVatRate2} .neq. }}-->
-			<tr>
+			<tr class="product-data">
 				<td align="right" class="normal">Steuersatz</td>
 				<td class="normal" style="padding-bottom:15px">
 					<input id="input_vat_1" type="radio" name="Steuersatz" value="" {{vtIf:{Steuersatz} .eq.}}checked{{vtEndIf}}>
@@ -316,6 +327,7 @@
 			</tr>
 			<!--{{vtEndIf}}-->
 			<!--{{vtEndIf}}-->
+			<!--{{vtIf: {vtGet:ProductGroup} .eq. }}-->
 			<tr>
 				<td align="right" class="normal">Bildzuordnung</td>
 				<td class="normal" style="padding-bottom:15px; line-height:1.7em">
@@ -359,8 +371,10 @@
 							</td>
 						</tr>
 					</table>
+				</td>
 			</tr>
-			<tr>
+			<!--{{vtEndIf}}-->
+			<tr class="product-data">
 				<td align="right" class="normal">Benutzerzuordnung</td>
 				<td class="normal">
 					<select name="Benutzer" size="1">
diff --git a/product.vtnew.html b/product.vtnew.html
index fba9d70..43be9a5 100644
--- a/product.vtnew.html
+++ b/product.vtnew.html
@@ -31,14 +31,8 @@
 			});
 
 			$( 'input[name="Typ"]' ).change( function(){
-				if ( $( 'input[name="Typ"]' ).first().prop('checked') )
-				{
-					$( '#pxprint_id' ).hide();
-				}
-				else
-				{
-					$( '#pxprint_id' ).show();
-				}
+				$('#pxprint_id').toggle( $('input[name="Typ"][value="Print"]').prop('checked') );
+				$('.product-data').toggle( ! $('input[name="Typ"][value="Gruppe"]').prop('checked') );
 			});
 
 			$( 'input[name="Rabatt_anwenden"]' ).change( function(){
@@ -112,7 +106,7 @@
 				return false;
 			}
 
-			if( f.Preis.value == '' ){
+			if( f.Preis.value == '' && ! f.Typ[0].checked ){
 				f.Preis.focus();
 				alert('Der Preis darf nicht leer bleiben.');
 				return false;
@@ -125,7 +119,7 @@
 				var vat_rate = {{vtIf:{vtGlobal:pxtcVatRate}.neq.}}{{vtGlobal:pxtcVatRate}}{{vtElse}}0.0{{vtEndIf}};
 			}
 			
-			if( ! check_price( price2number( f.Preis.value ), vat_rate ) ){
+			if( ! f.Typ[0].checked && ! check_price( price2number( f.Preis.value ), vat_rate ) ){
 				if( ! confirm( 'Es gibt keinen Nettopreis, der bei ' + vat_rate + '% MwSt. gerundet ' + f.Preis.value + ' EUR ergeben würde. Daher wird es bei der Rechnungsstellung zu Rundungsfehlern kommen. Trotzdem fortfahren?' ) ){
 					f.Preis.focus();
 					f.Preis.select();
@@ -225,6 +219,14 @@
 
 		<form name="formular" action="{{vtLink:-act='create',-target='{vtID}',-template='product'}}" method="post">
 		<table width="750" border="0" cellpadding="4"> 
+			<!--{{vtIf: {vtPageType} .eq. product .and. {Typ} .eq. Gruppe }}-->
+				<tr>
+					<td align="right" class="normal" width="100">Produktgruppe</td>
+					<td class="normal" style="padding-bottom:15px">
+						<a href="{{vtLink}}">{{Bezeichnung}}</a>
+					</td>
+				</tr>
+			<!--{{vtEndIf}}-->
 			<tr>
 				<td align="right" class="normal" width="100">Bezeichnung</td>
 				<td class="normal" style="padding-bottom:15px">
@@ -242,6 +244,11 @@
 			<tr>
 				<td align="right" class="normal">Typ</td>
 				<td class="normal" style="padding-bottom:15px">
+					<!--{{vtIf: {vtPageType} .eq. productlist }}-->
+					<input id="input_type_group" type="radio" name="Typ" value="Gruppe" {{vtIf:{Typ} .eq. Gruppe}}checked{{vtEndIf}}>
+					<label for="input_type_group">Produktgruppe</label>
+					&nbsp;&nbsp;&nbsp;
+					<!--{{vtEndIf}}-->
 					<input id="input_type_file" type="radio" name="Typ" value="Datei" checked>
 					<label for="input_type_file">Datei/Nutzungsrecht</label>
 					&nbsp;&nbsp;&nbsp;
@@ -256,7 +263,7 @@
 					</span>
 				</td>
 			</tr>
-			<tr>
+			<tr class="product-data">
 				<td align="right" class="normal">Preis</td>
 				<td class="normal" style="padding-bottom:15px">
 					<input type="text" name="Preis" size="7" onchange="make_price(this)"> {{vtGlobal:pxtcCurrency}}
@@ -270,7 +277,7 @@
 					<label for="input_rabatt_anwenden">Rabattstaffel anwenden</label>
 				</td>
 			</tr>
-			<tr id="Rabattstaffel">
+			<tr class="product-data" id="Rabattstaffel">
 				<td align="right" class="normal">Rabattstaffel</td>
 				<td id="rabattstaffel" class="normal" style="padding-bottom:15px">
 					<input type="hidden" name="Rabattstaffel" value="">
@@ -281,7 +288,7 @@
 			</tr>
 			<!--{{vtIf: {vtGlobal:pxtcVatHandling} .neq. }}-->
 			<!--{{vtIf: {vtGlobal:pxtcVatRate2} .neq. }}-->
-			<tr>
+			<tr class="product-data">
 				<td align="right" class="normal">Steuersatz</td>
 				<td class="normal" style="padding-bottom:15px">
 					<input id="input_vat_1" type="radio" name="Steuersatz" value="" checked>
@@ -293,7 +300,7 @@
 			</tr>
 			<!--{{vtEndIf}}-->
 			<!--{{vtEndIf}}-->
-			<tr>
+			<tr class="product-data">
 				<td align="right" class="normal">Bildzuordnung</td>
 				<td class="normal" style="padding-bottom:15px; line-height:1.7em">
 					<input id="input_zuordnung_1" type="radio" name="Zuordnung" value="1" checked> 
@@ -337,7 +344,7 @@
 						</tr>
 					</table>
 			</tr>
-			<tr>
+			<tr class="product-data">
 				<td align="right" class="normal">Benutzerzuordnung</td>
 				<td class="normal">
 					<select name="Benutzer" size="1">
diff --git a/productlist.html b/productlist.html
index aab0d4a..1d86496 100644
--- a/productlist.html
+++ b/productlist.html
@@ -5,7 +5,7 @@
 <head>
 	<!--{{vtInclude: includes/initialize.html}}-->
 	<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
-	<title>Produkte | {{vtGlobal:siteName}}</title>
+	<title>{{vtName}} | {{vtGlobal:siteName}}</title>
 	{{vtInclude: includes/html_headers_internal.html }}
 	<style type="text/css" media="screen">
 		td.fieldContent {
@@ -88,7 +88,7 @@
 		{{vtIf: {vtGetValue:-act} .in. create|update }} {{vtRedirect}} {{vtEndIf}}	
 
 		{{vtIf: {vtSelection:productlist,-type} .eq.}}
-			{{vtDo: -act="setSelection", -name="productlist", -type="product", -filter="{Preis} .gte. 0", -sortfield="vtName", -sortorder="asc" }}
+			{{vtDo: -act="setSelection", -name="productlist", -type="product", -filter="{Preis} .gte. 0", -sortfield="vtName", -sortorder="asc", -depth="1" }}
 			{{vtDo: -act="updateSession", ProductlistSortfield="name" }}
 		{{vtEndIf}}
 		
@@ -143,9 +143,11 @@
 			{{vtEndIf}}
 
 		{{vtEndIf}}
+
+		{{vtSet: PageType = "{vtPageType}" }}
 	-->
 	<div class="content" style="width:900px">
-		<!--{{vtIf: {vtCountPages} .gt. 1 }}-->
+		<!--{{vtIf: {vtCountPages} .gt. 1 .and. {vtPageType} .eq. productlist }}-->
 			<form action="{{vtLink}}" method="post" style="float:right; text-align:right;">
 				<span id="status_indicator" style="color:#aaa; font-style:italic"></span>
 				&nbsp;&nbsp;
@@ -163,7 +165,16 @@
 				</select>
 			</form>
 		<!--{{vtEndIf}}-->
-		<h1>Produkte</h1>
+		<div>
+			<h1 style="display:inline-block">{{vtName}}</h1>
+			<!--{{vtIf: {vtPageType} .eq. product }}-->
+				&nbsp;&nbsp;
+				<p style="display:inline-block">
+					<a href="{{vtLink:-met='vtedit'}}">bearbeiten</a> |
+					<a href="{{vtLink: {vtGet:ID_Produkte} }}">Produktübersicht</a>
+				</p>
+			<!--{{vtEndIf}}-->
+		</div>
 		<!--{{vtIf: {vtCountPages} .gt. 10 }}-->
 			<p style="margin-top:-2em; text-align:right"><a class="text_link" href="{{vtLink:-met='vtnew',-template='product'}}">Neues Produkt erstellen</a></p>
 		<!--{{vtEndIf}}-->
@@ -187,9 +198,11 @@
 					<th width="50" style="text-align:center" class="{{vtIf: {vtSession:ProductlistSortfield} .eq. typ}}active{{vtEndIf}}">
 						<a href="{{vtLink:sort='typ'}}">Typ</a>
 					</th>
+					<!--{{vtIf: {vtPageType} .eq. productlist }}-->
 					<th width="50" style="text-align:center" class="{{vtIf: {vtSession:ProductlistSortfield} .eq. zuordnung}}active{{vtEndIf}}">
 						<a href="{{vtLink:sort='zuordnung'}}">Zuordn.</a>
 					</th>
+					<!--{{vtEndIf}}-->
 					<!--{{vtIf: {vtLicenseType} .neq. a }}-->
 						<th width="100" style="text-align:center" class="{{vtIf: {vtSession:ProductlistSortfield} .eq. gruppe}}active{{vtEndIf}}">
 							<a href="{{vtLink:sort='gruppe'}}">Gruppe</a>
@@ -219,7 +232,7 @@
 						<input type="checkbox" class="object_selector" name="-obj[]" value="{{vtID}}">
 					</td>
 					<td class="fieldContent">
-						<a href="{{vtLink:-met='vtedit'}}">{{Bezeichnung}}</a>
+						<a href="{{vtIf: {Typ} .eq. Gruppe}}{{vtLink}}{{vtElse}}{{vtLink:-met='vtedit'}}{{vtEndIf}}">{{Bezeichnung}}</a>
 						<!--{{vtIf: {Beschreibung} .neq.}}-->
 						<a href="#" onclick="showInfo({{vtID}}); return false;"><img src="resources/btn_info.gif" width="10" height="10" alt="Btn Info" border="0" style="vertical-align:baseline"></a>
 						<!--{{vtEndIf}}-->
@@ -230,6 +243,7 @@
 					<td class="fieldContent" style="text-align:center">
 						{{Typ}}
 					</td>
+					<!--{{vtIf: {vtGet:PageType} .eq. productlist }}-->
 					<td class="fieldContent" style="text-align:center">
 						<!--{{vtIf: {Zuordnung} .eq. 1}}-->
 							automat.
@@ -237,6 +251,7 @@
 							manuell
 						<!--{{vtEndIf}}-->
 					</td>
+					<!--{{vtEndIf}}-->
 					<!--{{vtIf: {vtLicenseType} .neq. a }}-->
 					<td class="fieldContent" style="text-align:center">
 						<!--{{vtIf: {Benutzer} .eq. }}-->
diff --git a/register.html b/register.html
index b81dc0a..d30d6f2 100644
--- a/register.html
+++ b/register.html
@@ -305,6 +305,8 @@
 <!--{{vtEndCapture}}-->
 
 
+<!--{{vtIf: {vtGlobal:pxtcDesign} .eq. 1 }}-->
+
 <!--{{vtCapture:PageContentRight}}-->
 
 	<!--{{vtIf: workspace .and. {vtLicenseType} .eq. a }}-->
@@ -419,4 +421,138 @@
 
 <!--{{vtEndCapture}}-->
 
+<!--{{vtElse}}-->
+
+<!--{{vtCapture:PageContentRight}}-->
+
+	<!--{{vtIf: workspace .and. {vtLicenseType} .eq. a }}-->
+		<div class="alert alert-warning">
+			Um Benutzern zu ermöglichen, sich selbst zu registrieren, müssen Sie
+			Pixtacy auf die Professional-Edition aufrüsten.<br>
+			<br>
+			<a href="{{vtGet:LinkUpgrade}}" target="_blank">weitere Informationen</a>
+		</div>
+	<!--{{vtElseIf: workspace .and. {vtGlobal:pxtcAllowRegistration} .eq. }}-->
+		<div class="alert alert-warning">
+			<!--{{vtUse:76}}-->
+			Im Augenblick ist die Selbstregistrierung für Benutzer abgeschaltet. 
+			Um sie zu aktivieren, müssen Sie die entsprechende Option unter 
+			<a href="{{vtLink:Rechte, vtedit}}">Einstellungen > Rechte</a> ändern.
+			<!--{{vtEndUse}}-->
+		</div>
+	<!--{{vtEndIf}}-->
+
+	<h1 class="mb-4">
+		<!--{{vtIf: {vtGet:Language} .neq. de .and. {Text_en} .neq.}}-->
+			{{Headline_en}}
+		<!--{{vtElse}}-->
+			{{Headline}}
+		<!--{{vtEndIf}}-->
+	</h1>
+
+	<form name="formular" action="{{vtLink}}" method="post" onsubmit="return handleSubmit(this)">
+		<input type="hidden" name="register" value="1">
+		<input type="hidden" name="groups" value="{{vtGlobal:pxtcAllowRegistration}}">
+		<input type="hidden" name="jstest" value="0">
+		<!--{{vtIf: {vtGet:Error}.neq.}}-->
+			<div class="alert alert-danger alert-dismissible fade show" role="alert">
+				{{vtGet:Error}}
+				<button type="button" class="close" data-dismiss="alert" aria-label="Close">
+					<span aria-hidden="true">&times;</span>
+				</button>
+			</div>
+		<!--{{vtEndIf}}-->
+
+			<div class="form-group row">
+				<label for="inputEmail3" class="col-sm-4 col-form-label">{{vtGet:s_fld_username}}*:</label>
+				<div class="col-sm-8">
+					<input type="text" name="username" value="{{vtSession:username }}" class="form-control" required>
+				</div>
+			</div>
+			<div class="form-group row">
+				<label for="inputEmail3" class="col-sm-4 col-form-label">{{vtGet:s_fld_password}}*:</label>
+				<div class="col-sm-8">
+					<input type="password" name="password" value="" class="form-control" required>
+				</div>
+			</div>
+			<div class="form-group row">
+				<label for="inputEmail3" class="col-sm-4 col-form-label">{{vtGet:s_fld_password_repeat}}*:</label>
+				<div class="col-sm-8">
+					<input type="password" name="password2" value="" class="form-control" required>
+				</div>
+			</div>
+			<div class="form-group row">
+				<label for="inputEmail3" class="col-sm-4 col-form-label">{{vtGet:s_fld_email}}*:</label>
+				<div class="col-sm-8">
+					<input type="text" name="email" value="{{vtSession:email}}" class="form-control" required>
+				</div>
+			</div>
+			<!--{{vtRepeat: {vtGet:RegistrationFields} }}-->
+				<div class="form-group row">
+					<label for="inputEmail3" class="col-sm-4 col-form-label">
+						{{vtItem:label}}:
+						<!--{{vtIf: {vtItem:value} .in. {Mandatory_Fields:raw} }}-->*<!--{{vtEndIf}}-->
+					</label>
+					<div class="col-sm-8">
+						<!--{{vtIf: {vtItem:value} .eq. Anrede }}-->
+							<select name="Anrede" id="Anrede" class="form-control">
+								<!--{{vtIf: {vtSession:Anrede} .eq. }}-->
+									<option value=""></option>
+								<!--{{vtEndIf}}-->
+								<!--{{vtRepeat: {vtGet:Salutations} }}-->
+									<option value="{{vtItem:value}}" {{vtIf: {vtItem:value} .eq. {vtSession:Anrede} }}selected{{vtEndIf}}>{{vtItem:text}}</option>
+								<!--{{vtEndRepeat}}-->
+							</select>
+						<!--{{vtElse}}-->
+							<input type="text" name="{{vtItem:value}}" value="{{vtSession:{vtItem:value} }}" class="form-control"
+								{{vtIf: {vtItem:value} .in. {Mandatory_Fields:raw} }}required{{vtEndIf}}>
+						<!--{{vtEndIf}}-->
+					</div>
+				</div>
+			<!--{{vtEndRepeat}}-->
+			<div class="form-group row">
+				<label for="inputEmail3" class="col-sm-4 col-form-label">{{vtGet:s_fld_message}}:</label>
+				<div class="col-sm-8"><input type="text" name="Bemerkungen" value="{{vtSession:Bemerkungen}}" class="form-control"></div>
+			</div>
+			<!--{{vtIf: {Captcha} .eq. 1 }}-->
+			<div class="form-group row">
+				<label for="inputEmail3" class="col-sm-4 col-form-label">{{vtGet:s_fld_captcha_code}}*:</label>
+				<div class="col-sm-8">
+					<div class="row">
+						<div class="col-6">
+							<input type="text" name="-captcha" class="form-control" required>
+						</div>
+						<div class="col-6">
+							<img id="captcha" src="{{vtCaptcha}}" alt="Captcha" onclick="document.getElementById('captcha').src='{{vtCaptcha}}?'+Math.random()" title="{{vtGet:s_txt_0047}}" style="cursor:pointer">
+						</div>
+					</div>
+				</div>
+			</div>
+			<!--{{vtEndIf}}-->
+			<!--{{vtIf: {Seite_Datenschutz} .gt. 0}}-->
+				<div class="form-check">
+					<input class="form-check-input" type="checkbox" name="Datenschutz" id="checkbox_datenschutz" value="1" required>
+					<label class="form-check-label" for="checkbox_datenschutz">
+						{{vtGet:s_txt_0057}}
+						(<a href="{{vtLink:{Seite_Datenschutz} }}" target="_blank">{{vtGet:s_btn_read}}</a>)*
+					</label>
+				</div>
+			<!--{{vtEndIf}}-->
+			<div class="form-group row d-none">
+				<label for="inputEmail3" class="col-sm-4 col-form-label">Blindfeld:</label>
+				<div class="col-sm-8">
+					<input type="text" class="form-control" name="mail2">
+				</div>
+			</div>
+			<div class="form-group row mt-5">
+				<div class="col-sm-12 text-center"><button type="submit" class="btn btn-primary">{{vtGet:s_btn_send}}</div>
+			</div>
+			<div class="form-group row mt-5">
+				<div class="col-sm-12">*) {{vtGet:s_txt_0007}}</div>
+			</div>
+	</form>
+
+<!--{{vtEndCapture}}-->
+<!--{{vtEndIf}}-->
+
 {{vtTemplate: /config/views/register{vtGet:TemplateSuffix}.html, /config/views/default2{vtGet:TemplateSuffix}.html, views/default2{vtGet:TemplateSuffix}.html }}
diff --git a/resources/ConvertCharset.class.php b/resources/ConvertCharset.class.php
old mode 100755
new mode 100644
diff --git a/resources/functions.php b/resources/functions.php
index 0443d36..afb2758 100644
--- a/resources/functions.php
+++ b/resources/functions.php
@@ -95,7 +95,6 @@ function getIPTCHeader( $image, $header, $charset = '' )
 		'CreationDate' => '055',
 		'CreationTime' => '060',
 		'Photographer' => '080',
-		'ByLine' => '080',
 		'ByLineTitle' => '085',
 		'City' => '090',
 		'State' => '095',
@@ -2254,8 +2253,6 @@ function generate_image_file( $filePath, $imagingRule, $pageId = NULL )
 				 '2#055' => v::vtpage('CreationDate'),
 				 '2#060' => v::vtpage('CreationTime'),
 				 '2#080' => v::vtpage('Photographer'),
-				 '2#080' => v::vtpage('ByLine'),
-				 '2#085' => v::vtpage('ByLineTitle'),
 				 '2#090' => v::vtpage('City'),
 				 '2#095' => v::vtpage('State'),
 				 '2#100' => v::vtpage('CountryCode'),
@@ -2266,7 +2263,7 @@ function generate_image_file( $filePath, $imagingRule, $pageId = NULL )
 				 '2#120' => strip_tags( v::vtpage('Remarks') ),
 				 '2#040' => v::vtpage('Instructions'),
 				 '2#122' => v::vtpage('Writer')
-			), TRUE );
+			), FALSE );
 			v::vtenduse();
 		}
 	}
@@ -2323,150 +2320,4 @@ function hires_file_exists( $imagePath, $code )
 	return in_array( pathinfo( $imagePath, PATHINFO_FILENAME ), $listings[ $folder ] );
 }
 
-
-function image_is_buyable( $imagePath, $imageAssortment, $imageProducts, $returnProductList = FALSE )
-{
-	static $allImagesBuyable = FALSE;
-	static $noImageBuyable = FALSE;
-	static $globalProducts; // Gesamtliste der theoretisch kaufbaren Produkte
-	static $assortmentCodes; // Gesamtliste der Sortimente ( Seiten-ID = Schlüssel, Kennungen = Wert )
-	static $productAssortments; // Liste der Sortimente, denen ein Produkt (ID = Schlüssel) zugeordnet ist
-
-	if ( $allImagesBuyable && ! $returnProductList ) {
-		return TRUE;
-	}
-
-	if ( $noImageBuyable ) {
-		return FALSE;
-	}
-
-	if ( is_null( $productAssortments ) ) {
-		$sql = "SELECT c.`id`, a.`liste` 
-			FROM `%data_assortment` a LEFT JOIN `%content` c ON c.id = a.vtid 
-			WHERE c.containerID = " . (int) v::vtget('ID_Sortimente');
-		$result = v::query( $sql );
-
-		while ( $assortment = $result->fetch_assoc() ) {
-			$elements = json_decode( $assortment['liste'], TRUE );
-			foreach ( $elements as $element ) {
-				if ( ! empty( $element['product_id'] ) ) {
-					$productAssortments[ $element['product_id'] ][] = $assortment['id'];
-				}
-			}
-		}
-	}
-
-	if ( is_null( $globalProducts ) ) {
-		$paymentMethods = v::vtget('Bezahlmethoden');
-		$deliveryMethods = v::vtget('DeliveryMethods');
-		$deliveryPayment = v::vtget('DeliveryPayment');
-		$groups = explode( ',', v::vtuser('groups') );
-		$sql = "SELECT c.id, p.`benutzer`, p.`kennung`, p.`preis` + 0 as 'preis', p.`zuordnung`, p.`typ` 
-			FROM `%data_product` p LEFT JOIN `%content` c ON c.id = p.vtid 
-			WHERE c.containerID = " . (int) v::vtget('ID_Produkte');
-		$result = v::query( $sql );
-
-		while ( $product = $result->fetch_assoc() ) {
-			if ( ( empty( $paymentMethods ) && $product['preis'] && empty( $deliveryPayment ) )
-				|| ( empty( $deliveryMethods ) && strtolower( $product['typ'] ) == 'print' )
-				|| ( ! empty( $product['benutzer'] ) && ! in_array( $product['benutzer'], $groups ) 
-				&& ! ( $product['benutzer'] == 'guest' && v::vtuser('name') == '' )  
-				&& ! ( $product['benutzer'] == 'Alle' && v::vtuser('name') != '' ) ) 
-			) {
-				continue;
-			}
-			$prodId = (int) $product['id'];
-			$globalProducts[ $prodId ] = $product;
-			if ( $product['zuordnung'] ) {
-				// es ist ein automatisch zugeordnetes Produkt
-				if ( empty( $product['kennung'] ) ) {
-					// es ist nicht von High-res-Datei abhängig
-					$allImagesBuyable = TRUE;
-					if ( ! $returnProductList ){
-						return TRUE;
-					}
-				}
-				// von High-res-Datei abhängig - Kennung in automatisches Sortiment aufnehmen
-				if ( empty( $assortmentCodes[0] ) || ! in_array( $product['kennung'], $assortmentCodes[0] ) ){
-					$assortmentCodes[0][] = $product['kennung'];
-				}
-			}
-			elseif ( ! isset( $productAssortments[ $prodId ] ) ) { 
-				// Produkt ist keinem Sortiment zugeordnet
-				continue;
-			}
-			elseif ( empty( $product['kennung'] ) ) { 
-				// Produkt ist nicht von High-res-Datei abhängig
-				// setze alle Sortimente, denen das Produkt zugeordnet ist, auf "generell kaufbar"
-				foreach ( $productAssortments[ $prodId ] as $assortmentId ) {
-					$assortmentCodes[ $assortmentId ] = '~';
-				}
-			}
-			else {
-				// Produkt ist von High-res-Datei abhängig
-				// nimm Kennung in Kennungsliste der Sortimente auf, denen das Produkt zugeordnet ist
-				foreach ( $productAssortments[ $prodId ] as $assortmentId ) {
-					if ( empty( $assortmentCodes[ $assortmentId ] ) || ( $assortmentCodes[ $assortmentId ] != '~' 
-						&& ! in_array( $product['kennung'], $assortmentCodes[ $assortmentId ] ) ) 
-					) {
-						$assortmentCodes[ $assortmentId ][] = $product['kennung'];
-					}
-				}
-			}
-		}
-		if ( empty( $globalProducts ) ) {
-			$noImageBuyable = TRUE;
-			return FALSE;
-		}
-	}
-
-	// Prüfe Bild individuell
-
-	if ( $imageAssortment == -1 || ! isset( $assortmentCodes[ $imageAssortment ] ) ) {
-		// kein Sortiment zugeordnet
-		// prüfe automat. zugeordnete Produkte
-		if ( ! empty( $assortmentCodes[0] ) ){
-			foreach ( $assortmentCodes[0] as $code ){
-				if ( hires_file_exists( $imagePath, $code ) ){
-					if ( ! $returnProductList ){
-						return TRUE;
-					}
-				}
-			}
-		}
-		// prüfe individuell zugeordnete Produkte
-		if ( empty( $imageProducts ) && ! $returnProductList ) {
-			return FALSE;
-		}
-		foreach ( explode( "\n", $imageProducts ) as $product ) {
-			if ( isset( $globalProducts[ $product ] ) 
-				&& ( $globalProducts[ $product ]['kennung'] == '' || hires_file_exists( $imagePath, $globalProducts[ $product ]['kennung'] ) )
-			) {
-				if ( ! $returnProductList ){
-					return TRUE;
-				}
-			}
-		}
-		return FALSE;
-	}
-
-	if ( $assortmentCodes[ $imageAssortment ] == '~' ) {
-		// zugeordnetes Sortiment ist generell kaufbar
-		if ( ! $returnProductList ){
-			return TRUE;
-		}
-	}
-	
-	// zugeordnetes Sortiment ist nicht generell kaufbar - prüfe High-res-Dateien
-	foreach ( $assortmentCodes[ $imageAssortment ] as $code ) {
-		if ( hires_file_exists( $imagePath, $code ) ) {
-			if ( ! $returnProductList ){
-				return TRUE;
-			}
-		}
-	}
-
-	return $returnProductList ? $imageProducts : FALSE;
-}
-
 ?>
diff --git a/resources/httpconnection.class.php b/resources/httpconnection.class.php
old mode 100755
new mode 100644
diff --git a/resources/order_dialog.js b/resources/order_dialog.js
index d3a2725..f6932eb 100644
--- a/resources/order_dialog.js
+++ b/resources/order_dialog.js
@@ -52,50 +52,6 @@ $(document).ready( function(){
       $('body').addClass('modal-open');
    })
 
-   $('#add-to-cart').on( 'click', '.btn-minus, .btn-plus', function(){
-      $(this).blur();
-		var row = $(this).parents('tr');
-		var form = row.find('form');
-      var quantity = 1 * row.data('quantity') + ( $(this).hasClass('btn-minus') ? -1 : 1 );
-		form.find('input[name=q]').val( quantity );
-		if ( $(this).parents('.modal-dialog').data('type') == 'lightbox' ){
-			update_order_row( $(this).parents('tr'), quantity );
-			return;
-		}
-
-		$.ajax({
-         type: 'GET',
-         url: form.attr('action'),
-         data: form.serialize(),
-         success: function( data ){
-				if ( ! data.productId ){
-					console.log( data );
-					return;
-				}
-				
-				if ( data.itemId && data.itemId < 0 ){
-					alert( data.itemId = -1 ? errorMaxItems : errorDefault + ' (' + data.itemId + ')' );
-					return;
-				}
-
-				var row = $( 'tr[data-id=' + data.productId + ']' );
-				
-				if ( row.length ){
-					update_order_row( row, data.itemCount, data.itemPrice, data.itemNetprice );
-				}
-
-				if ( handle_cart_change ){
-					handle_cart_change( data.imageId, data.inCartStatus != '', data.cartCount );
-				}
-         },
-         error: function(data)
-         {
-            console.log('Error when changing cart');
-            console.log( data );
-         }
-      });
-   });
-
 	$('body').on( 'submit', '#lightbox-order', function(){
 		var products = [];
 		$('.orderform').each( function(){
diff --git a/setup_interfaces.html b/setup_interfaces.html
index 43f9008..892b0a4 100644
--- a/setup_interfaces.html
+++ b/setup_interfaces.html
@@ -11,7 +11,8 @@
 <body>
 	<div class="content">
 		<h1>Schnittstellen</h1>
-		<p style="width:800px">Bitte beachten Sie: Die Einstellungen für <strong>PayPal</strong> und <strong>sofortüberweisung.de</strong> finden Sie im Bereich <a href="{{vtLink:../Bezahlmethoden}}" class="text_link">Bezahlmethoden</a>.</p>
+		<p style="width:800px">Bitte beachten Sie: Die Einstellungen für Zahlungsdienstleister (z. B. PayPal)
+		finden Sie im Bereich <a href="{{vtLink:../Bezahlmethoden}}" class="text_link">Bezahlmethoden</a>.</p>
 		<!--{{vtCalc: checkSecureTransferMethod() }}-->
 		<!--{{vtIf: {vtGlobal:pxtcSecureTransferMethod} .nin. curl|socket }}-->
 		<p style="color:red">
diff --git a/setup_payment.html b/setup_payment.html
index e49368d..5afbe49 100644
--- a/setup_payment.html
+++ b/setup_payment.html
@@ -9,12 +9,12 @@
 	{{vtInclude: includes/html_headers_internal.html }}
 </head>
 <body>
-	<div class="content">
+	<div class="content" style="/*width:900px*/">
 		<h1>Bezahlmethoden</h1>
 		
 		<p>Im Augenblick sind die Bezahlmethoden folgenderma&szlig;en eingestellt:<br>&nbsp;</p>
 		
-		<table width="500" border="0" cellpadding="0" cellspacing="0">
+		<table width="700" border="0" cellpadding="0" cellspacing="0">
 			<tr>
 				<td style="width:12em">Vorkasse</td>
 				<td>
@@ -132,31 +132,65 @@
 				</td>
 			</tr>
 			<tr><td colspan="2">&nbsp;</td></tr>
-			<!--{{vtIf: {vtGet:PayrexxInitialized} .eq. 1 }}-->
 			<tr>
 				<td style="width:12em">Payrexx</td>
 				<td>
-					<!--{{vtIf: {pxtcPaymentPayrexx} .eq. 1}}-->
-						nur für angemeldete Benutzer
-					<!--{{vtElseIf: {pxtcPaymentPayrexx} .eq. 2}}-->
-						für alle Benutzer
-					<!--{{vtElseIf: {pxtcPaymentPayrexx} .neq.}}-->
-						für Mitglieder der Gruppe »{{pxtcPaymentPayrexx}}«
-						<!--{{vtIf: {vtLicenseType} .eq. a }}-->
-							<span style="color:red">*</span>
+					<!--{{vtIf: {vtGet:PayrexxInitialized} .eq. 1 }}-->
+						<!--{{vtIf: {pxtcPaymentPayrexx} .eq. 1}}-->
+							nur für angemeldete Benutzer
+						<!--{{vtElseIf: {pxtcPaymentPayrexx} .eq. 2}}-->
+							für alle Benutzer
+						<!--{{vtElseIf: {pxtcPaymentPayrexx} .neq.}}-->
+							für Mitglieder der Gruppe »{{pxtcPaymentPayrexx}}«
+							<!--{{vtIf: {vtLicenseType} .eq. a }}-->
+								<span style="color:red">*</span>
+							<!--{{vtEndIf}}-->
+						<!--{{vtElse}}-->
+							nicht verwenden
+						<!--{{vtEndIf}}-->
+						<!--{{vtIf: {pxtcPaymentPayrexx} .gte. 1}}-->
+						<br>
+						<span style="color:#aaa">Instanzname: {{pxtcPayrexxName}}<br>
+						<span style="color:#aaa">API-Schlüssel: {{pxtcPayrexxApiSecret}}<br>
 						<!--{{vtEndIf}}-->
 					<!--{{vtElse}}-->
-						nicht verwenden
+						<i>Kreditkarten, Google Pay, Apple Pay, Twint u.v.m.</i> &mdash;
+						<a href="https://www.pixtacy.de/virthos.php?/features/payrexx.html" target="_blank">
+							weitere Informationen
+						</a>
 					<!--{{vtEndIf}}-->
-					<!--{{vtIf: {pxtcPaymentPayrexx} .gte. 1}}-->
-					<br>
-					<span style="color:#aaa">Instanzname: {{pxtcPayrexxName}}<br>
-					<span style="color:#aaa">API-Schlüssel: {{pxtcPayrexxApiSecret}}<br>
+				</td>
+			</tr>
+			<tr><td colspan="2">&nbsp;</td></tr>
+			<tr>
+				<td style="width:12em">Mollie</td>
+				<td>
+					<!--{{vtIf: {vtGet:MollieInitialized} .eq. 1 }}-->
+						<!--{{vtIf: {pxtcPaymentMollie} .eq. 1}}-->
+							nur für angemeldete Benutzer
+						<!--{{vtElseIf: {pxtcPaymentMollie} .eq. 2}}-->
+							für alle Benutzer
+						<!--{{vtElseIf: {pxtcPaymentMollie} .neq.}}-->
+							für Mitglieder der Gruppe »{{pxtcPaymentMollie}}«
+							<!--{{vtIf: {vtLicenseType} .eq. a }}-->
+								<span style="color:red">*</span>
+							<!--{{vtEndIf}}-->
+						<!--{{vtElse}}-->
+							nicht verwenden
+						<!--{{vtEndIf}}-->
+						<!--{{vtIf: {pxtcPaymentMollie} .gte. 1}}-->
+						<br>
+						<span style="color:#aaa">API-Schlüssel: {{pxtcMollieApiKey}}<br>
+						<!--{{vtEndIf}}-->
+					<!--{{vtElse}}-->
+						<i>Kreditkarten, Google Pay, Apple Pay, Twint u.v.m.</i> &mdash;
+						<a href="https://www.pixtacy.de/virthos.php?/features/mollie.html" target="_blank">
+							weitere Informationen
+						</a>
 					<!--{{vtEndIf}}-->
 				</td>
 			</tr>
 			<tr><td colspan="2">&nbsp;</td></tr>
-			<!--{{vtEndIf}}-->
 		</table>
 
 		<!--{{vtIf: {vtLicenseType} .eq. a }}-->
diff --git a/setup_payment.vtedit.html b/setup_payment.vtedit.html
index de09d27..5ecb3c2 100644
--- a/setup_payment.vtedit.html
+++ b/setup_payment.vtedit.html
@@ -143,6 +143,18 @@
 			}
 		}
 
+		function handleChangeMollie() {
+			var f = document.formular;
+
+			if( f.pxtcPaymentMollie.selectedIndex > 0 ){
+				f.pxtcMollieApiKey.disabled = false;
+				f.pxtcMollieApiKey.select();
+				f.pxtcMollieApiKey.focus();
+			} else {
+				f.pxtcMollieApiKey.disabled = true;
+			}
+		}
+
 		function handleChangePaypal() {
 			var f = document.formular;
 
@@ -409,13 +421,13 @@
 					</table>
 				</td>
 			</tr>
-			<!--{{vtIf: {vtGet:PayrexxInitialized} .eq. 1 }}-->
 			<tr><td colspan="2">&nbsp;</td></tr>
 			<tr><td colspan="2"><hr></td></tr>
 			<tr><td colspan="2">&nbsp;</td></tr>
 			<tr>
 				<td>Payrexx</td>
 				<td>
+					<!--{{vtIf: {vtGet:PayrexxInitialized} .eq. 1 }}-->
 					<select name="pxtcPaymentPayrexx" onchange="handleChangePayrexx()">
 						<option value="">nicht verwenden</option>
 						<option value="2" {{vtIf:{pxtcPaymentPayrexx} .eq. 2}}selected{{vtEndIf}}>für alle Benutzer</option>
@@ -427,8 +439,15 @@
 							<!--{{vtEndIf}}-->
 						<!--{{vtEndRepeatUsers}}-->
 					</select>
+					<!--{{vtElse}}-->
+						<i>Kreditkarten, Google Pay, Apple Pay, Twint u.v.m.</i> &mdash;
+						<a href="https://www.pixtacy.de/virthos.php?/features/payrexx.html" target="_blank">
+							weitere Informationen
+						</a>
+					<!--{{vtEndIf}}-->
 				</td>
 			</tr>
+			<!--{{vtIf: {vtGet:PayrexxInitialized} .eq. 1 }}-->
 			<tr>
 				<td>&nbsp;</td>
 				<td>
@@ -450,6 +469,50 @@
 				</td>
 			</tr>
 			<!--{{vtEndIf}}-->
+			<tr><td colspan="2">&nbsp;</td></tr>
+			<tr><td colspan="2"><hr></td></tr>
+			<tr><td colspan="2">&nbsp;</td></tr>
+			<tr>
+				<td>Mollie</td>
+				<td>
+					<!--{{vtIf: {vtGet:MollieInitialized} .eq. 1 }}-->
+					<select name="pxtcPaymentMollie" onchange="handleChangeMollie()">
+						<option value="">nicht verwenden</option>
+						<option value="2" {{vtIf:{pxtcPaymentMollie} .eq. 2}}selected{{vtEndIf}}>für alle Benutzer</option>
+						<option value="1" {{vtIf:{pxtcPaymentMollie} .eq. 1}}selected{{vtEndIf}}>für alle angemeldeten Benutzer</option>
+						<!--{{vtSet: GroupExists=""}}-->
+						<!--{{vtRepeatUsers: group}}-->
+							<!--{{vtIf: {vtCurrentUserID} .neq. 4}}-->
+								<option {{vtGet:Disabled}} value="{{vtCurrentUserName}}" {{vtIf:{pxtcPaymentMollie}.eq.{vtCurrentUserName} }}selected{{vtSet:GroupExists='1'}}{{vtEndIf}}>für Mitglieder der Gruppe &raquo;{{vtCurrentUserName}}&laquo; {{vtGet:Asterisk}}</option>
+							<!--{{vtEndIf}}-->
+						<!--{{vtEndRepeatUsers}}-->
+					</select>
+					<!--{{vtElse}}-->
+						<i>Kreditkarten, Google Pay, Apple Pay, Twint u.v.m.</i> &mdash;
+						<a href="https://www.pixtacy.de/virthos.php?/features/mollie.html" target="_blank">
+							weitere Informationen
+						</a>
+					<!--{{vtEndIf}}-->
+				</td>
+			</tr>
+			<!--{{vtIf: {vtGet:MollieInitialized} .eq. 1 }}-->
+			<tr>
+				<td>&nbsp;</td>
+				<td>
+					<table>
+						<tr>
+							<td style="width:12em">API-Schlüssel:</td>
+							<td>
+								<input type="text" name="pxtcMollieApiKey" value="{{pxtcMollieApiKey}}" size="30" {{vtIf: {pxtcPaymentMollie} .lt. 1}}disabled{{vtEndIf}}>
+							</td>
+						</tr>
+					</table>
+				</td>
+			</tr>
+			<!--{{vtEndIf}}-->
+			<tr><td colspan="2">&nbsp;</td></tr>
+			<tr><td colspan="2"><hr></td></tr>
+			<tr><td colspan="2">&nbsp;</td></tr>
 			<!--{{vtIf: {vtLicenseType} .eq. a }}-->
 			<tr><td colspan="2">&nbsp;</td></tr>
 			<tr><td colspan="2"><hr></td></tr>
diff --git a/views/default2_r.html b/views/default2_r.html
index f2b6002..b60b68d 100644
--- a/views/default2_r.html
+++ b/views/default2_r.html
@@ -18,7 +18,7 @@
 		{{vtGet:PageContentBefore,raw}}
 		
 		<div class="row">
-			<div class="col-lg-6 col-md-12">
+			<div class="col-lg-6 col-md-12 mb-4">
 				<!--{{vtIf: {vtGet:ImageLeft} .neq. }}-->
 					<img src="{{vtGet:ImageLeft}}" alt="" style="max-width:100%">
 				<!--{{vtEndIf}}-->
diff --git a/views/gallery_r.html b/views/gallery_r.html
index 824d9c2..fe870c7 100644
--- a/views/gallery_r.html
+++ b/views/gallery_r.html
@@ -281,7 +281,7 @@
 			<?php function remove_linebreaks( $string ) { return str_replace( array( "\r\n", "\r", "\n" ), ' ', $string ); } ?>
 		<!--{{vtEndIf}}-->
 		<!--{{vtIf: {vtGet:ShowCartButtons} .eq. 1 }}-->
-			<script src="resources/order_dialog.js"></script>
+			<script src="resources/order_dialog.js?2"></script>
 		<!--{{vtEndIf}}-->
 
 		<script type="text/javascript">
diff --git a/views/invoice.html b/views/invoice.html
old mode 100755
new mode 100644
