event-tickets-with-ticket-scanner
Last commit date
3rd
1 week ago
css
1 week ago
img
1 week ago
includes
1 week ago
js
1 week ago
languages
1 week ago
ticket
1 week ago
vendors
1 week ago
SASO_EVENTTICKETS.php
1 week ago
backend.js
1 week ago
changelog-features.json
1 week ago
changelog.txt
1 week ago
db.php
1 week ago
index.php
1 week ago
init_file.php
1 week ago
order_details.js
1 week ago
pwa-sw.js
1 week ago
readme.txt
1 week ago
saso-eventtickets-validator.js
1 week ago
sasoEventtickets_AdminSettings.php
1 week ago
sasoEventtickets_Authtoken.php
1 week ago
sasoEventtickets_Base.php
1 week ago
sasoEventtickets_Core.php
1 week ago
sasoEventtickets_Frontend.php
1 week ago
sasoEventtickets_Messenger.php
1 week ago
sasoEventtickets_Options.php
1 week ago
sasoEventtickets_PDF.php
1 week ago
sasoEventtickets_Seating.php
1 week ago
sasoEventtickets_Ticket.php
1 week ago
sasoEventtickets_TicketBadge.php
1 week ago
sasoEventtickets_TicketDesigner.php
1 week ago
sasoEventtickets_TicketQR.php
1 week ago
ticket_events.js
1 week ago
ticket_scanner.js
1 week ago
validator.js
1 week ago
version-notices.json
1 week ago
vollstart-cross-promo.php
1 week ago
wc_backend.js
1 week ago
wc_frontend.js
1 week ago
woocommerce-hooks.php
1 week ago
wc_backend.js
649 lines
| 1 | function SasoEventticketsValidator_WC_backend($, phpObject) { |
| 2 | const { __, _x, _n, sprintf } = wp.i18n; |
| 3 | let _self = this; |
| 4 | let _sasoEventtickets; |
| 5 | let DATA = {}; |
| 6 | |
| 7 | function renderFormatterFields() { |
| 8 | let hiddenValueField = $('input[data-id="'+phpObject.formatterInputFieldDataId+'"]'); |
| 9 | let formatterValues = $(hiddenValueField).val(); |
| 10 | |
| 11 | if (formatterValues != "") { |
| 12 | try { |
| 13 | formatterValues = JSON.parse(formatterValues); |
| 14 | } catch (e) { |
| 15 | //console.log(e); |
| 16 | } |
| 17 | } |
| 18 | |
| 19 | let serialCodeFormatter = _sasoEventtickets.form_fields_serial_format($('#'+phpObject._divAreaId)); |
| 20 | serialCodeFormatter.setNoNumberOptions(); |
| 21 | serialCodeFormatter.setFormatterValues(formatterValues); |
| 22 | serialCodeFormatter.setCallbackHandle(_formatterValues=>{ |
| 23 | $(hiddenValueField).val(JSON.stringify(_formatterValues)); |
| 24 | }); |
| 25 | serialCodeFormatter.render(); |
| 26 | |
| 27 | $(hiddenValueField).val(JSON.stringify(serialCodeFormatter.getFormatterValues())); |
| 28 | } |
| 29 | |
| 30 | function _addHandlerToTheOrderCodeFields() { |
| 31 | if (typeof phpObject.tickets != "undefined") { |
| 32 | let ok = false; |
| 33 | for(let key in phpObject.tickets) { |
| 34 | if (phpObject.tickets[key].codes != "") { |
| 35 | ok = true; |
| 36 | break; |
| 37 | } |
| 38 | } |
| 39 | if (ok) { |
| 40 | $('body').find('button[data-id="'+phpObject.prefix+'btn_download_alltickets_one_pdf"]').prop('disabled', false).on('click', ()=>{ |
| 41 | let url = phpObject.ajaxurl + '?' |
| 42 | +'action='+encodeURIComponent(phpObject.action) |
| 43 | +'&nonce='+encodeURIComponent(phpObject.nonce) |
| 44 | +'&a_sngmbh=downloadAllTicketsAsOnePDF' |
| 45 | +'&data[order_id]='+encodeURIComponent(phpObject.order_id); |
| 46 | window.open(url, 'download_tickets'); |
| 47 | return false; |
| 48 | }); |
| 49 | $('body').find('button[data-id="'+phpObject.prefix+'btn_remove_tickets"]').prop('disabled', false).on('click', event=>{ |
| 50 | event.preventDefault(); |
| 51 | if (confirm("Do you want to remove the ticket from the order? Your customer will not be informed. New tickets will be assigned to the order if you change the order status and the status is set to assign ticket numbers. Or you use the add tickets button (Premium).")) { |
| 52 | let btn = event.target; |
| 53 | $(btn).prop("disabled", true); |
| 54 | let url = phpObject.ajaxurl; |
| 55 | let _data = { |
| 56 | action:encodeURIComponent(phpObject.action), |
| 57 | nonce:encodeURIComponent(phpObject.nonce), |
| 58 | a_sngmbh:'removeAllTicketsFromOrder', |
| 59 | "data[order_id]":encodeURIComponent(phpObject.order_id) |
| 60 | }; |
| 61 | // Pass through debug parameter if set in URL |
| 62 | var urlParams = new URLSearchParams(window.location.search); |
| 63 | if (urlParams.has('VollstartValidatorDebug')) { |
| 64 | _data['VollstartValidatorDebug'] = urlParams.get('VollstartValidatorDebug') || '1'; |
| 65 | } |
| 66 | $.get( url, _data, function( response ) { |
| 67 | if (!response.success) { |
| 68 | alert(response); |
| 69 | } else { |
| 70 | window.location.reload(true); |
| 71 | } |
| 72 | }); |
| 73 | } |
| 74 | return false; |
| 75 | }); |
| 76 | $('body').find('button[data-id="'+phpObject.prefix+'btn_download_badge"]').prop('disabled', false).on('click', event=>{ |
| 77 | event.preventDefault(); |
| 78 | // check how many tickets are in the order |
| 79 | // if more than 1, show a list of tickets |
| 80 | // if only 1, show the ticket |
| 81 | |
| 82 | let ticket_numbers = []; |
| 83 | for(var key in phpObject.tickets) { |
| 84 | let ticket = phpObject.tickets[key]; |
| 85 | if (ticket.codes != "") { |
| 86 | let codes = ticket.codes.split(','); |
| 87 | for(let i=0;i<codes.length;i++) { |
| 88 | let code = codes[i].trim(); |
| 89 | if (code != "") { |
| 90 | ticket_numbers.push(code); |
| 91 | } |
| 92 | } |
| 93 | } |
| 94 | } |
| 95 | |
| 96 | if (ticket_numbers.length > 1) { |
| 97 | let ticketList = $('<div>'); |
| 98 | for(let i=0;i<ticket_numbers.length;i++) { |
| 99 | let ticket_number = ticket_numbers[i]; |
| 100 | let elem = $('<div>').appendTo(ticketList); |
| 101 | elem.append($('<h4>').html('#'+(i+1)+'. '+ticket_number)); |
| 102 | elem.append($('<button>').html('Download').addClass('button button-primary')).on('click', event=>{ |
| 103 | event.preventDefault(); |
| 104 | _downloadFile('downloadPDFTicketBadge', {'code':ticket_number}); |
| 105 | return false; |
| 106 | }); |
| 107 | elem.append('<hr>'); |
| 108 | elem.appendTo(ticketList); |
| 109 | } |
| 110 | renderInfoBox(ticketList, 'Select a ticket badge to download'); |
| 111 | |
| 112 | } else { |
| 113 | _downloadFile('downloadPDFTicketBadge', {'code':ticket_numbers[0]}); |
| 114 | } |
| 115 | return false; |
| 116 | }); |
| 117 | $('body').find('button[data-id="'+phpObject.prefix+'btn_remove_non_tickets"]').prop('disabled', false).on('click', event=>{ |
| 118 | event.preventDefault(); |
| 119 | if (confirm("Do you want to remove the all ticket that cannot be found in the database from the order? This will keep the ticket numbers, that exists. Your customer will not be informed. New tickets will be assigned to the order if you change the order status and the status is set to assign ticket numbers. Or you use the add tickets button (Premium).")) { |
| 120 | let btn = event.target; |
| 121 | $(btn).prop("disabled", true); |
| 122 | let url = phpObject.ajaxurl; |
| 123 | let _data = { |
| 124 | action:encodeURIComponent(phpObject.action), |
| 125 | nonce:encodeURIComponent(phpObject.nonce), |
| 126 | a_sngmbh:'removeAllNonTicketsFromOrder', |
| 127 | "data[order_id]":encodeURIComponent(phpObject.order_id) |
| 128 | }; |
| 129 | // Pass through debug parameter if set in URL |
| 130 | var urlParams = new URLSearchParams(window.location.search); |
| 131 | if (urlParams.has('VollstartValidatorDebug')) { |
| 132 | _data['VollstartValidatorDebug'] = urlParams.get('VollstartValidatorDebug') || '1'; |
| 133 | } |
| 134 | $.get( url, _data, function( response ) { |
| 135 | if (!response.success) { |
| 136 | alert(response); |
| 137 | } else { |
| 138 | window.location.reload(true); |
| 139 | } |
| 140 | }); |
| 141 | } |
| 142 | return false; |
| 143 | }); |
| 144 | } |
| 145 | } |
| 146 | } |
| 147 | |
| 148 | function _addHandlerToTheCodeFields() { |
| 149 | $('body').find('button[data-id="'+phpObject.prefix+'btn_download_flyer"]').prop('disabled', false).on('click', ()=>{ |
| 150 | let url = phpObject.ajaxurl + '?' |
| 151 | +'action='+encodeURIComponent(phpObject.action) |
| 152 | +'&nonce='+encodeURIComponent(phpObject.nonce) |
| 153 | +'&a_sngmbh=downloadFlyer' |
| 154 | +'&data[product_id]='+encodeURIComponent(phpObject.product_id); |
| 155 | window.open(url, 'download_flyer'); |
| 156 | return false; |
| 157 | }); |
| 158 | |
| 159 | $('body').find('button[data-id="'+phpObject.prefix+'btn_download_ics"]').prop('disabled', false).on('click', ()=>{ |
| 160 | let url = phpObject.ajaxurl + '?' |
| 161 | +'action='+encodeURIComponent(phpObject.action) |
| 162 | +'&nonce='+encodeURIComponent(phpObject.nonce) |
| 163 | +'&a_sngmbh=downloadICSFile' |
| 164 | +'&data[product_id]='+encodeURIComponent(phpObject.product_id); |
| 165 | window.open(url, 'download_ics'); |
| 166 | return false; |
| 167 | }); |
| 168 | |
| 169 | $('body').find('button[data-id="'+phpObject.prefix+'btn_download_ticket_infos"]').prop('disabled', false).on('click', event=>{ |
| 170 | event.preventDefault(); |
| 171 | let btn = event.target; |
| 172 | $(btn).prop("disabled", true); |
| 173 | let url = phpObject.ajaxurl; |
| 174 | let _data = { |
| 175 | action:encodeURIComponent(phpObject.action), |
| 176 | nonce:encodeURIComponent(phpObject.nonce), |
| 177 | a_sngmbh:'downloadTicketInfosOfProduct', |
| 178 | "data[product_id]":encodeURIComponent(phpObject.product_id) |
| 179 | }; |
| 180 | // Pass through debug parameter if set in URL |
| 181 | var urlParams = new URLSearchParams(window.location.search); |
| 182 | if (urlParams.has('VollstartValidatorDebug')) { |
| 183 | _data['VollstartValidatorDebug'] = urlParams.get('VollstartValidatorDebug') || '1'; |
| 184 | } |
| 185 | $.get( url, _data, function( response ) { |
| 186 | if (!response.success) { |
| 187 | alert(response); |
| 188 | } else { |
| 189 | let ticket_infos = response.data.ticket_infos; |
| 190 | let product = response.data.product; |
| 191 | let w = window.open('about:blank'); |
| 192 | addStyleCode('.lds-dual-ring {display:inline-block;width:64px;height:64px;}.lds-dual-ring:after {content:" ";display:block;width:46px;height:46px;margin:1px;border-radius:50%;border:5px solid #fff;border-color:#2e74b5 transparent #2e74b5 transparent;animation:lds-dual-ring 0.6s linear infinite;}@keyframes lds-dual-ring {0% {transform: rotate(0deg);}100% {transform: rotate(360deg);}}', w.document); |
| 193 | w.document.body.innerHTML += _getSpinnerHTML(); |
| 194 | window.setTimeout(()=>{ |
| 195 | let output = $('<div style="margin-left:2.5cm;margin-top:1cm;">'); |
| 196 | output.append($('<h3>').html('Ticket Infos for Product "'+product.name+'"')); |
| 197 | for(let i=0;i<ticket_infos.length;i++) { |
| 198 | let ticket_info = ticket_infos[i]; |
| 199 | let metaObj = getCodeObjectMeta(ticket_info); |
| 200 | let elem = $('<div>').appendTo(output); |
| 201 | elem.append($('<h4>').html('#'+(i+1)+'. '+ticket_info.code_display)); |
| 202 | if (metaObj.wc_ticket._public_ticket_id) { |
| 203 | elem.append($('<div>').html('Ticket Public Id: '+metaObj.wc_ticket._public_ticket_id)); |
| 204 | } |
| 205 | elem.append("Order Id: "+metaObj.woocommerce.order_id+"<br>"); |
| 206 | if (ticket_info._customer_name) { |
| 207 | elem.append(ticket_info._customer_name); |
| 208 | } |
| 209 | elem.append($('<div style="margin-top:10px;margin-bottom:15px;">').qrcode(ticket_info.code)); |
| 210 | elem.append('<hr>'); |
| 211 | elem.appendTo(output); |
| 212 | } |
| 213 | $(w.document.body).html(output); |
| 214 | $(btn).prop("disabled", false); |
| 215 | w.print(); |
| 216 | }, 250); |
| 217 | } |
| 218 | }); |
| 219 | }); |
| 220 | } |
| 221 | |
| 222 | function _addHandlerToTheInputFields() { |
| 223 | //console.log(phpObject); |
| 224 | } |
| 225 | |
| 226 | function getCodeObjectMeta(codeObj) { |
| 227 | if (!codeObj.metaObj) codeObj.metaObj = JSON.parse(codeObj.meta); |
| 228 | return codeObj.metaObj; |
| 229 | } |
| 230 | |
| 231 | function _downloadFile(action, myData, filenameToStore, cbf, ecbf, pcbf) { |
| 232 | let _data = Object.assign({}, DATA); |
| 233 | _data.action = phpObject.action; |
| 234 | _data.a_sngmbh = action; |
| 235 | _data.t = new Date().getTime(); |
| 236 | _data.nonce = phpObject.nonce; |
| 237 | pcbf && pcbf(); |
| 238 | for(var key in myData) _data['data['+key+']'] = myData[key]; |
| 239 | let params = ""; |
| 240 | for(var key in _data) params += key+"="+_data[key]+"&"; |
| 241 | let url = phpObject.ajaxurl+'?'+params; |
| 242 | let window_name = myData.code ? myData.code : '_blank'; |
| 243 | let new_window = window.open(url, window_name); |
| 244 | //window.location.href = url; |
| 245 | //ajax_downloadFile(url, filenameToStore, cbf); |
| 246 | } |
| 247 | |
| 248 | function renderInfoBox(content, myTitle) { |
| 249 | let dlg = $('<div/>').html(content); |
| 250 | let _options = { |
| 251 | title: myTitle ? myTitle : 'Info', |
| 252 | modal: true, |
| 253 | minWidth: 400, |
| 254 | minHeight: 200, |
| 255 | buttons: [{text:'Ok', click:()=>{ |
| 256 | closeDialog(dlg); |
| 257 | }}] |
| 258 | }; |
| 259 | dlg.dialog(_options); |
| 260 | return dlg; |
| 261 | } |
| 262 | |
| 263 | function closeDialog(dlg) { |
| 264 | $(dlg).dialog( "close" ); |
| 265 | $(dlg).html(''); |
| 266 | $(dlg).dialog("destroy").remove(); |
| 267 | $(dlg).empty(); |
| 268 | $(dlg).remove(); |
| 269 | $('.ui-dialog-content').dialog('destroy'); |
| 270 | } |
| 271 | |
| 272 | function addStyleCode(content, d) { |
| 273 | if (!d) d = document; |
| 274 | let c = d.createElement('style'); |
| 275 | c.innerHTML = content; |
| 276 | d.getElementsByTagName("head")[0].appendChild(c); |
| 277 | } |
| 278 | |
| 279 | function _getSpinnerHTML() { |
| 280 | return '<span class="lds-dual-ring"></span>'; |
| 281 | } |
| 282 | |
| 283 | // ── Product Calendar (#191) ───────────────────────────────── |
| 284 | let calendarData = {}; |
| 285 | let calendarCurrentMonth = null; |
| 286 | |
| 287 | let $calendarContent = null; |
| 288 | |
| 289 | function calendarInit() { |
| 290 | if (!phpObject.product_id || phpObject.product_id <= 0) return; |
| 291 | |
| 292 | let $btn = $('button[data-id="' + phpObject.prefix + 'btn_product_calendar"]'); |
| 293 | if ($btn.length === 0) return; |
| 294 | |
| 295 | $btn.prop('disabled', false).on('click', function(e) { |
| 296 | e.preventDefault(); |
| 297 | $calendarContent = $('<div>').html(_getSpinnerHTML()); |
| 298 | $calendarContent.dialog({ |
| 299 | title: __('Sold Tickets Calendar', 'event-tickets-with-ticket-scanner'), |
| 300 | modal: true, |
| 301 | width: 520, |
| 302 | minHeight: 300, |
| 303 | close: function() { $(this).dialog('destroy').remove(); } |
| 304 | }); |
| 305 | calendarLoad(); |
| 306 | }); |
| 307 | |
| 308 | let $printBtn = $('button[data-id="' + phpObject.prefix + 'btn_product_calendar_print"]'); |
| 309 | if ($printBtn.length > 0) { |
| 310 | $printBtn.prop('disabled', false).on('click', function(e) { |
| 311 | e.preventDefault(); |
| 312 | calendarPrintList(); |
| 313 | }); |
| 314 | } |
| 315 | } |
| 316 | |
| 317 | function calendarPrintList() { |
| 318 | let w = window.open('about:blank'); |
| 319 | addStyleCode('.lds-dual-ring {display:inline-block;width:64px;height:64px;}.lds-dual-ring:after {content:" ";display:block;width:46px;height:46px;margin:1px;border-radius:50%;border:5px solid #fff;border-color:#2e74b5 transparent #2e74b5 transparent;animation:lds-dual-ring 0.6s linear infinite;}@keyframes lds-dual-ring {0% {transform: rotate(0deg);}100% {transform: rotate(360deg);}}', w.document); |
| 320 | w.document.body.innerHTML += _getSpinnerHTML(); |
| 321 | |
| 322 | $.get(phpObject.ajaxurl, { |
| 323 | action: phpObject.action, |
| 324 | nonce: phpObject.nonce, |
| 325 | a_sngmbh: 'getProductCalendarData', |
| 326 | 'data[product_id]': phpObject.product_id |
| 327 | }, function(response) { |
| 328 | if (!response.success) { |
| 329 | w.document.body.innerHTML = '<p style="color:red;">' + (response.data || 'Error') + '</p>'; |
| 330 | return; |
| 331 | } |
| 332 | let dates = response.data.dates || {}; |
| 333 | let sortedDates = Object.keys(dates).sort(); |
| 334 | |
| 335 | if (sortedDates.length === 0) { |
| 336 | w.document.body.innerHTML = '<p>' + __('No tickets found.', 'event-tickets-with-ticket-scanner') + '</p>'; |
| 337 | return; |
| 338 | } |
| 339 | |
| 340 | let promises = sortedDates.map(function(dateStr) { |
| 341 | return new Promise(function(resolve) { |
| 342 | $.get(phpObject.ajaxurl, { |
| 343 | action: phpObject.action, |
| 344 | nonce: phpObject.nonce, |
| 345 | a_sngmbh: 'getProductCalendarDetails', |
| 346 | 'data[product_id]': phpObject.product_id, |
| 347 | 'data[date]': dateStr |
| 348 | }, function(resp) { |
| 349 | resolve({date: dateStr, count: dates[dateStr], tickets: resp.success ? resp.data : []}); |
| 350 | }).fail(function() { |
| 351 | resolve({date: dateStr, count: dates[dateStr], tickets: []}); |
| 352 | }); |
| 353 | }); |
| 354 | }); |
| 355 | |
| 356 | Promise.all(promises).then(function(groups) { |
| 357 | let productName = $('#title').val() || document.title; |
| 358 | let $output = $('<div style="margin:1cm 2cm;font-family:sans-serif;">'); |
| 359 | $output.append('<h2>' + sprintf( |
| 360 | /* translators: %s: product name */ |
| 361 | __('Ticket List — %s', 'event-tickets-with-ticket-scanner'), |
| 362 | productName |
| 363 | ) + '</h2>'); |
| 364 | |
| 365 | let grandTotal = 0; |
| 366 | for (let i = 0; i < groups.length; i++) { |
| 367 | let g = groups[i]; |
| 368 | grandTotal += g.count; |
| 369 | |
| 370 | $output.append('<h3 style="margin-top:1.5em;border-bottom:1px solid #ccc;padding-bottom:4px;">' + g.date + ' (' + sprintf( |
| 371 | /* translators: %d: number of tickets */ |
| 372 | _n('%d ticket', '%d tickets', g.count, 'event-tickets-with-ticket-scanner'), |
| 373 | g.count |
| 374 | ) + ')</h3>'); |
| 375 | |
| 376 | if (g.tickets.length === 0) { |
| 377 | $output.append('<p><em>' + __('No details available.', 'event-tickets-with-ticket-scanner') + '</em></p>'); |
| 378 | continue; |
| 379 | } |
| 380 | |
| 381 | let $table = $('<table style="width:100%;border-collapse:collapse;margin-bottom:1em;table-layout:fixed;">'); |
| 382 | $table.append('<thead><tr style="background:#f0f0f0;">' |
| 383 | + '<th style="text-align:left;padding:4px 8px;border:1px solid #ddd;width:1cm;">#</th>' |
| 384 | + '<th style="text-align:left;padding:4px 8px;border:1px solid #ddd;">' + __('Ticket', 'event-tickets-with-ticket-scanner') + '</th>' |
| 385 | + '<th style="text-align:left;padding:4px 8px;border:1px solid #ddd;width:2cm;">' + __('Order', 'event-tickets-with-ticket-scanner') + '</th>' |
| 386 | + '<th style="text-align:left;padding:4px 8px;border:1px solid #ddd;width:2cm;">' + __('Status', 'event-tickets-with-ticket-scanner') + '</th>' |
| 387 | + '</tr></thead>'); |
| 388 | let $tbody = $('<tbody>'); |
| 389 | for (let j = 0; j < g.tickets.length; j++) { |
| 390 | let t = g.tickets[j]; |
| 391 | let statusText = t.redeemed |
| 392 | ? __('Redeemed', 'event-tickets-with-ticket-scanner') |
| 393 | : __('Active', 'event-tickets-with-ticket-scanner'); |
| 394 | $tbody.append('<tr>' |
| 395 | + '<td style="padding:3px 8px;border:1px solid #ddd;">' + (j + 1) + '</td>' |
| 396 | + '<td style="padding:3px 8px;border:1px solid #ddd;">' + t.code_display + '</td>' |
| 397 | + '<td style="padding:3px 8px;border:1px solid #ddd;">' + (t.order_id > 0 ? '#' + t.order_id : '-') + '</td>' |
| 398 | + '<td style="padding:3px 8px;border:1px solid #ddd;">' + statusText + '</td>' |
| 399 | + '</tr>'); |
| 400 | } |
| 401 | $table.append($tbody); |
| 402 | $output.append($table); |
| 403 | } |
| 404 | |
| 405 | $output.append('<p style="margin-top:1em;font-weight:bold;">' + sprintf( |
| 406 | /* translators: %d: total number of tickets */ |
| 407 | __('Total: %d tickets', 'event-tickets-with-ticket-scanner'), |
| 408 | grandTotal |
| 409 | ) + '</p>'); |
| 410 | |
| 411 | $(w.document.body).html($output); |
| 412 | w.print(); |
| 413 | }); |
| 414 | }); |
| 415 | } |
| 416 | |
| 417 | function calendarLoad() { |
| 418 | if ($calendarContent) $calendarContent.html(_getSpinnerHTML()); |
| 419 | |
| 420 | $.get(phpObject.ajaxurl, { |
| 421 | action: phpObject.action, |
| 422 | nonce: phpObject.nonce, |
| 423 | a_sngmbh: 'getProductCalendarData', |
| 424 | 'data[product_id]': phpObject.product_id |
| 425 | }, function(response) { |
| 426 | if (!response.success) { |
| 427 | if ($calendarContent) $calendarContent.html('<p style="color:red;">' + (response.data || 'Error') + '</p>'); |
| 428 | return; |
| 429 | } |
| 430 | calendarData = response.data.dates || {}; |
| 431 | |
| 432 | let dates = Object.keys(calendarData).sort(); |
| 433 | if (dates.length > 0) { |
| 434 | let parts = dates[dates.length - 1].split('-'); |
| 435 | calendarCurrentMonth = {year: parseInt(parts[0]), month: parseInt(parts[1]) - 1}; |
| 436 | } else { |
| 437 | let now = new Date(); |
| 438 | calendarCurrentMonth = {year: now.getFullYear(), month: now.getMonth()}; |
| 439 | } |
| 440 | calendarRender(); |
| 441 | }); |
| 442 | } |
| 443 | |
| 444 | function calendarRender() { |
| 445 | let $content = $calendarContent; |
| 446 | if (!$content) return; |
| 447 | let year = calendarCurrentMonth.year; |
| 448 | let month = calendarCurrentMonth.month; |
| 449 | |
| 450 | let monthNames = [ |
| 451 | __('January', 'event-tickets-with-ticket-scanner'), |
| 452 | __('February', 'event-tickets-with-ticket-scanner'), |
| 453 | __('March', 'event-tickets-with-ticket-scanner'), |
| 454 | __('April', 'event-tickets-with-ticket-scanner'), |
| 455 | __('May', 'event-tickets-with-ticket-scanner'), |
| 456 | __('June', 'event-tickets-with-ticket-scanner'), |
| 457 | __('July', 'event-tickets-with-ticket-scanner'), |
| 458 | __('August', 'event-tickets-with-ticket-scanner'), |
| 459 | __('September', 'event-tickets-with-ticket-scanner'), |
| 460 | __('October', 'event-tickets-with-ticket-scanner'), |
| 461 | __('November', 'event-tickets-with-ticket-scanner'), |
| 462 | __('December', 'event-tickets-with-ticket-scanner') |
| 463 | ]; |
| 464 | let dayHeaders = [ |
| 465 | __('Mon', 'event-tickets-with-ticket-scanner'), |
| 466 | __('Tue', 'event-tickets-with-ticket-scanner'), |
| 467 | __('Wed', 'event-tickets-with-ticket-scanner'), |
| 468 | __('Thu', 'event-tickets-with-ticket-scanner'), |
| 469 | __('Fri', 'event-tickets-with-ticket-scanner'), |
| 470 | __('Sat', 'event-tickets-with-ticket-scanner'), |
| 471 | __('Sun', 'event-tickets-with-ticket-scanner') |
| 472 | ]; |
| 473 | |
| 474 | let $nav = $('<div style="display:flex;justify-content:space-between;align-items:center;margin-bottom:8px;">'); |
| 475 | let $prev = $('<button type="button" class="button button-small">«</button>'); |
| 476 | let $next = $('<button type="button" class="button button-small">»</button>'); |
| 477 | let $title = $('<strong>' + monthNames[month] + ' ' + year + '</strong>'); |
| 478 | $prev.on('click', function(e) { e.preventDefault(); calendarNavigate(-1); }); |
| 479 | $next.on('click', function(e) { e.preventDefault(); calendarNavigate(1); }); |
| 480 | $nav.append($prev).append($title).append($next); |
| 481 | |
| 482 | let $table = $('<table class="widefat" style="table-layout:fixed;text-align:center;">'); |
| 483 | let $thead = $('<thead><tr></tr></thead>'); |
| 484 | for (let i = 0; i < 7; i++) { |
| 485 | $thead.find('tr').append('<th style="text-align:center;padding:4px;">' + dayHeaders[i] + '</th>'); |
| 486 | } |
| 487 | $table.append($thead); |
| 488 | |
| 489 | let $tbody = $('<tbody>'); |
| 490 | let firstDay = new Date(year, month, 1).getDay(); |
| 491 | let startOffset = (firstDay === 0 ? 6 : firstDay - 1); |
| 492 | let daysInMonth = new Date(year, month + 1, 0).getDate(); |
| 493 | let day = 1; |
| 494 | |
| 495 | for (let row = 0; row < 6 && day <= daysInMonth; row++) { |
| 496 | let $tr = $('<tr>'); |
| 497 | for (let col = 0; col < 7; col++) { |
| 498 | if ((row === 0 && col < startOffset) || day > daysInMonth) { |
| 499 | $tr.append('<td style="padding:4px;"></td>'); |
| 500 | } else { |
| 501 | let dateStr = year + '-' + String(month + 1).padStart(2, '0') + '-' + String(day).padStart(2, '0'); |
| 502 | let count = calendarData[dateStr] || 0; |
| 503 | let $td = $('<td style="padding:4px;position:relative;vertical-align:top;height:45px;">'); |
| 504 | $td.append('<div style="font-size:11px;color:#666;">' + day + '</div>'); |
| 505 | if (count > 0) { |
| 506 | let $badge = $('<div style="font-weight:bold;color:#0073aa;cursor:pointer;">' + count + '</div>'); |
| 507 | $badge.data('cal-date', dateStr); |
| 508 | $badge.on('click', function(e) { |
| 509 | e.preventDefault(); |
| 510 | calendarShowDetails($(this).data('cal-date')); |
| 511 | }); |
| 512 | $td.append($badge); |
| 513 | $td.css('background', '#f0f7ff'); |
| 514 | } |
| 515 | $tr.append($td); |
| 516 | day++; |
| 517 | } |
| 518 | } |
| 519 | $tbody.append($tr); |
| 520 | } |
| 521 | $table.append($tbody); |
| 522 | |
| 523 | let total = 0; |
| 524 | for (let d in calendarData) { total += calendarData[d]; } |
| 525 | let $totalDiv = $('<div style="margin-top:8px;font-size:12px;color:#666;">'); |
| 526 | $totalDiv.text( |
| 527 | sprintf( |
| 528 | /* translators: %d: total number of sold tickets */ |
| 529 | __('Total sold: %d tickets', 'event-tickets-with-ticket-scanner'), |
| 530 | total |
| 531 | ) |
| 532 | ); |
| 533 | |
| 534 | $content.empty().append($nav).append($table).append($totalDiv); |
| 535 | } |
| 536 | |
| 537 | function calendarNavigate(direction) { |
| 538 | calendarCurrentMonth.month += direction; |
| 539 | if (calendarCurrentMonth.month < 0) { |
| 540 | calendarCurrentMonth.month = 11; |
| 541 | calendarCurrentMonth.year--; |
| 542 | } else if (calendarCurrentMonth.month > 11) { |
| 543 | calendarCurrentMonth.month = 0; |
| 544 | calendarCurrentMonth.year++; |
| 545 | } |
| 546 | calendarRender(); |
| 547 | } |
| 548 | |
| 549 | function calendarShowDetails(dateStr) { |
| 550 | let $dlgContent = $('<div>').html(_getSpinnerHTML()); |
| 551 | $dlgContent.dialog({ |
| 552 | title: sprintf( |
| 553 | /* translators: %s: date string */ |
| 554 | __('Tickets for %s', 'event-tickets-with-ticket-scanner'), |
| 555 | dateStr |
| 556 | ), |
| 557 | modal: true, |
| 558 | width: 500, |
| 559 | close: function() { $(this).dialog('destroy'); } |
| 560 | }); |
| 561 | |
| 562 | $.get(phpObject.ajaxurl, { |
| 563 | action: phpObject.action, |
| 564 | nonce: phpObject.nonce, |
| 565 | a_sngmbh: 'getProductCalendarDetails', |
| 566 | 'data[product_id]': phpObject.product_id, |
| 567 | 'data[date]': dateStr |
| 568 | }, function(response) { |
| 569 | if (!response.success) { |
| 570 | $dlgContent.html('<p style="color:red;">' + (response.data || 'Error') + '</p>'); |
| 571 | return; |
| 572 | } |
| 573 | let tickets = response.data; |
| 574 | if (tickets.length === 0) { |
| 575 | $dlgContent.html('<p>' + __('No tickets found for this date.', 'event-tickets-with-ticket-scanner') + '</p>'); |
| 576 | return; |
| 577 | } |
| 578 | |
| 579 | let $table = $('<table class="widefat striped">'); |
| 580 | $table.append('<thead><tr>' |
| 581 | + '<th>' + __('Ticket', 'event-tickets-with-ticket-scanner') + '</th>' |
| 582 | + '<th>' + __('Order', 'event-tickets-with-ticket-scanner') + '</th>' |
| 583 | + '<th>' + __('Status', 'event-tickets-with-ticket-scanner') + '</th>' |
| 584 | + '</tr></thead>'); |
| 585 | let $tbody = $('<tbody>'); |
| 586 | |
| 587 | for (let i = 0; i < tickets.length; i++) { |
| 588 | let t = tickets[i]; |
| 589 | let $tr = $('<tr>'); |
| 590 | |
| 591 | let ticketHtml; |
| 592 | if (t.public_ticket_id && phpObject.ticket_base_url) { |
| 593 | ticketHtml = '<a href="' + phpObject.ticket_base_url + t.public_ticket_id + '" target="_blank">' + t.code_display + '</a>'; |
| 594 | } else { |
| 595 | ticketHtml = t.code_display; |
| 596 | } |
| 597 | $tr.append('<td>' + ticketHtml + '</td>'); |
| 598 | |
| 599 | let orderHtml = t.order_id > 0 |
| 600 | ? '<a href="' + phpObject.ajaxurl.replace('admin-ajax.php', 'post.php?post=' + t.order_id + '&action=edit') + '" target="_blank">#' + t.order_id + '</a>' |
| 601 | : '-'; |
| 602 | $tr.append('<td>' + orderHtml + '</td>'); |
| 603 | |
| 604 | let statusText = t.redeemed |
| 605 | ? __('Redeemed', 'event-tickets-with-ticket-scanner') |
| 606 | : __('Active', 'event-tickets-with-ticket-scanner'); |
| 607 | let statusColor = t.redeemed ? '#d63638' : '#00a32a'; |
| 608 | $tr.append('<td style="color:' + statusColor + ';">' + statusText + '</td>'); |
| 609 | |
| 610 | $tbody.append($tr); |
| 611 | } |
| 612 | $table.append($tbody); |
| 613 | $dlgContent.empty().append($table); |
| 614 | }); |
| 615 | } |
| 616 | |
| 617 | function starten() { |
| 618 | _sasoEventtickets = sasoEventtickets(phpObject, true); |
| 619 | if (phpObject.scope && phpObject.scope == "order") { |
| 620 | _addHandlerToTheOrderCodeFields(); |
| 621 | } else { |
| 622 | renderFormatterFields(); |
| 623 | _addHandlerToTheCodeFields(); |
| 624 | _addHandlerToTheInputFields(); |
| 625 | calendarInit(); |
| 626 | } |
| 627 | } |
| 628 | |
| 629 | function init() { |
| 630 | if (typeof sasoEventtickets === "undefined") { |
| 631 | $.ajax({ |
| 632 | url: phpObject._backendJS, |
| 633 | dataType: 'script', |
| 634 | success: function( data, textStatus, jqxhr ) { |
| 635 | starten(); |
| 636 | } |
| 637 | }); |
| 638 | } else { |
| 639 | starten(); |
| 640 | } |
| 641 | } |
| 642 | |
| 643 | init(); |
| 644 | } |
| 645 | (function($){ |
| 646 | $(document).ready(function(){ |
| 647 | SasoEventticketsValidator_WC_backend($, Ajax_sasoEventtickets_wc); |
| 648 | }); |
| 649 | })(jQuery); |