diff options
Diffstat (limited to 'views')
| -rwxr-xr-x | views/mods/mod_ticket/basket_row.phtml | 21 | ||||
| -rw-r--r-- | views/mods/mod_ticket/order_view.phtml | 125 | ||||
| -rwxr-xr-x | views/mods/mod_ticket/order_view_row.phtml | 41 | ||||
| -rw-r--r-- | views/mods/mod_ticket/product_addedit_content.phtml | 526 | ||||
| -rw-r--r-- | views/mods/mod_ticket/produkttemplate.phtml | 255 | ||||
| -rw-r--r-- | views/mods/mod_ticket/qrScanner.phtml | 221 | ||||
| -rw-r--r-- | views/mods/mod_ticket/settings_edit.phtml | 159 | ||||
| -rwxr-xr-x | views/mods/mod_ticket/settings_edit_templates.phtml | 209 | ||||
| -rw-r--r-- | views/mods/mod_ticket/ticket_mail.phtml | 21 | ||||
| -rw-r--r-- | views/mods/mod_ticket/ticket_mail_html.phtml | 20 |
10 files changed, 1598 insertions, 0 deletions
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> |
