summaryrefslogtreecommitdiff
path: root/views
diff options
context:
space:
mode:
authorDaniel Schmitzer <noreply@maennchen1.de>2026-05-28 04:16:42 +0000
committerDaniel Schmitzer <noreply@maennchen1.de>2026-05-28 04:16:42 +0000
commitfe1b43a2645ee78032acffc581d52609a6d1698a (patch)
tree3d7b0bb74c67a9bac23ea2fb513b8012f4e13dbc /views
parentfd9122e4359db02258da7f6a0460c0fc962e5420 (diff)
- Widerrufsformular
git-svn-id: https://[internal]/wordpress/plugins/wpsg4@8520 0d5edaf7-2b12-4e95-93f4-047927463d4b
Diffstat (limited to 'views')
-rw-r--r--views/mods/mod_revocation/ajaxDialogContent.phtml148
-rwxr-xr-xviews/mods/mod_revocation/mail_row.phtml15
-rwxr-xr-xviews/mods/mod_revocation/mail_row_html.phtml24
-rw-r--r--views/mods/mod_revocation/mails/mail_admin_html.phtml80
-rw-r--r--views/mods/mod_revocation/mails/mail_admin_text.phtml44
-rw-r--r--views/mods/mod_revocation/mails/mail_customer_html.phtml75
-rw-r--r--views/mods/mod_revocation/mails/mail_customer_text.phtml53
-rw-r--r--views/mods/mod_revocation/order_view_row.phtml19
-rw-r--r--views/mods/mod_revocation/produkt_edit_allgemein.phtml16
-rw-r--r--views/mods/mod_revocation/settings_edit.phtml121
-rw-r--r--views/mods/mod_revocation/wp_footer.phtml331
-rw-r--r--views/mods/mod_revocation/wpsg_mod_kundenverwaltung_order_after_products.phtml49
-rw-r--r--views/mods/mod_revocation/wpsg_producttemplate_afterButton.phtml25
-rw-r--r--views/mods/mod_revocation/wpsg_revocation.css58
-rw-r--r--views/mods/mod_revocation/wpsg_revocation.js0
15 files changed, 1058 insertions, 0 deletions
diff --git a/views/mods/mod_revocation/ajaxDialogContent.phtml b/views/mods/mod_revocation/ajaxDialogContent.phtml
new file mode 100644
index 0000000..e833a00
--- /dev/null
+++ b/views/mods/mod_revocation/ajaxDialogContent.phtml
@@ -0,0 +1,148 @@
+<?php
+
+ declare(strict_types=1);
+
+ /**
+ * @author: Daniel Schmitzer
+ * @date: 10.04.26
+ * @time: 09:10
+ */
+
+ namespace wpsgRevocation;
+
+ use \wpsg\M1;
+ use wpsg_product;
+
+ $arReason = \wpsgRevocation\Revocation::getReasons();
+
+ // Produkte
+ $dialog_config = json_decode((wp_kses_stripslashes($_REQUEST['dialog_config']??'[]')), true);
+
+ $contact_email = "";
+
+ $customer_login_id = intval(\wpsg_ShopController::getShop()->callMod('wpsg_mod_kundenverwaltung', 'isLoggedIn'));
+
+ if ($customer_login_id > 0) {
+
+ $oCustomer = \wpsg_customer::getInstance($customer_login_id);
+
+ $contact_email = $oCustomer->getEmail();
+
+ }
+
+?>
+
+<form id="wpsg_revocation_form" class="wpsg">
+
+ <div id="msg_target"></div>
+
+ <?php if (sizeof($dialog_config['arOrderProductID']) > 0) { ?>
+
+ <?php foreach ($dialog_config['arOrderProductID'] as $row) {
+
+ $order_id = intval($row['order_id']);
+ $order_product_id = intval($row['order_product_id']);
+ $amount = intval($row['amount']);
+
+ $oOrder = \wpsg_order::getInstance($order_id);
+ $oOrderProduct = \wpsg_order_product::getInstance($order_product_id);
+
+ if (!$oOrder->isLoaded() || !$oOrderProduct->isLoaded()) continue;
+
+ $key = $order_id.'_'.$order_product_id;
+
+ ?>
+
+ <fieldset class="wpsg_revocation_order_product">
+ <legend><?php echo $oOrderProduct->getProduct()->getProductName(); ?></legend>
+ <div>
+
+ <input type="hidden" readonly name="wpsg_revocation_reason[row][<?php echo $key; ?>][order_product_id]" value="<?php echo $oOrderProduct->getId(); ?>" />
+
+ <div class="form_field">
+ <div class="label"><?php echo __('Bestellnummer / Menge', 'wpsgRevocation'); ?></div>
+ <div class="value">
+ <input type="text" readonly name="wpsg_revocation_reason[row][<?php echo $key; ?>][order_nr]" value="<?php echo $oOrder->getNr(); ?>" />
+ <input type="number" min="1" max="<?php echo $amount; ?>" name="wpsg_revocation_reason[row][<?php echo $key; ?>][amount]" value="<?php echo $amount; ?>" />
+ </div>
+ </div>
+
+ <div class="form_field">
+ <div class="label"><?php echo __('Widerrufsgrund', 'wpsgRevocation'); ?></div>
+ <div class="value">
+ <select name="wpsg_revocation_reason[row][<?php echo $key; ?>][reason]" required>
+ <option value=""><?php echo __('Bitte einen Grund auswählen', 'wpsgRevocation'); ?></option>
+ <?php foreach ($arReason as $reason) { ?>
+ <option value="<?php echo htmlspecialchars($reason['id']); ?>"><?php echo htmlspecialchars($reason['text']); ?></option>
+ <?php } ?>
+ </select>
+ </div>
+ </div>
+
+ <div class="form_field">
+ <div class="label"><?php echo __('Bemerkung', 'wpsgRevocation'); ?></div>
+ <div class="value">
+ <textarea name="wpsg_revocation_reason[row][<?php echo $key; ?>][comment]"></textarea>
+ </div>
+ </div>
+
+ </div>
+ </fieldset>
+
+ <?php } ?>
+
+ <?php } else {
+
+ $key = 0;
+
+ ?>
+
+ <fieldset class="wpsg_revocation_order_product">
+
+ <div class="form_field">
+ <div class="label"><?php echo __('Produkt - Nr.', 'wpsgRevocation'); ?></div>
+ <div class="value">
+ <input type="text" name="wpsg_revocation_reason[row][<?php echo $key; ?>][product_nr]" value="<?php echo ($dialog_config['set_product_anr']??''); ?>" />
+ </div>
+ </div>
+
+ <div class="form_field">
+ <div class="label"><?php echo __('Bestellnummer / Menge', 'wpsgRevocation'); ?></div>
+ <div class="value">
+ <input type="text" name="wpsg_revocation_reason[row][<?php echo $key; ?>][order_nr]" value="" />
+ <input type="number" name="wpsg_revocation_reason[row][<?php echo $key; ?>][amount]" value="1" />
+ </div>
+ </div>
+
+ <div class="form_field">
+ <div class="label"><?php echo __('Widerrufsgrund', 'wpsgRevocation'); ?></div>
+ <div class="value">
+ <select name="wpsg_revocation_reason[row][<?php echo $key; ?>][reason]">
+ <?php foreach ($arReason as $reason) { ?>
+ <option value="<?php echo htmlspecialchars($reason['id']); ?>"><?php echo htmlspecialchars($reason['text']); ?></option>
+ <?php } ?>
+ </select>
+ </div>
+ </div>
+
+ <div class="form_field">
+ <div class="label"><?php echo __('Bemerkung', 'wpsgRevocation'); ?></div>
+ <div class="value">
+ <textarea name="wpsg_revocation_reason[row][<?php echo $key; ?>][comment]"></textarea>
+ </div>
+ </div>
+
+ </fieldset>
+
+ <?php } ?>
+
+ <div class="form_field">
+ <div class="label"><?php echo __('Kontakt - E-Mail', 'wpsgRevocation'); ?></div>
+ <div class="value">
+ <input type="email" required name="wpsg_revocation_reason[contact]" value="<?php echo $contact_email; ?>"
+ <?php echo (($contact_email !== '')?'readonly':''); ?>
+ />
+ </div>
+ </div>
+
+</form> \ No newline at end of file
diff --git a/views/mods/mod_revocation/mail_row.phtml b/views/mods/mod_revocation/mail_row.phtml
new file mode 100755
index 0000000..8a54f89
--- /dev/null
+++ b/views/mods/mod_revocation/mail_row.phtml
@@ -0,0 +1,15 @@
+<?php
+
+ /**
+ * Template für die Integration des Widerruflinks in die Kunden- und Adminmail
+ */
+
+ $order_id = intval($this->view['order_id']);
+ $order_nr = $this->view['wpsg_mod_revocation']['order_nr'];
+ $product_nr = $this->view['wpsg_mod_revocation']['product_nr'];
+ $amount = $this->view['wpsg_mod_revocation']['amount'];
+ $order_product_id = intval($this->view['order_product_id']);
+
+ $revo_url = get_home_url('/', '', 'http').'?wpsg_revo_order='.urlencode($order_nr).'&wpsg_revo_product='.urlencode($product_nr).'&wpsg_revo_amount='.urlencode($amount);
+
+?><?php echo wpsg_pad_left(__('Widerruf:', 'wpsgRevocation').' ', 15); ?> <?php echo $revo_url; ?> \ No newline at end of file
diff --git a/views/mods/mod_revocation/mail_row_html.phtml b/views/mods/mod_revocation/mail_row_html.phtml
new file mode 100755
index 0000000..e7f2945
--- /dev/null
+++ b/views/mods/mod_revocation/mail_row_html.phtml
@@ -0,0 +1,24 @@
+<?php
+
+ /**
+ * Template für die Integration des Widerruflinks in die Kunden- und Adminmail (HTML)
+ */
+
+ $i = intval($this->view['i']);
+
+ $order_id = intval($this->view['order_id']);
+ $order_nr = $this->view['wpsg_mod_revocation']['order_nr'];
+ $product_nr = $this->view['wpsg_mod_revocation']['product_nr'];
+ $amount = $this->view['wpsg_mod_revocation']['amount'];
+ $order_product_id = intval($this->view['order_product_id']);
+
+ $revo_url = get_home_url('/', '', 'http').'?wpsg_revo_order='.urlencode($order_nr).'&wpsg_revo_product='.urlencode($product_nr).'&wpsg_revo_amount='.urlencode($amount);
+
+?>
+<tr class="productrow productrow2 <?php echo ((($i % 2) == 0)?'productrow_odd':'productrow_even'); ?>">
+ <td style="padding:4px; line-height:100%; vertical-align:middle;" class="col_pos">&nbsp;</td>
+ <td style="padding:4px; line-height:100%; vertical-align:middle;" class="col_name"><?php echo __('Widerruf', 'wpsgRevocation'); ?>:</td>
+ <td style="padding:4px; line-height:100%; vertical-align:middle;" class="col_name" colspan="4">
+ <a href="<?php echo $revo_url; ?>"><?php echo __('Widerruf starten', 'wpsgRevocation'); ?></a>
+ </td>
+</tr>
diff --git a/views/mods/mod_revocation/mails/mail_admin_html.phtml b/views/mods/mod_revocation/mails/mail_admin_html.phtml
new file mode 100644
index 0000000..57920b5
--- /dev/null
+++ b/views/mods/mod_revocation/mails/mail_admin_html.phtml
@@ -0,0 +1,80 @@
+<?php
+
+ declare(strict_types=1);
+
+ /**
+ * @author: Daniel Schmitzer
+ * @date: 14.04.26
+ * @time: 09:21
+ */
+
+ namespace wpsgRevocation;
+
+ $arSubmitData = \wpsg_ShopController::getShop()->view['arSubmitData'] ?? [];
+ $arReason = Revocation::getReasons();
+
+?>
+<p><?php echo __('Hallo,', 'wpsgRevocation'); ?></p>
+
+<p><?php echo __('ein Kunde hat einen Widerruf für ein Produkt durchgeführt.', 'wpsgRevocation'); ?></p>
+
+<p>
+ <strong><?php echo __('Name', 'wpsgRevocation'); ?>:</strong> %kunde_anrede% %kunde_vname% %kunde_name%<br>
+ <strong><?php echo __('E-Mail', 'wpsgRevocation'); ?>:</strong> %kunde_email%
+</p>
+
+<hr>
+
+<?php foreach ($arSubmitData as $key => $d):
+
+ $oOrder = $d['oOrder'];
+ $oOrderProduct = $d['oOrderProduct'];
+
+ $reasonText = array_values(array_filter(
+ $arReason,
+ function($item) use ($d) {
+ return $item['id'] === $d['reason'];
+ }
+ ))[0]['text'] ?? '';
+?>
+
+ <div style="margin-bottom:15px; padding-bottom:10px; border-bottom:1px solid #ddd;">
+ <p>
+ <strong><?php echo __('Bestellung', 'wpsgRevocation'); ?>:</strong>
+ <?php echo $oOrder->getNr(); ?>
+ </p>
+
+ <p>
+ <strong><?php echo __('Produkt', 'wpsgRevocation'); ?>:</strong>
+ <?php echo $d['amount']; ?> x <?php echo $oOrderProduct->getProduct()->getProductName(true); ?>
+ / <?php echo __('Artikelnummer', 'wpsgRevocation'); ?>:
+ <?php echo $oOrderProduct->getProduct()->getNr(); ?>
+ </p>
+
+ <p>
+ <strong><?php echo __('Ausgewählter Grund', 'wpsgRevocation'); ?>:</strong>
+ <?php echo $reasonText; ?>
+ </p>
+
+ <p>
+ <strong><?php echo __('Bemerkung', 'wpsgRevocation'); ?>:</strong>
+ <?php echo nl2br(htmlspecialchars($d['comment'] ?? '')); ?>
+ </p>
+ </div>
+
+<?php endforeach; ?>
+
+<p>
+ <strong><?php echo __('Datum des Widerrufs', 'wpsgRevocation'); ?>:</strong>
+ <?php echo date('d.m.Y H:i:s'); ?>
+</p>
+
+<p>
+ <?php echo __('Bitte prüft den Vorgang und führt die Rückabwicklung (Storno / Rückerstattung) durch.', 'wpsgRevocation'); ?>
+</p>
+
+<p>
+ <?php echo __('Viele Grüße', 'wpsgRevocation'); ?><br>
+ <?php echo __(\wpsg_ShopController::getShop()->get_option('wpsg_shopdata_name'), 'wpsgRevocation'); ?>
+ - <?php echo __('Team', 'wpsgRevocation'); ?>
+</p> \ No newline at end of file
diff --git a/views/mods/mod_revocation/mails/mail_admin_text.phtml b/views/mods/mod_revocation/mails/mail_admin_text.phtml
new file mode 100644
index 0000000..8ce601a
--- /dev/null
+++ b/views/mods/mod_revocation/mails/mail_admin_text.phtml
@@ -0,0 +1,44 @@
+<?php
+
+ declare(strict_types=1);
+
+ /**
+ * @author: Daniel Schmitzer
+ * @date: 14.04.26
+ * @time: 09:21
+ */
+
+ namespace wpsgRevocation;
+
+ $arSubmitData = \wpsg_ShopController::getShop()->view['arSubmitData'] ?? [];
+ $arReason = Revocation::getReasons();
+
+?><?php echo __('Hallo,', 'wpsgRevocation'); ?>
+
+<?php echo __('ein Kunde hat einen Widerruf für ein Produkt durchgeführt.', 'wpsgRevocation'); ?>
+
+<?php echo mb_str_pad(__('Name', 'wpsgRevocation').':', 25); ?> %kunde_anrede% %kunde_vname% %kunde_name%
+<?php echo mb_str_pad(__('E-Mail', 'wpsgRevocation').':', 25); ?> %kunde_email%
+
+<?php foreach ($arSubmitData as $key => $d) {
+
+ /** @var \wpsg_order $oOrder */
+ $oOrder = $d['oOrder'];
+
+ /** @var \wpsg_order_product $oOrderProduct */
+ $oOrderProduct = $d['oOrderProduct'];
+
+?>
+<?php echo mb_str_pad(__('Bestellung', 'wpsgRevocation').':', 25); ?> <?php echo $oOrder->getNr(); ?>
+<?php echo mb_str_pad(__('Produkt', 'wpsgRevocation').':', 25); ?> <?php echo $d['amount']; ?> x <?php echo $oOrderProduct->getProduct()->getProductName(true); ?> / <?php echo __('Artikelnummer', 'wpsgRevocation'); ?>: <?php echo $oOrderProduct->getProduct()->getNr(); ?>
+<?php echo mb_str_pad(__('Ausgewählter Grund', 'wpsgRevocation').':', 25); ?> <?php echo array_values(array_filter($arReason, function($item) use ($d) { return $item['id'] === $d['reason']; }))[0]['text'] ?? ''; ?>
+<?php echo mb_str_pad(__('Bemerkung', 'wpsgRevocation').':', 25); ?> <?php echo $d['comment']; ?>
+
+<?php } ?>
+
+<?php echo mb_str_pad(__('Datum des Widerrufs', 'wpsgRevocation').':', 25); ?> <?php echo date('d.m.Y H:i:s'); ?>
+
+<?php echo __('Bitte prüft den Vorgang und führt die Rückabwicklung (Storno / Rückerstattung) durch.', 'wpsgRevocation'); ?>
+
+<?php echo __('Viele Grüße', 'wpsgRevocation'); ?>
+<?php echo __(\wpsg_ShopController::getShop()->get_option('wpsg_shopdata_name'), 'wpsgRevocation'); ?> - <?php echo __('Team', 'wpsgRevocation'); ?> \ No newline at end of file
diff --git a/views/mods/mod_revocation/mails/mail_customer_html.phtml b/views/mods/mod_revocation/mails/mail_customer_html.phtml
new file mode 100644
index 0000000..f946efa
--- /dev/null
+++ b/views/mods/mod_revocation/mails/mail_customer_html.phtml
@@ -0,0 +1,75 @@
+<?php
+
+ declare(strict_types=1);
+
+ /**
+ * @author: Daniel Schmitzer
+ * @date: 14.04.26
+ * @time: 09:21
+ */
+
+ namespace wpsgRevocation;
+
+ $arSubmitData = \wpsg_ShopController::getShop()->view['arSubmitData'] ?? [];
+ $arReason = Revocation::getReasons();
+
+?>
+<p><?php echo __('Hallo', 'wpsgRevocation'); ?> %kunde_anrede% %kunde_name%,</p>
+
+<p><?php echo __('wir haben Ihren Widerruf erhalten und bedanken uns für Ihre Mitteilung.', 'wpsgRevocation'); ?></p>
+
+<h3><?php echo __('Ihre Widerrufsanmeldung:', 'wpsgRevocation'); ?></h3>
+
+<?php foreach ($arSubmitData as $key => $d):
+
+ $oOrder = $d['oOrder'];
+ $oOrderProduct = $d['oOrderProduct'];
+
+ $reasonText = array_values(array_filter(
+ $arReason,
+ function($item) use ($d) {
+ return $item['id'] === $d['reason'];
+ }
+ ))[0]['text'] ?? '';
+?>
+
+ <div style="margin-bottom:20px; padding:15px; background-color:#f9f9f9; border-radius:5px;">
+ <p style="margin:0 0 10px 0;">
+ <strong><?php echo __('Bestellnummer', 'wpsgRevocation'); ?>:</strong>
+ <?php echo $oOrder->getNr(); ?>
+ </p>
+
+ <p style="margin:0 0 10px 0;">
+ <strong><?php echo __('Produkt', 'wpsgRevocation'); ?>:</strong>
+ <?php echo $d['amount']; ?> x <?php echo $oOrderProduct->getProduct()->getProductName(true); ?>
+ / <?php echo __('Artikelnr.', 'wpsgRevocation'); ?>:
+ <?php echo $oOrderProduct->getProduct()->getNr(); ?>
+ </p>
+
+ <p style="margin:0 0 10px 0;">
+ <strong><?php echo __('Grund', 'wpsgRevocation'); ?>:</strong>
+ <?php echo $reasonText; ?>
+ </p>
+
+ <?php if (!empty($d['comment'])): ?>
+ <p style="margin:0 0 10px 0;">
+ <strong><?php echo __('Bemerkung', 'wpsgRevocation'); ?>:</strong>
+ <?php echo nl2br(htmlspecialchars($d['comment'])); ?>
+ </p>
+ <?php endif; ?>
+ </div>
+
+<?php endforeach; ?>
+
+<p>
+ <strong><?php echo __('Widerrufdatum', 'wpsgRevocation'); ?>:</strong>
+ <?php echo date('d.m.Y H:i:s'); ?>
+</p>
+
+<p><?php echo __('Wir werden Ihren Widerruf nun schnellstmöglich bearbeiten und uns bei Fragen mit Ihnen in Verbindung setzen.', 'wpsgRevocation'); ?></p>
+
+<p>
+ <?php echo __('Mit freundlichen Grüßen', 'wpsgRevocation'); ?><br>
+ <?php echo \wpsg_ShopController::getShop()->get_option('wpsg_shopdata_name'); ?>
+ - <?php echo __('Team', 'wpsgRevocation'); ?>
+</p> \ No newline at end of file
diff --git a/views/mods/mod_revocation/mails/mail_customer_text.phtml b/views/mods/mod_revocation/mails/mail_customer_text.phtml
new file mode 100644
index 0000000..0608fc5
--- /dev/null
+++ b/views/mods/mod_revocation/mails/mail_customer_text.phtml
@@ -0,0 +1,53 @@
+<?php
+
+ declare(strict_types=1);
+
+ /**
+ * @author: Daniel Schmitzer
+ * @date: 14.04.26
+ * @time: 09:21
+ */
+
+ namespace wpsgRevocation;
+
+ $arSubmitData = \wpsg_ShopController::getShop()->view['arSubmitData'] ?? [];
+ $arReason = Revocation::getReasons();
+
+?><?php echo __('Hallo', 'wpsgRevocation'); ?> %kunde_anrede% %kunde_name%,
+
+<?php echo __('wir haben Ihren Widerruf erhalten und bedanken uns für Ihre Mitteilung.', 'wpsgRevocation'); ?>
+
+<?php echo __('Ihre Widerrufsanmeldung:', 'wpsgRevocation'); ?>
+
+<?php foreach ($arSubmitData as $key => $d):
+
+ $oOrder = $d['oOrder'];
+ $oOrderProduct = $d['oOrderProduct'];
+
+ $reasonText = array_values(array_filter(
+ $arReason,
+ function($item) use ($d) {
+ return $item['id'] === $d['reason'];
+ }
+ ))[0]['text'] ?? '';
+?>
+
+<?php echo mb_str_pad(__('Bestellnummer', 'wpsgRevocation').':', 20); ?> <?php echo $oOrder->getNr(); ?>
+
+<?php echo mb_str_pad(__('Produkt', 'wpsgRevocation').':', 20); ?> <?php echo $d['amount']; ?> x <?php echo $oOrderProduct->getProduct()->getProductName(true); ?> / <?php echo __('Artikelnr.', 'wpsgRevocation'); ?>: <?php echo $oOrderProduct->getProduct()->getNr(); ?>
+
+<?php echo mb_str_pad(__('Grund', 'wpsgRevocation').':', 20); ?> <?php echo $reasonText; ?>
+
+<?php if (!empty($d['comment'])): ?>
+<?php echo mb_str_pad(__('Bemerkung', 'wpsgRevocation').':', 20); ?> <?php echo $d['comment']; ?>
+<?php endif; ?>
+
+<?php endforeach; ?>
+
+<?php echo mb_str_pad(__('Widerrufdatum', 'wpsgRevocation').':', 20); ?> <?php echo date('d.m.Y H:i:s'); ?>
+
+<?php echo __('Wir werden Ihren Widerruf nun schnellstmöglich bearbeiten und uns bei Fragen mit Ihnen in Verbindung setzen.', 'wpsgRevocation'); ?>
+
+<?php echo __('Mit freundlichen Grüßen', 'wpsgRevocation'); ?>
+
+<?php echo \wpsg_ShopController::getShop()->get_option('wpsg_shopdata_name'); ?> - <?php echo __('Team', 'wpsgRevocation'); ?> \ No newline at end of file
diff --git a/views/mods/mod_revocation/order_view_row.phtml b/views/mods/mod_revocation/order_view_row.phtml
new file mode 100644
index 0000000..8c95b5b
--- /dev/null
+++ b/views/mods/mod_revocation/order_view_row.phtml
@@ -0,0 +1,19 @@
+<?php
+
+ declare(strict_types=1);
+
+ /**
+ * Integration eines Widerrufes in die Bestellansicht im Backend (Abo-Verlängerungen)
+ */
+
+ $row = $this->view['wpsg_mod_revocation']['row']??null;
+
+ if ($row === null) return;
+
+?>
+<tr class="wpsg_<?php echo (($this->view['i'] == 0)?'odd':'even'); ?>">
+ <td colspan="5">
+ <?php echo __('Widerruf', 'wpsgRevocation'); ?>:
+ <?php echo wpsg_translate(__('#1# Stück am #2# widerrufen', 'wpsgRevocation'), $row['amount'], \wp_date('d. F Y H:i:s', strtotime($row['time']))); ?>
+ </td>
+</tr> \ No newline at end of file
diff --git a/views/mods/mod_revocation/produkt_edit_allgemein.phtml b/views/mods/mod_revocation/produkt_edit_allgemein.phtml
new file mode 100644
index 0000000..42ff8ff
--- /dev/null
+++ b/views/mods/mod_revocation/produkt_edit_allgemein.phtml
@@ -0,0 +1,16 @@
+<?php
+
+ declare(strict_types=1);
+
+ /**
+ * @author: Daniel Schmitzer
+ * @date: 27.05.26
+ * @time: 14:42
+ */
+
+ namespace wpsgRevocation;
+
+ $oProduct = \wpsg_product::getInstance(intval($this->view['data']['id']));
+
+ echo wpsg_drawForm_Checkbox('wpsg_mod_revocation_disable', __('Widerrufsbutton nicht anzeigen', 'wpsg'), $oProduct->getMeta('wpsg_mod_revocation_disable', false, 0)); ?>
+ \ No newline at end of file
diff --git a/views/mods/mod_revocation/settings_edit.phtml b/views/mods/mod_revocation/settings_edit.phtml
new file mode 100644
index 0000000..fbab6a1
--- /dev/null
+++ b/views/mods/mod_revocation/settings_edit.phtml
@@ -0,0 +1,121 @@
+<?php
+
+ declare(strict_types=1);
+
+ /**
+ * @author: Daniel Schmitzer
+ * @date: 14.04.26
+ * @time: 06:32
+ */
+
+ $arReason = \wpsgRevocation\Revocation::getReasons();
+
+?>
+
+<div id="wpsg_mod_revocation_reason_wrap">
+ <div id="wpsg_mod_revocation_reason_app">
+
+ <ul class="nav nav-tabs" role="tablist">
+ <li role="presentation" :class="{ 'active': tab === 1 }"><a href="#tab1" @click.prevent.stop="tab = 1"><?php echo __('Einstellungen', 'wpsgRevocation'); ?></a></li>
+ <li role="presentation" :class="{ 'active': tab === 2 }"><a href="#tab2" @click.prevent.stop="tab = 2"><?php echo __('Gründe für Retouren', 'wpsgRevocation'); ?></a></li>
+ </ul>
+
+ <input type="hidden" name="wpsg_mod_revocation_reason" v-model="jsonString" />
+
+ <div class="tab-content">
+ <div v-show="tab === 1" class="tab-pane active">
+
+ <?php echo wpsg_drawForm_Checkbox('wpsg_mod_revocation_view_order', __('An Produkten im Kundenfrontend an den Bestellungen anzeigen.', 'wpsgRevocation'), wpsg_ShopController::getShop()->get_option('wpsg_mod_revocation_view_order'), ['fullWidth' => true]); ?>
+ <?php echo wpsg_drawForm_Checkbox('wpsg_mod_revocation_view_flyout', __('Auf allen Seiten ein Widerrufs-Flyout anzeigen.', 'wpsgRevocation'), wpsg_ShopController::getShop()->get_option('wpsg_mod_revocation_view_flyout'), ['fullWidth' => true]); ?>
+ <?php echo wpsg_drawForm_Checkbox('wpsg_mod_revocation_view_product', __('Im Produkt neben "In den Warenkorb" anzeigen.', 'wpsgRevocation'), wpsg_ShopController::getShop()->get_option('wpsg_mod_revocation_view_product'), ['fullWidth' => true]); ?>
+ <?php echo wpsg_drawForm_Checkbox('wpsg_mod_revocation_view_customer_mail', __('Widerruflink in Bestellbestätigungsmail an Kunden.', 'wpsgRevocation'), wpsg_ShopController::getShop()->get_option('wpsg_mod_revocation_view_customer_mail'), ['fullWidth' => true]); ?>
+
+ <p class="wpsg_note">
+ <?php echo wpsg_translate(
+ __('Einstellungen zu den E-Mails finden Sie in der <a href="#1#">E-Mail Konfiguration</a>.', 'wpsgRevocation'),
+ WPSG_URL_WP.'wp-admin/admin.php?page=wpsg-Admin&subaction=emailconf'
+ ); ?><br />
+ <?php echo __('Das Modul setzt eindeutige Artikelnummern voraus.', 'wpsgRevocation'); ?>
+ </p>
+
+ </div>
+ <div v-show="tab === 2" class="tab-pane active">
+ <div class="reason_wrap" v-if="arReason.length > 0">
+ <template v-for="r of arReason">
+ <div class="wpsg_form_field">
+ <label class="label"><?php echo __('ID', 'wpsgRevocation'); ?></label>
+ <div class="value">
+ {{r.id}}
+ <a data-id="1" class="removeReason" @click.prevent.stop="removeReason(r)" href="#"><span class="wpsg-glyphicon glyphicon glyphicon-trash"></span></a>
+ </div>
+ </div>
+ <div class="wpsg_form_field">
+ <label class="label"><?php echo __('Text', 'wpsgRevocation'); ?></label>
+ <div class="value">
+ <input type="text" v-model="r.text" />
+ </div>
+ </div>
+ <hr />
+ </template>
+ </div>
+ <p v-else><?php echo __('Keine Gründe definiert', 'wpsgRevocation'); ?></p>
+
+ <a href="#" @click.prevent.stop="addReason" class="addReason"><span class="wpsg-glyphicon glyphicon glyphicon-plus"></span><?php echo __('Neuen Grund anlegen', 'wpsgRevocation'); ?></a>
+ </div>
+ </div>
+
+ </div>
+</div>
+
+<style>
+
+ #wpsg_mod_revocation_reason_wrap {
+ .wpsg_note { margin-top:1rem; font-style:italic; }
+ .addReason { margin-top:1rem; display:block; }
+ .removeReason { position:absolute; right:0; top:7px; font-size:1.4rem; }
+ .wpsg_form_field { display:grid; grid-template-columns:100px 1fr; column-gap:2rem; row-gap:1rem; width:100%; align-items:center; position:relative; min-height:30px;
+ & > .label { font-weight:bold; display:block; padding:0; margin:0; color:black; font-size:100%; text-align:left; }
+ & > .value {
+ input { width:100%; }
+ }
+ }
+ }
+
+</style>
+
+<script type="module">
+
+ import { createApp, computed, ref } from '<?php echo wpsg_ShopController::getShop()->getRessourceURL('js/vue.esm-browser.prod.3.5.32.js'); ?>';
+
+ createApp({
+ setup() {
+
+ const tab = ref(1);
+ const arReason = ref(<?php echo json_encode($arReason); ?>);
+
+ const addReason = () => {
+
+ const id = Date.now().toString(36) + Math.random().toString(36).slice(2);
+ arReason.value.push({ text: '', id: id });
+
+ };
+ const removeReason = r => {
+
+ if (confirm('<?php echo __('Sind Sie sich sicher?', 'wpsgRevocation'); ?>')) {
+
+ arReason.value = arReason.value.filter(v => v !== r);
+
+ }
+
+ }
+
+ const jsonString = computed(() => JSON.stringify(arReason.value));
+
+ return {
+ addReason, removeReason,
+ arReason, jsonString, tab
+ };
+ }
+ }).mount('#wpsg_mod_revocation_reason_app');
+
+</script> \ No newline at end of file
diff --git a/views/mods/mod_revocation/wp_footer.phtml b/views/mods/mod_revocation/wp_footer.phtml
new file mode 100644
index 0000000..3c0f225
--- /dev/null
+++ b/views/mods/mod_revocation/wp_footer.phtml
@@ -0,0 +1,331 @@
+<?php
+
+ declare(strict_types=1);
+
+ /**
+ * @author: Daniel Schmitzer
+ * @date: 27.01.26
+ * @time: 09:26
+ */
+
+ namespace wpsgRevocation;
+
+?>
+
+<?php if (\wpsg_ShopController::getShop()->get_option('wpsg_mod_revocation_view_flyout') === '1') { ?>
+
+ <div id="wpsg_revocation_button">
+ <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M19,15V3H23V15H19M15,3A2,2 0 0,1 17,5V15C17,15.55 16.78,16.05 16.41,16.41L9.83,23L8.77,21.94C8.5,21.67 8.33,21.3 8.33,20.88L8.36,20.57L9.31,16H3C1.89,16 1,15.1 1,14V12C1,11.74 1.05,11.5 1.14,11.27L4.16,4.22C4.46,3.5 5.17,3 6,3H15M15,5H5.97L3,12V14H11.78L10.65,19.32L15,14.97V5Z" /></svg>
+ <span><?php echo __('Widerrufsformular', 'wpsgRevocation'); ?></span>
+ </div>
+
+<?php } else { ?>
+
+ <div id="wpsg_revocation_button" style="display:none;"></div>
+
+<?php } ?>
+
+<!-- Dialog -->
+<div id="wpsg_revocation_dialog" class="">
+ <div class="inner">
+ <div class="header">
+ <span><?php echo __('Widerrufsformular', 'wpsgRevocation'); ?></span>
+ <a href="#" class="close">
+ <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M19,6.41L17.59,5L12,10.59L6.41,5L5,6.41L10.59,12L5,17.59L6.41,19L12,13.41L17.59,19L19,17.59L13.41,12L19,6.41Z" /></svg>
+ </a>
+ </div>
+ <div class="content"></div>
+ <div class="footer">
+ <button class="button button-primary wpsg_revocation_button_submit"><?php echo __('Abschicken', 'wpsgRevocation'); ?></button>
+ </div>
+ <div class="loading">
+ <img src="<?php echo WPSG_URL; ?>views/gfx/ajax-loader.gif" alt="<?php echo __('Bitte warten ...', 'wpsgRevocation'); ?>" />
+ </div>
+ </div>
+</div>
+
+<script>
+
+ console.log('ok');
+
+ const wpsg_revocation_nonce = '<?php echo wp_create_nonce('wpsg_mod_revocation_nonce'); ?>';
+ const el_dialog = document.getElementById('wpsg_revocation_dialog');
+ const el_dialog_content = document.getElementById('wpsg_revocation_dialog').querySelector('.inner > .content');
+
+ const formDataToObject = (formData) => {
+
+ const obj = {};
+
+ for (const [key, value] of formData.entries()) {
+
+ const keys = key.split(/\[|\]/).filter(Boolean);
+ let current = obj;
+
+ keys.forEach((k, i) => {
+
+ const isLast = i === keys.length - 1;
+
+ if (isLast) { current[k] = value; }
+ else {
+
+ if (!current[k]) { current[k] = isNaN(keys[i + 1]) ? {} : []; }
+
+ current = current[k];
+
+ }
+
+ });
+
+ }
+
+ return obj;
+
+ }
+
+ const submit_dialog = event => {
+
+ event.preventDefault();
+ event.stopPropagation();
+
+ el_dialog.classList.add('loading');
+
+ // const form_data = Object.fromEntries(new FormData(el_dialog.querySelector('form#wpsg_revocation_form')).entries());
+ const form = el_dialog.querySelector('form#wpsg_revocation_form');
+ const formData = new FormData(form);
+ const form_data = formDataToObject(formData);
+
+ fetch('<?php echo admin_url('admin-ajax.php'); ?>?action=wpsg_mod_revocation&do=ajaxDialogSubmit', {
+ method: 'POST',
+ headers: {
+ 'Content-Type': 'application/json'
+ },
+ body: JSON.stringify({
+ nonce: wpsg_revocation_nonce,
+ form_data: form_data,
+ })
+ }).then(res => res.json()).then(res => {
+
+ let html = '';
+
+ if ((res.success??false) === false) {
+
+ html += '<ul id="wpsg_error" class="wpsg_error">';
+ (res.arError??[]).forEach(error => { html += `<li>${error}</li>`; });
+ html += '</ul>';
+
+ el_dialog_content.querySelector('#msg_target').innerHTML = html;
+
+ el_dialog.classList.remove('loading');
+
+ } else {
+
+ alert('<?php echo __('Ihr Widerruf ist bei uns eingegangen und wird bearbeitet.', 'wpsgRevocation'); ?>');
+ close_dialog(event);
+
+ document.querySelectorAll('.wpsg_revocation_order_product_checkbox:checked').forEach(el => {
+
+ el.checked = false;
+
+ });
+
+ }
+
+ });
+
+ }
+ const close_dialog = event => {
+
+ event.preventDefault();
+ event.stopPropagation();
+
+ el_dialog.classList.remove('visible');
+
+ };
+ const open_dialog = el => {
+
+ el_dialog.classList.toggle('visible');
+ el_dialog.classList.add('loading');
+
+ const dialog_config = {
+ arProductID: [],
+ arOrderProductID: [],
+ set_product_anr: ''
+ }
+
+ // Produkte auf der Seite
+ document.querySelectorAll('input[name="wpsg[produkt_id]"]').forEach(el => { dialog_config.arProductID.push(parseInt(el.value)); })
+
+ if (el !== undefined && el.classList.contains('wpsg_revocation_order_product')) {
+
+ el.querySelector('input').checked = true;
+
+ }
+
+ if (el !== undefined && el.classList.contains('wpsg_revocation_product_button')) {
+
+ dialog_config.set_product_anr = el.dataset.product_anr;
+
+ }
+
+ // Bestellung / Produkte
+ document.querySelectorAll('.wpsg_revocation_order_product_checkbox:checked').forEach(el => {
+
+ const order_id = parseInt(el.dataset.order_id);
+ const order_product_id = parseInt(el.dataset.order_product_id);
+ const product_id = parseInt(el.dataset.product_id);
+ const amount = parseInt(el.dataset.amount);
+
+ dialog_config.arOrderProductID.push({
+ order_id: order_id,
+ order_product_id: order_product_id,
+ amount: amount
+ });
+
+ dialog_config.arProductID.push(product_id);
+
+ });
+
+ fetch('<?php echo admin_url('admin-ajax.php'); ?>', {
+ method: 'POST',
+ body: new URLSearchParams({
+ nonce: wpsg_revocation_nonce,
+ action: 'wpsg_mod_revocation',
+ do: 'ajaxDialogContent',
+ dialog_config: JSON.stringify(dialog_config),
+ })
+ }).then(res => res.text()).then(html => {
+
+ el_dialog_content.innerHTML = html;
+ el_dialog.classList.remove('loading');
+
+ });
+
+ };
+
+ // Button am Produkt
+ document.querySelectorAll('.wpsg_revocation_product_button').forEach(el => {
+
+ el.addEventListener('click', event => {
+
+ open_dialog(el);
+
+ });
+
+ });
+
+ // Button Listener FlyOut
+ document.getElementById('wpsg_revocation_button').addEventListener('click', event => { open_dialog(); });
+
+ // GET Parameter verarbeiten
+ const urlParams = new URLSearchParams(window.location.search);
+
+ const get_order_nr = urlParams.get('wpsg_revo_order');
+ const get_product_nr = urlParams.get('wpsg_revo_product');
+ const get_amount = urlParams.get('wpsg_revo_amount');
+ const get_contact = urlParams.get('wpsg_revo_contact');
+
+ if (get_order_nr !== null) {
+
+ document.addEventListener('DOMContentLoaded', () => {
+
+ open_dialog();
+
+ const checkAndFillForm = () => {
+
+ const form = el_dialog.querySelector('form#wpsg_revocation_form');
+
+ if (!form) {
+
+ setTimeout(checkAndFillForm, 100);
+ return;
+
+ }
+
+ if (get_product_nr) {
+
+ const productNrInput = form.querySelector('input[name*="[product_nr]"]');
+
+ if (productNrInput) productNrInput.value = get_product_nr;
+
+ }
+
+ if (get_order_nr) {
+
+ const orderNrInput = form.querySelector('input[name*="[order_nr]"]');
+
+ if (orderNrInput) orderNrInput.value = get_order_nr;
+
+ }
+
+ if (get_amount) {
+
+ const amountInput = form.querySelector('input[name*="[amount]"]');
+
+ if (amountInput) amountInput.value = get_amount;
+
+ }
+
+ if (get_contact) {
+
+ const contactInput = form.querySelector('input[name="wpsg_revocation_reason[contact]"]');
+
+ if (contactInput) contactInput.value = get_contact;
+
+ }
+
+ };
+
+ checkAndFillForm();
+
+ });
+
+ }
+
+ // Layer Listener
+ el_dialog.addEventListener('click', event => {
+
+ if (!event.target.closest('.inner')) close_dialog(event);
+
+ });
+
+ // Produkte in Bestellung auf der Seite Listener
+ document.querySelectorAll('.wpsg_revocation_order_product')?.forEach(el => {
+
+ el.addEventListener('click', event => {
+
+ if (!event.target.closest('input[type="checkbox"]')) {
+
+ open_dialog(el);
+
+ }
+
+ });
+
+ });
+
+ // Close Button Listener
+ el_dialog.querySelectorAll('.close')?.forEach(el => {
+
+ el.addEventListener('click', event => { close_dialog(event); })
+
+ })
+
+ // Submit Button Listener
+ el_dialog.querySelectorAll('.wpsg_revocation_button_submit')?.forEach(el => {
+
+ el.addEventListener('click', event => { submit_dialog(event); });
+
+ })
+
+ // ESC Taste lauschen
+ document.addEventListener('keydown', function (e) {
+
+ if (e.key === 'Escape') {
+
+ el_dialog.classList.remove('visible');
+
+ }
+
+ });
+
+</script> \ No newline at end of file
diff --git a/views/mods/mod_revocation/wpsg_mod_kundenverwaltung_order_after_products.phtml b/views/mods/mod_revocation/wpsg_mod_kundenverwaltung_order_after_products.phtml
new file mode 100644
index 0000000..841da99
--- /dev/null
+++ b/views/mods/mod_revocation/wpsg_mod_kundenverwaltung_order_after_products.phtml
@@ -0,0 +1,49 @@
+<?php
+
+ declare(strict_types=1);
+
+ /**
+ * @author: Daniel Schmitzer
+ * @date: 10.04.26
+ * @time: 10:16
+ */
+
+ namespace wpsgRevocation;
+
+ use wpsg\M1;
+
+ $view = \wpsg_ShopController::getShop()->view;
+
+ /** @var \wpsg_order_product $oOrderProduct */
+ $oOrderProduct = $view['oOrderProduct'];
+
+ /** @var \wpsg_order $oOrder */
+ $oOrder = $view['oOrder'];
+
+ /** @var int $amount */
+ $amount = $view['amount'];
+
+?>
+
+<tr>
+ <td colspan="2">
+
+ <?php if (Revocation::getRevocationPossible($oOrder->getId(), $oOrderProduct->getId())) { ?>
+ <div class="wpsg_revocation_order_product">
+ <input type="checkbox"
+ class="wpsg_revocation_order_product_checkbox"
+ data-order_id="<?php echo $oOrder->getId(); ?>"
+ data-order_product_id="<?php echo $oOrderProduct->getId(); ?>"
+ data-product_id="<?php echo $oOrderProduct->getProduct()->getId(); ?>"
+ data-amount="<?php echo $amount; ?>"
+ />
+ <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M19,15V3H23V15H19M15,3A2,2 0 0,1 17,5V15C17,15.55 16.78,16.05 16.41,16.41L9.83,23L8.77,21.94C8.5,21.67 8.33,21.3 8.33,20.88L8.36,20.57L9.31,16H3C1.89,16 1,15.1 1,14V12C1,11.74 1.05,11.5 1.14,11.27L4.16,4.22C4.46,3.5 5.17,3 6,3H15M15,5H5.97L3,12V14H11.78L10.65,19.32L15,14.97V5Z" /></svg>
+ <span><?php echo __('Produkt widerrufen', 'wpsgRevocation'); ?></span>
+ </div>
+ <?php } else { ?>
+
+ <p class="wpsg_revocation_complete"><?php echo __('Bereits komplett widerrufen', 'wpsgRevocation'); ?></p>
+
+ <?php } ?>
+ </td>
+</tr> \ No newline at end of file
diff --git a/views/mods/mod_revocation/wpsg_producttemplate_afterButton.phtml b/views/mods/mod_revocation/wpsg_producttemplate_afterButton.phtml
new file mode 100644
index 0000000..241357e
--- /dev/null
+++ b/views/mods/mod_revocation/wpsg_producttemplate_afterButton.phtml
@@ -0,0 +1,25 @@
+<?php
+
+ declare(strict_types=1);
+
+ /**
+ * @author: Daniel Schmitzer
+ * @date: 10.04.26
+ * @time: 09:31
+ */
+
+ namespace wpsgRevocation;
+
+ use \wpsg\M1;
+
+ // M1::d(\wpsg_ShopController::getShop()->view['data']);
+
+?>
+
+<?php if (\wpsg_ShopController::getShop()->get_option('wpsg_mod_revocation_view_product') === '1') { ?>
+
+ <div class="wpsg_revocation_product_button" data-product_anr="<?php echo \wpsg_ShopController::getShop()->view['data']['anr']; ?>">
+ <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M19,15V3H23V15H19M15,3A2,2 0 0,1 17,5V15C17,15.55 16.78,16.05 16.41,16.41L9.83,23L8.77,21.94C8.5,21.67 8.33,21.3 8.33,20.88L8.36,20.57L9.31,16H3C1.89,16 1,15.1 1,14V12C1,11.74 1.05,11.5 1.14,11.27L4.16,4.22C4.46,3.5 5.17,3 6,3H15M15,5H5.97L3,12V14H11.78L10.65,19.32L15,14.97V5Z" /></svg>
+ </div>
+
+<?php } ?> \ No newline at end of file
diff --git a/views/mods/mod_revocation/wpsg_revocation.css b/views/mods/mod_revocation/wpsg_revocation.css
new file mode 100644
index 0000000..9ee5d0f
--- /dev/null
+++ b/views/mods/mod_revocation/wpsg_revocation.css
@@ -0,0 +1,58 @@
+#wpsg_revocation_button { position:fixed; right:0; top:25%; display:flex; gap:1rem; align-items:center; justify-content:flex-start; flex-wrap:nowrap; transform:translateX(calc(100% - (50px + 1rem + 0.5rem))); cursor:pointer; z-index:10;
+ background-color:white; border:1px solid black; border-radius:0.5rem; padding:0.5rem 1rem 0.5rem 0.5rem; transition:all 0.4s;
+ svg { width:50px; fill:black; }
+ span { white-space:nowrap; }
+ &:hover { transform:translateX(0.5rem); }
+}
+
+#wpsg_revocation_dialog {
+ z-index:10; opacity:0; pointer-events:none; transition:all 0.4s;
+ position:fixed; left:0; top:0; height:100vh; width:100vw;
+ background-color:rgba(0,0,0,0.5); display:flex; align-items:center; justify-content:center;
+ &.visible { opacity:1; pointer-events:all; }
+ .inner { width:calc(100% - 3rem); height:auto; max-width:800px; max-height:800px;
+ border:1px solid black; position:relative;
+ background-color:white; border-radius:0.5rem; padding:1rem; display:flex; flex-direction:column;
+ & > .loading { transition:all 0.2s; opacity:0; pointer-events:none; background-color:rgba(0, 0, 0, 0.25); position:absolute; z-index:2; left:0; top:0; height:100%; width:100%; display:flex; align-items:center; justify-content:center; }
+ & > .header { height:50px; flex-shrink:0; flex-grow:0;
+ display:flex; align-items:center; justify-content:space-between; font-size:2rem; font-weight:bold;
+ .close { width:30px; height:30px; cursor:pointer; display:flex; align-items:center; justify-content:center; }
+ }
+ & > .content { flex-grow:0.2; overflow-y:auto; margin-top:1rem; margin-bottom:1rem; }
+ & > .footer { flex-shrink:0; flex-grow:0; display:flex; align-items:center; justify-content:start; height: 35px; margin-bottom: 2rem;}
+ #wpsg_error { padding-left:5px; color:red; }
+ }
+ &.loading > .inner > .loading { opacity:1; pointer-events:all; }
+}
+
+.wpsg_revocation_product_button {
+ flex-shrink:0; padding:0.25rem; width:35px; height:35px;
+ border:1px solid black; display:flex; cursor:pointer;
+ svg { width:auto; }
+}
+
+#wpsg_revocation_form { display:flex; flex-direction:column; gap:0.5rem; width:100%;
+ .wpsg_revocation_order_product > div { width:100%; }
+ .form_field { display:flex; width:100%; flex-direction:column; gap:0.125rem;
+ .label { color: black; font-size: 1.25rem; }
+ .value { display:flex; justify-content:stretch; gap:0.25rem;
+ input, textarea, select { width:auto; flex-grow:1; min-height:30px; text-indent:0.25rem; flex-shrink:1; }
+ textarea { min-height:90px; padding:0.25rem; }
+ select { height:36px; }
+ input[type="number"] { flex-shrink:2; flex-grow:0; }
+ }
+ }
+}
+
+.wpsg_mod_kundenverwaltung_order {
+ .wpsg_revocation_order_product { display:inline-flex; align-items:center; gap:0.5rem; border:1px solid black; border-radius:0.5rem; padding:0.5rem;
+ margin-bottom:1rem; user-select:none; flex-direction: row;
+ & > svg { height:30px; width:30px; }
+ & > input { width:25px; height:25px; flex-shrink:0; }
+ & > .inner { cursor:pointer; }
+ }
+}
+
+.wpsg_amount_label {
+ word-break: normal;
+} \ No newline at end of file
diff --git a/views/mods/mod_revocation/wpsg_revocation.js b/views/mods/mod_revocation/wpsg_revocation.js
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/views/mods/mod_revocation/wpsg_revocation.js