diff options
36 files changed, 2293 insertions, 53 deletions
diff --git a/views/admin/kundendaten_tab3.phtml b/views/admin/kundendaten_tab3.phtml index 8abd619..36c4916 100644 --- a/views/admin/kundendaten_tab3.phtml +++ b/views/admin/kundendaten_tab3.phtml @@ -17,6 +17,7 @@ <?php
echo wpsg_drawForm_Select('wpsg_customerpreset_payment', __('Standard Zahlungsart', 'wpsg'), [
+ '0' => __('Bitte wählen', 'wpsg'),
'-1' => __('günstigste Zahlungsart', 'wpsg')
] + $this->view['arPayment'], $this->get_option('wpsg_customerpreset_payment'), array('help' => 'wpsg_customerpreset_payment'));
diff --git a/views/css/frontend.css b/views/css/frontend.css index e63ba95..70da2f2 100644 --- a/views/css/frontend.css +++ b/views/css/frontend.css @@ -36,7 +36,7 @@ input.wpsg_error { border-color:red !important; } .basket_product_wrap .basket_product_row .product_action .title { width: 60%; display:inline-block; margin-top:0.3em; margin-bottom:0.3em; }
.basket_product_wrap .basket_product_row .product_action .price { width: 39%; display:inline-block; text-align:right; }
.basket_product_wrap .basket_product_row .product_action .price_total { width: 39%; display:inline-block; font-weight:bold; text-align:right; }
-.basket_product_wrap .basket_product_row .product_info { display:flex; width:100%; justify-content:space-between; align-items:center; }
+.basket_product_wrap .basket_product_row .product_info { display:flex; width:100%; justify-content:space-between; align-items:center; margin-bottom:0.25rem; }
.basket_product_wrap .basket_product_row .product_upload { }
.basket_product_wrap .basket_product_row .product_upload .wpsg_mod_orderupload_target { margin-left:15px; flex-grow:1; }
.basket_product_wrap .basket_product_row .product_upload .wpsg_mod_orderupload_target ul { margin:0px; }
@@ -44,7 +44,7 @@ input.wpsg_error { border-color:red !important; } .basket_product_wrap .basket_product_row .product_upload .wpsg_mod_orderupload_target li a.removeLink { text-decoration:none; box-shadow:none; align-self:center; }
.basket_product_wrap .basket_product_row .product_upload ul li { list-style:none; }
.basket_product_wrap .basket_product_row .product_info .titlep { min-width:120px; display:inline-block; margin-top:0.3em; margin-bottom:0.3em; }
-.basket_product_wrap .basket_product_row .product_info .title { width: 30%; display:inline-block; margin-top:0.3em; margin-bottom:0.3em; }
+.basket_product_wrap .basket_product_row .product_info .title { display:inline-block; margin-top:0.3em; margin-bottom:0.3em; }
.basket_product_wrap .basket_product_row .product_info .valuel { width: 50%; display:inline-block; font-weight:normal; text-align:left; }
.basket_product_wrap .basket_product_row .product_info .valuer { width: 50%; display:inline-block; font-weight:normal; text-align:right; }
.basket_product_wrap .basket_product_row .product_info .fulll { width: 80%; display:inline-block; font-weight:normal; text-align:left; }
@@ -165,7 +165,7 @@ input.wpsg_error { border-color:red !important; } .wpsg_overview .wpsg_table_wrap .overview_product_row .product_action .price_total { width: 39%; display:inline-block; font-weight:bold; text-align:right; }
.wpsg_overview .wpsg_table_wrap .overview_product_row .product_info { display:flex; width:100%; justify-content:space-between; align-items:center; }
.wpsg_overview .wpsg_table_wrap .overview_product_row .product_info .titlep { min-width:120px; display:inline-block; margin-top:0.3em; margin-bottom:0.3em; }
-.wpsg_overview .wpsg_table_wrap .overview_product_row .product_info .title { width: 30%; display:inline-block; margin-top:0.3em; margin-bottom:0.3em; }
+.wpsg_overview .wpsg_table_wrap .overview_product_row .product_info .title { display:inline-block; margin-top:0.3em; margin-bottom:0.3em; }
.wpsg_overview .wpsg_table_wrap .overview_product_row .product_info .valuel { width: 50%; display:inline-block; font-weight:normal; text-align:left; }
.wpsg_overview .wpsg_table_wrap .overview_product_row .product_info .valuer { width: 50%; display:inline-block; font-weight:normal; text-align:right; }
.wpsg_overview .wpsg_table_wrap .overview_product_row .product_info .fulll { width: 80%; display:inline-block; font-weight:normal; text-align:left; }
diff --git a/views/mods/mod_gutschein/index.phtml b/views/mods/mod_gutschein/index.phtml index 27a8314..a665516 100644 --- a/views/mods/mod_gutschein/index.phtml +++ b/views/mods/mod_gutschein/index.phtml @@ -101,6 +101,8 @@ <span class="edit"><a title="<?php echo __("Diesen Gutschein bearbeiten", "wpsg"); ?>" href="#" class="wpsg_voucher_edit" onclick="return false;" data-voucher_id="<?php echo $oVoucher->getId(); ?>"><?php echo __("Bearbeiten", "wpsg"); ?></a></span>
|
<span class="delete"><a onclick="return confirm('<?php echo __('Sind Sie sich sicher, dass Sie diesen Gutschein löschen möchten?', 'wpsg'); ?>');" title="<?php echo __('Diese Gutschein löschen', 'wpsg'); ?>" href="<?php echo WPSG_URL_WP; ?>wp-admin/admin.php?page=wpsg-Admin&action=module&modul=wpsg_mod_gutschein&subaction=delete&noheader=1&voucher_id=<?php echo $oVoucher->getId(); ?>"><?php echo __('Löschen', 'wpsg'); ?></a></span>
+ |
+ <span><a title="<?php echo __('Bestellungen anzeigen', 'wpsg'); ?>" href="<?php echo WPSG_URL_WP; ?>wp-admin/admin.php?page=wpsg-Order&filter[status]=-1&filter[voucher_id]=<?php echo $oVoucher->getId(); ?>"><?php echo __('Bestellungen suchen', 'wpsg'); ?></a></span>
</div>
</td>
diff --git a/views/mods/mod_klarna/gfx/klarna.svg b/views/mods/mod_klarna/gfx/klarna.svg new file mode 100644 index 0000000..e0ceb03 --- /dev/null +++ b/views/mods/mod_klarna/gfx/klarna.svg @@ -0,0 +1 @@ +<svg xmlns="http://www.w3.org/2000/svg" width="100" height="40.4494" viewBox="0 0 100 40.4494"><defs><style>.cls-1{fill:#ffb3c7;}</style></defs><g id="Lager_2" data-name="Lager 2"><g id="Layer_1" data-name="Layer 1"><rect class="cls-1" width="100" height="40.4494" rx="11.7384"/><path d="M80.0772,17.7235a6.194,6.194,0,1,0,0,10.2373v.75h3.5145V16.9727H80.0772Zm-3.1964,8.1388a3.0243,3.0243,0,1,1,3.1849-3.02A3.1059,3.1059,0,0,1,76.8808,25.8623Z"/><rect x="28.2027" y="11.7416" width="3.678" height="16.9694"/><path d="M64.1542,16.6569a4.2694,4.2694,0,0,0-3.62,1.6383V16.9733h-3.5V28.711h3.5421V22.5424a2.4754,2.4754,0,0,1,2.6383-2.6591c1.5447,0,2.4325.9228,2.4325,2.6348V28.711h3.5107V21.2464C69.1577,18.5146,66.9857,16.6569,64.1542,16.6569Z"/><path d="M43,17.7235a6.194,6.194,0,1,0,0,10.2373v.75h3.5145V16.9727H43Zm-3.1965,8.1388a3.0243,3.0243,0,1,1,3.1845-3.02A3.1058,3.1058,0,0,1,39.8034,25.8623Z"/><path d="M51.9513,18.5017V16.9728H48.353V28.7111h3.606v-5.48c0-1.8491,2.0042-2.843,3.3949-2.843.014,0,.0276.0014.0417.0015V16.9735A4.3821,4.3821,0,0,0,51.9513,18.5017Z"/><path d="M87.323,24.5476a2.2059,2.2059,0,1,0,2.206,2.2059A2.2057,2.2057,0,0,0,87.323,24.5476Z"/><path d="M25.6675,11.7384H21.8558a9.7488,9.7488,0,0,1-3.9412,7.8678l-1.51,1.131,5.8513,7.9792h4.8106l-5.3837-7.342A13.5049,13.5049,0,0,0,25.6675,11.7384Z"/><rect x="12.1204" y="11.7384" width="3.8185" height="16.9773"/></g></g></svg>
\ No newline at end of file diff --git a/views/mods/mod_klarna/order_done.phtml b/views/mods/mod_klarna/order_done.phtml new file mode 100644 index 0000000..7385448 --- /dev/null +++ b/views/mods/mod_klarna/order_done.phtml @@ -0,0 +1,42 @@ +<?php + + declare(strict_types=1); + + /** + * @author: daniel + * @date: 04.03.24 + * @time: 13:39 + */ + + namespace wpsgKlarna; + + $view = $this->view['wpsg_mod_klarna']; + +?> + +<div class="order_done_wpsg_mod_klarna <?php echo ($view['state']??''); ?>"> + + <?php if (($view['state']??'') === 'PAYED_DONE') { ?> + + <p><?php echo __('Betrag wurde mit Klarna bezahlt.', 'wpsgKlarna'); ?></p> + + <?php } else if (($view['state']??'') === 'PAYED') { ?> + + <p><?php echo __('Betrag wurde bereits mit Klarna bezahlt.', 'wpsgKlarna'); ?></p> + + <?php } else if (($view['state']??'') === 'TOPAY') { ?> + + <div id="wpsg_mod_klarna_widget"></div> + <input type="button" class="button" id="klarna_payment_button" value="<?php echo __('Jetzt mit Klarna bezahlen.', 'wpsgKlarna'); ?>" /> + + <?php + + $this->view['wpsg_mod_klarna']['button_id'] = 'klarna_payment_button'; + + echo $this->render(dirname(__FILE__).'/pay.phtml'); + + ?> + + <?php } ?> + +</div> diff --git a/views/mods/mod_klarna/order_view_afterpayment.phtml b/views/mods/mod_klarna/order_view_afterpayment.phtml new file mode 100644 index 0000000..032bf7e --- /dev/null +++ b/views/mods/mod_klarna/order_view_afterpayment.phtml @@ -0,0 +1,31 @@ +<?php + + declare(strict_types=1); + + /** + * @author: daniel + * @date: 04.03.24 + * @time: 16:38 + */ + + namespace wpsgKlarna; + + $oOrder = \wpsg_order::getInstance(intval($this->view['data']['id'])); + + $client_token = $oOrder->getMeta('wpsg_mod_klarna_client_token', false, ''); + $session_id = $oOrder->getMeta('wpsg_mod_klarna_session_id', false, ''); + $authorization_token = $oOrder->getMeta('wpsg_mod_klarna_authorization_token', false, ''); + $klarna_order_id = $oOrder->getMeta('wpsg_mod_klarna_order_id', false, ''); + $capture_id = $oOrder->getMeta('wpsg_mod_klarna_capture_id', false, ''); + +?> + +<br /> + +<?php if ($client_token !== '') { echo wpsg_drawForm_Input('', __('Klarna ClientToken', 'wpsg'), $client_token, ['readonly' => true]); } ?> +<?php if ($session_id !== '') { echo wpsg_drawForm_Input('', __('Klarna SessionID', 'wpsg'), $session_id, ['readonly' => true]); } ?> +<?php if ($authorization_token !== '') { echo wpsg_drawForm_Input('', __('Klarna AuthorizationToken', 'wpsg'), $authorization_token, ['readonly' => true]); } ?> +<?php if ($klarna_order_id !== '') { echo wpsg_drawForm_Input('', __('Klarna OrderId', 'wpsg'), $klarna_order_id, ['readonly' => true]); } ?> +<?php if ($capture_id !== '') { echo wpsg_drawForm_Input('', __('Klarna CaptureId', 'wpsg'), $capture_id, ['readonly' => true]); } ?> + + diff --git a/views/mods/mod_klarna/pay.phtml b/views/mods/mod_klarna/pay.phtml new file mode 100644 index 0000000..79661d6 --- /dev/null +++ b/views/mods/mod_klarna/pay.phtml @@ -0,0 +1,114 @@ +<?php + + declare(strict_types=1); + + /** + * @author: daniel + * @date: 05.03.24 + * @time: 07:20 + */ + + namespace wpsgKlarna; + + $view = $this->view['wpsg_mod_klarna']; + + /** @var \wpsg_order $oOrder */ + $oOrder = $view['oOrder']; + + $authorize_arg = [ + 'billing_address' => [ + 'given_name' => $oOrder->getInvoiceFirstName(), + 'family_name' => $oOrder->getInvoiceName(), + 'email' => $oOrder->getCustomer()->getEMail(), + 'street_address' => $oOrder->getInvoiceStreet(), + 'postal_code' => $oOrder->getInvoiceZip(), + 'city' => $oOrder->getInvoiceCity(), + ] + ]; + +?> + +<script> + + window.klarnaAsyncCallback = () => { + + const el_pppl_loading_blocker = document.getElementById('pppl_loading_blocker'); + + Klarna.Payments.init({ + client_token: '<?php echo $view['client_token']; ?>' + }); + + Klarna.Payments.load({ + container: '#wpsg_mod_klarna_widget' + }, { + + }, function (res) { + + console.log(res); + + }); + + document.getElementById('<?php echo $view['button_id']; ?>').addEventListener('click', (event) => { + + event.preventDefault(); + + if (el_pppl_loading_blocker) el_pppl_loading_blocker.style.display = 'block'; + + Klarna.Payments.authorize( + {}, {}, + function(res) { + + console.log(res); + + if (res.authorization_token) { + + try { + + fetch('<?php echo $view['url_setAuthToken']; ?>', { + method: 'POST', + headers: { + "Content-Type": "application/json" + }, + body: JSON.stringify({ + 'authorization_token': res.authorization_token + }) + }).then(response => { + + return response.json(); + + }).then(data => { + + if (data.success) { + + location.href = data.href; + + } else throw Error(); + + }).catch(e => { + + if (el_pppl_loading_blocker) el_pppl_loading_blocker.style.display = 'none'; + + }); + + } catch (error) { + + if (el_pppl_loading_blocker) el_pppl_loading_blocker.style.display = 'none'; + + } + + } else { + + if (el_pppl_loading_blocker) el_pppl_loading_blocker.style.display = 'none'; + + } + + } + ); + + }); + + }; + +</script> + +<script src="https://x.klarnacdn.net/kp/lib/v1/api.js" async></script> diff --git a/views/mods/mod_klarna/settings_edit.phtml b/views/mods/mod_klarna/settings_edit.phtml index 1085fcc..d622a10 100644 --- a/views/mods/mod_klarna/settings_edit.phtml +++ b/views/mods/mod_klarna/settings_edit.phtml @@ -1,25 +1,58 @@ -<?php
-
- /**
- * Template für die Einstellungen des Klarna Moduls
- */
-
-?>
-<?php echo wpsg_drawForm_Input('wpsg_mod_klarna_bezeichnung', __('Bezeichnung', 'wpsg'), $this->get_option('wpsg_mod_klarna_bezeichnung'), array('help' => 'wpsg_mod_klarna_bezeichnung')); ?>
-<?php echo wpsg_drawForm_Checkbox('wpsg_mod_klarna_aktiv', __('Aktiv', 'wpsg'), $this->get_option('wpsg_mod_klarna_aktiv'), array('help' => 'wpsg_mod_klarna_aktiv')); ?>
-<?php echo wpsg_drawForm_Input('wpsg_mod_klarna_aktiv_from', __('Aktiv ab Betrag', 'wpsg'), $this->get_option('wpsg_mod_klarna_aktiv_from'), array('help' => 'wpsg_mod_klarna_aktiv_from')); ?>
-<?php echo wpsg_drawForm_Input('wpsg_mod_klarna_aktiv_to', __('Aktiv bis Betrag', 'wpsg'), $this->get_option('wpsg_mod_klarna_aktiv_to'), array('help' => 'wpsg_mod_klarna_aktiv_to')); ?>
-<?php echo wpsg_drawForm_Textarea('wpsg_mod_klarna_hint', __('Hinweistext', 'wpsg'), $this->get_option('wpsg_mod_klarna_hint'), array('help' => 'wpsg_mod_klarna_hint')); ?>
-<br />
-<?php echo wpsg_drawForm_Input('wpsg_mod_klarna_merchantID', __('Händler ID (Merchant ID)', 'wpsg'), $this->get_option('wpsg_mod_klarna_merchantID'), array('help' => 'wpsg_mod_klarna_merchantID')); ?>
-<?php echo wpsg_drawForm_Input('wpsg_mod_klarna_sharedSecret', __('Geheimnis', 'wpsg'), $this->get_option('wpsg_mod_klarna_sharedSecret'), array('help' => 'wpsg_mod_klarna_sharedSecret')); ?>
-<br />
-<?php echo wpsg_drawForm_Checkbox('wpsg_mod_klarna_sandbox', __('Sandboxmodus', 'wpsg'), $this->get_option('wpsg_mod_klarna_sandbox'), array('help' => 'wpsg_mod_klarna_sandbox')); ?>
-<br />
-<?php echo wpsg_drawForm_Input('wpsg_mod_klarna_gebuehr', __('Gebühr', 'wpsg'), wpsg_ff($this->get_option('wpsg_mod_klarna_gebuehr'), true), array('help' => 'wpsg_mod_klarna_gebuehr','unit' => $this->get_option('wpsg_currency').' / %')); ?>
-<?php echo wpsg_drawForm_Select('wpsg_mod_klarna_mwst', __('Mehrwertsteuersatz', 'wpsg'), wpsg_tax_groups(), $this->get_option('wpsg_mod_klarna_mwst'), array('help' => 'wpsg_mod_klarna_mwst')); ?>
-<?php echo wpsg_drawForm_Checkbox('wpsg_mod_klarna_mwstland', __('Keine MwSt. wenn Land steuerfrei', 'wpsg'), $this->get_option('wpsg_mod_klarna_mwstland'), array('help' => 'wpsg_mod_klarna_mwstland')); ?>
-<br />
-<?php echo wpsg_drawForm_Select('wpsg_mod_klarna_success', __('Erfolgsseite', 'wpsg'), $this->view['pages'], $this->get_option('wpsg_mod_klarna_success'), array('help' => 'wpsg_mod_klarna_success')); ?>
-<?php echo wpsg_drawForm_Select('wpsg_mod_klarna_error', __('Fehlerseite', 'wpsg'), $this->view['pages'], $this->get_option('wpsg_mod_klarna_error'), array('help' => 'wpsg_mod_klarna_error')); ?>
-
+<?php + + declare(strict_types=1); + + /** + * @author: daniel + * @date: 04.03.24 + * @time: 11:56 + */ + + namespace wpsgKlarna; + +?> + +<?php echo wpsg_drawForm_Checkbox('wpsg_mod_klarna_active', __('Zahlungsart für neue Bestellungen aktiv', 'wpsg'), $this->get_option('wpsg_mod_klarna_active'), ['help' => 'wpsg_mod_klarna_active']); ?> +<?php echo wpsg_drawForm_Checkbox('wpsg_mod_klarna_admin_active', __('Zahlungsart nur für Admins aktiv', 'wpsgPayone'), $this->get_option('wpsg_mod_klarna_admin_active'), ['help' => 'wpsg_mod_klarna_admin_active']); ?> + +<?php echo wpsg_drawForm_Input('wpsg_mod_klarna_api_user', __('API Benutzername', 'wpsg'), $this->get_option('wpsg_mod_klarna_api_user'), ['help' => 'wpsg_mod_klarna_api_user']); ?> +<?php echo wpsg_drawForm_Input('wpsg_mod_klarna_api_password', __('API Passwort', 'wpsg'), $this->get_option('wpsg_mod_klarna_api_password'), ['help' => 'wpsg_mod_klarna_api_password']); ?> + +<?php echo wpsg_drawForm_Checkbox('wpsg_mod_klarna_sandbox', __('Sandbox Modus', 'wpsg'), $this->get_option('wpsg_mod_klarna_sandbox'), ['help' => 'wpsg_mod_klarna_sandbox']); ?> + +<div id="wpsg_mod_klarna_sandbox_layer"> + <?php echo wpsg_drawForm_Input('wpsg_mod_klarna_sandbox_user', __('(Sandbox) API Benutzername', 'wpsg'), $this->get_option('wpsg_mod_klarna_sandbox_user'), ['help' => 'wpsg_mod_klarna_sandbox_user']); ?> + <?php echo wpsg_drawForm_Input('wpsg_mod_klarna_sandbox_password', __('(Sandbox) API Passwort', 'wpsg'), $this->get_option('wpsg_mod_klarna_sandbox_password'), ['help' => 'wpsg_mod_klarna_sandbox_password']); ?> +</div> + +<?php echo wpsg_drawForm_Checkbox('wpsg_mod_klarna_debug', __('API Anfragen im Bestellprotokoll protokollieren', 'wpsg'), $this->get_option('wpsg_mod_klarna_debug'), ['help' => 'wpsg_mod_klarna_debug']); ?> + +<br /> + +<?php echo wpsg_drawForm_Checkbox('wpsg_mod_klarna_checkout', __('Zahlungen im Checkout vorauthorisieren', 'wpsg'), $this->get_option('wpsg_mod_klarna_checkout'), array('help' => 'wpsg_mod_klarna_checkout')); ?> + +<br /> + +<script> + + const el_wpsg_mod_klarna_sandbox = document.getElementById('wpsg_mod_klarna_sandbox'); + const el_wpsg_mod_klarna_sandbox_layer = document.getElementById('wpsg_mod_klarna_sandbox_layer'); + + el_wpsg_mod_klarna_sandbox.addEventListener('change', (event) => { + + if (event.target.checked) el_wpsg_mod_klarna_sandbox_layer.style.display = 'block'; + else el_wpsg_mod_klarna_sandbox_layer.style.display = 'none'; + + }); + + el_wpsg_mod_klarna_sandbox.dispatchEvent(new Event('change')); + + +</script> + +<br /> + +<?php echo wpsg_drawForm_Input('wpsg_mod_klarna_fee', __('Gebühr', 'wpsg'), wpsg_ff($this->get_option('wpsg_mod_klarna_fee'), true), array('help' => 'wpsg_mod_klarna_fee','unit' => $this->get_option('wpsg_currency').' / %')); ?> +<?php echo wpsg_drawForm_Select('wpsg_mod_klarna_tax_key', __('Mehrwertsteuersatz', 'wpsg'), wpsg_tax_groups(), $this->get_option('wpsg_mod_klarna_tax_key'), array('help' => 'wpsg_mod_klarna_tax_key')); ?> +<?php echo wpsg_drawForm_Checkbox('wpsg_mod_klarna_notaxcountry', __('Keine MwSt. wenn Land steuerfrei', 'wpsg'), $this->get_option('wpsg_mod_klarna_notaxcountry'), array('help' => 'wpsg_mod_klarna_notaxcountry')); ?> +<?php echo wpsg_drawForm_Textarea('wpsg_mod_klarna_hint', __('Hinweistext', 'wpsg'), $this->get_option('wpsg_mod_klarna_hint'), array('help' => 'wpsg_mod_klarna_hint')); ?> diff --git a/views/mods/mod_ordercondition/overview_top.phtml b/views/mods/mod_ordercondition/overview_top.phtml index 2b7e683..3ad7b70 100644 --- a/views/mods/mod_ordercondition/overview_top.phtml +++ b/views/mods/mod_ordercondition/overview_top.phtml @@ -11,7 +11,7 @@ <?php foreach ($this->view['wpsg_mod_ordercondition']['data'] as $oc) { ?>
<div class="wpsg_agb" id="wpsg_agb_<?php echo $oc['id']; ?>">
<label>
- <input type="checkbox" value="1" name="wpsg_mod_ordercondition[<?php echo $oc['id']; ?>]" />
+ <input type="checkbox" value="1" name="wpsg_mod_ordercondition[<?php echo $oc['id']; ?>]" required />
<?php if (strlen($oc['text']) < $minLength) { ?>
<?php echo $oc['text']; ?>
<?php } else { ?>
diff --git a/views/mods/mod_paypal/settings_edit.phtml b/views/mods/mod_paypal/settings_edit.phtml index d9b4942..a366dff 100644 --- a/views/mods/mod_paypal/settings_edit.phtml +++ b/views/mods/mod_paypal/settings_edit.phtml @@ -60,6 +60,7 @@ <?php echo wpsg_drawForm_Checkbox('wpsg_mod_paypal_sandbox', __('Sandbox Modus', 'wpsg'), $this->get_option('wpsg_mod_paypal_sandbox'), array('help' => 'wpsg_mod_paypal_sandbox')); ?>
<?php echo wpsg_drawForm_Input('wpsg_mod_paypal_subject', __('Betreff der Überweisung', 'wpsg'), $this->get_option('wpsg_mod_paypal_subject'), array('help' => 'wpsg_mod_paypal_subject')); ?>
+<?php echo wpsg_drawForm_Input('wpsg_mod_paypal_invoicenumber', __('Formatierung InvoiceNumber', 'wpsg'), $this->get_option('wpsg_mod_paypal_invoicenumber'), array('help' => 'wpsg_mod_paypal_invoicenumber')); ?>
<br />
diff --git a/views/mods/mod_paypalapi/checkout2_inner_prebutton.phtml b/views/mods/mod_paypalapi/checkout2_inner_prebutton.phtml new file mode 100644 index 0000000..5c2e29d --- /dev/null +++ b/views/mods/mod_paypalapi/checkout2_inner_prebutton.phtml @@ -0,0 +1,60 @@ +<?php + + declare(strict_types=1); + + /** + * @author: daniel + * @date: 09.06.24 + * @time: 12:04 + */ + + namespace wpsg; + +?> + +<?php echo GiroPayPalAPI::getInstance()->integrateSDK(); ?> + +<script> + + paypal.PaymentFields({ + fundingSource: paypal.FUNDING.GIROPAY, + style: { + variables: {}, + rules: {}, + }, + onInit: (data, actions) => { + + const form = document.querySelector("form#wpsg_checkout_form"); + + form.addEventListener("submit", (e) => { + + const formData = new FormData(form); + const paymentSource = formData.get("wpsg[checkout][payment]"); + + if (paymentSource === '10_1') { + + e.preventDefault(); + + actions.validate().then((valid) => { + + if (valid) { + + window.location.href = '<?php echo $this->getUrl(\wpsg_ShopController::URL_BASKET, 'wpsg_mod_paypalapi', 'giroPaySet', [], true); ?>'; + + } + + }); + + } + + }); + + }, + fields: { + name: { + value: "<?php echo ($_SESSION['wpsg']['checkout']['vname']??'').' '.($_SESSION['wpsg']['checkout']['name']??''); ?>" + }, + }, + }).render("#giropay-container"); + +</script> diff --git a/views/mods/mod_paypalapi/gfx/giropay.svg b/views/mods/mod_paypalapi/gfx/giropay.svg new file mode 100644 index 0000000..dd1928f --- /dev/null +++ b/views/mods/mod_paypalapi/gfx/giropay.svg @@ -0,0 +1 @@ +<svg width="75px" height="32px" viewBox="0 0 75 32" version="1.1" xmlns="http://www.w3.org/2000/svg"><title>logo giropay</title><desc>Created with Sketch.</desc><defs><polygon id="path-1" points="0 0.017902439 46.0918699 0.017902439 46.0918699 19.8373984 0 19.8373984"></polygon><polygon id="path-3" points="0 19.9821138 46.0918699 19.9821138 46.0918699 0.162601626 0 0.162601626"></polygon></defs><g id="SPB_&_AltPay_NewAssets" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd" transform="matrix(1.614571, 0, 0, 1.614571, -161.457123, -256.816772)"><g id="logo-giropay" transform="translate(100.000000, 159.000000)"><g id="Group-3" transform="translate(0.000000, 0.144715)"><mask id="mask-2" fill="#FFFFFF"><polygon points="0 0.017902439 46.0918699 0.017902439 46.0918699 19.8373984 0 19.8373984" transform="matrix(1, 0, 0, 1, 0, 0)"></polygon></mask><g id="Clip-2"></g><path d="M0,3.5735122 C0,1.60977236 1.5998374,0.017902439 3.57349593,0.017902439 L42.5182114,0.017902439 C44.4918699,0.017902439 46.0918699,1.60977236 46.0918699,3.5735122 L46.0918699,16.2818049 C46.0918699,18.2455447 44.4918699,19.8374146 42.5182114,19.8374146 L3.57349593,19.8374146 C1.5998374,19.8374146 0,18.2455447 0,16.2818049 L0,3.5735122 Z" id="Fill-1" fill="#003a7d" mask="url(#mask-2)"></path></g><path d="M1.46738211,3.84021138 L1.46738211,16.3065528 C1.46738211,17.5338699 2.46738211,18.5288293 3.70087805,18.5288293 L24.1036423,18.5288293 L24.1036423,1.61793496 L3.70087805,1.61793496 C2.46738211,1.61793496 1.46738211,2.61289431 1.46738211,3.84021138" id="Fill-4" fill="#ffffff"></path><path d="M5.67102439,10.0205528 C5.67102439,9.34152846 6.00582114,8.77730081 6.64663415,8.77730081 C7.42126829,8.77730081 7.74630894,9.39892683 7.74630894,9.95356098 C7.74630894,10.7187642 7.25866667,11.235187 6.64663415,11.235187 C6.13004878,11.235187 5.67102439,10.795187 5.67102439,10.0205528 Z M9.41053659,7.57226016 L7.8515122,7.57226016 L7.8515122,8.47112195 L7.8324878,8.47112195 C7.46907317,7.85908943 6.87606504,7.45746341 6.13964228,7.45746341 C4.59021138,7.45746341 3.8921626,8.56689431 3.8921626,10.0491707 C3.8921626,11.5221789 4.74321951,12.5550244 6.11102439,12.5550244 C6.79964228,12.5550244 7.37346341,12.2872195 7.78468293,11.7038049 L7.80370732,11.7038049 L7.80370732,11.9716098 C7.80370732,12.9472195 7.26826016,13.4158374 6.27362602,13.4158374 C5.55622764,13.4158374 5.11622764,13.2628293 4.59021138,13.0046179 L4.50419512,14.3626667 C4.90582114,14.5060813 5.58500813,14.6782764 6.40744715,14.6782764 C8.41590244,14.6782764 9.41053659,14.0182764 9.41053659,11.9716098 L9.41053659,7.57226016 Z" id="Fill-6" fill="#ED1C24"></path><mask id="mask-4" fill="#FFFFFF"><polygon points="0 19.9821138 46.0918699 19.9821138 46.0918699 0.162601626 0 0.162601626" transform="matrix(1, 0, 0, 1, 0, 0)"></polygon></mask><g id="Clip-9"></g><path d="M10.5985366,6.75918699 L12.32,6.75918699 L12.32,5.49674797 L10.5985366,5.49674797 L10.5985366,6.75918699 Z M10.598374,12.5549593 L12.3198374,12.5549593 L12.3198374,7.57219512 L10.598374,7.57219512 L10.598374,12.5549593 Z" id="Fill-8" fill="#ED1C24" mask="url(#mask-4)"></path><path d="M17.1133333,7.51479675 C16.9411382,7.48617886 16.7307317,7.45739837 16.5299187,7.45739837 C15.7839024,7.45739837 15.3534959,7.85918699 15.0570732,8.4904065 L15.0380488,8.4904065 L15.0380488,7.57219512 L13.4694309,7.57219512 L13.4694309,12.5549593 L15.1910569,12.5549593 L15.1910569,10.4508943 C15.1910569,9.47544715 15.6404878,8.89203252 16.4439024,8.89203252 C16.6447154,8.89203252 16.835935,8.89203252 17.0273171,8.94943089 L17.1133333,7.51479675 Z" id="Fill-10" fill="#ED1C24" mask="url(#mask-4)"></path><path d="M20.0773496,11.4647154 C19.2835285,11.4647154 18.9583252,10.804878 18.9583252,10.0682927 C18.9583252,9.32243902 19.2835285,8.66243902 20.0773496,8.66243902 C20.8711707,8.66243902 21.196374,9.32243902 21.196374,10.0682927 C21.196374,10.804878 20.8711707,11.4647154 20.0773496,11.4647154 M20.0773496,12.6697561 C21.7223902,12.6697561 22.9752358,11.7133333 22.9752358,10.0682927 C22.9752358,8.41382114 21.7223902,7.45739837 20.0773496,7.45739837 C18.4323089,7.45739837 17.1794634,8.41382114 17.1794634,10.0682927 C17.1794634,11.7133333 18.4323089,12.6697561 20.0773496,12.6697561" id="Fill-11" fill="#ED1C24" mask="url(#mask-4)"></path><path d="M29.3757073,10.0110244 C29.3757073,10.8048455 28.9836748,11.3500488 28.3332683,11.3500488 C27.7594472,11.3500488 27.2812358,10.8048455 27.2812358,10.0780163 C27.2812358,9.332 27.7020488,8.77720325 28.3332683,8.77720325 C29.0026992,8.77720325 29.3757073,9.35102439 29.3757073,10.0110244 Z M25.5597724,14.5633821 L27.2812358,14.5633821 L27.2812358,11.856878 L27.3002602,11.856878 C27.6254634,12.4498862 28.2758699,12.6697236 28.8783089,12.6697236 C30.360748,12.6697236 31.1545691,11.4456585 31.1545691,9.97265041 C31.1545691,8.76777236 30.399122,7.45736585 29.0218862,7.45736585 C28.2376585,7.45736585 27.5106667,7.77297561 27.166439,8.47118699 L27.147252,8.47118699 L27.147252,7.5721626 L25.5597724,7.5721626 L25.5597724,14.5633821 Z" id="Fill-12" fill="#ffffff" mask="url(#mask-4)"></path><path d="M33.505252,10.9769919 C33.505252,10.4987805 33.9642764,10.3169919 34.5476911,10.3169919 C34.8059024,10.3169919 35.0546829,10.3361789 35.2745203,10.3457724 C35.2745203,10.929187 34.8633008,11.5221951 34.2128943,11.5221951 C33.8112683,11.5221951 33.505252,11.3212195 33.505252,10.9769919 Z M36.9769593,12.5550407 C36.900374,12.1628455 36.8813496,11.770813 36.8813496,11.3786179 L36.8813496,9.52317073 C36.8813496,8.00252033 35.7815122,7.45747967 34.5094797,7.45747967 C33.7730569,7.45747967 33.1322439,7.56268293 32.5202114,7.81130081 L32.5488293,8.97813008 C33.0270407,8.7103252 33.5816748,8.60512195 34.1364715,8.60512195 C34.7580976,8.60512195 35.2650894,8.78674797 35.2745203,9.46577236 C35.0546829,9.42756098 34.7485041,9.39894309 34.4711057,9.39894309 C33.5530569,9.39894309 31.8984228,9.58056911 31.8984228,11.1013821 C31.8984228,12.1820325 32.7784228,12.6698374 33.7634634,12.6698374 C34.4711057,12.6698374 34.9493171,12.392439 35.3415122,11.770813 L35.3606992,11.770813 C35.3606992,12.0290244 35.3893171,12.2872358 35.3989106,12.5550407 L36.9769593,12.5550407 Z" id="Fill-13" fill="#ffffff" mask="url(#mask-4)"></path><path d="M37.750748,14.5634634 C38.1045691,14.6398862 38.4583902,14.6782602 38.8218049,14.6782602 C40.3998537,14.6782602 40.7728618,13.463626 41.2606667,12.2107805 L43.0873333,7.5722439 L41.3658699,7.5722439 L40.3426179,10.8239512 L40.3234309,10.8239512 L39.2522114,7.5722439 L37.3967642,7.5722439 L39.414813,12.6698049 C39.2904228,13.1098049 38.9653821,13.3584228 38.5445691,13.3584228 C38.3053821,13.3584228 38.0949756,13.3296423 37.8655447,13.2532195 L37.750748,14.5634634 Z" id="Fill-14" fill="#ffffff" mask="url(#mask-4)"></path></g></g></svg>
\ No newline at end of file diff --git a/views/mods/mod_paypalapi/order_done_giropay.phtml b/views/mods/mod_paypalapi/order_done_giropay.phtml new file mode 100644 index 0000000..5d765e4 --- /dev/null +++ b/views/mods/mod_paypalapi/order_done_giropay.phtml @@ -0,0 +1,80 @@ +<?php + + declare(strict_types=1); + + /** + * @author: daniel + * @date: 13.06.24 + * @time: 14:59 + */ + + namespace wpsg; + + $client_id = $this->view['clientId']??null; + +?> + +<?php if ($client_id !== null) { ?> + + <p><?php echo __('Die Bestellung ist bei uns eingegangen, bitte begleichen Sie den offenen Betrag mit giroPAy über folgenden Button.', 'wpsg'); ?></p> + + <script src="https://sandbox.paypal.com/sdk/js?client-id=<?php echo $client_id; ?>&components=buttons,payment-fields,marks,funding-eligibility&enable-funding=giropay¤cy=EUR"></script> + + <div id="giropay-btn"></div> + + <script> + + paypal.Buttons({ + fundingSource: paypal.FUNDING.GIROPAY, + style: { + label: "pay", + }, + createOrder() { + return fetch('<?php echo $this->getUrl(\wpsg_ShopController::URL_BASKET, 'wpsg_mod_paypalapi', 'giroPayCreateOrder', [ + 'order_id' => intval($_REQUEST['order_id']) + ], true); ?>', { + method: "POST", + headers: { + "Content-Type": "application/json", + }, + body: null, + }) + .then((response) => response.json()) + .then((order) => order.id); + }, + onApprove(data) { + + console.log('onApprove'); + + return fetch('<?php echo $this->getUrl(\wpsg_ShopController::URL_BASKET, 'wpsg_mod_paypalapi', 'giroPayApproveOrder', [], true); ?>', { + method: "POST", + headers: { + "Content-Type": "application/json", + }, + body: JSON.stringify({ + orderID: data.orderID + }) + }) + .then((response) => response.json()) + .then((orderData) => { + + //console.log('Capture result', orderData, JSON.stringify(orderData, null, 2)); + //const transaction = orderData.purchase_units[0].payments.captures[0]; + //console.log('Transaction Status:', transaction.status); + //console.log('Transaction ID:', transaction.id); + + location.reload(); + + }); + }, + onCancel(data, actions) { console.log(`Order Canceled - ID: ${data.orderID}`); }, + onError(err) { console.error(err); } + }).render("#giropay-btn"); + + </script> + +<?php } else { ?> + + <p><?php echo __('Den Betrag haben wir mittels GiroPay dankend erhalten.', 'wpsg'); ?></p> + +<?php }
\ No newline at end of file diff --git a/views/mods/mod_paypalapi/overview_button.phtml b/views/mods/mod_paypalapi/overview_button.phtml new file mode 100644 index 0000000..dfe5490 --- /dev/null +++ b/views/mods/mod_paypalapi/overview_button.phtml @@ -0,0 +1,89 @@ +<?php + + declare(strict_types=1); + + /** + * @author: daniel + * @date: 13.06.24 + * @time: 14:48 + */ + + namespace wpsg; + +?> + +<?php GiroPayPalAPI::getInstance()->integrateSDK(); ?> + + +<div style="width:300px; float:right;"> + <div id="giropay-btn"></div> +</div> + +<script> + + paypal.Buttons({ + fundingSource: paypal.FUNDING.GIROPAY, + style: { + label: "pay", + }, + createOrder() { + + const form = document.getElementById('wpsg_form'); + + if (form.checkValidity()) { + + return fetch("<?php echo $this->getUrl(\wpsg_ShopController::URL_BASKET, 'wpsg_mod_paypalapi', 'giroPayCreateOrderFromSession', [ ], true); ?>", { + method: "POST", + headers: { + "Content-Type": "application/json", + }, + body: { } + }) + .then((response) => response.json()) + .then((order) => order.id); + + } else form.reportValidity(); + + }, + onApprove(data) { + + return fetch("<?php echo $this->getUrl(\wpsg_ShopController::URL_BASKET, 'wpsg_mod_paypalapi', 'giroPayApproveOrder', [], true); ?>", { + method: "POST", + headers: { + "Content-Type": "application/json", + }, + body: JSON.stringify({ + orderID: data.orderID + }) + }) + .then((response) => response.json()) + .then((orderData) => { + + location.href = orderData.order_done_url; + + // Successful capture! For dev/demo purposes: + // console.log('Capture result', orderData, JSON.stringify(orderData, null, 2)); + + // const transaction = orderData.order_paypal.purchase_units[0].payments.captures[0]; + + //console.log('Transaction Status:', transaction.status); + //console.log('Transaction ID:', transaction.id); + + }); + + }, + onCancel(data, actions) { + + console.log(`Order Canceled - ID: ${data.orderID}`); + + location.href = '<?php echo $this->getUrl(\wpsg_ShopController::URL_BASKET, 'wpsg_mod_paypalapi', 'giroPayCancelOrder', [], true); ?>'; + + }, + onError(err) { + + <?php if ($GLOBALS['wpsg_sc']->get_option('wpsg_debugModus') === "1") { ?>console.error(err);<?php } ?> + + } + }).render("#giropay-btn"); + +</script>
\ No newline at end of file diff --git a/views/mods/mod_paypalapi/settings_edit.phtml b/views/mods/mod_paypalapi/settings_edit.phtml index 9fd277b..9e33bc9 100644 --- a/views/mods/mod_paypalapi/settings_edit.phtml +++ b/views/mods/mod_paypalapi/settings_edit.phtml @@ -59,6 +59,12 @@ <?php echo wpsg_drawForm_Checkbox('wpsg_mod_paypalapi_aktiv', __('PayPal für neue Bestellungen erlauben', 'wpsg'), $this->get_option('wpsg_mod_paypalapi_aktiv'), array('help' => 'wpsg_shippay_activ')); ?>
<?php echo wpsg_drawForm_Checkbox('wpsg_mod_paypalapi_plus_aktiv', __('PayPal Plus aktivieren', 'wpsg'), $this->get_option('wpsg_mod_paypalapi_plus_aktiv'), array('help' => 'wpsg_mod_paypalapi_plus_aktiv')); ?>
+<?php echo wpsg_drawForm_Checkbox('wpsg_mod_paypalapi_giropay_aktiv', __('GiroPay aktivieren', 'wpsg'), $this->get_option('wpsg_mod_paypalapi_giropay_aktiv'), array('help' => 'wpsg_mod_paypalapi_giropay_aktiv ')); ?>
+
+<div id="wpsg_mod_paypalapi_giropay_aktiv_layer">
+ <?php echo wpsg_drawForm_Input('wpsg_mod_paypalapi_giropay_name', __('Bezeichnung (GiroPay)', 'wpsg'), $this->get_option('wpsg_mod_paypalapi_giropay_name'), array('help' => 'wpsg_shippay_name')); ?>
+ <?php echo wpsg_drawForm_Textarea('wpsg_mod_paypalapi_giropay_hint', __('Hinweistext (GiroPay)', 'wpsg'), $this->get_option('wpsg_mod_paypalapi_giropay_hint'), array('help' => 'wpsg_shippay_hint')); ?>
+</div>
<div class="wpsg_mod_paypalapi_plus_aktiv_layer wpsg_mod_paypalapi_plus_aktiv_layer_1">
<?php echo wpsg_drawForm_Checkbox('wpsg_mod_paypalapi_plus_basket', __('Zahlungsauswahl im Warenkorb', 'wpsg'), $this->get_option('wpsg_mod_paypalapi_plus_basket'), array('help' => 'wpsg_mod_paypalapi_plus_basket')); ?>
@@ -85,7 +91,9 @@ <?php echo wpsg_drawForm_Checkbox('wpsg_mod_paypalapi_paypalexpress_details', __('Warenkorbdetails übertragen', 'wpsg'), $this->get_option('wpsg_mod_paypalapi_paypalexpress_details'), array('help' => 'wpsg_mod_paypalapi_paypalexpress_details')); ?>
<br />
+
<?php echo wpsg_drawForm_Input('wpsg_mod_paypalapi_experience_label', __('Bezeichnung im PayPal Zahlungsinterface', 'wpsg'), $this->get_option('wpsg_mod_paypalapi_experience_label'), array('help' => 'wpsg_mod_paypalapi_experience_label', 'hint' => __('Max. 127 Zeichen', 'wpsg'))); ?>
+
<?php echo wpsg_drawForm_Input('wpsg_mod_paypalapi_experience_logo', __('URL für ein Logo im PayPal Zahlungsinterface', 'wpsg'), $this->get_option('wpsg_mod_paypalapi_experience_logo'), array('help' => 'wpsg_mod_paypalapi_experience_logo', 'hint' => __('gif|png|jpg, Max. 190x60', 'wpsg'))); ?>
<?php echo wpsg_drawForm_Select('wpsg_mod_paypalapi_experience_locale_code', __('Sprache im PayPal Zahlungsinterface', 'wpsg'), array(
'DE' => __('Deutsch', 'wpsg'),
@@ -174,4 +182,40 @@ } );
+ const el_wpsg_mod_paypalapi_plus_aktiv = document.getElementById('wpsg_mod_paypalapi_plus_aktiv');
+ const el_wpsg_mod_paypalapi_giropay_aktiv = document.getElementById('wpsg_mod_paypalapi_giropay_aktiv');
+ const el_wpsg_mod_paypalapi_giropay_aktiv_layer = document.getElementById('wpsg_mod_paypalapi_giropay_aktiv_layer');
+
+ el_wpsg_mod_paypalapi_plus_aktiv.addEventListener('change', event => {
+
+ if (el_wpsg_mod_paypalapi_plus_aktiv.checked) {
+
+ el_wpsg_mod_paypalapi_giropay_aktiv.disabled = true;
+ el_wpsg_mod_paypalapi_giropay_aktiv.checked = false;
+
+ } else {
+
+ el_wpsg_mod_paypalapi_giropay_aktiv.disabled = false;
+
+ }
+
+ });
+
+ el_wpsg_mod_paypalapi_giropay_aktiv.addEventListener('change', event => {
+
+ if (el_wpsg_mod_paypalapi_giropay_aktiv.checked) {
+
+ el_wpsg_mod_paypalapi_giropay_aktiv_layer.style.display = 'block';
+
+ } else {
+
+ el_wpsg_mod_paypalapi_giropay_aktiv_layer.style.display = 'none';
+
+ }
+
+ });
+
+ el_wpsg_mod_paypalapi_plus_aktiv.dispatchEvent(new Event('change'));
+ el_wpsg_mod_paypalapi_giropay_aktiv.dispatchEvent(new Event('change'));
+
</script>
\ No newline at end of file diff --git a/views/mods/mod_productvariants/settings_edit.phtml b/views/mods/mod_productvariants/settings_edit.phtml index 3b32cd0..0f669e3 100644 --- a/views/mods/mod_productvariants/settings_edit.phtml +++ b/views/mods/mod_productvariants/settings_edit.phtml @@ -22,6 +22,17 @@ <?php echo wpsg_drawForm_Checkbox('wpsg_mod_productvariants_price', __('Preis der Variation direkt anzeigen'), $this->get_option('wpsg_mod_productvariants_price')); ?>
<?php echo wpsg_drawForm_Checkbox('wpsg_vp_detailview', __('Erweiterte Variantenanzeige aktivieren', 'wpsg'), $this->get_option('wpsg_vp_detailview'), array('help' => 'wpsg_vp_detailview')); ?>
<?php echo wpsg_drawForm_Checkbox('wpsg_vp_replaceanr', __('Produktartikelnummer ersetzen', 'wpsg'), $this->get_option('wpsg_vp_replaceanr'), array('hint' => __('Ersetzt die Produktartikelnummer durch die zusammengesetzte Artikelnummern der Varianten.', 'wpsg'), 'help' => 'wpsg_vp_replaceanr')); ?>
+ <?php echo wpsg_drawForm_Checkbox('wpsg_vp_product_stock_nocalc', __('Produktbestand nach Kauf nicht berechnen', 'wpsg'), $this->get_option('wpsg_vp_product_stock_nocalc'), [
+ 'hint' => __('Ist diese Option aktiv, so bildet sich der Bestand im Produkt bei Variantenprodukten nicht aus den Varianten neu sondern wird einfach reduziert.', 'wpsg'), 'help' => 'wpsg_vp_product_stock_nocalc'
+ ]); ?>
+
+ <?php echo wpsg_drawForm_Checkbox('wpsg_vp_product_stock_varinotchange', __('Produktbestand in Varianten nicht verringern', 'wpsg'), $this->get_option('wpsg_vp_product_stock_varinotchange'), [
+ 'hint' => __('Ist diese Option aktiv, so wird bei Kauf der Bestand in den Varianten nicht verringert.', 'wpsg'), 'help' => 'wpsg_vp_product_stock_varinotchange'
+ ]); ?>
+
+ <?php echo wpsg_drawForm_Checkbox('wpsg_vp_product_stock_display', __('Produktbestand statt Variantenbestand anzeigen', 'wpsg'), $this->get_option('wpsg_vp_product_stock_display'), [
+ 'hint' => __('Ist diese Option aktiv, so wird im nur der Produktbestand im Produkttemplate (Frontend) angezeigt..', 'wpsg'), 'help' => 'wpsg_vp_product_stock_display'
+ ]); ?>
</div>
</div>
diff --git a/views/mods/mod_productvars/basket_row.phtml b/views/mods/mod_productvars/basket_row.phtml index da8716b..7bcae7d 100644 --- a/views/mods/mod_productvars/basket_row.phtml +++ b/views/mods/mod_productvars/basket_row.phtml @@ -11,7 +11,7 @@ <div class="title">
<?php echo __($pv['name'], 'wpsg'); ?><?php if ($pv['pflicht'] == '1') { ?><span class="wpsg_required">*</span><?php } ?>
</div>
- <div class="valuel">
+ <div class="value">
<?php if ($pv['typ'] == '1') { // Auswahlfeld ?>
<select class="<?php echo ((in_array("wpsg_mod_productvars_".$pv['id']."_".$this->view['wpsg_mod_productvars']['p']['product_index'], (array)$this->view['error']))?'wpsg_error':''); ?>" name="wpsg_mod_productvars[<?php echo $pv['id']; ?>][<?php echo $this->view['wpsg_mod_productvars']['p']['product_index']; ?>]">
<option value="not_set"><?php echo __('Bitte wählen', 'wpsg'); ?></option>
@@ -31,6 +31,5 @@ class="<?php echo ((in_array("wpsg_mod_productvars_".$pv['id']."_".$this->view['wpsg_mod_productvars']['p']['product_index'], (array)$this->view['error']))?'wpsg_error':''); ?>"><?php echo @wpsg_hspc($this->view['wpsg_mod_productvars']['p']['wpsg_mod_productvars'][$pv['id']]); ?></textarea>
<?php } ?>
</div>
-
</div>
<?php } ?>
\ No newline at end of file diff --git a/views/mods/mod_productvars/overview_row.phtml b/views/mods/mod_productvars/overview_row.phtml index 99d020f..2247072 100644 --- a/views/mods/mod_productvars/overview_row.phtml +++ b/views/mods/mod_productvars/overview_row.phtml @@ -13,7 +13,7 @@ <?php if ($this->view['$bPicture'] == true) { ?>class="titlep"><?php } else { ?>class="title"><?php } ?>
<?php echo __($pv['name'], 'wpsg'); ?><?php if ($pv['pflicht'] == '1') { ?><span class="wpsg_required">*</span><?php } ?>
</div>
- <div class="valuel">
+ <div class="value">
<?php if ($pv['typ'] == '1') { // Auswahlfeld ?>
<?php if ($this->view['wpsg_mod_productvars']['p']['wpsg_mod_productvars'][$pv['id']] == 'not_set') { ?>
<?php echo __('Nicht angegeben', 'wpsg'); ?>
@@ -32,10 +32,6 @@ <?php echo nl2br(wpsg_hspc($this->view['wpsg_mod_productvars']['p']['wpsg_mod_productvars'][$pv['id']])); ?>
<?php } ?>
</div>
- <div class="dummyr">
- <?php echo __(' '); ?>
- </div>
-
</div>
<?php } ?>
<?php } ?>
\ No newline at end of file diff --git a/views/mods/mod_rechnungen/settings_edit.phtml b/views/mods/mod_rechnungen/settings_edit.phtml index 18c393b..c2579de 100644 --- a/views/mods/mod_rechnungen/settings_edit.phtml +++ b/views/mods/mod_rechnungen/settings_edit.phtml @@ -4,6 +4,8 @@ * Template für die Einstellungen des Rechnungen Moduls
*/
+ use horstoeko\zugferd\ZugferdProfiles;
+
?>
<div>
@@ -182,6 +184,47 @@ </div>
<div id="tab3" role="tabpanel" class="tab-pane" >
+ <?php echo wpsg_drawForm_Select('wpsg_mod_rechnungen_einvoice', __('E-Rechnung', 'wpsg'), [
+ 0 => __('Keine E-Rechnungsdaten erzeugen', 'wpsg'),
+ 100 + ZugferdProfiles::PROFILE_MINIMUM => __('EN16931 Minimum', 'wpsg'),
+ 100 + ZugferdProfiles::PROFILE_BASIC => __('EN16931 Basic', 'wpsg'),
+ 100 + ZugferdProfiles::PROFILE_BASICWL => __('EN16931 Basic WL', 'wpsg'),
+ 100 + ZugferdProfiles::PROFILE_EN16931 => __('EN16931 Comfort', 'wpsg'),
+ 100 + ZugferdProfiles::PROFILE_EXTENDED => __('EN16931 Extended', 'wpsg'),
+ 100 + ZugferdProfiles::PROFILE_XRECHNUNG => __('EN16931 XRechnung 1', 'wpsg'),
+ 100 + ZugferdProfiles::PROFILE_XRECHNUNG_2 => __('EN16931 XRechnung 2', 'wpsg'),
+ 100 + ZugferdProfiles::PROFILE_XRECHNUNG_2_1 => __('EN16931 XRechnung 2.1', 'wpsg'),
+ 100 + ZugferdProfiles::PROFILE_XRECHNUNG_2_2 => __('EN16931 XRechnung 2.2', 'wpsg'),
+ 100 + ZugferdProfiles::PROFILE_XRECHNUNG_2_3 => __('EN16931 XRechnung 2.3', 'wpsg'),
+ 100 + ZugferdProfiles::PROFILE_XRECHNUNG_3 => __('EN16931 XRechnung 3', 'wpsg'),
+ ], $this->get_option('wpsg_mod_rechnungen_einvoice'), ['help' => 'wpsg_mod_rechnungen_einvoice']); ?>
+
+ <p style="line-height:normal; margin-bottom:1rem; margin-top:1rem; display:none; font-style:italic;" id="wpsg_mod_rechnungen_einvoice_description"><?php echo __('Die Platzhalter können bei den Formatfeldern und dem Dateinamen verwendet werden. Der Platzhalter %nr% sollte dabei immer Verwendung finden.', 'wpsg'); ?></p>
+
+ <script>
+
+ const eInvoiceProfileDev = <?php echo json_encode(ZugferdProfiles::PROFILEDEF); ?>;
+ const el_wpsg_mod_rechnungen_einvoice_description = document.getElementById('wpsg_mod_rechnungen_einvoice_description');
+
+ document.getElementById('wpsg_mod_rechnungen_einvoice').addEventListener('change', ev => {
+
+ if (eInvoiceProfileDev[ev.target.value] !== undefined) {
+
+ el_wpsg_mod_rechnungen_einvoice_description.innerText = eInvoiceProfileDev[ev.target.value].description;
+ el_wpsg_mod_rechnungen_einvoice_description.style.display = 'block';
+
+ } else {
+
+ el_wpsg_mod_rechnungen_einvoice_description.style.display = 'hidden';
+
+ }
+
+ });
+
+ document.getElementById('wpsg_mod_rechnungen_einvoice').dispatchEvent(new Event('change'));
+
+ </script>
+
<?php echo wpsg_drawForm_Input('wpsg_rechnungen_url', __('URL Benachrichtigung', 'wpsg'), $this->get_option('wpsg_rechnungen_url'), array('help' => 'wpsg_rechnung_url')); ?>
<?php echo wpsg_drawForm_Select('wpsg_mod_rechnungen_auto', __('Rechnungserstellung', 'wpsg'), array(
'0' => __('Manuell', 'wpsg'),
diff --git a/views/mods/mod_relatedproducts/list.phtml b/views/mods/mod_relatedproducts/list.phtml index b6c808e..d4db6c6 100644 --- a/views/mods/mod_relatedproducts/list.phtml +++ b/views/mods/mod_relatedproducts/list.phtml @@ -9,15 +9,38 @@ <?php if (sizeof($this->view['wpsg_mod_relatedproducts']['data']) <= 0) { ?>
<p><?php echo __('Noch keine Produkte zugeordnet', 'wpsg'); ?></p>
<?php } else { ?>
-<?php foreach ($this->view['wpsg_mod_relatedproducts']['data'] as $p) { ?>
- <span id="wpsg_rp_<?php echo $p['id']; ?>">
- <?php echo wpsg_drawForm_Select('wpsg_mod_relatedproduct['.$p['id'].']', '<a href="'.wp_nonce_url(WPSG_URL_WP.'wp-admin/admin.php?page=wpsg-Produkt&action=edit&edit_id='.$p['product_id'], 'wpsg-product-edit-'.$p['product_id']).'">'.$p['name'].'</p>', $this->view['wpsg_mod_relatedproducts']['arTemplates'], $p['template'], array('icon' => 'wpsg_icon_remove glyphicon glyphicon-trash')); ?>
- </span>
- <div class="wpsg_clear"></div>
-<?php } ?>
+ <div id="wpsg_mod_relatedproduct_list">
+ <?php foreach ($this->view['wpsg_mod_relatedproducts']['data'] as $p) { ?>
+ <div class="order_item">
+ <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-chevron-bar-expand" viewBox="0 0 16 16">
+ <path fill-rule="evenodd" d="M3.646 10.146a.5.5 0 0 1 .708 0L8 13.793l3.646-3.647a.5.5 0 0 1 .708.708l-4 4a.5.5 0 0 1-.708 0l-4-4a.5.5 0 0 1 0-.708m0-4.292a.5.5 0 0 0 .708 0L8 2.207l3.646 3.647a.5.5 0 0 0 .708-.708l-4-4a.5.5 0 0 0-.708 0l-4 4a.5.5 0 0 0 0 .708M1 8a.5.5 0 0 1 .5-.5h13a.5.5 0 0 1 0 1h-13A.5.5 0 0 1 1 8"/>
+ </svg>
+ <span id="wpsg_rp_<?php echo $p['id']; ?>">
+ <?php echo wpsg_drawForm_Select('wpsg_mod_relatedproduct['.$p['id'].']', '<a href="'.wp_nonce_url(WPSG_URL_WP.'wp-admin/admin.php?page=wpsg-Produkt&action=edit&edit_id='.$p['product_id'], 'wpsg-product-edit-'.$p['product_id']).'">'.$p['name'].'</a>', $this->view['wpsg_mod_relatedproducts']['arTemplates'], $p['template'], array('icon' => 'wpsg_icon_remove glyphicon glyphicon-trash')); ?>
+ </span>
+ </div>
+ <?php } ?>
+ </div>
<?php } ?>
-<script type="text/javascript">
+<style>
+
+ #wpsg_mod_relatedproduct_list { display:flex; flex-direction:column; gap:5px;
+ & > .order_item { display:block; position:relative; cursor:pointer !important;
+ & > svg { display:none; width:16px; height:16px; left:0; top:50%; transform:translateY(-50%); position:absolute; cursor:pointer !important; }
+ &:hover > svg { display:block; }
+ .form-group { margin-top:0; margin-bottom:0;
+ & > * { cursor:pointer;
+ a { display:inline; }
+ }
+ & > label { display:flex; justify-content:flex-end; }
+ }
+ }
+ }
+
+</style>
+
+<script>
jQuery('#relatedproducts_list a.wpsg_icon_remove').on('click', function() {
@@ -39,5 +62,13 @@ return false;
} );
+
+ jQuery(document).ready(function() {
+
+ jQuery("#wpsg_mod_relatedproduct_list").sortable({
+
+ }).disableSelection();
+
+ });
</script>
\ No newline at end of file diff --git a/views/mods/mod_stock/product_addedit_content.phtml b/views/mods/mod_stock/product_addedit_content.phtml index 93ba804..ededa28 100644 --- a/views/mods/mod_stock/product_addedit_content.phtml +++ b/views/mods/mod_stock/product_addedit_content.phtml @@ -4,6 +4,9 @@ * Template für die Integration des Lagerbestandes in die Produktverwaltung
*/
+ /** @var wpsg_product $oProduct */
+ $oProduct = $this->view['oProduct'];
+
?>
<?php echo wpsg_drawForm_AdminboxStart(__('Lagerbestand', 'wpsg')); ?>
@@ -25,7 +28,42 @@ <br />
- <div class="info"><?php echo __('Lagerbestand = Bestand(Variante 1) + Bestand(Variante 2) + Bestand(Variante X)','wpsg'); ?></div>
+ <?php if ($this->hasMod('wpsg_mod_productvariants')) { ?>
+
+ <?php echo wpsg_drawForm_Select('meta[wpsg_vp_product_stock_nocalc]', __('Produktbestand nach Kauf', 'wpsg'), [
+ '0' => wpsg_translate(
+ __('Voreinstellung (#1#)', 'wpsg'),
+ (($this->get_option('wpsg_vp_product_stock_nocalc') === '1')?'nicht berechnen':'berechnen')
+ ),
+ '2' => __('berechnen'),
+ '1' => __('nicht berechnen')
+ ], $oProduct->getMeta('wpsg_vp_product_stock_nocalc'), [
+ 'hint' => __('Ist hier "berechnen" eingestellt, wird beim Ändern des Bestandes einer Variante der Bestand im Produkt aus den Varianten ermittelt. (Lagerbestand im Produkt = Bestand(Variante 1) + Bestand(Variante 2) + ... )', 'wpsg')
+ ]); ?>
+
+ <?php echo wpsg_drawForm_Select('meta[wpsg_vp_product_stock_varinotchange]', __('Produktbestand in Varianten nicht verringern', 'wpsg'), [
+ '0' => wpsg_translate(
+ __('Voreinstellung (#1#)', 'wpsg'),
+ (($this->get_option('wpsg_vp_product_stock_varinotchange') === '1')?'nicht verringern':'verringern')
+ ),
+ '2' => __('verringern'),
+ '1' => __('nicht verringern')
+ ], $oProduct->getMeta('wpsg_vp_product_stock_varinotchange'), [
+ 'hint' => __('Ist hier "nicht verringern" aktiviert, so wird der Bestand in der Variante beim Kauf nicht reduziert.', 'wpsg')
+ ]); ?>
+
+ <?php echo wpsg_drawForm_Select('meta[wpsg_vp_product_stock_display]', __('Produktbestand oder Variantenbestand anzeigen', 'wpsg'), [
+ '0' => wpsg_translate(
+ __('Voreinstellung (#1#)', 'wpsg'),
+ (($this->get_option('wpsg_vp_product_stock_display') === '1')?'Produktbestand':'Variantenbestand')
+ ),
+ '2' => __('Variantenbestand'),
+ '1' => __('Produktbestand')
+ ], $oProduct->getMeta('wpsg_vp_product_stock_display'), [
+ 'hint' => __('Bestimmt ob der Variantenbestand (Produktbestand + Variantenbestand) oder nur der Produktbestand im Frontend angezeigt werden soll.', 'wpsg')
+ ]); ?>
+
+ <?php } ?>
<?php /* Mailbenachrichtigung beim Erreichen des Minimalbestandes des Produktes */ ?>
<?php if ($this->get_option('wpsg_mod_stock_minstockproduct') == '1') { ?>
diff --git a/views/mods/mod_ticket/basket_row.phtml b/views/mods/mod_ticket/basket_row.phtml new file mode 100755 index 0000000..a04669e --- /dev/null +++ b/views/mods/mod_ticket/basket_row.phtml @@ -0,0 +1,21 @@ +<?php + + /** + * Template für die Integration der Produktvariablen innerhalb des Warenkorbs + */ + + namespace wpsgTicket; + + /** @var Ticket $oTicket */ + $oTicket = $this->view['oTicket']; + +?> + +<div class="product_info"> + <div class="title"> + <?php echo __('Datum', 'wpsg'); ?> + </div> + <div class="value"> + <?php echo $oTicket->getLabel(); ?> + </div> +</div>
\ No newline at end of file diff --git a/views/mods/mod_ticket/order_view.phtml b/views/mods/mod_ticket/order_view.phtml new file mode 100644 index 0000000..06a16aa --- /dev/null +++ b/views/mods/mod_ticket/order_view.phtml @@ -0,0 +1,125 @@ +<?php + + declare(strict_types=1); + + /** + * @author: Daniel Schmitzer (daniel@maennchen1.de) + * @date: 03.12.23 + * @time: 15:14 + */ + + namespace wpsgTicket; + + /** @var \wpsg_order $oOrder */ + $oOrder = \wpsg_order::getInstance(intval($this->view['data']['id'])); + + $data = []; + + foreach ($oOrder->getOrderProducts() as $oOrderProduct) { + + if (intval($oOrderProduct->getMeta('ticket_id', false, 0)) > 0) { + + for ($amount_index = 0; $amount_index < $oOrderProduct->getAmount(); $amount_index++) { + + $oTicketBooking = TicketBooking::getInstanceByBookingKey(TicketBooking::encodeBookingKey($oOrderProduct->getId(), $amount_index)); + + $data[] = $oTicketBooking->toJSON(); + + } + + } + + } + +?> + +<?php echo wpsg_drawForm_AdminboxStart(__('Ticketbuchungen', 'wpsg')); ?> + <div id="order_view_app"> + + <table> + <thead> + <tr> + <th class="col_ticket"><?php echo __('Ticket', 'wpsg'); ?></th> + <th class="col_product"><?php echo __('Ticket Produkt', 'wpsg'); ?></th> + <th class="col_date"><?php echo __('Datum / Zeitraum', 'wpsg'); ?></th> + <th class="col_state"><?php echo __('Status', 'wpsg'); ?></th> + </tr> + </thead> + <tbody v-for="(row, i) in data"> + <tr> + <td class="col_ticket"> + <a :href="row.urls.pdf" target="_blank">{{row.label}}</a> + </td> + <td class="col_product"> + <a :href="row.urls.product_edit">{{row.ticket_product_label}}</a> + </td> + <td class="col_date">{{row.ticket_data.label}}</td> + <td class="col_state"> + <span :class="{'text-red': row.state_code === <?php echo TicketBooking::STATUS_UNAVAILABLE; ?>, 'text-green': row.state_code === <?php echo TicketBooking::STATUS_AVAILABLE; ?>}">{{row.state_label}}</span> + <span v-if="row.is_send" :title="row.is_send_tooltip" class="ml-4 glyphicon glyphicon-send text-green"></span> + </td> + </tr> + <template v-if="row.arProductVars.length > 0"> + <template v-for="(pv_data, pv_id) of row.arProductVars"> + <tr> + <td colspan="2"> + {{pv_data['name']}}: + </td> + <td colspan="2"> + {{pv_data['value']}} + </td> + </tr> + </template> + </template> + </tbody> + </table> + + <br /> + + <div class="flex items-center gap-2"> + + <a href="<?php echo \add_query_arg([ + 'action' => 'wpsg_ticket', + 'ticket_action' => 'export', + 'order_id' => $oOrder->getId() + ], \admin_url('admin-ajax.php')); ?>" target="_blank" class="button"><?php echo __('Terminübersicht exportieren', 'wpsg'); ?></a> + + <a href="<?php echo \add_query_arg([ + 'action' => 'wpsg_ticket', + 'ticket_action' => 'resend', + 'order_id' => $oOrder->getId() + ], \admin_url('admin-ajax.php')); ?>" class="button"><?php echo __('Tickets per E-Mail an Kunden versenden', 'wpsg'); ?></a> + + </div> + + </div> + <style> + + #order_view_app table { width:100%; } + #order_view_app table tr td { padding:0.25rem 0.5rem 0.25rem 0; border-bottom:1px solid #DEDEDE; } + #order_view_app table tr th { border-bottom:1px solid black; } + #order_view_app .text-red { color:red; } + #order_view_app .text-green { color:green; } + #order_view_app .flex { display:flex; } + #order_view_app .items-center { align-items:center; } + #order_view_app .ml-4 { margin-left:1rem; } + #order_view_app .gap-2 { gap:0.5rem; } + + </style> +<?php echo wpsg_drawForm_AdminboxEnd(); ?> + +<script type="module"> + + const wpsgSettings = { + baseUrl: '<?php echo WPSG_URL; ?>' + }; + + import { order_view } from '<?php echo WPSG_URL; ?>mods/mod_ticket/assets/js/wpsg_order_view.js'; + + order_view(wpsgSettings, <?php echo json_encode([ + 'order_id' => $oOrder->getId(), + 'data' => $data, + 'ajax_url' => \admin_url('admin-ajax.php') + ]); ?>); + +</script> diff --git a/views/mods/mod_ticket/order_view_row.phtml b/views/mods/mod_ticket/order_view_row.phtml new file mode 100755 index 0000000..961bdcc --- /dev/null +++ b/views/mods/mod_ticket/order_view_row.phtml @@ -0,0 +1,41 @@ +<?php + + /** + * Anzeige des Variantennamens in der Bestellverwaltung + */ + + namespace wpsgTicket; + + $i = $this->view['i']; + $p = $this->view['p']; + + /** @var Ticket $oTicket */ + $oTicket = $this->view['oTicket']; + + /** @var \wpsg_order_product $oOrderProduct */ + $oOrderProduct = $this->view['oOrderProduct']; + +?> + +<tr class="wpsg_<?php echo (($i % 2 == 0)?'odd':'even'); ?>"> + <td class="wpsg_cell_name"> + <?php echo __('Datum', 'wpsg'); ?>: + </td> + <td class="wpsg_cell_ticket text-right" colspan="<?php echo ((sizeof($this->view['arCalculation']['tax']) > 1 || $this->get_option('wpsg_showMwstAlways') == '1')?4:3); ?>"> + <?php echo $oTicket->getLabel(); ?> + </td> +</tr> +<tr class="wpsg_<?php echo (($i % 2 == 0)?'odd':'even'); ?>"> + <td class="wpsg_cell_name"> + <?php if ($p['amount'] > 1) { ?> + <?php echo __('Tickets', 'wpsg'); ?>: + <?php } else { ?> + <?php echo __('Ticket', 'wpsg'); ?>: + <?php } ?> + </td> + <td class="wpsg_cell_ticket text-right" colspan="<?php echo ((sizeof($this->view['arCalculation']['tax']) > 1 || $this->get_option('wpsg_showMwstAlways') == '1')?4:3); ?>"> + <?php for ($i = 0; $i < $p['amount']; $i ++) { ?> + <a target="_blank" href="<?php echo $oTicket->getTicketPublicURL($oOrderProduct->getId(), $i); ?>">Ticket #<?php echo $i + 1; ?></a> + <?php } ?> + </td> +</tr> diff --git a/views/mods/mod_ticket/product_addedit_content.phtml b/views/mods/mod_ticket/product_addedit_content.phtml new file mode 100644 index 0000000..2d1870d --- /dev/null +++ b/views/mods/mod_ticket/product_addedit_content.phtml @@ -0,0 +1,526 @@ +<?php + + declare(strict_types=1); + + /** + * @author: Daniel Schmitzer (daniel@maennchen1.de) + * @date: 14.10.23 + * @time: 07:56 + */ + + namespace wpsgTicket; + + $oProduct = \wpsg_product::getInstance($this->view['data']['id']); + + \wpsg_drawForm_AdminboxStart(__('Ticketprodukt', 'wpsg')); + + $arTicketTemplate = []; + foreach (TicketTemplate::find([], null, true) as $oTicketTemplate) $arTicketTemplate[$oTicketTemplate->getId()] = $oTicketTemplate->getLabel(); + +?> + +<script type="module"> + + import { product_addedit_content } from '<?php echo WPSG_URL; ?>mods/mod_ticket/assets/js/wpsg_ticket.js'; + + const wpsgSettings = { + baseUrl: '<?php echo WPSG_URL; ?>' + }; + + product_addedit_content(wpsgSettings, <?php echo $oProduct->getId(); ?>, '<?php echo \admin_url('admin-ajax.php'); ?>'); + +</script> + +<?php echo wpsg_drawForm_Checkbox('meta[ticket_product]', __('Produkt ist ein Ticket Produkt', 'wpsg'), $oProduct->getMeta('ticket_product', false, '0')); ?> + +<hr /> + +<div id="wpsg_ticket_product" style="display:none;"> + + <?php echo wpsg_drawForm_Select('meta[ticket_template]', __('Ticket Template', 'wpsg'), $arTicketTemplate, $oProduct->getMeta('ticket_template', false, '0')); ?> + + <template v-if="mounted"> + + <br /> + + <div class="flex justify-between"> + <div class="flex gap-2 items-center"> + <a href="#" @click.prevent="addSerialevent" class="button"><?php echo __('Neuen Serientermin definieren', 'wpsg'); ?></a> + <a href="#" @click.prevent="addEvent" class="button"><?php echo __('Neuen Einzeltermin anlegen', 'wpsg'); ?></a> + <a href="<?php echo \add_query_arg([ + 'action' => 'wpsg_ticket', + 'ticket_action' => 'export', + 'ticket_product_id' => $oProduct->getId() + ], \admin_url('admin-ajax.php')); ?>" target="_blank" class="button"><?php echo __('Terminübersicht exportieren', 'wpsg'); ?></a> + </div> + <a href="/wp-admin/admin.php?page=wpsg-Admin&action=module&modul=wpsg_mod_ticket"><?php echo __('Zur Modulkonfiguration', 'wpsg'); ?></a> + </div> + + <br /> + + <div class="nav nav-tabs"> + <li :class="{'active': tab === 2}"><a @click.prevent="tab = 2" href="#"><?php echo __('Serientermine', 'wpsg'); ?></a></li> + <li :class="{'active': tab === 1}"><a @click.prevent="tab = 1" href="#"><?php echo __('Termine', 'wpsg'); ?></a></li> + <li :class="{'active': tab === 3}"><a @click.prevent="tab = 3" href="#"><?php echo __('Belegungsansicht', 'wpsg'); ?></a></li> + </div> + <div class="tab-content"> + <div v-if="tab === 1" class="ticket_list"> + <div class="head"> + <div class="tablenav"> + <div class="flex justify-between items-center grow pr-4"> + <label> + <input type="checkbox" v-model="data.filter.hideInactive" @change="reload" /><span><?php echo __('Nur buchbare Termine anzeigen', 'wpsg'); ?></span> + </label> + <select style="width:200px;" v-if="data_serial.items.length > 0" v-model.number="data.filter.autoticket_id" @change="load()"> + <option :value="0"><?php echo __('Alle', 'wpsg'); ?></option> + <template v-for="(st, i) of data_serial.items"> + <option :value="st.id">{{st.label}}</option> + </template> + </select> + </div> + <span class="tablenav-pages" v-if="data.pager.count > 0"> + <span class="displaying-num">{{data.pager.count}} Tickets</span> + <span class="pagination-links"> + <a href="#" @click.prevent="goPage(1)" class="tablenav-pages-navspan button" :class="{'disabled': data.pager.page <= 1}">«</a> + <a href="#" @click.prevent="goPage(data.pager.page - 1)" class="tablenav-pages-navspan button" :class="{'disabled': data.pager.page <= 1}">‹</a> + <span class="paging-input"> + <span class="tablenav-paging-text"> + <span class="total-pages">{{data.pager.page}}</span> + von + <span class="total-pages">{{data.pager.pages}}</span> + </span> + </span> + <a href="#" @click.prevent="goPage(data.pager.page + 1)" class="next-page button" :class="{'disabled': data.pager.page >= data.pager.pages}">›</a> + <a href="#" @click.prevent="goPage(data.pager.pages)" class="last-page button" :class="{'disabled': data.pager.page >= data.pager.pages}">»</a> + </span> + </span> + </div> + </div> + <div class="content" v-if="data.items.length > 0"> + + <table> + <thead> + <tr> + <th class="col_date"><?php echo __('Datum', 'wpsg'); ?></th> + <th class="col_order"><?php echo __('Bestellungen', 'wpsg'); ?></th> + <th class="col_slots"><?php echo __('Slots', 'wpsg'); ?></th> + <th class="col_state"><?php echo __('Status', 'wpsg'); ?></th> + </tr> + </thead> + <tbody v-for="(t, i) of data.items"> + <tr> + <td class="col_date">{{t.label}}</td> + <td class="col_order"></td> + <td class="col_slots"> + {{t.slots_used}} / {{t.slots}} + </td> + <td class="col_state"> + <div class="inner"> + + <span v-if="t.state === 1" class="active"><?php echo __('aktiv', 'wpsg'); ?></span> + <span v-else-if="t.state === 2" class="inactive"><?php echo __('inaktiv', 'wpsg'); ?></span> + + <span> / </span> + + <span v-if="t.booking_state === 1" class="text-green"><?php echo __('buchbar', 'wpsg'); ?></span> + <span v-else-if="t.booking_state === 2" class="text-red"> + <span v-if="t.slots_used >= t.slots_available"> + <?php echo __('ausgebucht', 'wpsg'); ?> + </span> + <span v-else> + <?php echo __('ausgelaufen', 'wpsg'); ?> + </span> + </span> + + </div> + </td> + </tr> + <tr> + <td class="col_action"> + <div class="inner"> + <a href="#" @click.prevent="changeTerminState(t)"> + <span v-if="t.state === 1"><?php echo __('deaktivieren', 'wpsg'); ?></span> + <span v-else-if="t.state === 2"><?php echo __('aktivieren', 'wpsg'); ?></span> + </a> + <span> | </span> + <a href="#" @click.prevent="deleteTicket(t)"><?php echo __('löschen', 'wpsg'); ?></a> + </div> + </td> + <td class="col_order" colspan="2"> + <template v-if="t.order.length > 10"> + {{t.order.length}} Bestellungen + </template> + <span v-else class="flex flex-wrap gap-4"> + <span v-for="(o, i2) of t.order"><a :href="o.order_link">{{o.order_nr}}</a> ({{o.amount}})</span> + </span> + </td> + <td> + <template v-if="t.autoticket_id > 0"> + <a title="<?php echo __('Termine dieses Serientermins anzeigen', 'wpsg'); ?>" href="#" @click.prevent="display_autoTermin(t.autoticket_id)"><?php echo __('Serientermin'); ?> #{{t.autoticket_id}}</a> + </template> + </td> + </tr> + </tbody> + </table> + + </div> + </div> + <div v-if="tab === 2" class="ticket_serial ticket_list"> + <div class="head"> + <div class="tablenav"> + <div></div> + <span class="tablenav-pages" v-if="data_serial.pager.count > 0"> + <span class="displaying-num">{{data_serial.pager.count}} Serientermine</span> + <span class="pagination-links"> + <a href="#" @click.prevent="goSerialPage(1)" class="tablenav-pages-navspan button" :class="{'disabled': data_serial.pager.page <= 1}">«</a> + <a href="#" @click.prevent="goSerialPage(data_serial.pager.page - 1)" class="tablenav-pages-navspan button" :class="{'disabled': data_serial.pager.page <= 1}">‹</a> + <span class="paging-input"> + <span class="tablenav-paging-text"> + <span class="total-pages">{{data_serial.pager.page}}</span> + von + <span class="total-pages">{{data_serial.pager.pages}}</span> + </span> + </span> + <a href="#" @click.prevent="goSerialPage(data_serial.pager.page + 1)" class="next-page button" :class="{'disabled': data_serial.pager.page >= data_serial.pager.pages}">›</a> + <a href="#" @click.prevent="goSerialPage(data_serial.pager.pages)" class="last-page button" :class="{'disabled': data_serial.pager.page >= data_serial.pager.pages}">»</a> + </span> + </span> + </div> + </div> + <div class="content" v-if="data_serial.items.length > 0"> + + <table> + <thead> + <tr> + <th class="col_date"><?php echo __('Datum', 'wpsg'); ?></th> + <th class="col_tickets"><?php echo __('Termine', 'wpsg'); ?></th> + <th class="col_state"><?php echo __('Status', 'wpsg'); ?></th> + </tr> + </thead> + <tbody v-for="(t, i) of data_serial.items"> + <tr> + <td class="col_date"> + <a href="#" title="<?php echo __('Termine dieses Serientermins anzeigen', 'wpsg'); ?>" @click.prevent="display_autoTermin(t.id)">{{t.label}}</a> + </td> + <td class="col_tickets">{{t.count_tickets}}</td> + <td class="col_state"> + <div class="inner"> + + <span v-if="t.state === 1" class="active"><?php echo __('aktiv', 'wpsg'); ?></span> + <span v-else-if="t.state === 2" class="inactive"><?php echo __('inaktiv', 'wpsg'); ?></span> + + </div> + </td> + </tr> + <tr> + <td class="col_action"> + <div class="inner"> + <a href="#" @click.prevent="editTicket(t)"> + <?php echo __('bearbeiten', 'wpsg'); ?> + </a> + <span> | </span> + <a href="#" @click.prevent="changeTerminState(t)"> + <span v-if="t.state === 1"><?php echo __('deaktivieren', 'wpsg'); ?></span> + <span v-else-if="t.state === 2"><?php echo __('aktivieren', 'wpsg'); ?></span> + </a> + <span> | </span> + <a href="#" @click.prevent="deleteTicket(t)"><?php echo __('löschen', 'wpsg'); ?></a> + </div> + </td> + <td class="col_order" colspan="2"> + <template v-if="t.order.length > 10"> + {{t.order.length}} Bestellungen + </template> + <span v-else class="flex flex-wrap gap-4"> + <span v-for="(o, i2) of t.order"><a :href="o.order_link">{{o.order_nr}}</a> ({{o.amount}})</span> + </span> + </td> + </tr> + </tbody> + </table> + + </div> + </div> + <div v-if="tab === 3" class="ticket_cal relative"> + <div class="flex"> + <div id="calendar" ref="ref_calendar"></div> + <div v-if="arOccupancy && day_selected" class="occupancy_view"> + + <template v-for="(t, i) of arOccupancy[day_selected].arTicket"> + + <h3> + <span><?php echo __('Ticket', 'wpsg'); ?> #{{t.id}} {{t.label}}</span> + <span>{{t.slots}} <?php echo __('Slots', 'wpsg'); ?></span> + </h3> + + <ul> + <template v-for="(o, j) of t.order"> + <li> + <a :href="o.order_link"><?php echo __('Bestellung', 'wpsg'); ?> {{o.order_nr}} / {{o.order_invoice_name}}</a> + <span>{{o.amount}} <?php echo __('Slots', 'wpsg'); ?></span> + </li> + </template> + </ul> + + </template> + + </div> + </div> + <div v-if="cal_loading" class="loading_layer"> + <img src="<?php echo WPSG_URL; ?>views/gfx/ajax-loader.gif" alt="<?php echo __('Bitte warten ...', 'wpsg'); ?>" /> + </div> + </div> + </div> + + <div class="dialog" v-if="dialog_add"> + <form class="inner" @submit.stop.prevent="dialog_submit"> + <div class="head"> + <span><?php echo __('Neue Termine', 'wpsg'); ?></span> + <a href="#" @click.prevent="closeDialog">X</a> + </div> + <div class="content"> + <div class="form_col"> + <div class="form_field"> + <label> + <?php echo __('Start', 'wpsg'); ?> + </label> + <div class="flex gap-2 items-center"> + <input type="date" v-model="dialog_add.from_date" required="required" /> + <input type="time" v-model="dialog_add.from_time" /> + </div> + </div> + <div class="form_field"> + <label> + <?php echo __('Ende', 'wpsg'); ?> + </label> + <div class="flex gap-2 items-center"> + <input type="date" v-model="dialog_add.to_date" /> + <input type="time" v-model="dialog_add.to_time" /> + </div> + </div> + <div class="form_field"> + <label> + <?php echo __('Anzahl Slots', 'wpsg'); ?> + </label> + <div class="flex gap-2 items-center"> + <input type="number" min="1" max="100" v-model="dialog_add.slots" /> + </div> + </div> + <p style="max-width:500px; padding-top:1rem;"> + <?php echo __('Ein Termin kann so oft gebucht/bestellt werden wie freie Slots verfügbar sind und er in der Zukunft liegt. Ein Termin kann über mehrere Tage gehen, dann wird der gesammte Zeitraum gebucht. Wird eine Startzeit angegeben, muss auch eine Endzeit angegeben werden', 'wpsg'); ?> + </p> + </div> + </div> + <div class="foot"> + <input type="submit" class="button button-primary" value="<?php echo __('Termin anlegen', 'wpsg'); ?>" /> + </div> + </form> + </div> + + <div class="dialog" v-if="serial"> + <form class="inner" @submit.stop.prevent="submitSerial"> + <div class="head"> + <span v-if="serial.id > 0"><?php echo __('Serientermin bearbeiten', 'wpsg'); ?></span> + <span v-else><?php echo __('Neuen Serientermin definieren', 'wpsg'); ?></span> + <a href="#" @click.prevent="closeSerialDialog">X</a> + </div> + <div class="content"> + <div class="form_col"> + <div class="form_field"> + <label><?php echo __('Bezeichnung (optional)', 'wpsg'); ?></label> + <div> + <input type="text" v-model="serial.label" style="width:275px;" /> + </div> + </div> + <div class="form_field"> + <label><?php echo __('Kurztext (Kalender)', 'wpsg'); ?></label> + <div> + <input type="text" v-model="serial.label_short" style="width:275px;" /> + </div> + </div> + <div class="form_field"> + <label> + <?php echo __('Zeitraum', 'wpsg'); ?> + </label> + <div class="flex gap-2 items-center justify-between grow"> + <input type="date" v-model="serial.from_date" required style="width:125px;" /> + <span>-</span> + <input type="date" v-model="serial.to_date" required style="width:125px;" /> + </div> + </div> + <div class="form_field"> + <label> + <?php echo __('Uhrzeit (optional)', 'wpsg'); ?> + </label> + <div class="flex gap-2 items-center justify-between grow"> + <input type="time" v-model="serial.event_data.from_time" style="width:125px;" /> + <span>-</span> + <input type="time" v-model="serial.event_data.to_time" style="width:125px;" /> + </div> + </div> + <div class="form_field"> + <label> + <?php echo __('Slots', 'wpsg'); ?> + </label> + <div class="flex gap-2 items-center"> + <input type="number" v-model.number="serial.event_data.slots" style="width:275px;" /> + </div> + </div> + <div class="form_field"> + <label> + <?php echo __('Tage im voraus planen', 'wpsg'); ?> + </label> + <div class="flex gap-2 items-center"> + <select v-model.number="serial.days_future" class="w-full" style="width:275px;"> + <option value="30">30</option> + <option value="60">60</option> + <option value="90">90</option> + </select> + </div> + </div> + <div class="form_field"> + <label> + <?php echo __('Wochentage', 'wpsg'); ?> + </label> + <div class="weekday_wrap"> + <label v-for="i in 7"> + <div> + <template v-if="i === 1">Mo</template> + <template v-if="i === 2">Die</template> + <template v-if="i === 3">Mi</template> + <template v-if="i === 4">Do</template> + <template v-if="i === 5">Fr</template> + <template v-if="i === 6">Sa</template> + <template v-if="i === 7">So</template> + </div> + <div> + <input type="checkbox" @change="setWeekDay($event, i - 1)" :checked="serial.days.includes(i - 1)" /> + </div> + </label> + </div> + </div> + <div v-if="serial.id > 0"> + <br /> + <?php echo __('Eine Bearbeitung des Serientermins wirkt sich nur auf', 'wpsg'); ?><br /> + <?php echo __('zukünftige Termine dieses Serientermins aus.', 'wpsg'); ?> + </div> + </div> + </div> + <div class="foot"> + <input v-if="serial.id > 0" type="submit" class="button button-primary" value="<?php echo __('Serientermin speichen', 'wpsg'); ?>" /> + <input v-else type="submit" class="button button-primary" value="<?php echo __('Serientermin + Termine anlegen', 'wpsg'); ?>" /> + </div> + </form> + </div> + + <div v-if="loading" class="loading_layer"> + <img src="<?php echo WPSG_URL; ?>views/gfx/ajax-loader.gif" alt="<?php echo __('Bitte warten ...', 'wpsg'); ?>" /> + </div> + + </template> +</div> + +<style> + + #wpsg_ticket_product .occupancy_view { padding-left:2rem; flex-grow:1; + h3 { padding:0; display:flex; justify-content:space-between; align-items:flex-start; margin:1.5rem 0 1rem 0; + * { font-size:14px; font-weight:bold; line-height:1.5rem; } + } + ul { padding-left:1.5rem; font-size:14px; + li { list-style:disc; display:flex; align-items:flex-start; justify-content:space-between; position:relative; + &:before { content:'-'; position:absolute; margin-left:-1rem; } + } + } + pre { white-space:break-spaces; } + } + #wpsg_ticket_product .flex { display:flex; } + #wpsg_ticket_product .items-center { align-items:center; } + #wpsg_ticket_product .justify-between { justify-content:space-between; } + #wpsg_ticket_product .grow { flex-grow:1; } + #wpsg_ticket_product .pr-4 { padding-right:1rem; } + #wpsg_ticket_product label { margin-bottom:0; } + #wpsg_ticket_product .dialog { position:fixed; left:0; top:0; height:100dvh; width:100dvw; background-color:rgba(0, 0, 0, 0.75); z-index:99999; display:flex; justify-content:center; align-items:center; } + #wpsg_ticket_product .dialog > .inner { background-color:white; border:1px solid black; min-width:500px; min-height:275px; display:flex; flex-direction:column; } + #wpsg_ticket_product .dialog > .inner > .head { padding:1rem 2rem; border-bottom:1px solid black; font-weight:bold; font-size:1em; display:flex; align-items:center; justify-content:space-between; } + #wpsg_ticket_product .dialog > .inner > .head a { color:black; font-weight:bold; font-size:1.5em; } + #wpsg_ticket_product .dialog > .inner > .head a:hover { text-decoration:none !important; } + #wpsg_ticket_product .dialog > .inner > .content { padding:1rem 2rem; flex-grow:1; } + #wpsg_ticket_product .dialog > .inner > .foot { padding:1rem 2rem; } + #wpsg_ticket_product .dialog > .inner .form_field { display:flex; align-items:center; justify-content:flex-start; } + #wpsg_ticket_product .dialog > .inner .form_field label { width:200px; } + #wpsg_ticket_product .dialog > .inner .form_col { display:flex; flex-direction:column; gap:0.5rem; } + #wpsg_ticket_product .ticket_list { display:flex; flex-direction:column; } + #wpsg_ticket_product .ticket_list .head .tablenav { display:flex; justify-content:space-between; align-items:center; padding-top:0;} + #wpsg_ticket_product .ticket_list .head .tablenav label { display:flex; justify-content:flex-start; align-items:center; gap:0.5rem; font-weight:normal; } + #wpsg_ticket_product .ticket_list .head .tablenav label input { margin:0; } + #wpsg_ticket_product .ticket_list .head .tablenav-pages { display:flex; align-items:center; justify-content:flex-start; margin:0; } + #wpsg_ticket_product .ticket_list .head .pagination-links { display:flex; align-items:center; justify-content:flex-start; gap:0.5rem; } + #wpsg_ticket_product .ticket_list .content { border:1px solid #c3c4c7; padding:0; } + #wpsg_ticket_product .ticket_list .content table { width:100%; } + #wpsg_ticket_product .ticket_list .content table thead tr th { border-bottom:1px solid #c3c4c7; } + #wpsg_ticket_product .ticket_list .content table > * > tr > * { padding:3px 5px 0px 5px; text-align:center; } + #wpsg_ticket_product .ticket_list .content table > * > tr > *:first-child { text-align:left; } + #wpsg_ticket_product .ticket_list .content table > * > tr > *:last-child { text-align:right; } + #wpsg_ticket_product .ticket_list .content table > * > tr > .col_action { padding-top:0; padding-bottom:3px; } + #wpsg_ticket_product .ticket_list .content table > * > tr > .col_action > .inner { display:flex; gap:0.5rem; justify-content:flex-start; align-items:center; flex-wrap:wrap; } + #wpsg_ticket_product .ticket_list .content table > * > tr > .col_date { width:250px; } + #wpsg_ticket_product .ticket_list .content table > * > tr > .col_order { text-align:left; padding-bottom:3px; } + #wpsg_ticket_product .ticket_list .content table > * > tr > .col_state .inner { display:flex; justify-content:flex-end; align-items:center; gap:0.5rem; } + #wpsg_ticket_product .ticket_list .content table > *:nth-child(even) > tr > * { background-color:#f6f7f7; } + #wpsg_ticket_product .ticket_list .content table .inactive, + #wpsg_ticket_product .text-red { color:red; } + #wpsg_ticket_product .ticket_list .content table .active, + #wpsg_ticket_product .text-green { color:green; } + #wpsg_ticket_product .flex { display:flex; } + #wpsg_ticket_product .grow { flex-grow:1; } + #wpsg_ticket_product .flex-wrap { flex-wrap:wrap; } + #wpsg_ticket_product .gap-2 { gap:0.5rem; } + #wpsg_ticket_product .gap-4 { gap:1rem; } + #wpsg_ticket_product .relative { position:relative; } + #wpsg_ticket_product { position:relative; padding:1rem 0; } + #wpsg_ticket_product .loading_layer { position:absolute; left:0; top:0; width:100%; height:100%; transition:all 0.1s; display:flex; align-items:center; justify-content:center; background-color:rgba(255, 255, 255, 0.75); } + #wpsg_ticket_product .ticket_cal { all:initial !important; font-family:'Arial' !important; } + #wpsg_ticket_product .ticket_cal * { font-family:'Arial' !important; } + #wpsg_ticket_product .ticket_cal .vanilla-calendar-week__day { font-size:12px !important; } + #wpsg_ticket_product .vanilla-calendar-month, + #wpsg_ticket_product .vanilla-calendar-year { font-size:14px !important; font-family:'Arial' !important; } + #wpsg_ticket_product .vanilla-calendar-days { column-gap:15px; } + #wpsg_ticket_product .vanilla-calendar-days { row-gap:0.5rem; } + #wpsg_ticket_product .vanilla-calendar-day__btn { font-size:1rem; } + #wpsg_ticket_product .vanilla-calendar-day__btn:not(.vanilla-calendar-day__btn_disabled) { background-color:#fde047; color:black; } + #wpsg_ticket_product .vanilla-calendar-day__btn.full { background-color:green; color:white; } + #wpsg_ticket_product .weekday_wrap { display:flex; flex-grow:1; justify-content:space-between; align-items:flex-start; } + #wpsg_ticket_product .weekday_wrap > label { display:flex; flex-direction:column; gap:0.125rem; width:initial !important; margin-bottom:0 !important; } + +</style> + +<script> + + const el_ticket_product = document.getElementById('metaticket_product'); + const el_wpsg_ticket_product = document.getElementById('wpsg_ticket_product'); + const el_basket_multiple = document.getElementById('basket_multiple'); + + el_ticket_product.addEventListener('change', (event) => { + + if (event.target.checked) { + + el_basket_multiple.disabled = true; + el_basket_multiple.selectedIndex = 2; + wpsg_ticket_product.style.display = 'block'; + + } else { + + el_basket_multiple.disabled = false; + wpsg_ticket_product.style.display = 'none'; + + } + + }); + + el_ticket_product.dispatchEvent(new Event('change')); + +</script> + +<?php + + \wpsg_drawForm_AdminboxEnd();
\ No newline at end of file diff --git a/views/mods/mod_ticket/produkttemplate.phtml b/views/mods/mod_ticket/produkttemplate.phtml new file mode 100644 index 0000000..47d9cbc --- /dev/null +++ b/views/mods/mod_ticket/produkttemplate.phtml @@ -0,0 +1,255 @@ +<?php + + declare(strict_types=1); + + /** + * @author: Daniel Schmitzer (daniel@maennchen1.de) + * @date: 21.10.23 + * @time: 15:42 + */ + + namespace wpsgTicket; + + /** @var \wpsg_product $oProduct */ + $oProduct = $this->view['oProduct']; + + $product_key = $this->view['data']['product_key']; + + /** @var TicketProduct $oTicketProduct */ + $oTicketProduct = TicketProduct::getInstance($oProduct->getId()); + + TicketProduct::$enqueTicket = true; + + $arTicket = $oTicketProduct->getAvailableTickets(); + + if (sizeof($arTicket) <= 0) { wpsg_debug(__('Keine Tickets verfügbar', 'wpsg')); return; } + + $arProductVars = false; + + if ($this->hasMod('wpsg_mod_productvars')) { + + $arProductVars = array_values($this->callMod('wpsg_mod_productvars', 'getAllProductVars', [$oTicketProduct->getProductId()])); + foreach ($arProductVars as $k => $v) $arProductVars[$k]['value'] = ''; + + } + + $json_data = [ + 'template_index' => $this->getTemplateIndex(), + 'ajax_url' => \admin_url('admin-ajax.php'), + 'product_id' => $oProduct->getId(), + 'product_key' => $product_key, + 'price' => $oProduct->getPrice($product_key, \wpsg_ShopController::getShop()->getFrontendTaxview()), + 'product_vars' => $arProductVars + ]; + + if ($this->hasMod('wpsg_mod_productvariants')) { + + if ($this->callMod('wpsg_mod_productvariants', 'isVariantsProductKey', [$product_key])) { + + $product_id = $this->getProduktID($product_key); + $json_data['vp_data'] = $this->callMod('wpsg_mod_productvariants', 'getVariants', [$product_id, true, true, true]); + $json_data['vp_info'] = $this->callMod('wpsg_mod_productvariants', 'getVariantenInfoArray', [$product_key]); + + foreach ($json_data['vp_data'] as $k => $v) { + + foreach ($v['arVariation'] as $k2 => $v2) { + + $simulated_product_key = $this->callMod('wpsg_mod_productvariants', 'getSimulatedVariKey', array($this->view['data']['product_key'], $v['id'], $v2['variation_id'])); + $attachmentID = $this->imagehandler->getAttachmentID($simulated_product_key); + $json_data['vp_data'][$k]['arVariation'][$k2]['img'] = \wp_get_attachment_image($attachmentID, 'thumbnail'); + + } + + } + + } + + } + +?> + +<div class="wpsg_ticket_product"> + <div style="display:none;" class="json_data"><?php echo base64_encode(json_encode($json_data)); ?></div> + <template v-if="mounted"> + + <div v-if="layer_msg" class="layer_msg"> + <div class="inner"> + <div class="msg">{{layer_msg}}</div> + <div class="button_wrap"> + <a class="wp-element-button" href="#" @click.prevent="layer_msg = undefined;"><?php echo __('OK', 'wpsg'); ?></a> + <a class="wp-element-button" href="<?php echo \wpsg_ShopController::getShop()->getURL(\wpsg_ShopController::URL_BASKET); ?>"><?php echo __('Zum Warenkorb', 'wpsg'); ?></a> + </div> + </div> + </div> + + <div class="wpsg_produkt wpsg_product_name"> + + <?php if (!$this->titleDisplayed) { ?> + <h1 class="wpsg_producttitle"><?php echo $oProduct->getProductName(); ?></h1> + <h2 class="wpsg_productdetailtitle"><?php echo $this->view['data']['detailname']; ?></h2> + <?php } ?> + + <?php $this->callMods('product_top_afterheadline', array(&$this->view['data']['id'], $this->getTemplateIndex())); ?> + + </div> + + <?php $this->callMods('product_top', array(&$this->view['data']['id'], $this->getTemplateIndex())); ?> + + <?php /* Block für die Produktbilder START */ ?> + <?php + + /* Das ist das primäre Anzeigebild des Produktes (AttachmentID) */ + $arAttachmentID = $this->imagehandler->getAttachmentID($this->view['data']['product_key']); + + /* Array mit allen AttachmentIDs der Produktbilder */ + $arAttachmentIDsAll = $this->imagehandler->getAttachmentIDs($this->view['data']['product_id']); + + ?> + + <div class="product_top"> + <?php if (sizeof($arAttachmentIDsAll) > 0) { ?> + <div class="wpsg_productimages"> + + <div class="wpsg_produkt_produktbilder"> + + <?php if (sizeof($arAttachmentIDsAll) > 0) { for ($i = 0; $i < sizeof($arAttachmentIDsAll); $i ++) { ?> + + <?php /* URL für die Lightbox */ ?> + <?php $att = \wp_get_attachment_image_src($arAttachmentIDsAll[$i], array(800, 600), false); ?> + + <meta itemprop="image" content="<?php echo $att[0]; ?>" /> + + <a <?php if ($arAttachmentIDsAll[$i] != $arAttachmentID) echo 'style="display:none;"'; ?> data-fslightbox="<?php echo $this->getTemplateIndex(); ?>" title="<?php echo $oProduct->getProductName(); ?>" href="<?php echo $att[0]; ?>"> + + <?php echo \wp_get_attachment_image($arAttachmentIDsAll[$i], array(600, 600), false, array()); ?> + + </a> + + <?php } } ?> + + </div> + + </div> + <?php } ?> + <?php /* Block für die Produktbilder ENDE */ ?> + <div class="product_top_content"> + + <?php if (strlen(trim($this->view['data']['beschreibung'])) > 0) { ?> + <div class="wpsg_product_information_short"> + <div class="wpsg_produkt_additional_information"> + <div itemprop="description" class="wpsg_produkt_shortdescription"> + <span><?php echo $this->view['data']['beschreibung']; ?></span> + </div> + </div> + </div> + <?php } ?> + + </div> + </div> + + <?php if (strlen(trim($this->view['data']['longdescription'])) > 0) { ?> + <div class="wpsg_product_information_long"> + <span><?php echo $this->view['data']['longdescription']; ?></span> + </div> + <?php } ?> + + <div class="calendar_wrap"> + <div ref="ref_calendar"></div> + </div> + + <div v-if="data.product_vars" class="variant_wrap"> + <template v-for="(pv, i) of data.product_vars"> + <div class="variant_row"> + <span>{{pv.name}}</span> + <span> + <template v-if="pv.typ === '1'"><!-- Auswahl --> + <select v-model="pv.value" :required="pv.pflicht === '1'" :name="'wpsg_mod_productvars[' + pv.id + ']'"> + <option value=""><?php echo __('Bitte auswählen', 'wpsg'); ?></option> + <option v-for="(option, i) of pv.auswahl.split('|')" :value="option"> + {{option}} + </option> + </select> + </template> + <template v-else-if="pv.typ === '2'"><!-- Textzeile --> + <input type="text" v-model="pv.value" :required="pv.pflicht === '1'" :name="'wpsg_mod_productvars[' + pv.id + ']'" /> + </template> + <template v-else-if="pv.typ === '4'"><!-- Textfeld --> + <textarea v-model="pv.value" :required="pv.pflicht === '1'" :name="'wpsg_mod_productvars[' + pv.id + ']'"></textarea> + </template> + <template v-else-if="pv.typ === '3'"><!-- Checkbox --> + <input type="checkbox" value="1" v-model="pv.value" :required="pv.pflicht === '1'" :name="'wpsg_mod_productvars[' + pv.id + ']'" /> + </template> + </span> + </div> + </template> + </div> + + <div v-if="data.vp_data" class="variant_wrap"> + <template v-for="(vp, i) of data.vp_data"> + <div v-if="(vp.deleted + vp.count_variation) !== 1" class="variant_row"> + <span>{{vp.name}}</span> + <span> + <select v-if="vp.type == '<?php echo \wpsg_mod_productvariants::TYPE_SELECT; ?>'" @change="setVari(vp.id, $event.target.value)"> + <template v-for="(o, j) of vp.arVariation"> + <option v-if="o.active" :value="o.variation_id" :checked="((data.vp_info[vp.id]['vari_id'] === o.id)?'checked':'')"> + {{o.name}} <?php if ($this->get_option('wpsg_mod_productvariants_price') === '1') { ?>(+ {{ff(o.price)}} <?php echo $this->get_option('wpsg_currency'); ?>)<?php } ?> + </option> + </template> + </select> + <div v-else-if="vp.type == '<?php echo \wpsg_mod_productvariants::TYPE_RADIO; ?>'" class="radio_wrap"> + <template v-for="(o, j) of vp.arVariation"> + <label class="radio" v-if="o.active"> + + <input type="radio" :value="o.variation_id" :name="vp.id + 'radio'" v-if="data.vp_info[vp.id]['vari_id'] === o.id" checked="checked" /> + <input v-else type="radio" :value="o.id" :name="vp.id + 'radio'" @change.prevent="setVari(vp.id, o.id)" /> + + <span>{{o.name}} <?php if ($this->get_option('wpsg_mod_productvariants_price') === '1') { ?>(+ {{ff(o.price)}} <?php echo $this->get_option('wpsg_currency'); ?>)<?php } ?></span> + </label> + </template> + </div> + <div v-else-if="vp.type == '<?php echo \wpsg_mod_productvariants::TYPE_IMAGE; ?>'" class="image_wrap"> + <template v-for="(o, j) of vp.arVariation"> + <div class="image" v-if="o.active" :class="{'act': o.set}" @click="setVari(vp.id, o.variation_id)"> + <div v-html="o.img"></div> + </div> + </template> + </div> + </span> + </div> + </template> + </div> + + <div class="no_event" v-if="ticket === undefined"> + <?php echo __('Bitte einen Termin im Kalender wählen.', 'wpsg'); ?> + </div> + <template v-else> + + <div class="mt-8 flex justify-between items-center"> + <div> + <strong><?php echo __('Ausgewählter Termin: ', 'wpsg'); ?></strong>{{ticket.label}} + </div> + <div> + <?php if ($this->view['oProduct']->canDisplayPrice()) { ?> + <span class="price">{{ff(data.price)}} <?php echo $this->get_option('wpsg_currency'); ?></span> + <?php } ?> + </div> + </div> + + <div class="ticket_selection"> + <span> + <input v-if="ticket.slots !== 1" type="number" min="1" :max="ticket.slots" v-model="ticket.amount" /> + </span> + + <button type="submit" class="wp-element-button" :class="computedButtonClass"> + {{computedButtonText}} + </button> + </div> + + </template> + + <div v-if="loading" class="loading_layer"> + <!--<img src="<?php echo WPSG_URL; ?>views/gfx/ajax-loader.gif" alt="<?php echo __('Bitte warten ...', 'wpsg'); ?>" />--> + </div> + + </template> +</div> diff --git a/views/mods/mod_ticket/qrScanner.phtml b/views/mods/mod_ticket/qrScanner.phtml new file mode 100644 index 0000000..3b9bd59 --- /dev/null +++ b/views/mods/mod_ticket/qrScanner.phtml @@ -0,0 +1,221 @@ +<?php + + declare(strict_types=1); + + /** + * @author: Daniel Schmitzer (daniel@maennchen1.de) + * @date: 13.11.23 + * @time: 19:11 + */ + + namespace wpsgTicket; + +?> + +<div id="qr_scanner_app" style="display:none; padding-right:2rem; padding-top:2rem; max-height:400px;"> + + <div id="reader" style="width:500px;"></div> + + <div id="ticket_dialog" v-if="ticket_dialog"> + <div class="inner"> + + <div v-if="ticket_dialog.loading" class="loading_layer"> + <img src="<?php echo WPSG_URL; ?>views/gfx/ajax-loader.gif" alt="<?php echo __('Bitte warten ...', 'wpsg'); ?>" /> + </div> + + <div class="head"> + <div class="flex justify-between items-center"> + <div class="flex items-center justify-start"> + TicketBuchung #{{ticket_dialog.booking_id}} + <div class="button_wrap"> + <a @click="ticket_dialog.tab = 1" :class="{'active': ticket_dialog.tab === 1}"><?php echo __('Informationen', 'wpsg'); ?></a> + <a @click="ticket_dialog.tab = 2" :class="{'active': ticket_dialog.tab === 2}"><?php echo __('Protokoll', 'wpsg'); ?></a> + <a :href="ticket_dialog.urls.pdf" target="_blank"><?php echo __('PDF', 'wpsg'); ?></a> + <!--<a @click="ticket_dialog.tab = 3" :class="{'active': ticket_dialog.tab === 3}"><?php echo __('RAW', 'wpsg'); ?></a>--> + </div> + </div> + <div class="flex flex-items-center justify-end"> + <div :class="'state ' + 'state' + ticket_dialog.state_code"> + {{ticket_dialog.state_label}} + </div> + <a @click.prevent="hideDialg">X</a> + </div> + </div> + </div> + <div class="content"> + <template v-if="ticket_dialog.tab === 1"> + <div class="grid-cols-2 grid"> + <div> + <div class="form_row"> + <div class="form_label"><?php echo __('Ticket-Produkt', 'wpsg'); ?></div> + <div class="form_value"> + <a :href="ticket_dialog.urls.product_edit">{{ticket_dialog.ticket_product_label}}</a> + </div> + </div> + <div class="form_row"> + <div class="form_label"><?php echo __('Datum/Zeitraum', 'wpsg'); ?></div> + <div class="form_value" :class="{'text-red': ticket_dialog.time_raised}">{{ticket_dialog.ticket_data.label}}</div> + </div> + <div class="form_row"> + <div class="form_label"><?php echo __('Kaufpreis', 'wpsg'); ?></div> + <div class="form_value">{{ticket_dialog.order_product_price_ff}}</div> + </div> + </div> + <div> + <div class="form_row"> + <div class="form_label"><?php echo __('Bestellnummer', 'wpsg'); ?></div> + <div class="form_value"> + <a :href="ticket_dialog.urls.order_edit">{{ticket_dialog.order_nr}}</a> + </div> + </div> + <div class="form_row"> + <div class="form_label"><?php echo __('Bestellstatus', 'wpsg'); ?></div> + <div class="form_value" :class="{ + 'text-red': !ticket_dialog.wpsg_mod_ticket_orderstate_active.includes(ticket_dialog.order_state), + 'text-green': ticket_dialog.wpsg_mod_ticket_orderstate_active.includes(ticket_dialog.order_state) + }">{{ticket_dialog.order_state_label}}</div> + </div> + <div class="form_row"> + <div class="form_label"><?php echo __('Käufer', 'wpsg'); ?></div> + <div class="form_value">{{ticket_dialog.order_title}} {{ticket_dialog.order_firstname}} {{ticket_dialog.order_lastname}}</div> + </div> + </div> + </div> + <br /> + <div class="form_row form_row_1_4"> + <div class="form_label"><?php echo __('Ticket-Status', 'wpsg'); ?></div> + <div class="form_value"> + <span class="text-red" v-if="ticket_dialog.state_code === <?php echo TicketBooking::STATUS_UNAVAILABLE; ?>"> + {{ticket_dialog.revoke_text}} + </span> + <span class="text-green" v-if="ticket_dialog.state_code === <?php echo TicketBooking::STATUS_AVAILABLE; ?>"> + <?php echo __('Gültig', 'wpsg'); ?> + </span> + </div> + </div> + <br /> + <div v-if="ticket_dialog.sibling.length > 0"> + <strong><?php echo __('Zusammengkaufte Tickets', 'wpsg'); ?> ({{ticket_dialog.sibling.length}} Stück)</strong> + <table> + <thead> + <tr> + <td><?php echo __('Buchung', 'wpsg'); ?></td> + <td><?php echo __('Datum/Zeitraum', 'wpsg'); ?></td> + <td class="col_ticket_state"><?php echo __('Ticket-Status', 'wpsg'); ?></td> + </tr> + </thead> + <tbody v-for="(ts, i) of ticket_dialog.sibling"> + <tr> + <td><a @click.prevent="showTicket(ts.booking_id)" href="#">#{{ts.booking_id}}</a> <a :href="ts.urls.pdf" target="_blank">[<?php echo __('PDF', 'wpsg'); ?>]</a></td> + <td :class="{'text-red': ticket_dialog.time_raised}">{{ticket_dialog.ticket_data.label}}</td> + <td> + <span class="text-red" v-if="ts.state_code === <?php echo TicketBooking::STATUS_UNAVAILABLE; ?>"> + <span v-if="ts.revoked"> + <?php echo __('Entwertet', 'wpsg'); ?> + </span> + <template v-else> + <span v-if="ts.time_raised" class="text-red"><?php echo __('Ausgelaufen', 'wpsg'); ?></span> + <span v-else><?php echo __('Ungültig', 'wpsg'); ?></span> + </template> + </span> + <span class="text-green" v-if="ts.state_code === <?php echo TicketBooking::STATUS_AVAILABLE; ?>"> + <?php echo __('Gültig', 'wpsg'); ?> + [<a v-if="ts.state_code === <?php echo TicketBooking::STATUS_AVAILABLE; ?>" href="#" @click="revokeBooking(ts.booking_id, false)" class="revokeBooking">entwerten</a>] + </span> + </td> + </tr> + </tbody> + </table> + </div> + </template> + <div v-if="ticket_dialog.tab === 2"> + <table> + <thead> + <tr> + <th><?php echo __('Datum/Zeit', 'wpsg'); ?></th> + <th><?php echo __('Benutzer', 'wpsg'); ?></th> + <th><?php echo __('Aktion', 'wpsg'); ?></th> + </tr> + </thead> + <tbody v-for="(l, i) of ticket_dialog.log"> + <tr> + <td class="col_time">{{en_de_date_time(l.date_time)}}</td> + <td class="col_user">{{l.user_name}}</td> + <td> + <span class="text-green" v-if="l.log === <?php echo TicketBooking::LOG_SCAN; ?>"><?php echo __('gescannt', 'wpsg'); ?></span> + <span class="text-red" v-else-if="l.log === <?php echo TicketBooking::LOG_REVOKE; ?>"><?php echo __('entwertet', 'wpsg'); ?></span> + </td> + </tr> + </tbody> + </table> + </div> + <div v-if="ticket_dialog.tab === 3"> + <pre>{{ticket_dialog}}</pre> + </div> + </div> + <div class="foot" v-if="ticket_dialog.state_code === 1"> + <a href="#" @click="revokeBooking(ticket_dialog.booking_id)" v-if="ticket_dialog.state_code === 1" class="revokeBooking"><?php echo __('Ticket entwerten', 'wpsg'); ?></a> + </div> + </div> + </div> + +</div> + +<style> + + #qr_scanner_app .flex { display:flex; } + #qr_scanner_app .grid { display:grid; } + #qr_scanner_app .text-red { color:red; } + #qr_scanner_app .justify-between { justify-content:space-between; } + #qr_scanner_app .justify-start { justify-content:flex-start; } + #qr_scanner_app .justify-end { justify-content:flex-end; } + #qr_scanner_app .items-center { align-items:center; } + #qr_scanner_app .text-green { color:green; } + #qr_scanner_app .text-red { color:red; } + #qr_scanner_app .grid-cols-2 { grid-template-columns: repeat(2, minmax(0, 1fr)); } + + #ticket_dialog { position:fixed; left:0; top:0; width:100dvw; height:100dvh; display:flex; justify-content:center; align-items:center; z-index:10000; background-color:rgba(255, 255, 255, 0.95); } + #ticket_dialog > .inner { background-color:white; border:1px solid #003664; position:relative; } + #ticket_dialog > .inner .loading_layer { position:absolute; left:0; top:0; width:100%; height:100%; transition:all 0.1s; display:flex; align-items:center; justify-content:center; background-color:rgba(255, 255, 255, 0.75); } + #ticket_dialog > .inner > .head { border-bottom:1px solid #003664; padding:0.5rem 1rem; font-size:1.25em; font-weight:bold; color:white; background-color:#003664; } + #ticket_dialog > .inner > .head .button_wrap { font-size:0.75em; margin-left:1.5rem; display:flex; gap:0.5rem; align-items:center; } + #ticket_dialog > .inner > .head .button_wrap > a { border:1px solid white; display:block; padding:0.25rem 0.75rem; } + #ticket_dialog > .inner > .head .button_wrap > a.active { background-color:white; color:#003664; } + #ticket_dialog > .inner > .head .state { font-size:0.75em; border:1px solid white; display:flex; align-items:center; padding:0.25rem 0.75rem; margin-right:1.5rem; } + #ticket_dialog > .inner > .head .state2 { background-color:red; } + #ticket_dialog > .inner > .head .state1 { background-color:green; } + #ticket_dialog > .inner > .head a { color:#FFFFFF; cursor:pointer; } + #ticket_dialog > .inner > .head > a:hover { text-decoration:none; } + #ticket_dialog > .inner > .head > a { padding:0.5rem; display:inline-block; cursor:pointer; color:#003664; } + #ticket_dialog > .inner > .content { padding:1rem; width:50dvw; max-width:calc(100dvw - 60px); height:500px; max-height:calc(100dvh - 60px); overflow:auto; } + #ticket_dialog > .inner > .content .form_row { display:flex; padding:0.25rem 0; justify-content:space-between; } + #ticket_dialog > .inner > .content .form_row .form_label { } + #ticket_dialog > .inner > .content .form_row .form_value { width:50%; } + #ticket_dialog > .inner > .content .form_row_1_4 .form_value { width:75%; } + #ticket_dialog > .inner > .content table { width:100%; } + #ticket_dialog > .inner > .content table thead > tr > * { background-color:#003664; color:#FFFFFF; padding:0.25rem 0.5rem; } + #ticket_dialog > .inner > .content table tbody > tr > * { padding:0.25rem 0.5rem; } + #ticket_dialog > .inner > .content table tbody > tr:last-child > * { border-bottom:1px solid #333333; } + #ticket_dialog > .inner > .content table tr > *.col_time { width:130px; } + #ticket_dialog > .inner > .content table tr > *.col_user { width:250px; } + #ticket_dialog > .inner > .foot { border-top:1px solid #003664; padding:0.5rem 1rem; display:flex; justify-content:space-between; align-items:center; } + #ticket_dialog > .inner > .foot a { padding:0.25rem 0.75rem; background-color:green; border:1px solid #003664; color:#FFFFFF; } + #ticket_dialog .revokeBooking { } + #ticket_dialog .col_ticket_state { width:150px; } + +</style> + +<script src="<?php echo WPSG_URL; ?>mods/mod_ticket/assets/js/HTML5QrScannerv2.3.8.js"></script> +<script type="module"> + + const wpsgSettings = { + baseUrl: '<?php echo WPSG_URL; ?>' + }; + + import { wpsg_ticket_qrScanner } from '<?php echo WPSG_URL; ?>mods/mod_ticket/assets/js/wpsg_qrscanner.js'; + + wpsg_ticket_qrScanner(wpsgSettings, <?php echo json_encode([ + 'admin_url' => \admin_url('admin-ajax.php') + ]); ?>); + +</script>
\ No newline at end of file diff --git a/views/mods/mod_ticket/settings_edit.phtml b/views/mods/mod_ticket/settings_edit.phtml new file mode 100644 index 0000000..120fb89 --- /dev/null +++ b/views/mods/mod_ticket/settings_edit.phtml @@ -0,0 +1,159 @@ +<?php + + declare(strict_types=1); + + /** + * @author: Daniel Schmitzer (daniel@maennchen1.de) + * @date: 26.10.23 + * @time: 18:55 + */ + + namespace wpsgTicket; + + $arTicketTemplates = TicketTemplate::find(); + + $arFontVue = []; + + foreach ($this->view['arFonts'] as $font_code => $font_label) { + + $arFontVue[] = ['code' => $font_code, 'label' => $font_label]; + + } + +?> + +<div id="wpsg_ticket_modul"> + + <ul class="nav nav-tabs" role="tablist"> + <li role="presentation" class="active"><a href="#tab1" role="tab" data-toggle="tab"><?php echo __('Einstellungen', 'wpsg'); ?></a></li> + <li role="presentation" class=""><a href="#tab2" role="tab" data-toggle="tab"><?php echo __('Templates', 'wpsg'); ?></a></li> + <li role="presentation" style="float:right;"><a href="#tab5" role="tab" data-toggle="tab"><?php echo __('Info / Hilfe', 'wpsg'); ?></a></li> + </ul> + <div class="tab-content"> + <div role="tabpanel" class="tab-pane active" id="tab1"> + + <p> + <?php echo __('Beim Wechsel einer Bestellung auf einen der folgenden Bestellzuständen wird einmalig eine E-Mail mit den Tickets versendet.', 'wpsg'); ?> + </p> + + <?php + + $wpsg_mod_ticket_orderstate_send = Plugin::getInstance()->getSendOrderState(); + + ?> + <select id="wpsg_mod_ticket_orderstate_send" multiple="multiple" size="5" style="border:1px solid black; width:100%;"> + <?php foreach ($this->arStatus as $status_key => $status_label) { ?> + <option + <?php echo ((in_array($status_key, $wpsg_mod_ticket_orderstate_send))?'selected="selected"':''); ?> + value="<?php echo $status_key; ?>"><?php echo $status_label; ?></option> + <?php } ?> + </select> + + <hr /> + + <p> + <?php echo __('Bei folgenden Bestellzuständen gilt ein Ticket als "aktiv" sofern es noch nicht entwertet wurde.', 'wpsg'); ?> + </p> + + <?php + + $wpsg_mod_ticket_orderstate_active = Plugin::getInstance()->getActiveOrderState(); + ?> + <select id="wpsg_mod_ticket_orderstate_active" multiple="multiple" size="5" style="border:1px solid black; width:100%;"> + <?php foreach ($this->arStatus as $status_key => $status_label) { ?> + <option + <?php echo ((in_array($status_key, $wpsg_mod_ticket_orderstate_active))?'selected="selected"':''); ?> + value="<?php echo $status_key; ?>"><?php echo $status_label; ?></option> + <?php } ?> + </select> + + </div> + <div role="tabpanel" class="tab-pane" id="tab2"> + <?php echo $this->render(WPSG_PATH_VIEW.'/mods/mod_ticket/settings_edit_templates.phtml'); ?> + </div> + <div role="tabpanel" class="tab-pane" id="tab5"> + TODO + </div> + </div> + + <div v-if="loading" class="loading_layer"> + <img src="<?php echo WPSG_URL; ?>views/gfx/ajax-loader.gif" alt="<?php echo __('Bitte warten ...', 'wpsg'); ?>" /> + </div> + +</div> + +<style> + + .items-center { justify-content:center; } + .items-start { justify-content:start; } + .flex { display:flex; } + .justify-between { justify-content:space-between; } + .mb-4 { margin-bottom:1rem; } + .gap-2 { gap:0.5rem; } + .text-center { text-align:center; } + + #wpsg_ticket_modul .control-label { padding-top:0; font-size:1em; } + + .checkbox_row { display:flex; flex-direction:row; align-items:center; justify-content:flex-start; gap:1rem; margin-bottom:0.5rem; } + .checkbox_row input { margin:0; } + + #wpsg_ticket_modul { position:relative; } + #wpsg_ticket_modul a { text-decoration:none; position:relative; } + #wpsg_ticket_modul select.template_select { width:200px; } + #wpsg_ticket_modul > .loading_layer { position:absolute; left:0; top:0; width:100%; height:100%; transition:all 0.1s; display:flex; align-items:center; justify-content:center; background-color:rgba(255, 255, 255, 0.75); } + + #wpsg_ticket_modul .field_table { width:100%; border-top:1px solid #dddddd; border-left:1px solid #dddddd; border-right:1px solid #dddddd; font-size:12px; } + #wpsg_ticket_modul .field_table td { padding:1px 5px; } + #wpsg_ticket_modul .field_table tbody > tr:first-child > * { padding-top:1rem; } + #wpsg_ticket_modul .field_table tbody > tr:last-child > * { padding-bottom:1rem; } + #wpsg_ticket_modul .field_table th { padding:1px 5px; } + #wpsg_ticket_modul .field_table tr > * { background-color:#f9f9f9; } + #wpsg_ticket_modul .field_table tr:nth-child(4) > * { border-bottom:1px solid #dddddd; padding-bottom:1rem; } + #wpsg_ticket_modul .field_table .w-1 { width:100px; font-size:12px; } + #wpsg_ticket_modul .field_table .w-2 { width:200px; font-size:12px; } + + #wpsg_ticket_modul_template .head { width:100%; display:flex; align-items:center; justify-content:space-between; border-bottom:1px solid #DDDDDD; margin-bottom:1rem; padding-bottom:1rem; } + #wpsg_ticket_modul_template .head select { width:300px; } + #wpsg_ticket_modul_template .head div { flex-grow:1; } + #wpsg_ticket_modul_template .wpsg_field_wrap_template_name { display:flex; justify-content:space-between; align-items:center; padding-right:10px !important; } + #wpsg_ticket_modul_template .wpsg_field_wrap_template_name > div { gap:1rem; display:flex; justify-content:flex-start; align-items:center; } + #wpsg_ticket_modul_template .template td.col_bg, + #wpsg_ticket_modul_template .template td.col_align { width:50px; text-align:center; } + #wpsg_ticket_modul_template .template tr td { vertical-align:middle; } + #wpsg_ticket_modul_template .template tr td:last-child { text-align:right; } + #wpsg_ticket_modul_template .template tr td:last-child .wpsg-glyphicon { margin-right:0; } + #wpsg_ticket_modul_template .uploadstate { display:flex; justify-content:flex-start; align-items:center; } + #wpsg_ticket_modul_template .uploadstate > img { margin-right:1rem; } + #wpsg_ticket_modul_template .file_wrap { display:flex; justify-content:space-between; align-items:center; } + #wpsg_ticket_modul_template .file_wrap .file { display:flex; gap:1rem; justify-content:flex-end; align-items:center; } + #wpsg_ticket_modul_template .file_wrap .file .wpsg-glyphicon { margin-right:8px; } + #wpsg_ticket_modul_template .label-copy { display:flex; justify-content:space-between; } + #wpsg_ticket_modul_template .label-copy .glyphicon { font-size:14px; } + #wpsg_ticket_modul_template .col_w0 { width:50px; } + #wpsg_ticket_modul_template .col_w1 { width:100px; } + #wpsg_ticket_modul_template .col_w1 select, + #wpsg_ticket_modul_template .col_w1 input { width:100% !important; } + + +</style> + +<script type="module"> + + const wpsgSettings = { + baseUrl: '<?php echo WPSG_URL; ?>' + }; + + import { ticket_settings_edit } from '<?php echo WPSG_URL; ?>mods/mod_ticket/assets/js/wpsg_modul.js'; + + ticket_settings_edit(wpsgSettings, '<?php echo \admin_url('admin-ajax.php'); ?>', <?php echo json_encode([ + 'arTemplates' => $arTicketTemplates, + 'arFonts' => $arFontVue, + 'label' => [ + 'copyTemplateConfirm' => __('Sind Sie sich sicher, dass sie das Template kopieren möchten?', 'wpsg'), + 'removeFieldConfirm' => __('Sind Sie sich sicher, dass sie das Feld löschen möchten?', 'wpsg'), + 'newTemplate' => __('Bitte die Bezeichnung des neuen Templates angeben.', 'wpsg'), + 'error_noTemplateName' => __('Bitte eine Bezeichnung angeben', 'wpsg') + ] + ]); ?>); + +</script> diff --git a/views/mods/mod_ticket/settings_edit_templates.phtml b/views/mods/mod_ticket/settings_edit_templates.phtml new file mode 100755 index 0000000..fe16757 --- /dev/null +++ b/views/mods/mod_ticket/settings_edit_templates.phtml @@ -0,0 +1,209 @@ +<?php + + namespace wpsgTicket; + +?> + +<div id="wpsg_ticket_modul_template"> + + <div class="head"> + + <a href="#" @click.prevent="addTemplate" title="<?php echo __('Neues Template anlegen', 'wpsg'); ?>"> + <span class="wpsg-glyphicon glyphicon glyphicon-plus"></span> + </a> + + <div v-if="data.arTemplates.length > 0"> + + <select v-model="template"> + <option :value="null"><?php echo __('Bitte auswählen', 'wpsg'); ?></option> + <option v-for="(template, index) in data.arTemplates" :value="template"> + {{template.template_name}} ({{template.config.arField.length}} <?php echo __('Felder', 'wpsg'); ?><template v-if="template.defaulttemplate">, <?php echo __('Standard', 'wpsg'); ?></template>) + </option> + </select> + + </div> + <div v-else> + + <?php echo __('Keine Templates vorhanden', 'wpsg'); ?> + + </div> + + <a v-if="template" href="#" @click.prevent="removeTemplate" title="<?php echo __('Template löschen', 'wpsg'); ?>"> + <span class="wpsg-glyphicon glyphicon glyphicon-trash"></span> + </a> + + </div> + + <div v-if="template" class="template"> + + <div class="form-group form-group-sm has-feedback"> + <label class="col-sm-6 control-label label-copy" for="wpsg_mod_downloadplus_filename"> + <a href="#" title="<?php echo __('Template kopieren', 'wpsg'); ?>" @click="copyTemplate()"><span class="wpsg-glyphicon glyphicon glyphicon-copy"></span></a> + <span><?php echo __('Name des Templates', 'wpsg'); ?></span> + </label> + <div class="col-sm-6"> + <div class="wpsg_field_wrap wpsg_field_wrap_template_name"> + <input type="text" v-model="template.template_name" /> + <div> + <label class="control-label"><?php echo __('Standard: ', 'wpsg'); ?></label> + <input type="checkbox" :checked="template.defaulttemplate" @click="setDefaultTemplate" /> + </div> + </div> + </div> + </div> + <div class="form-group form-group-sm has-feedback"> + <label class="col-sm-6 control-label"><?php echo __('Template Größe (mm)', 'wpsg'); ?></label> + <div class="col-sm-6"> + <div class="wpsg_field_wrap flex items-center justify-start gap-2"> + <input type="text" class="form-control input-sm" autocomplete="off" v-model="template.config.width"> + x + <input type="text" class="form-control input-sm" autocomplete="off" v-model="template.config.height"> + </div> + </div> + </div> + <div class="form-group form-group-sm has-feedback"> + <label class="col-sm-6 control-label"><?php echo __('Hintergrund (PDF/JPEG)', 'wpsg'); ?></label> + <div class="col-sm-6"> + <div class="wpsg_field_wrap flex items-start justify-between gap-2"> + <input type="file" @change.prevent="uploadBg" ref="file_upload" accept=".jpeg,.jpg,.pdf" /> + <span class="flex items-center"> + <a v-if="template.hasBackground" :href="template.url_bg_download" target="_blank"><?php echo __('Anzeigen', 'wpsg'); ?></a> + </span> + </div> + </div> + </div> + + <br /> + + <table class="table table_qr table-body-striped wpsg_mod_downloadplus_fieldtable"> + <thead> + <tr> + <th colspan="8"><?php echo __('QR - Code', 'wpsg'); ?></th> + </tr> + </thead> + <template v-for="(field, field_index) in template.config.arField"> + <tbody v-if="field.text === '%qr%'"> + <tr> + <td class="col_w0"></td> + <td class="col_w1"> + <div class="text-right"><strong><?php echo __('X / Y', 'wpsg'); ?></strong></div> + </td> + <td class="col_w1"> + <div clasS="flex items-center gap-2"> + <input type="text" style="width:50px;" v-model="field.x" /> + <span>/</span> + <input type="text" style="width:50px;" v-model="field.y" /> + </div> + </td> + <td class="col_w1"> + <div class="text-right"><strong><?php echo __('Breite', 'wpsg'); ?></strong></div> + </td> + <td class="col_w1"> + <input type="text" style="width:50px;" v-model="field.w" /> + </td> + <td class="col_w1"> + <div class="text-right"><strong><?php echo __('Höhe', 'wpsg'); ?>:</strong></div> + </td> + <td class="col_w1"> + <input type="text" style="width:50px;" v-model="field.h" /> + </td> + <td class="col_w0"></td> + </tr> + </tbody> + </template> + </table> + + <table class="table table-body-striped wpsg_mod_downloadplus_fieldtable"> + <thead> + <tr> + <th colspan="8"><?php echo __('Weitere Felder mit Platzhaltern', 'wpsg'); ?></th> + </tr> + <tr> + <th class="col_w0"> + <a href="#" @click.prevent="addField" title="<?php echo __('Neues Feld', 'wpsg'); ?>"> + <span class="wpsg-glyphicon glyphicon glyphicon-plus"></span> + </a> + </th> + <th class="col_w1"><?php echo __('X', 'wpsg'); ?></th> + <th class="col_w1"><?php echo __('Y', 'wpsg'); ?></th> + <th class="col_w1"><?php echo __('Ausrichtung', 'wpsg'); ?></th> + <th class="col_w1"><?php echo __('Farbe', 'wpsg'); ?></th> + <th class="col_w1"><?php echo __('Deckkraft', 'wpsg'); ?></th> + <th class="col_w1"><?php echo __('Winkel', 'wpsg'); ?></th> + <th class="col_action"></th> + </tr> + </thead> + <template v-for="(field, field_index) in template.config.arField"> + <tbody v-if="field.text !== '%qr%'"> + <tr> + <td class="col_w0">#{{field_index + 1}}</td> + <td class="col_w1"> + <input type="text" style="width:50px;" v-model="field.x" /> + </td> + <td class="col_w1"> + <input type="text" style="width:50px;" v-model="field.y" /> + </td> + <td class="col_w1"> + <select v-model="field.align" v-if="field.text !== '%qr%'"> + <option value="L">Links</option> + <option value="C">Zentriert</option> + <option value="R">Rechts</option> + </select> + <div v-else class="text-right"><strong><?php echo __('Breite', 'wpsg'); ?></strong></div> + </td> + <td class="col_w1"> + <input class="wpsg_hideBarcode" v-if="field.text !== '%qr%'" type="text" style="width:75px;" v-model="field.color" /> + <input v-else type="text" style="width:50px;" v-model="field.w" /> + </td> + <td class="col_w1"> + <input class="wpsg_hideBarcode" v-if="field.text !== '%qr%'" type="text" style="width:50px;" v-model="field.opaque" /> + <div v-else class="text-right"><strong><?php echo __('Höhe', 'wpsg'); ?>:</strong></div> + </td> + <td class="col_w1"> + <input class="wpsg_hideBarcode" v-if="field.text !== '%qr%'" type="text" style="width:50px;" v-model="field.angle" /> + <input v-else type="text" style="width:50px;" v-model="field.h" /> + </td> + <td class="col_w0"></td> + </tr> + <tr> + <td class="col_w0"> + <a href="#" @click.prevent="addField(field_index)" title="<?php echo __('Neues Feld davor einfügen', 'wpsg'); ?>"> + <span class="wpsg-glyphicon glyphicon glyphicon-plus"></span> + </a> + </td> + <td class="col_freitext_label col_w1" colspan="1"> + <span v-if="field.text !== '%qr%'"><?php echo __('Freitext', 'wpsg'); ?>:</span> + </td> + <td colspan="5" class="col_freitext"> + <div class="flex items-center gap-2"> + <input v-if="field.text !== '%qr%'" type="text" style="width:100%;" v-model="field.text" /> + <span v-else>QR Code</span> + + <template v-if="field.text !== '%qr%'"> + <select class="fontselect" v-model="field.font" style="width:100%;"> + <option v-for="(font, index_font) in data.arFonts" :value="font.code">{{font.label}}</option> + </select> + <select v-model="field.fontsize" style="width:100%;"> + <option v-for="size in [4,5,6,7,8,9,10,11,12,13,14,16,18,20,22,24,26,28,30,32,34]" :value="size">{{size}}</option> + </select> + </template> + + </div> + </td> + <td> + <a v-if="field.text !== '%qr%'" target="_blank" href="#" @click.prevent="removeField(field_index)" title="<?php echo __('Feld löschen', 'wpsg'); ?>"> + <span class="wpsg-glyphicon glyphicon glyphicon-trash"></span> + </a> + </td> + </tr> + </tbody> + </template> + </table> + + <a :href="template.url_preview" target="_blank" class="button button-primary"><?php echo __('Vorschau', 'wpsg'); ?></a> + + </div> + + <br /> + +</div> diff --git a/views/mods/mod_ticket/ticket_mail.phtml b/views/mods/mod_ticket/ticket_mail.phtml new file mode 100644 index 0000000..b1a3283 --- /dev/null +++ b/views/mods/mod_ticket/ticket_mail.phtml @@ -0,0 +1,21 @@ +<?php + + declare(strict_types=1); + + /** + * @author: Daniel Schmitzer (daniel@maennchen1.de) + * @date: 03.12.23 + * @time: 13:12 + */ + + namespace wpsgTicket; + + /** @var \wpsg_order $oOrder */ + $oOrder = $this->view['oOrder']; + + /** @var int[] $arTicketBookingIDSend */ + $arTicketBookingIDSend = $this->view['arTicketBookingIDSend']; + +?>Hallo <?php echo $oOrder->getCustomer()->getFirstname().' '.$oOrder->getCustomer()->getName(); ?> + +Hiermit erhalten Sie im Anhang Ihre Tickets aus der Bestellung <?php echo $oOrder->getNr(); ?>. diff --git a/views/mods/mod_ticket/ticket_mail_html.phtml b/views/mods/mod_ticket/ticket_mail_html.phtml new file mode 100644 index 0000000..183b316 --- /dev/null +++ b/views/mods/mod_ticket/ticket_mail_html.phtml @@ -0,0 +1,20 @@ +<?php + + declare(strict_types=1); + + /** + * @author: Daniel Schmitzer (daniel@maennchen1.de) + * @date: 03.12.23 + * @time: 13:13 + */ + + namespace wpsgTicket; + + /** @var \wpsg_order $oOrder */ + $oOrder = $this->view['oOrder']; + + /** @var int[] $arTicketBookingIDSend */ + $arTicketBookingIDSend = $this->view['arTicketBookingIDSend']; + +?><p>Hallo <?php echo $oOrder->getCustomer()->getFirstname().' '.$oOrder->getCustomer()->getName(); ?></p> +<p>Hiermit erhalten Sie im Anhang Ihre Tickets aus der Bestellung <?php echo $oOrder->getNr(); ?>.</p> diff --git a/views/order/index.phtml b/views/order/index.phtml index fb42ac3..e8b439b 100644 --- a/views/order/index.phtml +++ b/views/order/index.phtml @@ -54,6 +54,8 @@ <input id="wpsg_order" type="hidden" name="filter[order]" value="<?php echo @$this->view['arFilter']['order']; ?>" />
<input id="wpsg_ascdesc" type="hidden" name="filter[ascdesc]" value="<?php echo @$this->view['arFilter']['ascdesc']; ?>" />
+ <input type="hidden" name="filter[voucher_id]" value="<?php echo intval($this->view['arFilter']['voucher_id']??0); ?>" />
+
<?php echo wpsg_drawForm_Input('filter[s]', __('Suchfeld', 'wpsg'), wpsg_getStr($this->view['arFilter']['s'])); ?>
<?php echo wpsg_drawForm_Input('filter[k_id]', __('Kunde (ID)', 'wpsg'), wpsg_getStr($this->view['arFilter']['k_id'])); ?>
<?php echo wpsg_drawForm_Select('filter[payment_key]', __('Zahlungsart', 'wpsg'), $arPaymentKeySelect, wpsg_getStr($this->view['arFilter']['payment_key'])); ?>
diff --git a/views/produkt/addedit_general.phtml b/views/produkt/addedit_general.phtml index f717c8d..0a5bcc2 100644 --- a/views/produkt/addedit_general.phtml +++ b/views/produkt/addedit_general.phtml @@ -38,7 +38,9 @@ <?php } ?>
<?php echo wpsg_drawForm_TextEnd(__('Übersetzungen', 'wpsg')); ?>
<?php } ?>
- <?php echo wpsg_drawForm_Input('detailname', __('Produktname (Detail)', 'wpsg'), wpsg_getStr($this->view['data']['detailname'])); ?>
+ <?php echo wpsg_drawForm_Input('detailname', __('Produktname (Detail)', 'wpsg'), wpsg_getStr($this->view['data']['detailname']), [
+ 'help' => 'product_detailname', 'hint' => __('Wird im Frontend anstelle des Produktnamens verwendet', 'wpsg')
+ ]); ?>
<?php echo wpsg_drawForm_Input('shortdesc', __('Produktbeschreibung (Kurz)', 'wpsg'), wpsg_getStr($this->view['data']['shortdesc'])); ?>
<?php if (wpsg_isSizedInt($this->view['data']['id']) && !isset($_REQUEST['wpsg_lang'])) { ?>
<?php echo wpsg_drawForm_Input(false, __('Produkt ID', 'wpsg'), wpsg_getStr($this->view['data']['id']), array('readonly' => true)); ?>
diff --git a/views/produkttemplates/standard.phtml b/views/produkttemplates/standard.phtml index 87073ce..c517bd8 100644 --- a/views/produkttemplates/standard.phtml +++ b/views/produkttemplates/standard.phtml @@ -189,14 +189,35 @@ <div class="wpsg_clear"></div>
<?php /* Lagerbestand START*/ ?>
- <?php if ($this->hasMod('wpsg_mod_stock') && $this->get_option('wpsg_mod_stock_showProduct') == '1') { ?>
+ <?php
+
+ if ($this->hasMod('wpsg_mod_stock') && $this->get_option('wpsg_mod_stock_showProduct') == '1') {
+
+ $stock_source_display = '0'; // Variantenbestand
+
+ if ($oProduct->getMeta('wpsg_vp_product_stock_display', false, '0') === '0') {
+
+ // Einstellung
+ if ($this->get_option('wpsg_vp_product_stock_display') === '1') $stock_source_display = '1';
+
+ } else if ($oProduct->getMeta('wpsg_vp_product_stock_display') === '1') {
+
+ $stock_source_display = '1'; // Produktbestand
+
+ }
+
+ $stock_display = $this->view['data']['stock'];
+
+ if ($stock_source_display === '1') $stock_display = $oProduct->__get('stock');
+
+ ?>
<div class="wpsg_mod_produktindex_stock">
- <?php if (intval($this->view['data']['stock']) > 0) {?>
+ <?php if ($stock_display > 0) {?>
<label><?php echo __('Lagerbestand', 'wpsg'); ?></label>
- <?php echo wpsg_translate(__('#1# Artikel auf Lager','wpsg'), $this->view['data']['stock']); ?>
+ <?php echo wpsg_translate(__('#1# Artikel auf Lager','wpsg'), $stock_display); ?>
<?php } else { ?>
@@ -291,7 +312,7 @@ <?php /* Varianten ENDE */ ?>
<?php $this->callMods('product_bottom', array(&$this->view['data']['product_key'], $this->getTemplateIndex())); ?>
-
+
<div class="wpsg_product_buttonarea">
<div class="wpsg_product_buttons_add_basket">
<?php if ($this->view['oProduct']->canOrder()) { ?>
@@ -300,7 +321,7 @@ <label class="wpsg_amount_label" for="wpsg_menge_<?php echo $this->getTemplateIndex(); ?>"><?php echo __('Anzahl', 'wpsg'); ?></label>
<input type="text" value="<?php echo ((wpsg_isSizedInt($this->view['data']['menge']))?$this->view['data']['menge']:'1'); ?>" name="wpsg[menge]" class="wpsg_menge" id="wpsg_menge_<?php echo $this->getTemplateIndex(); ?>" <?php echo (($this->view['data']['basket_multiple'] == 4)?' readonly="readonly" ':''); ?> />
-
+
<?php /* Urlaubsmodus aktiv */ ?>
<?php if ($this->hasMod('wpsg_mod_deliverytime') && ($this->get_option('wpsg_mod_deliverytime_holiday') == '1')) { ?>
diff --git a/views/warenkorb/checkout2.phtml b/views/warenkorb/checkout2.phtml index 2a0fd4a..b886977 100644 --- a/views/warenkorb/checkout2.phtml +++ b/views/warenkorb/checkout2.phtml @@ -33,7 +33,7 @@ <?php } else { ?>
<div class="wpsg_payship_name"><?php echo __($s['name'], 'wpsg'); ?></div>
<?php } ?>
- <?php if ((isset($s['hint']) && trim($s['hint']) != '') || wpsg_getFloat($s['price']) > 0) { ?>
+ <?php if ((isset($s['hint']) && trim($s['hint']) != '') || wpsg_getFloat($s['price']) > 0) { ?>
<div id="shipping_<?php echo $s['id']; ?>_hint" class="shippay_hint">
<?php if ($s['price'] > 0) { ?>
<?php echo __('Gebühr', 'wpsg'); ?>: <?php echo wpsg_ff($s['price'], $this->get_option('wpsg_currency')); ?><br />
diff --git a/views/warenkorb/overview.phtml b/views/warenkorb/overview.phtml index 28b3bd4..d481d45 100644 --- a/views/warenkorb/overview.phtml +++ b/views/warenkorb/overview.phtml @@ -18,7 +18,7 @@ <?php $GLOBALS['step'] = 4; $this->render(WPSG_PATH_VIEW.'/warenkorb/progress.phtml'); ?>
<?php } ?>
- <form method="post" action="<?php echo $this->getURL(wpsg_ShopController::URL_BASKET); ?>">
+ <form method="post" action="<?php echo $this->getURL(wpsg_ShopController::URL_BASKET); ?>" id="wpsg_form">
<h2><?php echo __('Zusammenfassung', 'wpsg'); ?></h2>
@@ -27,7 +27,7 @@ <?php if (!$this->hasMod('wpsg_mod_ordercondition')) { ?>
<div class="wpsg_agb">
<label>
- <input type="checkbox" value="1" name="wpsg[agb]" />
+ <input type="checkbox" value="1" name="wpsg[agb]" required />
<?php echo wpsg_translate(__('Ich habe die #1# des Anbieters gelesen und erkläre mit dem Absenden der Bestellung mein Einverständnis. Die #2# habe ich zur Kenntnis genommen.', 'wpsg'),
'<a target="_blank" href="'.$this->getURL(wpsg_ShopController::URL_AGB).'">'.__('AGB', 'wpsg').'</a>',
'<a target="_blank" href="'.$this->getURL(wpsg_ShopController::URL_WIDERRUF).'">'.__('Widerrufsbelehrung', 'wpsg').'</a>');
|
