130130 </div>
131131
132132 <div class="col-md-3 align-items-end">
133- <button type="button" class="btn btn-primary btn-block" onclick="upload(this)">
134- <i class="fa fa-upload mr-1"></i> ' .tr ('Carica ricevuta ' ).'
135- </button>
133+ <div class="btn-group btn-block">
134+ <button type="button" class="btn btn-primary" onclick="upload(this)">
135+ <i class="fa fa-upload mr-1"></i> ' .tr ('Carica ricevuta ' ).'
136+ </button>
137+ <button type="button" class="btn btn-info" onclick="manual_upload(this)" title=" ' .tr ('Carica e associa manualmente ' ).'">
138+ <i class="fa fa-link"></i>
139+ </button>
140+ </div>
136141 </div>
137142 </div>
138143 </div>
@@ -258,6 +263,41 @@ function searchReceipts(button) {
258263 $(".tip").tooltip();
259264 });
260265}
266+
267+ function manual_upload(btn) {
268+ if ($("#blob").val()) {
269+ var restore = buttonLoading(btn);
270+
271+ // Mostra un \'animazione di caricamento
272+ $("#main_loading").show();
273+
274+ $("#upload").ajaxSubmit({
275+ url: globals.rootdir + "/actions.php",
276+ data: {
277+ op: "save",
278+ id_module: " ' .$ id_module .'",
279+ id_plugin: " ' .$ id_plugin .'",
280+ },
281+ type: "post",
282+ success: function(data){
283+ $("#main_loading").fadeOut();
284+ var result = JSON.parse(data);
285+
286+ // Mostra sempre il selettore per l \'associazione manuale
287+ showInvoiceSelector(result.file, btn, restore, result);
288+ },
289+ error: function(xhr) {
290+ $("#main_loading").fadeOut();
291+ swal(" ' .tr ('Errore ' ).'", xhr.responseJSON.error.message, "error");
292+
293+ buttonRestore(btn, restore);
294+ }
295+ });
296+ } else {
297+ swal(" ' .tr ('Attenzione ' ).'", " ' .tr ('Seleziona un file da caricare ' ).'", "warning");
298+ }
299+ }
300+
261301function upload(btn) {
262302 if ($("#blob").val()) {
263303 var restore = buttonLoading(btn);
@@ -276,7 +316,6 @@ function upload(btn) {
276316 success: function(data){
277317 $("#main_loading").fadeOut();
278318 importMessage(data);
279-
280319 buttonRestore(btn, restore);
281320 },
282321 error: function(xhr) {
@@ -347,20 +386,30 @@ function importAllReceipt(btn) {
347386 var html = " ' .tr ('Non sono state trovate ricevute da importare ' ).'.";
348387 } else {
349388 var html = " ' .tr ('Sono state elaborate le seguenti ricevute: ' ).'";
389+ var ricevute_non_associate = [];
350390
351391 data.forEach(function(element) {
352392 var text = "";
353393 if(element.fattura) {
354394 text += element.fattura;
355395 } else {
356- text += "<i> ' .tr ('Fattura relativa alla ricevuta non rilevata. Controlla che esista una fattura di vendita corrispondente caricata a gestionale. ' ).'</i>";
396+ text += "<i> ' .tr ('Fattura relativa alla ricevuta non rilevata ' ).'</i>";
397+ ricevute_non_associate.push(element.file);
357398 }
358399
359400 text += " (" + element.file + ")";
360401
361402 html += "<small><li>" + text + "</li></small>";
362403 });
363404
405+ if (ricevute_non_associate.length > 0) {
406+ html += "<br><div class=\"alert alert-warning\"><strong> ' .tr ('Attenzione ' ).':</strong> ' .tr ('Le seguenti ricevute non sono state associate automaticamente ' ).':<br>";
407+ ricevute_non_associate.forEach(function(file) {
408+ html += "<small>- " + file + "</small><br>";
409+ });
410+ html += " ' .tr ('Puoi associarle manualmente utilizzando il pulsante di importazione per ogni singola ricevuta ' ).'</div>";
411+ }
412+
364413 html += "<br><small> ' .tr ("Se si sono verificati degli errori durante la procedura e il problema continua a verificarsi, contatta l'assistenza ufficiale " ).'</small>";
365414 }
366415
@@ -386,4 +435,198 @@ function importAllReceipt(btn) {
386435 }
387436 });
388437}
438+
439+ function showInvoiceSelector(receiptFile, originalButton, originalRestore, receiptData) {
440+ // Se receiptData non è fornito, ottieni le informazioni sulla ricevuta
441+ if (!receiptData) {
442+ $.ajax({
443+ url: globals.rootdir + "/actions.php",
444+ type: "get",
445+ data: {
446+ id_module: " ' .$ id_module .'",
447+ id_plugin: " ' .$ id_plugin .'",
448+ op: "get_receipt_info",
449+ name: receiptFile,
450+ },
451+ success: function(data) {
452+ var receiptInfo = JSON.parse(data);
453+ showInvoiceSelectorInternal(receiptFile, originalButton, originalRestore, receiptInfo);
454+ },
455+ error: function(xhr) {
456+ swal(" ' .tr ('Errore ' ).'", " ' .tr ('Errore nel caricamento delle informazioni della ricevuta ' ).'", "error");
457+ buttonRestore(originalButton, originalRestore);
458+ }
459+ });
460+ } else {
461+ showInvoiceSelectorInternal(receiptFile, originalButton, originalRestore, receiptData);
462+ }
463+ }
464+
465+ function showInvoiceSelectorInternal(receiptFile, originalButton, originalRestore, receiptInfo) {
466+
467+ // Poi cerca le fatture in elaborazione
468+ $.ajax({
469+ url: globals.rootdir + "/actions.php",
470+ type: "get",
471+ data: {
472+ id_module: " ' .$ id_module .'",
473+ id_plugin: " ' .$ id_plugin .'",
474+ op: "search_fatture_elaborazione",
475+ },
476+ success: function(data) {
477+ var fatture = JSON.parse(data);
478+
479+ if (fatture.length === 0) {
480+ swal({
481+ title: " ' .tr ('Nessuna fattura trovata ' ).'",
482+ html: " ' .tr ('Non sono state trovate fatture con stato \"In elaborazione\" da associare alla ricevuta ' ).' <strong>" + receiptFile + "</strong>",
483+ type: "warning",
484+ });
485+ buttonRestore(originalButton, originalRestore);
486+ return;
487+ }
488+
489+ // Crea le opzioni per il select
490+ var options = "";
491+ var hasMatchingProgressivo = false;
492+
493+ fatture.forEach(function(fattura) {
494+ var isMatching = (fattura.progressivo_invio === receiptInfo.progressivo_invio && receiptInfo.progressivo_invio);
495+ var selected = isMatching ? "selected" : "";
496+ if (isMatching) hasMatchingProgressivo = true;
497+
498+ var dataFormatted = new Date(fattura.data).toLocaleDateString("it-IT");
499+ var totaleFormatted = parseFloat(fattura.totale).toLocaleString("it-IT", {
500+ style: "currency",
501+ currency: "EUR"
502+ });
503+
504+ var anagraficaTruncated = fattura.anagrafica.length > 25 ?
505+ fattura.anagrafica.substring(0, 25) + "..." : fattura.anagrafica;
506+
507+ var optionText = fattura.numero_esterno + " - " + dataFormatted + " - " + anagraficaTruncated + " - " + totaleFormatted;
508+
509+ if (fattura.progressivo_invio && fattura.progressivo_invio !== null && fattura.progressivo_invio !== "") {
510+ var progressivoShort = fattura.progressivo_invio.toString().slice(-5);
511+ optionText += " (" + progressivoShort + ")";
512+ }
513+
514+ if (isMatching) {
515+ optionText = "★ " + optionText + " ★";
516+ options += "<option value=\"" + fattura.id + "\" " + selected + " class=\"matching\">" + optionText + "</option>";
517+ } else {
518+ options += "<option value=\"" + fattura.id + "\" " + selected + ">" + optionText + "</option>";
519+ }
520+ });
521+
522+ swal({
523+ title: " ' .tr ('Seleziona fattura da associare ' ).'",
524+ html: "<style>" +
525+ "#swal-fattura-select { width: 95% !important; margin: 0 auto; display: block; max-height: 200px; overflow-y: auto; }" +
526+ "#swal-fattura-select option { white-space: normal !important; word-wrap: break-word !important; padding: 8px 4px !important; line-height: 1.3 !important; height: auto !important; }" +
527+ ".swal2-popup { word-wrap: break-word !important; }" +
528+ "</style>" +
529+ "<div style=\"background: #f8f9fa; border: 1px solid #dee2e6; border-radius: 6px; padding: 12px; margin-bottom: 20px;\">" +
530+ "<div style=\"display: flex; justify-content: space-between; margin-bottom: 8px;\"><span style=\"font-weight: 600; color: #495057; font-size: 13px;\"> ' .tr ('Ricevuta ' ).':</span><span style=\"color: #212529; font-size: 13px; font-weight: 500;\">" + receiptFile + "</span></div>" +
531+ "<div style=\"display: flex; justify-content: space-between; margin-bottom: 8px;\"><span style=\"font-weight: 600; color: #495057; font-size: 13px;\"> ' .tr ('Progressivo invio ' ).':</span><span style=\"color: #212529; font-size: 13px; font-weight: 500;\">" + (receiptInfo.progressivo_invio || " ' .tr ('Non disponibile ' ).'") + "</span></div>" +
532+ "</div>" +
533+ "<div style=\"margin: 15px 0;\">" +
534+ "<label style=\"display: block; margin-bottom: 8px; font-weight: 600; color: #495057; font-size: 14px;\"> ' .tr ('Seleziona la fattura da associare ' ).':</label>" +
535+ "<select id=\"swal-fattura-select\" class=\"form-control\">" +
536+ "<option value=\"\"> ' .tr ('Seleziona una fattura ' ).'...</option>" +
537+ options +
538+ "</select>" +
539+ "<div style=\"font-size: 12px; color: #6c757d; margin-top: 8px; font-style: italic; text-align: center;\">" +
540+ (hasMatchingProgressivo ? " ' .tr ('★ Fattura con progressivo corrispondente trovata e preselezionata ' ).' ★" : " ' .tr ('Nessuna fattura con progressivo corrispondente trovata. Seleziona manualmente. ' ).'") +
541+ "</div>" +
542+ "</div>",
543+ showCancelButton: true,
544+ confirmButtonText: " ' .tr ('Associa ' ).'",
545+ cancelButtonText: " ' .tr ('Annulla ' ).'",
546+ width: 600
547+ }).then(function(result) {
548+ if (result) {
549+ var selectedFattura = $("#swal-fattura-select").val();
550+ if (selectedFattura && selectedFattura !== "") {
551+ associateReceiptToInvoice(receiptFile, selectedFattura, originalButton, originalRestore);
552+ } else {
553+ swal(" ' .tr ('Errore ' ).'", " ' .tr ('Seleziona una fattura ' ).'", "error");
554+ buttonRestore(originalButton, originalRestore);
555+ }
556+ } else {
557+ buttonRestore(originalButton, originalRestore);
558+ }
559+ }).catch(function() {
560+ buttonRestore(originalButton, originalRestore);
561+ });
562+ },
563+ error: function(xhr) {
564+ swal(" ' .tr ('Errore ' ).'", " ' .tr ('Errore nel caricamento delle fatture ' ).'", "error");
565+ buttonRestore(originalButton, originalRestore);
566+ }
567+ });
568+ }
569+
570+ function associateReceiptToInvoice(receiptFile, fatturaId, originalButton, originalRestore) {
571+ $("#main_loading").show();
572+
573+ $.ajax({
574+ url: globals.rootdir + "/actions.php",
575+ type: "get",
576+ data: {
577+ id_module: " ' .$ id_module .'",
578+ id_plugin: " ' .$ id_plugin .'",
579+ op: "associa_ricevuta_fattura",
580+ name: receiptFile,
581+ id_fattura: fatturaId,
582+ },
583+ success: function(data) {
584+ $("#main_loading").fadeOut();
585+
586+ try {
587+ var result = JSON.parse(data);
588+
589+ if (result.success) {
590+ // Mostra messaggio di successo
591+ if(result.fattura) {
592+ var data_fattura = new Date(result.fattura.data);
593+ data_fattura = data_fattura.toLocaleDateString("it-IT", {
594+ year: "numeric",
595+ month: "2-digit",
596+ day: "2-digit"
597+ });
598+
599+ swal({
600+ title: " ' .tr ('Associazione completata! ' ).'",
601+ html: " ' .tr ('Ricevuta associata correttamente alla fattura ' ).': <h4>" + result.fattura.numero_esterno + " ' .tr ('del ' ).' " + data_fattura + "</h4><br><h5> ' .tr ('Ricevuta ' ).': " + result.file + "</h5>",
602+ type: "success",
603+ });
604+ } else {
605+ swal({
606+ title: " ' .tr ('Associazione completata! ' ).'",
607+ html: result.message + "<br><h5> ' .tr ('Ricevuta ' ).': " + result.file + "</h5>",
608+ type: "success",
609+ });
610+ }
611+
612+ // Ricarica la lista
613+ $("#list-receiptfe").load(" ' .$ structure ->fileurl ('list.php ' ).'?id_module= ' .$ id_module .'&id_plugin= ' .$ id_plugin .'", function() {
614+ start_local_datatables();
615+ });
616+ } else {
617+ swal(" ' .tr ('Errore ' ).'", result.message || " ' .tr ('Errore sconosciuto ' ).'", "error");
618+ }
619+ } catch (e) {
620+ swal(" ' .tr ('Errore ' ).'", " ' .tr ('Errore nel parsing della risposta del server ' ).'", "error");
621+ }
622+
623+ buttonRestore(originalButton, originalRestore);
624+ },
625+ error: function(xhr) {
626+ $("#main_loading").fadeOut();
627+ swal(" ' .tr ('Errore ' ).'", " ' .tr ('Errore durante l \'associazione ' ).'", "error");
628+ buttonRestore(originalButton, originalRestore);
629+ }
630+ });
631+ }
389632</script> ' ;
0 commit comments