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')); $anagrafica_azienda = Anagrafica::find(setting('Azienda predefinita'));
$block_edit = !empty($note_accredito) || $record['stato'] == 'Emessa' || $record['stato'] == 'Pagato' || $record['stato'] == 'Parzialmente pagato'; $block_edit = !empty($note_accredito) || in_array($record['stato'], ['Emessa', 'Pagato', 'Parzialmente pagato']) || !$abilita_genera;
$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'];
if ($dir == 'entrata') { if ($dir == 'entrata') {
$conto = 'vendite'; $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)); $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>'; 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') { elseif ($record['stato'] == 'Bozza') {
$query .= " WHERE descrizione IN ('Emessa', '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' : ''; ?>> <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à'); ?>" ]} {[ "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> </div>
<!-- TODO: da nascondere per le fatture di vendita in quanto questa data sarà sempre uguale alla data di emissione --> <!-- 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'; ?>> <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'); ?>" ]} {[ "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'; ?> > <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> </div>
<?php <?php
} }
?>
<div class="col-md-<?php echo ($is_fiscale) ? 2 : 6; ?>"> echo '
<!-- TODO: Rimuovere possibilità di selezionare lo stato pagato obbligando l'utente ad aggiungere il movimento in prima nota --> <div class="col-md-'.($is_fiscale ? 2 : 6).'">
{[ "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']; ?>); }}\" " ]} <!-- 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> </div>
<div class="row"> <div class="row">
<div class="col-md-6"> <div class="col-md-6">
<?php '.Modules::link('Anagrafiche', $record['idanagrafica'], null, null, 'class="pull-right"');
echo Modules::link('Anagrafiche', $record['idanagrafica'], null, null, 'class="pull-right"');
if ($dir == 'entrata') { if ($dir == 'entrata') {
?> ?>
@ -411,7 +406,7 @@ echo '
</div> </div>
</div>'; </div>';
if ($tipodoc == 'Fattura accompagnatoria di vendita') { if ($record['descrizione_tipo'] == 'Fattura accompagnatoria di vendita') {
echo ' echo '
<div class="box box-info"> <div class="box box-info">
<div class="box-header with-border"> <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>'; </script>';

View File

@ -29,6 +29,7 @@ if ($module['name'] == 'Fatture di vendita') {
if (isset($id_record)) { if (isset($id_record)) {
$fattura = Fattura::with('tipo', 'stato')->find($id_record); $fattura = Fattura::with('tipo', 'stato')->find($id_record);
$dir = $fattura->direzione;
$is_fiscale = false; $is_fiscale = false;
if (!empty($fattura)) { if (!empty($fattura)) {
@ -44,7 +45,7 @@ if (isset($id_record)) {
co_documenti.id AS iddocumento, co_documenti.id AS iddocumento,
co_documenti.split_payment AS split_payment, co_documenti.split_payment AS split_payment,
co_statidocumento.descrizione AS `stato`, co_statidocumento.descrizione AS `stato`,
co_tipidocumento.descrizione AS `descrizione_tipodoc`, co_tipidocumento.descrizione AS `descrizione_tipo`,
co_pagamenti.riba AS `riba`, co_pagamenti.riba AS `riba`,
(SELECT is_fiscale FROM zz_segments WHERE id = id_segment) AS is_fiscale, (SELECT is_fiscale FROM zz_segments WHERE id = id_segment) AS is_fiscale,
(SELECT descrizione FROM co_ritenutaacconto WHERE id=idritenutaacconto) AS ritenutaacconto_desc, (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 LEFT JOIN co_pagamenti ON co_documenti.idpagamento=co_pagamenti.id
WHERE co_tipidocumento.dir = '.prepare($dir).' AND co_documenti.id='.prepare($id_record)); 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)); $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 // 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); $rs = $dbo->fetchArray($query);
$n = sizeof($rs); $n = sizeof($rs);
$data = $rs[0]['data_competenza']; $data = $rs[0]['data_competenza'];
@ -256,9 +256,9 @@ function aggiungi_movimento($iddocumento, $dir, $primanota = 0)
// Abbreviazioni contabili dei movimenti // Abbreviazioni contabili dei movimenti
$tipodoc = ''; $tipodoc = '';
if ($rs[0]['descrizione_tipodoc'] == 'Nota di credito') { if ($rs[0]['descrizione_tipo'] == 'Nota di credito') {
$tipodoc = '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'; $tipodoc = 'Nota di debito';
} else { } else {
$tipodoc = 'Fattura'; $tipodoc = 'Fattura';

View File

@ -24,6 +24,7 @@ use Carbon\Carbon;
use Common\Components\Component; use Common\Components\Component;
use Common\Document; use Common\Document;
use Illuminate\Database\Eloquent\Builder; use Illuminate\Database\Eloquent\Builder;
use Models\Upload;
use Modules\Anagrafiche\Anagrafica; use Modules\Anagrafiche\Anagrafica;
use Modules\Banche\Banca; use Modules\Banche\Banca;
use Modules\Fatture\Gestori\Bollo as GestoreBollo; use Modules\Fatture\Gestori\Bollo as GestoreBollo;
@ -474,6 +475,23 @@ class Fattura extends Document
})->sortBy('created_at'); })->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. * Controlla se la fattura di acquisto è elettronica.
* *

View File

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

View File

@ -19,18 +19,20 @@
include_once __DIR__.'/init.php'; include_once __DIR__.'/init.php';
use Models\Upload;
use Plugins\ExportFE\FatturaElettronica; use Plugins\ExportFE\FatturaElettronica;
use Plugins\ExportFE\Interaction; 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.*/ /* 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']); $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)) { if (!empty($fattura_pa)) {
$disabled = false; $generata = $fattura_pa->isGenerated();
$generated = $fattura_pa->isGenerated();
} else { } else {
$disabled = true; $generata = false;
$generated = false;
} }
$checks = FatturaElettronica::controllaFattura($fattura); $checks = FatturaElettronica::controllaFattura($fattura);
@ -75,28 +77,30 @@ echo '
<input type="hidden" name="backto" value="record-edit"> <input type="hidden" name="backto" value="record-edit">
<input type="hidden" name="op" value="generate"> <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').' <i class="fa fa-file"></i> '.tr('Genera').'
</button> </button>
</form>'; </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 ' echo '
<i class="fa fa-arrow-right fa-fw text-muted"></i> <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').' <i class="fa fa-eye"></i> '.tr('Visualizza').'
</a>'; </a>';
// Scelgo quando posso inviarla // 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 ' echo '
<i class="fa fa-arrow-right fa-fw text-muted"></i> <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').' <i class="fa fa-download"></i> '.tr('Scarica').'
</a>'; </a>';
@ -104,38 +108,29 @@ echo '
<i class="fa fa-arrow-right fa-fw text-muted"></i> <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').' <i class="fa fa-paper-plane"></i> '.tr('Invia').'
</button>'; </button>';
$verify = Interaction::isEnabled() && $generated; $verify = Interaction::isEnabled() && $generata;
echo ' echo '
<i class="fa fa-arrow-right fa-fw text-muted"></i> <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').' <i class="fa fa-question-circle"></i> '.tr('Verifica notifiche').'
</button> </button>
</div>'; </div>';
echo '<br><br>'; echo '<br><br>';
// Messaggio esito invio // Messaggio informativo sulla ricevuta principale impostata
$ultima_ricevuta = $fattura->getRicevute()->last(); if (!empty($fattura->codice_stato_fe)) {
if (!empty($record['codice_stato_fe'])) { echo '
if ($record['codice_stato_fe'] == 'GEN') { <div class="alert alert-'.$stato_fe['tipo'].'">
echo ' <div class="pull-right">
<div class="alert alert-info"><i class="fa fa-info-circle"></i> '.tr("La fattura è stata generata ed è pronta per l'invio").'.</div>'; <i class="fa fa-clock-o tip" title="'.tr('Data e ora').'"></i> '.timestampFormat($record['data_stato_fe']);
} 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';
}
if (!empty($ricevuta_principale)) {
echo ' echo '
<div class="alert alert-'.$class.'"> <div class="alert alert-'.$class.'">
<div class="pull-right"> <div class="pull-right">
@ -143,25 +138,39 @@ if (!empty($record['codice_stato_fe'])) {
if (!empty($ultima_ricevuta)) { if (!empty($ultima_ricevuta)) {
echo ' 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').' <i class="fa fa-external-link"></i> '.tr('Visualizza ricevuta').'
</a>'; </a>';
} }
echo ' echo '
</div> </div>
<big><i class="'.$stato_fe['icon'].'" style="color:#fff;"></i> <big>
<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'] : '').' <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>'; </div>';
// Lettura della ricevuta // Lettura della ricevuta
if (!empty($ultima_ricevuta) && $stato_fe['codice'] == 'NS') { if (!empty($ricevuta_principale)) {
$contenuto_ricevuta = \Util\XML::readFile($ultima_ricevuta->filepath); $contenuto_ricevuta = XML::readFile($ricevuta_principale->filepath);
$lista_errori = $contenuto_ricevuta['ListaErrori']; $lista_errori = $contenuto_ricevuta['ListaErrori'];
if (!empty($lista_errori)) { if (!empty($lista_errori)) {
echo ' echo '
<h4>'.tr('Elenco degli errori').'</h4> <h4>'.tr('Elenco degli errori').'</h4>
<table class="table table-striped"> <table class="table table-striped">
<thead> <thead>
@ -172,60 +181,66 @@ if (!empty($record['codice_stato_fe'])) {
</thead> </thead>
<tbody>'; <tbody>';
$lista_errori = $lista_errori[0] ? $lista_errori : [$lista_errori]; $lista_errori = $lista_errori[0] ? $lista_errori : [$lista_errori];
foreach ($lista_errori as $errore) { foreach ($lista_errori as $errore) {
$errore = $errore['Errore']; $errore = $errore['Errore'];
echo ' echo '
<tr> <tr>
<td>'.$errore['Codice'].'</td> <td>'.$errore['Codice'].'</td>
<td>'.$errore['Descrizione'].'</td> <td>'.$errore['Descrizione'].'</td>
</tr>'; </tr>';
} }
echo ' echo '
</tbody> </tbody>
</table>'; </table>';
}
} }
} }
} }
echo ' echo '
<script> <script>
function send(btn) { function inviaFE(button) {
var restore = buttonLoading(btn); if (confirm("'.tr('Inviare la fattura al SDI?').'")) {
let restore = buttonLoading(button);
$.ajax({ $.ajax({
url: globals.rootdir + "/actions.php", url: globals.rootdir + "/actions.php",
type: "post", type: "post",
data: { dataType: "json",
op: "send", data: {
id_module: "'.$id_module.'", op: "send",
id_plugin: "'.$id_plugin.'", id_module: "'.$id_module.'",
id_record: "'.$id_record.'", id_plugin: "'.$id_plugin.'",
}, id_record: "'.$id_record.'",
success: function(data) { },
buttonRestore(btn, restore); success: function(data) {
data = JSON.parse(data); buttonRestore(button, restore);
if (data.code == "200") { if (data.code === 200) {
swal("'.tr('Fattura inviata!').'", data.message, "success"); swal("'.tr('Fattura inviata!').'", data.message, "success");
$(btn).attr("disabled", true).addClass("disabled"); $(button).attr("disabled", true).addClass("disabled");
} else { } else if (data.code === 301) {
swal("'.tr('Invio fallito').'", data.code + " - " + data.message, "error"); 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) { function verificaNotificheFE(button) {
var restore = buttonLoading(btn); openModal("'.tr('Gestione ricevute').'", "'.$structure->fileurl('notifiche.php').'");
/*
let restore = buttonLoading(button);
$.ajax({ $.ajax({
url: globals.rootdir + "/actions.php", url: globals.rootdir + "/actions.php",
@ -237,7 +252,7 @@ echo '
id_record: "'.$id_record.'", id_record: "'.$id_record.'",
}, },
success: function(data) { success: function(data) {
buttonRestore(btn, restore); buttonRestore(button, restore);
data = JSON.parse(data); data = JSON.parse(data);
if (data.file) { if (data.file) {
@ -251,27 +266,26 @@ echo '
error: function(data) { error: function(data) {
swal("'.tr('Errore').'", "'.tr('Errore durante la verifica').'", "error"); swal("'.tr('Errore').'", "'.tr('Errore durante la verifica').'", "error");
buttonRestore(btn, restore); buttonRestore(button, restore);
} }
}); });*/
} }
$("#genera").click(function(event) { function generaFE(button) {
event.preventDefault(); salvaForm(button, "#edit-form").then(function(valid) {
salvaForm(this, "#edit-form").then(function(valid) {
if (valid) {'; if (valid) {';
if ($generated) { if ($generata) {
echo ' 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({ swal({
title: "'.tr('Sei sicuro di rigenerare la fattura?').'", 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", type: "warning",
showCancelButton: true, showCancelButton: true,
confirmButtonColor: "#30d64b", confirmButtonColor: "#30d64b",
cancelButtonColor: "#d33", cancelButtonColor: "#d33",
confirmButtonText: "Genera" confirmButtonText: "'.tr('Genera').'"
}).then((result) => { }).then((result) => {
if (result) { if (result) {
$("#form-xml").submit(); $("#form-xml").submit();
@ -291,5 +305,5 @@ echo '
}); });
} }
}); });
}); };
</script>'; </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', [ database()->update('co_documenti', [
'progressivo_invio' => $this->getDocumento()['progressivo_invio'], 'progressivo_invio' => $this->getDocumento()['progressivo_invio'],
'codice_stato_fe' => 'GEN', 'codice_stato_fe' => 'GEN',
'id_ricevuta_principale' => null,
'data_stato_fe' => date('Y-m-d H:i:s'), 'data_stato_fe' => date('Y-m-d H:i:s'),
], ['id' => $this->getDocumento()['id']]); ], ['id' => $this->getDocumento()['id']]);

View File

@ -381,7 +381,7 @@ if (!empty($righe)) {
</div> </div>
<div class="col-md-3"> <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> </div>
</td> </td>
</tr>'; </tr>';

View File

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

View File

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

View File

@ -19,11 +19,10 @@
namespace Plugins\ReceiptFE; namespace Plugins\ReceiptFE;
use Modules; use Models\Upload;
use Modules\Fatture\Fattura; use Modules\Fatture\Fattura;
use Plugins; use Plugins;
use UnexpectedValueException; use UnexpectedValueException;
use Uploads;
use Util\XML; use Util\XML;
use Util\Zip; use Util\Zip;
@ -48,6 +47,7 @@ class Ricevuta
{ {
$file = static::getImportDirectory().'/'.$name; $file = static::getImportDirectory().'/'.$name;
// Estrazione implicita per il formato ZIP
if (ends_with($name, '.zip')) { if (ends_with($name, '.zip')) {
$original_file = $file; $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) public static function store($filename, $content)
{ {
$directory = static::getImportDirectory(); $directory = static::getImportDirectory();
@ -90,6 +126,11 @@ class Ricevuta
return $filename; return $filename;
} }
/**
* Restituisce la cartella temporanea utilizzabile per il salvataggio della ricevuta.
*
* @return string|null
*/
public static function getImportDirectory() public static function getImportDirectory()
{ {
if (!isset(self::$directory)) { if (!isset(self::$directory)) {
@ -101,32 +142,51 @@ class Ricevuta
return self::$directory; return self::$directory;
} }
/**
* @param string $codice
*
* @return Upload|null
*/
public function saveAllegato($codice) 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'), 'category' => tr('Fattura Elettronica'),
'id_module' => $module->id, 'id_module' => $module->id,
'id_record' => $this->fattura->id, 'id_record' => $fattura->id,
];
// Registrazione XML come allegato
Uploads::upload($this->file, array_merge($info, [
'name' => tr('Ricevuta _TYPE_', [ 'name' => tr('Ricevuta _TYPE_', [
'_TYPE_' => $codice, '_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(); $fattura = $this->getFattura();
// Modifica lo stato solo se la fattura non è già stata consegnata (per evitare problemi da doppi invii) // 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, // 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.
// quindi aggiungo eccezione nel caso il nuovo codice della ricevuta sia NE.
if ($fattura->codice_stato_fe == 'RC' && ($codice != 'EC01' || $codice != 'EC02')) { if ($fattura->codice_stato_fe == 'RC' && ($codice != 'EC01' || $codice != 'EC02')) {
return; return;
} }
@ -138,11 +198,15 @@ class Ricevuta
$fattura->data_stato_fe = $data ? date('Y-m-d H:i:s', strtotime($data)) : ''; $fattura->data_stato_fe = $data ? date('Y-m-d H:i:s', strtotime($data)) : '';
$fattura->codice_stato_fe = $codice; $fattura->codice_stato_fe = $codice;
$fattura->descrizione_ricevuta_fe = $descrizione; $fattura->descrizione_ricevuta_fe = $descrizione;
$fattura->id_ricevuta_principale = $id_allegato;
$fattura->save(); $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); $name = basename($this->file);
$filename = explode('.', $name)[0]; $filename = explode('.', $name)[0];
@ -157,22 +221,32 @@ class Ricevuta
$codice_nome = $codice_nome.' - '.$errore['Errore']['Codice']; $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 ($cambia_stato) {
if ($codice_stato == 'NE') { // In caso di Notifica Esito il codice è definito dal nodo <Esito> della ricevuta
$codice_stato = $this->xml['EsitoCommittente']['Esito']; 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() public function getFattura()
{ {
return $this->fattura; return $this->fattura;
} }
public function delete() /**
* Rimuove i file temporanei relativi alla ricevuta.
*/
public function cleanup()
{ {
delete($this->file); 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 -- 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'; 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 -- Aggiunta riferimenti testuali su descrizione righe per Fatture
UPDATE `co_righe_documenti` 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% -- 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 `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');