Merge branch 'gestione-ricevute'

This commit is contained in:
Dasc3er 2020-10-09 17:37:27 +02:00
commit 89c030e9b4
13 changed files with 445 additions and 181 deletions

View File

@ -24,11 +24,7 @@ include_once __DIR__.'/../../core.php';
$anagrafica_azienda = Anagrafica::find(setting('Azienda predefinita'));
$block_edit = !empty($note_accredito) || $record['stato'] == 'Emessa' || $record['stato'] == 'Pagato' || $record['stato'] == 'Parzialmente pagato';
$rs = $dbo->fetchArray('SELECT co_tipidocumento.descrizione, dir FROM co_tipidocumento INNER JOIN co_documenti ON co_tipidocumento.id=co_documenti.idtipodocumento WHERE co_documenti.id='.prepare($id_record));
$dir = $rs[0]['dir'];
$tipodoc = $rs[0]['descrizione'];
$block_edit = !empty($note_accredito) || in_array($record['stato'], ['Emessa', 'Pagato', 'Parzialmente pagato']) || !$abilita_genera;
if ($dir == 'entrata') {
$conto = 'vendite';
@ -167,7 +163,7 @@ if (empty($record['is_fiscale'])) {
$plugin = $dbo->fetchArray("SELECT id FROM zz_plugins WHERE name='Fatturazione Elettronica' AND idmodule_to = ".prepare($id_module));
echo '<script>$("#link-tab_'.$plugin[0]['id'].'").addClass("disabled");</script>';
}
//Forzo il passaggio della fattura da Bozza ad Emessa per il corretto calcolo del numero.
// Forzo il passaggio della fattura da Bozza ad Emessa per il corretto calcolo del numero.
elseif ($record['stato'] == 'Bozza') {
$query .= " WHERE descrizione IN ('Emessa', 'Bozza')";
}
@ -181,6 +177,7 @@ elseif ($record['stato'] == 'Bozza') {
<div class="col-md-2" <?php echo ($dir == 'entrata') ? 'hidden' : ''; ?>>
{[ "type": "date", "label": "<?php echo tr('Data registrazione'); ?>", <?php echo $readonly; ?> "name": "data_registrazione", "required": 0, "value": "$data_registrazione$", "help": "<?php echo tr('Data in cui si è effettuata la registrazione della fattura in contabilità'); ?>" ]}
</div>
<!-- TODO: da nascondere per le fatture di vendita in quanto questa data sarà sempre uguale alla data di emissione -->
<div class="col-md-2" <?php echo ($is_fiscale) ? '' : 'hidden'; ?>>
{[ "type": "date", "class":"<?php echo (dateFormat($fattura->data_competenza) < dateFormat($fattura->data)) ? 'unblockable' : ''; ?>", "label": "<?php echo tr('Data competenza'); ?>", "name": "data_competenza", "required": 1, "value": "$data_competenza$", "min-date": "$data_registrazione$", "help": "<?php echo tr('Data nella quale considerare il movimento contabile, che può essere posticipato rispetto la data della fattura'); ?>" ]}
@ -191,24 +188,22 @@ elseif ($record['stato'] == 'Bozza') {
?>
<div class="col-md-2" <?php echo ($is_fiscale) ? '' : 'hidden'; ?> >
{[ "type": "select", "label": "<?php echo tr('Stato FE'); ?>", "name": "codice_stato_fe", "required": 0, "values": "query=SELECT codice as id, CONCAT_WS(' - ',codice,descrizione) as text FROM fe_stati_documento", "value": "$codice_stato_fe$", "disabled": <?php echo intval(API\Services::isEnabled() || $record['stato'] == 'Bozza'); ?>, "class": "unblockable", "help": "<?php echo (!empty($record['data_stato_fe'])) ? Translator::timestampToLocale($record['data_stato_fe']) : ''; ?>" ]}
{[ "type": "select", "label": "<?php echo tr('Stato FE'); ?>", "name": "codice_stato_fe", "required": 0, "values": "query=SELECT codice as id, CONCAT_WS(' - ',codice,descrizione) as text FROM fe_stati_documento", "value": "$codice_stato_fe$", "disabled": <?php echo intval(API\Services::isEnabled() || ($record['stato'] == 'Bozza' && $abilita_genera)); ?>, "class": "unblockable", "help": "<?php echo (!empty($record['data_stato_fe'])) ? Translator::timestampToLocale($record['data_stato_fe']) : ''; ?>" ]}
</div>
<?php
}
?>
<div class="col-md-<?php echo ($is_fiscale) ? 2 : 6; ?>">
<!-- TODO: Rimuovere possibilità di selezionare lo stato pagato obbligando l'utente ad aggiungere il movimento in prima nota -->
{[ "type": "select", "label": "<?php echo tr('Stato'); ?>", "name": "idstatodocumento", "required": 1, "values": "query=<?php echo $query; ?>", "value": "$idstatodocumento$", "class": "unblockable", "extra": " onchange = \"if ($('#idstatodocumento option:selected').text()=='Pagato' || $('#idstatodocumento option:selected').text()=='Parzialmente pagato' ){if( confirm('<?php echo tr('Sicuro di voler impostare manualmente la fattura come pagata senza aggiungere il movimento in prima nota?'); ?>') ){ return true; }else{ $('#idstatodocumento').selectSet(<?php echo $record['idstatodocumento']; ?>); }}\" " ]}
echo '
<div class="col-md-'.($is_fiscale ? 2 : 6).'">
<!-- TODO: Rimuovere possibilità di selezionare lo stato pagato obbligando l\'utente ad aggiungere il movimento in prima nota -->
{[ "type": "select", "label": "'.tr('Stato').'", "name": "idstatodocumento", "required": 1, "values": "query='.$query.'", "value": "$idstatodocumento$", "class": "'.(!$abilita_genera ? '' : 'unblockable').'", "extra": "onchange=\"return cambiaStato()\"" ]}
</div>
</div>
<div class="row">
<div class="col-md-6">
<?php
echo Modules::link('Anagrafiche', $record['idanagrafica'], null, null, 'class="pull-right"');
'.Modules::link('Anagrafiche', $record['idanagrafica'], null, null, 'class="pull-right"');
if ($dir == 'entrata') {
?>
@ -411,7 +406,7 @@ echo '
</div>
</div>';
if ($tipodoc == 'Fattura accompagnatoria di vendita') {
if ($record['descrizione_tipo'] == 'Fattura accompagnatoria di vendita') {
echo '
<div class="box box-info">
<div class="box-header with-border">
@ -894,4 +889,16 @@ $(document).ready(function () {
}
});
});
function cambiaStato() {
let testo = $("#idstatodocumento option:selected").text();
if (testo === "Pagato" || testo === "Parzialmente pagato") {
if(confirm("'.tr('Sicuro di voler impostare manualmente la fattura come pagata senza aggiungere il movimento in prima nota?').'")) {
return true;
} else {
$("#idstatodocumento").selectSet('.$record['idstatodocumento'].');
}
}
}
</script>';

View File

@ -29,6 +29,7 @@ if ($module['name'] == 'Fatture di vendita') {
if (isset($id_record)) {
$fattura = Fattura::with('tipo', 'stato')->find($id_record);
$dir = $fattura->direzione;
$is_fiscale = false;
if (!empty($fattura)) {
@ -44,7 +45,7 @@ if (isset($id_record)) {
co_documenti.id AS iddocumento,
co_documenti.split_payment AS split_payment,
co_statidocumento.descrizione AS `stato`,
co_tipidocumento.descrizione AS `descrizione_tipodoc`,
co_tipidocumento.descrizione AS `descrizione_tipo`,
co_pagamenti.riba AS `riba`,
(SELECT is_fiscale FROM zz_segments WHERE id = id_segment) AS is_fiscale,
(SELECT descrizione FROM co_ritenutaacconto WHERE id=idritenutaacconto) AS ritenutaacconto_desc,
@ -57,5 +58,10 @@ if (isset($id_record)) {
LEFT JOIN co_pagamenti ON co_documenti.idpagamento=co_pagamenti.id
WHERE co_tipidocumento.dir = '.prepare($dir).' AND co_documenti.id='.prepare($id_record));
// Note di credito collegate
$note_accredito = $dbo->fetchArray("SELECT co_documenti.id, IF(numero_esterno != '', numero_esterno, numero) AS numero, data FROM co_documenti JOIN co_tipidocumento ON co_documenti.idtipodocumento=co_tipidocumento.id WHERE reversed = 1 AND ref_documento=".prepare($id_record));
// Blocco gestito dallo stato della Fattura Elettronica
$stato_fe = $database->fetchOne('SELECT * FROM fe_stati_documento WHERE codice = '.prepare($fattura->codice_stato_fe));
$abilita_genera = empty($fattura->codice_stato_fe) || intval($stato_fe['is_generabile']);
}

View File

@ -237,7 +237,7 @@ function aggiungi_movimento($iddocumento, $dir, $primanota = 0)
}
// Lettura info fattura
$query = 'SELECT *, co_documenti.data_competenza, co_documenti.note, co_documenti.idpagamento, co_documenti.id AS iddocumento, co_statidocumento.descrizione AS `stato`, co_tipidocumento.descrizione AS `descrizione_tipodoc` FROM ((co_documenti LEFT OUTER JOIN co_statidocumento ON co_documenti.idstatodocumento=co_statidocumento.id) INNER JOIN an_anagrafiche ON co_documenti.idanagrafica=an_anagrafiche.idanagrafica) INNER JOIN co_tipidocumento ON co_documenti.idtipodocumento=co_tipidocumento.id WHERE co_documenti.id='.prepare($iddocumento);
$query = 'SELECT *, co_documenti.data_competenza, co_documenti.note, co_documenti.idpagamento, co_documenti.id AS iddocumento, co_statidocumento.descrizione AS `stato`, co_tipidocumento.descrizione AS `descrizione_tipo` FROM ((co_documenti LEFT OUTER JOIN co_statidocumento ON co_documenti.idstatodocumento=co_statidocumento.id) INNER JOIN an_anagrafiche ON co_documenti.idanagrafica=an_anagrafiche.idanagrafica) INNER JOIN co_tipidocumento ON co_documenti.idtipodocumento=co_tipidocumento.id WHERE co_documenti.id='.prepare($iddocumento);
$rs = $dbo->fetchArray($query);
$n = sizeof($rs);
$data = $rs[0]['data_competenza'];
@ -256,9 +256,9 @@ function aggiungi_movimento($iddocumento, $dir, $primanota = 0)
// Abbreviazioni contabili dei movimenti
$tipodoc = '';
if ($rs[0]['descrizione_tipodoc'] == 'Nota di credito') {
if ($rs[0]['descrizione_tipo'] == 'Nota di credito') {
$tipodoc = 'Nota di credito';
} elseif ($rs[0]['descrizione_tipodoc'] == 'Nota di debito') {
} elseif ($rs[0]['descrizione_tipo'] == 'Nota di debito') {
$tipodoc = 'Nota di debito';
} else {
$tipodoc = 'Fattura';

View File

@ -24,6 +24,7 @@ use Carbon\Carbon;
use Common\Components\Component;
use Common\Document;
use Illuminate\Database\Eloquent\Builder;
use Models\Upload;
use Modules\Anagrafiche\Anagrafica;
use Modules\Banche\Banca;
use Modules\Fatture\Gestori\Bollo as GestoreBollo;
@ -474,6 +475,23 @@ class Fattura extends Document
})->sortBy('created_at');
}
/**
* Restituisce la ricevuta principale, impostata attraverso il campo aggiuntivo id_ricevuta_principale.
*
* @return Upload|null
*/
public function getRicevutaPrincipale()
{
if (empty($this->id_ricevuta_principale)) {
return null;
}
return $this->getModule()
->uploads($this->id)
->where('id', $this->id_ricevuta_principale)
->first();
}
/**
* Controlla se la fattura di acquisto è elettronica.
*

View File

@ -20,7 +20,6 @@
include_once __DIR__.'/init.php';
use Plugins\ExportFE\Interaction;
use Plugins\ReceiptFE\Interaction as RecepitInteraction;
use Plugins\ReceiptFE\Ricevuta;
switch (filter('op')) {
@ -62,23 +61,27 @@ switch (filter('op')) {
}
// Importazione ultima ricevuta individuata
RecepitInteraction::getReceipt($last_recepit);
$fattura = null;
try {
$receipt = new Ricevuta($last_recepit);
$receipt->save();
$fattura = $receipt->getFattura()->numero_esterno;
$receipt->delete();
RecepitInteraction::processReceipt($name);
} catch (UnexpectedValueException $e) {
}
$fattura = Ricevuta::process($last_recepit);
$numero_esterno = $fattura ? $fattura->numero_esterno : null;
echo json_encode([
'file' => $last_recepit,
'fattura' => $numero_esterno,
]);
break;
case 'gestione_ricevuta':
$name = filter('name');
$type = filter('type');
$cambia_stato = $type != 'download';
$fattura = Ricevuta::process($name, false);
$numero_esterno = $fattura ? $fattura->numero_esterno : null;
echo json_encode([
'file' => $name,
'fattura' => $fattura,
]);

View File

@ -19,18 +19,20 @@
include_once __DIR__.'/init.php';
use Models\Upload;
use Plugins\ExportFE\FatturaElettronica;
use Plugins\ExportFE\Interaction;
use Util\XML;
/* per le PA EC02 e EC01 sono dei stati successivi a NE il quale a sua volta è successivo a RC. EC01 e EC02 sono definiti all'interno della ricevuta di NE che di fatto indica il rifiuto o l'accettazione.*/
$abilita_genera = empty($fattura->codice_stato_fe) || in_array($fattura->codice_stato_fe, ['GEN', 'NS', 'EC02', 'ERR']);
/* Per le PA EC02 e EC01 sono dei stati successivi a NE il quale a sua volta è successivo a RC. EC01 e EC02 sono definiti all'interno della ricevuta di NE che di fatto indica il rifiuto o l'accettazione. */
$stato_fe = $database->fetchOne('SELECT * FROM fe_stati_documento WHERE codice = '.prepare($fattura->codice_stato_fe));
$abilita_genera = (empty($fattura->codice_stato_fe) && $fattura->stato->descrizione != 'Bozza') || intval($stato_fe['is_generabile']);
$ricevuta_principale = $fattura->getRicevutaPrincipale();
if (!empty($fattura_pa)) {
$disabled = false;
$generated = $fattura_pa->isGenerated();
$generata = $fattura_pa->isGenerated();
} else {
$disabled = true;
$generated = false;
$generata = false;
}
$checks = FatturaElettronica::controllaFattura($fattura);
@ -75,28 +77,30 @@ echo '
<input type="hidden" name="backto" value="record-edit">
<input type="hidden" name="op" value="generate">
<button id="genera" type="submit" class="btn btn-primary btn-lg '.($disabled || !$abilita_genera ? 'disabled' : '').'" '.($disabled || !$abilita_genera ? ' disabled' : null).'>
<button type="button" class="btn btn-primary btn-lg '.(!$abilita_genera ? 'disabled' : '').'" onclick="generaFE(this)">
<i class="fa fa-file"></i> '.tr('Genera').'
</button>
</form>';
$file = $generated ? Models\Upload::where('filename', $fattura_pa->getFilename())->where('id_record', $id_record)->first() : null;
$file = $generata ? Upload::where('filename', $fattura_pa->getFilename())
->where('id_record', $id_record)
->first() : null;
echo '
<i class="fa fa-arrow-right fa-fw text-muted"></i>
<a href="'.base_path().'/view.php?file_id='.($file ? $file->id : null).'" class="btn btn-info btn-lg '.($generated ? '' : 'disabled').'" target="_blank" '.($generated ? '' : 'disabled').'>
<a href="'.base_path().'/view.php?file_id='.($file ? $file->id : null).'" class="btn btn-info btn-lg '.($generata ? '' : 'disabled').'" target="_blank" '.($generata ? '' : 'disabled').'>
<i class="fa fa-eye"></i> '.tr('Visualizza').'
</a>';
// Scelgo quando posso inviarla
$send = Interaction::isEnabled() && $generated && in_array($record['codice_stato_fe'], ['GEN', 'ERVAL', 'ERR']);
$inviabile = Interaction::isEnabled() && $generata && intval($stato_fe['is_inviabile']);
echo '
<i class="fa fa-arrow-right fa-fw text-muted"></i>
<a href="'.$structure->fileurl('download.php').'?id_record='.$id_record.'" class="btn btn-primary btn-lg '.($generated ? '' : 'disabled').'" target="_blank" '.($generated ? '' : 'disabled').'>
<a href="'.$structure->fileurl('download.php').'?id_record='.$id_record.'" class="btn btn-primary btn-lg '.($generata ? '' : 'disabled').'" target="_blank" '.($generata ? '' : 'disabled').'>
<i class="fa fa-download"></i> '.tr('Scarica').'
</a>';
@ -104,38 +108,29 @@ echo '
<i class="fa fa-arrow-right fa-fw text-muted"></i>
<button onclick="if( confirm(\''.tr('Inviare la fattura al SDI?').'\') ){ send(this); }" class="btn btn-success btn-lg '.($send ? '' : 'disabled').'" target="_blank" '.($send ? '' : 'disabled').'>
<button type="button" onclick="inviaFE(this)" class="btn btn-success btn-lg '.($inviabile ? '' : 'disabled').'">
<i class="fa fa-paper-plane"></i> '.tr('Invia').'
</button>';
$verify = Interaction::isEnabled() && $generated;
$verify = Interaction::isEnabled() && $generata;
echo '
<i class="fa fa-arrow-right fa-fw text-muted"></i>
<button class="btn btn-warning btn-lg '.($verify ? '' : 'disabled').'" target="_blank" '.($verify ? '' : 'disabled').' onclick="verify(this)">
<button type="button" onclick="verificaNotificheFE(this)" class="btn btn-warning btn-lg '.($verify ? '' : 'disabled').'">
<i class="fa fa-question-circle"></i> '.tr('Verifica notifiche').'
</button>
</div>';
echo '<br><br>';
// Messaggio esito invio
$ultima_ricevuta = $fattura->getRicevute()->last();
if (!empty($record['codice_stato_fe'])) {
if ($record['codice_stato_fe'] == 'GEN') {
echo '
<div class="alert alert-info"><i class="fa fa-info-circle"></i> '.tr("La fattura è stata generata ed è pronta per l'invio").'.</div>';
} else {
$stato_fe = database()->fetchOne('SELECT codice, descrizione, icon FROM fe_stati_documento WHERE codice='.prepare($record['codice_stato_fe']));
if (in_array($stato_fe['codice'], ['EC01', 'RC'])) {
$class = 'success';
} elseif (in_array($stato_fe['codice'], ['ERVAL', 'GEN', 'MC', 'WAIT', 'NE'])) {
$class = 'warning';
} else {
$class = 'danger';
}
// Messaggio informativo sulla ricevuta principale impostata
if (!empty($fattura->codice_stato_fe)) {
echo '
<div class="alert alert-'.$stato_fe['tipo'].'">
<div class="pull-right">
<i class="fa fa-clock-o tip" title="'.tr('Data e ora').'"></i> '.timestampFormat($record['data_stato_fe']);
if (!empty($ricevuta_principale)) {
echo '
<div class="alert alert-'.$class.'">
<div class="pull-right">
@ -143,25 +138,39 @@ if (!empty($record['codice_stato_fe'])) {
if (!empty($ultima_ricevuta)) {
echo '
<a href="'.base_path().'/view.php?file_id='.$ultima_ricevuta->id.'" target="_blank" class="btn btn-info btn-xs">
<a href="'.ROOTDIR.'/view.php?file_id='.$ultima_ricevuta->id.'" target="_blank" class="btn btn-info btn-xs">
<i class="fa fa-external-link"></i> '.tr('Visualizza ricevuta').'
</a>';
}
}
echo '
echo '
</div>
<big><i class="'.$stato_fe['icon'].'" style="color:#fff;"></i>
<b>'.$stato_fe['codice'].'</b> - '.$stato_fe['descrizione'].'</big> '.(!empty($record['descrizione_ricevuta_fe']) ? '<br><b>'.tr('Note', [], ['upper' => true]).':</b> '.$record['descrizione_ricevuta_fe'] : '').'
<big>
<i class="'.$stato_fe['icon'].'" style="color:#fff;"></i>
<b>'.$stato_fe['codice'].'</b> - '.$stato_fe['descrizione'].'
</big>';
if (!empty($record['descrizione_ricevuta_fe'])) {
echo '
<br><b>'.tr('Note', [], ['upper' => true]).':</b> '.$record['descrizione_ricevuta_fe'];
}
if ($fattura->codice_stato_fe == 'GEN') {
echo '
<br><i class="fa fa-info-circle"></i> '.tr("La fattura è stata generata ed è pronta per l'invio").'.';
}
echo '
</div>';
// Lettura della ricevuta
if (!empty($ultima_ricevuta) && $stato_fe['codice'] == 'NS') {
$contenuto_ricevuta = \Util\XML::readFile($ultima_ricevuta->filepath);
$lista_errori = $contenuto_ricevuta['ListaErrori'];
// Lettura della ricevuta
if (!empty($ricevuta_principale)) {
$contenuto_ricevuta = XML::readFile($ricevuta_principale->filepath);
$lista_errori = $contenuto_ricevuta['ListaErrori'];
if (!empty($lista_errori)) {
echo '
if (!empty($lista_errori)) {
echo '
<h4>'.tr('Elenco degli errori').'</h4>
<table class="table table-striped">
<thead>
@ -172,60 +181,66 @@ if (!empty($record['codice_stato_fe'])) {
</thead>
<tbody>';
$lista_errori = $lista_errori[0] ? $lista_errori : [$lista_errori];
foreach ($lista_errori as $errore) {
$errore = $errore['Errore'];
echo '
$lista_errori = $lista_errori[0] ? $lista_errori : [$lista_errori];
foreach ($lista_errori as $errore) {
$errore = $errore['Errore'];
echo '
<tr>
<td>'.$errore['Codice'].'</td>
<td>'.$errore['Descrizione'].'</td>
</tr>';
}
}
echo '
echo '
</tbody>
</table>';
}
}
}
}
echo '
<script>
function send(btn) {
var restore = buttonLoading(btn);
function inviaFE(button) {
if (confirm("'.tr('Inviare la fattura al SDI?').'")) {
let restore = buttonLoading(button);
$.ajax({
url: globals.rootdir + "/actions.php",
type: "post",
data: {
op: "send",
id_module: "'.$id_module.'",
id_plugin: "'.$id_plugin.'",
id_record: "'.$id_record.'",
},
success: function(data) {
buttonRestore(btn, restore);
data = JSON.parse(data);
$.ajax({
url: globals.rootdir + "/actions.php",
type: "post",
dataType: "json",
data: {
op: "send",
id_module: "'.$id_module.'",
id_plugin: "'.$id_plugin.'",
id_record: "'.$id_record.'",
},
success: function(data) {
buttonRestore(button, restore);
if (data.code == "200") {
swal("'.tr('Fattura inviata!').'", data.message, "success");
if (data.code === 200) {
swal("'.tr('Fattura inviata!').'", data.message, "success");
$(btn).attr("disabled", true).addClass("disabled");
} else {
swal("'.tr('Invio fallito').'", data.code + " - " + data.message, "error");
$(button).attr("disabled", true).addClass("disabled");
} else if (data.code === 301) {
swal("'.tr('Invio già effettuato').'", data.code + " - " + data.message, "error");
} else {
swal("'.tr('Invio fallito').'", data.code + " - " + data.message, "error");
}
},
error: function() {
swal("'.tr('Errore').'", "'.tr('Errore durante il salvataggio').'", "error");
buttonRestore(button, restore);
}
},
error: function(data) {
swal("'.tr('Errore').'", "'.tr('Errore durante il salvataggio').'", "error");
buttonRestore(btn, restore);
}
});
});
}
}
function verify(btn) {
var restore = buttonLoading(btn);
function verificaNotificheFE(button) {
openModal("'.tr('Gestione ricevute').'", "'.$structure->fileurl('notifiche.php').'");
/*
let restore = buttonLoading(button);
$.ajax({
url: globals.rootdir + "/actions.php",
@ -237,7 +252,7 @@ echo '
id_record: "'.$id_record.'",
},
success: function(data) {
buttonRestore(btn, restore);
buttonRestore(button, restore);
data = JSON.parse(data);
if (data.file) {
@ -251,27 +266,26 @@ echo '
error: function(data) {
swal("'.tr('Errore').'", "'.tr('Errore durante la verifica').'", "error");
buttonRestore(btn, restore);
buttonRestore(button, restore);
}
});
});*/
}
$("#genera").click(function(event) {
event.preventDefault();
salvaForm(this, "#edit-form").then(function(valid) {
function generaFE(button) {
salvaForm(button, "#edit-form").then(function(valid) {
if (valid) {';
if ($generated) {
if ($generata) {
echo '
/*<p class=\"text-danger\">'.tr('Se stai attendendo una ricevuta dal sistema SdI, rigenerando la fattura elettronica non sarà possibile corrispondere la ricevuta una volta emessa').'.</p>*/
swal({
title: "'.tr('Sei sicuro di rigenerare la fattura?').'",
html: "<p>'.tr('Attenzione: sarà generato un nuovo progressivo invio').'.</p><p class=\"text-danger\">'.tr('Se stai attendendo una ricevuta dal sistema SdI, rigenerando la fattura elettronica non sarà possibile corrispondere la ricevuta una volta emessa').'.</p>",
html: "<p>'.tr('Attenzione: sarà generato un nuovo progressivo invio').'.</p>",
type: "warning",
showCancelButton: true,
confirmButtonColor: "#30d64b",
cancelButtonColor: "#d33",
confirmButtonText: "Genera"
confirmButtonText: "'.tr('Genera').'"
}).then((result) => {
if (result) {
$("#form-xml").submit();
@ -291,5 +305,5 @@ echo '
});
}
});
});
};
</script>';

View File

@ -0,0 +1,146 @@
<?php
use Modules\Fatture\Fattura;
use Plugins\ExportFE\Interaction;
include_once __DIR__.'/../../core.php';
$result = Interaction::getInvoiceRecepits($id_record);
$recepits = $result['results'];
$documento = Fattura::find($id_record);
if (empty($recepits)) {
echo '
<p>'.tr('Il documento non ha notifiche disponibili').'.</p>';
return;
}
echo '
<p>'.tr("Segue l'elenco completo delle notifiche/ricevute relative alla fatture elettronica di questo documento").'.</p>
<p>'.tr('La procedura di importazione prevede di impostare in modo autonomo la notifica più recente come principale, ma si verificano alcune situazioni in cui il comportamento richiesto deve essere distinto').'. '.tr('Qui si può procedere a scaricare una specifica notifica e a impostarla manualmente come principale per il documento').'.</p>
<table class="table">
<thead>
<tr>
<th>'.tr('Nome').'</th>
<th class="text-center">'.tr('Scaricata').'</th>
<th class="text-center">'.tr('Opzioni').'</th>
</tr>
</thead>
<tbody>';
foreach ($recepits as $nome) {
$upload = $documento->uploads()
->where('name', 'Fattura Elettronica')
->where('original', $nome)
->first();
// Individuazione codice ricevuta
$filename = explode('.', $nome)[0];
$pieces = explode('_', $filename);
$codice_stato = $pieces[2];
// Informazioni sullo stato indicato
$stato_fe = $database->fetchOne('SELECT * FROM fe_stati_documento WHERE codice = '.prepare($codice_stato));
echo '
<tr data-name="'.$nome.'">
<td>'.$nome.'</td>
<td class="text-center">';
if (empty($upload)) {
echo tr('No');
} else {
echo '
<a href="'.ROOTDIR.'/view.php?file_id='.$upload->id.'" target="_blank">
<i class="fa fa-external-link"></i> '.tr('Visualizza').'
</a>';
}
echo '
<td class="text-center">';
if (empty($upload)) {
echo '
<button type="button" class="btn btn-info btn-sm" onclick="scaricaRicevuta(this)">
<i class="fa fa-download"></i>
</button>';
}
if (empty($upload) || $upload->id != $documento->id_ricevuta_principale) {
echo '
<button type="button" class="btn btn-warning btn-sm" onclick="impostaRicevuta(this)">
<i class="fa fa-check-circle"></i>
</button>';
} elseif ($upload->id == $documento->id_ricevuta_principale) {
echo '
<button type="button" class="btn btn-success btn-sm disabled">
<i class="fa fa-check-circle"></i>
</button>';
}
echo '
</td>
</tr>';
}
echo '
</tbody>
</table>
<script>
function scaricaRicevuta(button) {
let riga = $(button).closest("tr");
let name = riga.data("name");
gestioneRicevuta(button, name, "download");
}
function impostaRicevuta(button) {
let riga = $(button).closest("tr");
let name = riga.data("name");
gestioneRicevuta(button, name, "imposta");
}
function gestioneRicevuta(button, name, type) {
let restore = buttonLoading(button);
$.ajax({
url: globals.rootdir + "/actions.php",
type: "post",
dataType: "json",
data: {
op: "gestione_ricevuta",
id_module: "'.$id_module.'",
id_plugin: "'.$id_plugin.'",
id_record: "'.$id_record.'",
name: name,
type: type,
},
success: function(response) {
buttonRestore(button, restore);
if(response.fattura) {
swal({
title: "'.tr('Importazione completata!').'",
type: "success",
});
} else {
swal({
title: "'.tr('Importazione fallita!').'",
type: "error",
});
}
},
error: function() {
buttonRestore(button, restore);
swal("'.tr('Errore').'", "'.tr('Errore durante il salvataggio').'", "error");
}
});
}
</script>';

View File

@ -301,6 +301,7 @@ class FatturaElettronica
database()->update('co_documenti', [
'progressivo_invio' => $this->getDocumento()['progressivo_invio'],
'codice_stato_fe' => 'GEN',
'id_ricevuta_principale' => null,
'data_stato_fe' => date('Y-m-d H:i:s'),
], ['id' => $this->getDocumento()['id']]);

View File

@ -381,7 +381,7 @@ if (!empty($righe)) {
</div>
<div class="col-md-3">
{[ "type": "select", "name": "selezione_riferimento['.$key.']", "ajax-source": "riferimenti-fe", "select-options": '.json_encode(['id_anagrafica' => $anagrafica ? $anagrafica->id : '']).', "required": 0, "label": "'.tr('Riferimento').'", "icon-after": '.json_encode('<button type="button" onclick="rimuoviRiferimento(this)" class="btn btn-primary disabled" id="rimuovi_riferimento_'.$key.'"><i class="fa fa-close"></i></button>').' ]}
{[ "type": "select", "name": "selezione_riferimento['.$key.']", "ajax-source": "riferimenti-fe", "select-options": '.json_encode(['id_anagrafica' => $anagrafica ? $anagrafica->id : '']).', "label": "'.tr('Riferimento').'", "icon-after": '.json_encode('<button type="button" onclick="rimuoviRiferimento(this)" class="btn btn-primary disabled" id="rimuovi_riferimento_'.$key.'"><i class="fa fa-close"></i></button>').' ]}
</div>
</td>
</tr>';

View File

@ -29,24 +29,12 @@ switch (filter('op')) {
$results = [];
foreach ($list as $element) {
$name = $element['name'];
Interaction::getReceipt($name);
$fattura = null;
try {
$receipt = new Ricevuta($name);
$receipt->save();
$fattura = $receipt->getFattura()->numero_esterno;
$receipt->delete();
Interaction::processReceipt($name);
} catch (UnexpectedValueException $e) {
}
$fattura = Ricevuta::process($name);
$numero_esterno = $fattura ? $fattura->numero_esterno : null;
$results[] = [
'file' => $name,
'fattura' => $fattura,
'fattura' => $numero_esterno,
];
}
@ -63,20 +51,9 @@ switch (filter('op')) {
// no break
case 'prepare':
$name = $name ?: get('name');
Interaction::getReceipt($name);
$fattura = Ricevuta::process($name);
$fattura = null;
try {
$receipt = new Ricevuta($name);
$receipt->save();
$fattura = $receipt->getFattura()->numero_esterno;
$receipt->delete();
Interaction::processReceipt($name);
} catch (UnexpectedValueException $e) {
}
$numero_esterno = $fattura ? $fattura->numero_esterno : null;
echo json_encode([
'file' => $name,

View File

@ -69,18 +69,11 @@ class ReceiptHook extends Manager
// Importazione ricevuta
$name = $element['name'];
Interaction::getReceiptList($name);
try {
$receipt = new Ricevuta($name);
$receipt->save();
$receipt->delete();
Interaction::processReceipt($name);
$fattura = Ricevuta::process($name);
if (!empty($fattura)) {
$completed[] = $element;
unset($todo[$i]);
} catch (UnexpectedValueException $e) {
}
}

View File

@ -19,11 +19,10 @@
namespace Plugins\ReceiptFE;
use Modules;
use Models\Upload;
use Modules\Fatture\Fattura;
use Plugins;
use UnexpectedValueException;
use Uploads;
use Util\XML;
use Util\Zip;
@ -48,6 +47,7 @@ class Ricevuta
{
$file = static::getImportDirectory().'/'.$name;
// Estrazione implicita per il formato ZIP
if (ends_with($name, '.zip')) {
$original_file = $file;
@ -79,6 +79,42 @@ class Ricevuta
}
}
/**
* Funzione per gestire in modo autonomo il download, l'importazione e il salvataggio di una specifica ricevuta identificata tramite nome.
*
* @param string $name
* @param bool $cambia_stato
*
* @return Fattura|null
*/
public static function process($name, $cambia_stato = true)
{
Interaction::getReceipt($name);
$fattura = null;
try {
$receipt = new Ricevuta($name);
$receipt->save($cambia_stato);
$fattura = $receipt->getFattura();
$receipt->cleanup();
Interaction::processReceipt($name);
} catch (UnexpectedValueException $e) {
}
return $fattura;
}
/**
* Salva il file indicato nella cartella temporanea per una futura elaborazione.
*
* @param string $filename
* @param string $content
*
* @return string
*/
public static function store($filename, $content)
{
$directory = static::getImportDirectory();
@ -90,6 +126,11 @@ class Ricevuta
return $filename;
}
/**
* Restituisce la cartella temporanea utilizzabile per il salvataggio della ricevuta.
*
* @return string|null
*/
public static function getImportDirectory()
{
if (!isset(self::$directory)) {
@ -101,32 +142,51 @@ class Ricevuta
return self::$directory;
}
/**
* @param string $codice
*
* @return Upload|null
*/
public function saveAllegato($codice)
{
$module = Modules::get('Fatture di vendita');
$filename = basename($this->file);
$fattura = $this->getFattura();
$info = [
// Controllo sulla presenza della stessa ricevuta
$upload_esistente = $fattura->getModule()
->uploads($fattura->id)
->where('original', $filename)
->first();
if (!empty($upload_esistente)) {
return $upload_esistente;
}
// Registrazione del file XML come allegato
$upload = Upload::build($this->file, [
'category' => tr('Fattura Elettronica'),
'id_module' => $module->id,
'id_record' => $this->fattura->id,
];
// Registrazione XML come allegato
Uploads::upload($this->file, array_merge($info, [
'id_record' => $fattura->id,
'name' => tr('Ricevuta _TYPE_', [
'_TYPE_' => $codice,
]),
'original' => basename($this->file),
]));
'original' => $filename,
]);
return $upload;
}
public function saveStato($codice)
/**
* Aggiorna lo stato della fattura relativa alla ricevuta in modo tale da rispecchiare i dati richiesti.
*
* @param $codice
* @param $id_allegato
*/
public function saveStato($codice, $id_allegato)
{
$fattura = $this->getFattura();
// Modifica lo stato solo se la fattura non è già stata consegnata (per evitare problemi da doppi invii)
// In realtà per le PA potrebbe esserci lo stato NE (che può contenere un esito positivo EC01 o negativo EC02) successivo alla RC,
// quindi aggiungo eccezione nel caso il nuovo codice della ricevuta sia NE.
// In realtà per le PA potrebbe esserci lo stato NE (che può contenere un esito positivo EC01 o negativo EC02) successivo alla RC, quindi aggiungo eccezione nel caso il nuovo codice della ricevuta sia NE.
if ($fattura->codice_stato_fe == 'RC' && ($codice != 'EC01' || $codice != 'EC02')) {
return;
}
@ -138,11 +198,15 @@ class Ricevuta
$fattura->data_stato_fe = $data ? date('Y-m-d H:i:s', strtotime($data)) : '';
$fattura->codice_stato_fe = $codice;
$fattura->descrizione_ricevuta_fe = $descrizione;
$fattura->id_ricevuta_principale = $id_allegato;
$fattura->save();
}
public function save()
/**
* Effettua le operazioni di salvataggio della ricevuta nella fattura relativa.
*/
public function save($cambia_stato = true)
{
$name = basename($this->file);
$filename = explode('.', $name)[0];
@ -157,22 +221,32 @@ class Ricevuta
$codice_nome = $codice_nome.' - '.$errore['Errore']['Codice'];
}
$this->saveAllegato($codice_nome);
$upload = $this->saveAllegato($codice_nome);
// In caso di Notifica Esito il codice è definito dal nodo <Esito> della ricevuta
if ($codice_stato == 'NE') {
$codice_stato = $this->xml['EsitoCommittente']['Esito'];
if ($cambia_stato) {
// In caso di Notifica Esito il codice è definito dal nodo <Esito> della ricevuta
if ($codice_stato == 'NE') {
$codice_stato = $this->xml['EsitoCommittente']['Esito'];
}
$this->saveStato($codice_stato, $upload->id);
}
$this->saveStato($codice_stato);
}
/**
* Restituisce la fattura identificata per la ricevuta.
*
* @return Fattura|null
*/
public function getFattura()
{
return $this->fattura;
}
public function delete()
/**
* Rimuove i file temporanei relativi alla ricevuta.
*/
public function cleanup()
{
delete($this->file);
}

View File

@ -90,6 +90,16 @@ UPDATE `zz_settings` SET `valore` = 'v3' WHERE `nome` = 'OSMCloud Services API V
-- Aggiornamento margini stampa barbcode
UPDATE `zz_prints` SET `options` = '{"width": 54, "height": 20, "format": [64, 55], "margins": {"top": 5,"bottom": 0,"left": 0,"right": 0}}' WHERE `zz_prints`.`name` = 'Barcode';
-- Aggiunto collegamento con allegato per impostare la ricevuta principale
ALTER TABLE `co_documenti` ADD `id_ricevuta_principale` INT(11);
UPDATE `co_documenti` SET `co_documenti`.`id_ricevuta_principale` = (
SELECT `zz_files`.`id` FROM `zz_files` WHERE `zz_files`.`id_module` = (
SELECT `zz_modules`.`id` FROM `zz_modules` WHERE `zz_modules`.`name` = 'Fatture di vendita'
) AND `zz_files`.`id_record` = `co_documenti`.`id`
AND `zz_files`.`name` LIKE 'Ricevuta%'
ORDER BY `zz_files`.`created_at`
LIMIT 1
);
-- Aggiunta riferimenti testuali su descrizione righe per Fatture
UPDATE `co_righe_documenti`
@ -282,3 +292,18 @@ UPDATE `co_iva` SET `deleted_at` = now() WHERE `co_iva`.`codice_natura_fe` IN ('
-- Impostazione percentuale deducibile di default al 100%
ALTER TABLE `co_pianodeiconti3` CHANGE `percentuale_deducibile` `percentuale_deducibile` DECIMAL(5,2) NOT NULL DEFAULT '100';
ALTER TABLE `fe_stati_documento` ADD `is_generabile` BOOLEAN DEFAULT FALSE,
ADD `is_inviabile` BOOLEAN DEFAULT FALSE,
ADD `tipo` varchar(255) NOT NULL;
UPDATE `fe_stati_documento` SET `is_generabile` = '1', `is_inviabile` = '1' WHERE `codice` = 'ERVAL';
UPDATE `fe_stati_documento` SET `is_generabile` = '1', `is_inviabile` = '1' WHERE `codice` = 'ERR';
UPDATE `fe_stati_documento` SET `is_generabile` = '1', `is_inviabile` = '1' WHERE `codice` = 'GEN';
UPDATE `fe_stati_documento` SET `is_generabile` = '1' WHERE `codice` = 'NS';
UPDATE `fe_stati_documento` SET `is_generabile` = '1' WHERE `codice` = 'EC02';
UPDATE `fe_stati_documento` SET `tipo` = 'danger';
UPDATE `fe_stati_documento` SET `tipo` = 'warning' WHERE `codice` IN ('ERVAL', 'MC', 'WAIT', 'NE');
UPDATE `fe_stati_documento` SET `tipo` = 'success' WHERE `codice` IN ('EC01', 'RC');
UPDATE `fe_stati_documento` SET `tipo` = 'info' WHERE `codice` IN ('GEN');