PluginProbe ʕ •ᴥ•ʔ
Event Tickets with Ticket Scanner / 3.1.2
Event Tickets with Ticket Scanner v3.1.2
3.1.2 3.1.1 3.1.0 3.0.9 3.0.8 3.0.7 3.0.6 3.0.5 3.0.4 trunk 2.6.0 2.7.0 2.7.1 2.7.10 2.7.2 2.7.3 2.7.4 2.7.5 2.7.6 2.7.7 2.7.8 2.7.9 2.8.0 2.8.1 2.8.10 2.8.2 2.8.3 2.8.4 2.8.5 2.8.6 2.8.7 2.8.8 2.8.9 2.9.0 2.9.2 2.9.3 2.9.4 2.9.5 2.9.6 2.9.7 2.9.8 2.9.9 3.0.0 3.0.1 3.0.2 3.0.3
event-tickets-with-ticket-scanner / wc_backend.js
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">&laquo;</button>');
476 let $next = $('<button type="button" class="button button-small">&raquo;</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);