This commit is contained in:
Beppe 2021-12-06 16:14:16 +01:00
commit 7f29f28a7d
71 changed files with 3547 additions and 553 deletions

View File

@ -4,6 +4,7 @@ Tutti i maggiori cambiamenti di questo progetto saranno documentati in questo fi
Il formato utilizzato è basato sulle linee guida di [Keep a Changelog](http://keepachangelog.com/), e il progetto segue il [Semantic Versioning](http://semver.org/) per definire le versioni delle release.
- [2.4.28 (2021-12-)](#2428-2021-12-)
- [2.4.27 (2021-10-25)](#2427-2021-10-26)
- [2.4.26 (2021-09-24)](#2426-2021-09-24)
- [2.4.25 (2021-08-25)](#2425-2021-08-25)
@ -38,6 +39,57 @@ Il formato utilizzato è basato sulle linee guida di [Keep a Changelog](http://k
- [2.2 (2016-11-10)](#22-2016-11-10)
- [2.1 (2015-04-02)](#21-2015-04-02)
## 2.4.28 (2021-12-)
### Aggiunto (Added)
- Aggiunta colonna documento di acquisto e prezzo nel plugin **seriali**
- Aggiunto flag Calcola km nel modulo **tipi di attività**
- Aggiunta azione di gruppo per aggiornare unità di misura degli **articoli**
- Aggiunta azione di gruppo per aggiornare liste **newsletter**
- Aggiunta azione di gruppo in **articoli** per aggiornare conto acquisto/vendita
- Aggiunta colonna mail Inviata in **attività**
- Aggiunta gestione dell'arrotondamento nell'azione di gruppo per aggiornare il prezzo di vendita
- Aggiunta impostazione per riportare il riferimento del documento
- Aggiunto controllo widget Fatturato per escludere le fatture in stato Bozza
- Aggiunta stampa **libro giornale**
- Aggiunta creazione sottocategoria al volo dal modulo **articoli**
- Aggiunta creazione dinamica della sede in attività
- Aggiunta tabella **mansioni** e gestione aggiunta destinatari mail
- Aggiunte impostazioni per notificare intervento ai tecnici
- Aggiunte nuove colonne nel widget **interventi da programmare**
- Aggiunto filtro di ricerca nel Piano dei conti
- Aggiunto plugin **Movimenti contabili** in Fatture e Anagrafiche
- Aggiunta possibilità di associare varianti della combinazione collegandole ad articoli esistenti
- Aggiunto plugin **Presentazioni bancarie** in Scadenzario
- Aggiunta gestione Abi e Cab in fase di creazione banca
- Aggiunte note interne in template mail
- Aggiunta duplicazione **DDT**
### Modificato (Changed)
- Compilazione automatica tipo documento in fase di import FE solo se il campo non è impostato
- Rimossa data conclusione preventivo automatica
- Miglioramenti modal modifica sessione tecnico
- Modifica apertura attività in dashboard con click e doppio click da smartphone
- Migliorie modulo Coda di invio
- Importazione righe della fattura elettronica con quantità e importo a 0 come riga di tipo descrizione
- Rimosso modulo Gestione componenti
### Fixed
- Fix controllo corrispondenza tra xml e documento
- Fix stampa senza intestazione **fattura di vendita**
- Fix eliminazione movimenti manuali
- Fix stampa registro iva
- Fix select articoli
- Fix calcolo prezzi e iva tabella **seriali**
- Fix importazione fatture con importi negativi
- Fix destinatari modal invio mail
- Fix calcolo guadagno riga
- Fix pulsante disabilita widget
- Fix calcolo sessioni interventi in fase di duplicazione
- Fix stampa documento tramite comando da tastiera
- Fix campi abi cab nel modulo **banche**
- Fix stampa fatturato
## 2.4.27 (2021-10-26)
### Aggiunto (Added)
@ -56,11 +108,13 @@ Il formato utilizzato è basato sulle linee guida di [Keep a Changelog](http://k
- Aggiunta selezione prezzo di acquisto per stampa inventario
- Aggiunto costo medio in fase di aggiunta riga articolo
- Aggiunta azione di gruppo per aggiornare il prezzo di acquisto per gli articoli a cui non è impostato, in base all'ultima fattura di acquisto
### Modificato (Changed)
- Ampliata **ricerca articoli** in importazione fatturazione elettronica per collegamento automatico
- Ridotto il valid time per la cache
- Ordinamento **gestione documentale** per data decrescente
- Spostamento stampe situazione contabile e bilancio in **Stampe contabili**
### Fixed
- Fix sconti in **fatturazione interventi**
- Fix statistiche **fatture**

View File

@ -58,7 +58,9 @@
"symfony/translation": "^3.3",
"symfony/var-dumper": "^3.3",
"thenetworg/oauth2-azure": "^2.0",
"willdurand/geocoder": "^3.3"
"willdurand/geocoder": "^3.3",
"digitick/sepa-xml": "^1.6",
"wdog/sdd_ita": "dev-master"
},
"require-dev": {
"codeception/codeception": "^3.0",
@ -114,7 +116,8 @@
"Plugins\\ListinoClienti\\": ["plugins/listino_clienti/custom/src/", "plugins/listino_clienti/src/"],
"Plugins\\ListinoFornitori\\": ["plugins/listino_fornitori/custom/src/", "plugins/listino_fornitori/src/"],
"Plugins\\ComponentiImpianti\\": ["plugins/componenti/custom/src/", "plugins/componenti/src/"],
"Modules\\StatoEmail\\": ["modules/stato_email/custom/src/", "modules/stato_email/src/"]
"Modules\\StatoEmail\\": ["modules/stato_email/custom/src/", "modules/stato_email/src/"],
"Plugins\\PresentazioniBancarie\\": ["plugins/presentazioni_bancarie/custom/src/", "plugins/presentazioni_bancarie/src/"]
},
"files": [
"lib/functions.php",
@ -124,13 +127,19 @@
"lib/deprecated.php"
]
},
"repositories": [
{
"type": "vcs",
"url": "https://github.com/wdog/sdd_ita"
}
],
"config": {
"sort-packages": true,
"optimize-autoloader": false,
"apcu-autoloader": true,
"prefer-stable": true,
"platform": {
"php": "5.6.4"
"php": "7.1"
}
}
}

View File

@ -502,3 +502,14 @@ exports.srcCSS = srcCSS;
exports.bower = bower;
exports.release = release;
exports.default = bower;
// Watch task - lanciato con `gulp watch`, resta in attesa e ogni volta che viene modificato un asset in src
// viene aggiornata la dist
gulp.task('watch', function () {
gulp.watch('assets/src/css/*.css', gulp.series(srcCSS, CSS));
gulp.watch('assets/src/css/print/*.css', gulp.series(srcCSS, CSS));
gulp.watch('assets/src/css/themes/*.css', gulp.series(srcCSS, CSS));
gulp.watch('assets/src/js/base/*.js', gulp.series(srcJS, JS));
gulp.watch('assets/src/js/functions/*.js', gulp.series(srcJS, JS));
gulp.watch('assets/src/img/*', gulp.series(images));
});

View File

@ -31,6 +31,17 @@ $subject = $module->replacePlaceholders($id_record, $template['subject']);
$emails = explode(';', $module->replacePlaceholders($id_record, '{email}'));
$id_anagrafica = $module->replacePlaceholders($id_record, '{id_anagrafica}');
// Aggiungo email referenti in base alla mansione impostata nel template
$mansioni = $dbo->select('em_mansioni_template', 'idmansione', ['id_template' => $template->id]);
foreach ($mansioni as $mansione) {
$referenti = $dbo->select('an_referenti', 'email', ['idmansione' => $mansione['idmansione']]);
foreach ($referenti as $referente) {
if (!in_array($referente['email'], $emails)) {
$emails[] = $referente['email'];
}
}
}
// Campi mancanti
$campi_mancanti = [];

View File

@ -110,7 +110,7 @@ echo '
<div class="row">
<div class="col-md-4">
{[ "type": "text", "label": "'.tr('Email').'", "name": "email", "class": "email-mask", "placeholder":"casella@dominio.ext", "icon-before": "<i class=\"fa fa-envelope\"></i>" ]}
{[ "type": "text", "label": "'.tr('Email').'", "name": "email", "class": "email-mask", "placeholder":"casella@dominio.ext", "icon-before": "<i class=\"fa fa-envelope\"></i>", "validation": "email" ]}
</div>
<div class="col-md-4">

View File

@ -111,17 +111,4 @@ switch ($resource) {
echo json_encode($results);
break;
case 'get_mansioni':
$q = 'SELECT DISTINCT mansione FROM an_referenti';
$rs = $dbo->fetchArray($q);
$n = sizeof($rs);
for ($i = 0; $i < $n; ++$i) {
echo html_entity_decode($rs[$i]['mansione']);
if (($i + 1) < $n) {
echo '|';
}
}
break;
}

View File

@ -87,10 +87,10 @@ foreach ($rs as $r) {
// Referenti anagrafiche
$fields = [
'Nome' => 'nome',
'Mansione' => 'mansione',
'Telefono' => 'telefono',
'Email' => 'email',
'Nome' => 'an_referenti.nome',
'Mansione' => 'an_mansioni.nome',
'Telefono' => 'an_referenti.telefono',
'Email' => 'an_referenti.email',
];
$query = 'SELECT *, idanagrafica as id';
@ -99,7 +99,7 @@ foreach ($fields as $name => $value) {
$query .= ', '.$value." AS '".str_replace("'", "\'", $name)."'";
}
$query .= ' FROM an_referenti WHERE idanagrafica IN('.implode(',', $idanagrafiche).') ';
$query .= ' FROM an_referenti LEFT JOIN an_mansioni ON an_referenti.idmansione=an_mansioni.id WHERE idanagrafica IN('.implode(',', $idanagrafiche).') ';
foreach ($fields as $name => $value) {
$query .= ' OR '.$value.' LIKE "%'.$term.'%"';

View File

@ -289,10 +289,10 @@ switch ($resource) {
*/
case 'referenti':
if (isset($superselect['idanagrafica'])) {
$query = 'SELECT id, nome AS descrizione, an_referenti.mansione AS optgroup FROM an_referenti |where| ORDER BY optgroup, nome';
$query = 'SELECT an_referenti.id, an_referenti.nome AS descrizione, an_mansioni.nome AS optgroup FROM an_referenti LEFT JOIN an_mansioni ON an_referenti.idmansione=an_mansioni.id |where| ORDER BY optgroup, an_referenti.nome';
foreach ($elements as $element) {
$filter[] = 'id='.prepare($element);
$filter[] = 'an_referenti.id='.prepare($element);
}
if (isset($superselect['idclientefinale'])) {
@ -302,7 +302,7 @@ switch ($resource) {
}
if (!empty($search)) {
$search_fields[] = 'nome LIKE '.prepare('%'.$search.'%');
$search_fields[] = 'an_referenti.nome LIKE '.prepare('%'.$search.'%');
}
}
break;

View File

@ -209,7 +209,7 @@ if (sizeof($problemi_anagrafica) > 0) {
</div>
<div class="col-md-4">
{[ "type": "text", "label": "<?php echo tr('Email'); ?>", "name": "email", "placeholder": "casella@dominio.ext", "value": "$email$", "icon-before": "<i class='fa fa-envelope'></i>", "validation": "email" ]}
{[ "type": "text", "label": "<?php echo tr('Email'); ?>", "name": "email", "class": "email-mask", "placeholder": "casella@dominio.ext", "value": "$email$", "icon-before": "<i class='fa fa-envelope'></i>", "validation": "email" ]}
</div>
</div>

View File

@ -32,6 +32,7 @@ switch ($resource) {
$prezzi_ivati = setting('Utilizza prezzi di vendita comprensivi di IVA');
$usare_dettaglio_fornitore = $superselect['dir'] == 'uscita';
$usare_iva_anagrafica = $superselect['dir'] == 'entrata' && !empty($superselect['idanagrafica']);
$solo_non_varianti = $superselect['solo_non_varianti'];
$query = "SELECT
IF(`categoria`.`nome` IS NOT NULL, CONCAT(`categoria`.`nome`, IF(`sottocategoria`.`nome` IS NOT NULL, CONCAT(' (', `sottocategoria`.`nome`, ')'), '-')), '<i>".tr('Nessuna categoria')."</i>') AS optgroup,
@ -139,6 +140,10 @@ switch ($resource) {
$where[] = 'mg_articoli.attivo = 1';
$where[] = 'mg_articoli.deleted_at IS NULL';
if ($solo_non_varianti) {
$where[] = 'mg_articoli.id_combinazione IS NULL';
}
if (!empty($search)) {
$search_fields[] = 'mg_articoli.descrizione LIKE '.prepare('%'.$search.'%');
$search_fields[] = 'mg_articoli.codice LIKE '.prepare('%'.$search.'%');

View File

@ -53,7 +53,7 @@ include_once __DIR__.'/../../core.php';
</div>
<div class="col-md-6">
{[ "type": "select", "label": "<?php echo tr('Sottocategoria'); ?>", "name": "subcategoria", "value": "$id_sottocategoria$", "ajax-source": "sottocategorie", "select-options": <?php echo json_encode(['id_categoria' => $record['id_categoria']]); ?>, "icon-after": "add|<?php echo Modules::get('Categorie articoli')['id']; ?>"|id_original=<?php echo $record['id_categoria']; ?>" ]}
{[ "type": "select", "label": "<?php echo tr('Sottocategoria'); ?>", "name": "subcategoria", "value": "$id_sottocategoria$", "ajax-source": "sottocategorie", "select-options": <?php echo json_encode(['id_categoria' => $record['id_categoria']]); ?>, "icon-after": "add|<?php echo Modules::get('Categorie articoli')['id']; ?>|id_original=<?php echo $record['id_categoria']; ?>" ]}
</div>
</div>
</div>

View File

@ -46,6 +46,20 @@ echo '
</div>
</div>
<div class="row">
<div class="col-md-4">
{[ "type": "select", "label": "'.tr('Nazione').'", "name": "id_nazione", "ajax-source": "nazioni" ]}
</div>
<div class="col-md-4">
{[ "type": "text", "label": "'.tr('Codice banca nazionale (ABI)').'", "name": "bank_code", "class": "alphanumeric-mask" ]}
</div>
<div class="col-md-4">
{[ "type": "text", "label": "'.tr('Codice filiale (CAB)').'", "name": "branch_code", "class": "alphanumeric-mask" ]}
</div>
</div>
<!-- PULSANTI -->
<div class="row">
<div class="col-md-12 text-right">
@ -55,3 +69,99 @@ echo '
</div>
</div>
</form>';
?>
<script>
var iban = input("iban");
var branch_code = input("branch_code");
var bank_code = input("bank_code");
var id_nazione = input("id_nazione");
var components = [branch_code, bank_code, id_nazione];
$(document).ready(function (){
iban.trigger("keyup");
});
iban.on("keyup", function () {
if (!iban.isDisabled()){
let value = iban.get();
for (const component of components){
component.setDisabled(value !== "")
}
scomponiIban();
}
});
for (const component of components){
component.on("keyup", function () {
let i = input(this);
if (!i.isDisabled()) {
iban.setDisabled(i.get() !== "")
componiIban();
}
});
}
function scomponiIban() {
$.ajax({
url: globals.rootdir + '/actions.php',
data: {
id_module: globals.id_module,
op: "decompose",
iban: iban.get(),
},
type: 'GET',
dataType: "json",
success: function (response) {
compilaCampi(response);
},
error: function() {
toastr["error"]("<?php echo tr('Formato IBAN non valido'); ?>");
}
});
}
function componiIban() {
// Controllo su campi con valore impostato
let continua = false;
for (const component of components){
continua |= !([undefined, null, ""].includes(component.get()));
}
if (!continua){
return;
}
$.ajax({
url: globals.rootdir + '/actions.php',
data: {
id_module: globals.id_module,
op: "compose",
branch_code: branch_code.get(),
bank_code: bank_code.get(),
id_nazione: id_nazione.get(),
},
type: 'GET',
dataType: "json",
success: function (response) {
compilaCampi(response);
},
error: function() {
toastr["error"]("<?php echo tr('Formato IBAN non valido'); ?>");
}
});
}
function compilaCampi(values) {
for([key, value] of Object.entries(values)) {
if (typeof value === 'object' && value !== null) {
input(key).getElement().selectSetNew(value.id, value.text, value);
} else {
input(key).set(value);
}
}
}
</script>

View File

@ -153,10 +153,10 @@ if (!empty($numero_documenti)) {
var components = [branch_code, bank_code, account_number, check_digits, national_check_digits, id_nazione];
$(document).ready(function (){
iban.trigger("change");
iban.trigger("keyup");
});
iban.change(function () {
iban.on("keyup", function () {
if (!iban.isDisabled()){
let value = iban.get();
for (const component of components){
@ -168,7 +168,7 @@ if (!empty($numero_documenti)) {
});
for (const component of components){
component.change(function () {
component.on("keyup", function () {
let i = input(this);
if (!i.isDisabled()) {
iban.setDisabled(i.get() !== "")

View File

@ -22,7 +22,7 @@ include_once __DIR__.'/../../core.php';
$subcategorie = $dbo->fetchArray('SELECT * FROM `mg_categorie` WHERE `parent`='.prepare($id_record).' ORDER BY nome ASC ');
foreach ($subcategorie as $sub) {
$n_articoli = $dbo->fetchNum('SELECT * FROM `mg_articoli` WHERE `id_sottocategoria`='.prepare($sub['id']));
$n_articoli = $dbo->fetchNum('SELECT * FROM `mg_articoli` WHERE `id_sottocategoria`='.prepare($sub['id']).' AND deleted_at IS NULL');
echo '
<tr>
<td>'.$sub['nome'].'</td>

View File

@ -44,7 +44,7 @@ switch (filter('op')) {
break;
case 'gestione-variante':
$combinazione->generaVariante((array) filter('attributo'));
$combinazione->generaVariante((array) filter('attributo'), filter('id_articolo'));
flash()->info(tr('Variante aggiunta correttamente!'));

View File

@ -34,6 +34,12 @@ foreach ($attributi as $key => $attributo) {
</div>';
}
// Scelta articolo esistente
echo '
<div class="col-md-4">
{[ "type": "select", "label": "'.tr('Collega articolo esistente').' ('.tr('facoltativo').')", "name": "id_articolo", "ajax-source": "articoli", "select-options": {"solo_non_varianti": 1, "permetti_movimento_a_zero": 1} ]}
</div>';
echo '
</div>

View File

@ -76,7 +76,7 @@ class Combinazione extends Model
*
* @param $valori_attributi
*/
public function generaVariante($valori_attributi)
public function generaVariante($valori_attributi, $id_articolo = null)
{
$database = database();
@ -84,20 +84,42 @@ class Combinazione extends Model
$variante = ValoreAttributo::findMany($valori_attributi)->pluck('nome')->all();
// Generazione Articolo di base
$articoli = $this->articoli;
if ($articoli->isEmpty()) {
$articolo = Articolo::build($this->nome, $this->nome);
$articolo->id_combinazione = $this->id;
if (empty($id_articolo)) {
$articoli = $this->articoli;
if ($articoli->isEmpty()) {
$articolo = Articolo::build($this->nome, $this->nome);
$articolo->id_combinazione = $this->id;
$articolo->id_categoria = $this->id_categoria;
$articolo->id_sottocategoria = $this->id_sottocategoria;
} else {
$articolo_base = $articoli->first();
$articolo = $articolo_base->replicate();
$articolo->id_categoria = $this->id_categoria;
$articolo->id_sottocategoria = $this->id_sottocategoria;
} else {
$articolo_base = $articoli->first();
$articolo = $articolo_base->replicate();
$nome_immagine = $articolo_base->immagine_upload->name;
$allegato = $articolo_base->uploads()->where('name', $nome_immagine)->first();
if (!empty($allegato)) {
$allegato->copia([
'id_module' => $articolo->getModule()->id,
'id_record' => $articolo->id,
]);
$articolo->immagine = $articolo->uploads()->where('name', $nome_immagine)->first()->filename;
$articolo->save();
}
}
$articolo->descrizione = $this->nome.' ['.implode(', ', $variante).']';
$articolo->codice = $this->codice.'-'.implode('|', $variante);
$articolo->save();
}
// Uso di un articolo già esistente
else {
$articolo = Articolo::find($id_articolo);
$articolo->id_combinazione = $this->id;
$articolo->save();
}
$articolo->descrizione = $this->nome.' ['.implode(', ', $variante).']';
$articolo->codice = $this->codice.'-'.implode('|', $variante);
$articolo->save();
// Associazione valori della variante
foreach ($valori_attributi as $id => $id_valore) {
@ -106,19 +128,6 @@ class Combinazione extends Model
'id_valore' => $id_valore,
]);
}
// Salvataggio immagine relativa
if (!$articoli->isEmpty()) {
$nome_immagine = $articolo_base->immagine_upload->name;
$allegato = $articolo_base->uploads()->where('name', $nome_immagine)->first();
$allegato->copia([
'id_module' => $articolo->getModule()->id,
'id_record' => $articolo->id,
]);
$articolo->immagine = $articolo->uploads()->where('name', $nome_immagine)->first()->filename;
$articolo->save();
}
}
/**

View File

@ -480,6 +480,36 @@ switch (filter('op')) {
$id_record = $copia->id;
$id_module = $ddt->direzione == 'entrata' ? Module::pool('Ddt di acquisto')->id : Module::pool('Ddt di vendita')->id;
break;
// Duplica ddt
case 'copy':
$new = $ddt->replicate();
$new->numero = DDT::getNextNumero($new->data, $dir);
$new->numero_esterno = DDT::getNextNumeroSecondario($new->data, $dir);
$stato = Stato::where('descrizione', '=', 'Bozza')->first();
$new->stato()->associate($stato);
$new->save();
$id_record = $new->id;
$righe = $ddt->getRighe();
foreach ($righe as $riga) {
$new_riga = $riga->replicate();
$new_riga->setDocument($new);
$new_riga->qta_evasa = 0;
$new_riga->idordine = 0;
$new_riga->save();
if ($new_riga->isArticolo()) {
$new_riga->movimenta($new_riga->qta);
}
}
flash()->info(tr('DDT duplicato correttamente!'));
break;
}

View File

@ -77,3 +77,15 @@ echo '
<button class="btn btn-info '.($ddt->isImportabile() ? '' : 'disabled').'" data-href="'.$structure->fileurl('crea_documento.php').'?id_module='.$id_module.'&id_record='.$id_record.'&documento=fattura" data-toggle="modal" data-title="'.tr('Crea ').($ddt->reversed ? 'nota di credito' : ($dir == 'entrata' ? 'fattura di vendita' : 'fattura di acquisto')).'"><i class="fa fa-magic"></i> '.tr('Crea ').($ddt->reversed ? 'nota di credito' : ($dir == 'entrata' ? 'fattura di vendita' : 'fattura di acquisto')).'
</button>
</div>';
// Duplica ddt
echo '
<button type="button" class="btn btn-primary" onclick="if( confirm(\''.tr('Duplicare questo ddt?').'\') ){ $(\'#copia-ddt\').submit(); }">
<i class="fa fa-copy"></i> '.tr('Duplica ddt').'
</button>';
echo '
<form action="" method="post" id="copia-ddt">
<input type="hidden" name="backto" value="record-edit">
<input type="hidden" name="op" value="copy">
</form>';

View File

@ -45,9 +45,11 @@ switch (post('op')) {
'bcc' => post('bcc'),
'body' => $_POST['body'], // post('body'),
'read_notify' => post('read_notify'),
'note_aggiuntive' => post('note_aggiuntive'),
], ['id' => $id_record]);
$dbo->sync('em_print_template', ['id_template' => $id_record], ['id_print' => (array) post('prints')]);
$dbo->sync('em_mansioni_template', ['id_template' => $id_record], ['idmansione' => (array) post('idmansioni')]);
flash()->info(tr('Informazioni salvate correttamente!'));

View File

@ -87,13 +87,22 @@ if (!$record['predefined']) {
// Stampe
$selected_prints = $dbo->fetchArray('SELECT id_print FROM em_print_template WHERE id_template = '.prepare($id_record));
$selected = array_column($selected_prints, 'id_print');
$selected_prints = array_column($selected_prints, 'id_print');
$selected_mansioni = $dbo->fetchArray('SELECT idmansione FROM em_mansioni_template WHERE id_template = '.prepare($id_record));
$selected_mansioni = array_column($selected_mansioni, 'idmansione');
echo '
<div class="row">
<div class="col-md-12">
{[ "type": "select", "multiple": "1", "label": "'.tr('Stampe').'", "name": "prints[]", "value": "'.implode(',', $selected).'", "values": "query=SELECT id, title AS text FROM zz_prints WHERE id_module = '.prepare($record['id_module']).' AND enabled=1" ]}
{[ "type": "select", "multiple": "1", "label": "'.tr('Stampe').'", "name": "prints[]", "value": "'.implode(',', $selected_prints).'", "values": "query=SELECT id, title AS text FROM zz_prints WHERE id_module = '.prepare($record['id_module']).' AND enabled=1" ]}
</div>
</div>
<div class="row">
<div class="col-md-12">
{[ "type": "select", "multiple": "1", "label": "'.tr('Mansioni').'", "name": "idmansioni[]", "value": "'.implode(',', $selected_mansioni).'", "ajax-source": "mansioni" ]}
</div>
</div>';
@ -105,6 +114,12 @@ echo '
</div>
</div>
<div class="row">
<div class="col-md-12">
{[ "type": "textarea", "label": "<?php echo tr('Note interne'); ?>", "name": "note_aggiuntive", "value": "$note_aggiuntive$", "class": "unblockable" ]}
</div>
</div>
<?php
// Variabili utilizzabili

View File

@ -20,6 +20,7 @@
namespace Modules\Fatture\Gestori;
use Modules\Fatture\Fattura;
use Modules\Iva\Aliquota;
use Modules\PrimaNota\Mastrino;
use Modules\PrimaNota\Movimento;
@ -75,6 +76,7 @@ class Movimenti
$is_acquisto = $direzione == 'uscita';
$split_payment = $this->fattura->split_payment;
$is_nota = $this->fattura->isNota();
$reverse_charge = 0;
// Totali utili per i movimenti
$totale = $this->fattura->totale;
@ -126,6 +128,10 @@ class Movimenti
'avere' => $imponibile,
];
}
if (substr($riga->aliquota->codice_natura_fe, 0, 2) == 'N6' && $is_acquisto) {
$reverse_charge += $riga->totale_imponibile;
}
}
/*
@ -152,6 +158,20 @@ class Movimenti
];
}
/*
* Reverse charge
* Viene registrato solo il movimento impostando l'iva predefinita (l'iva della riga rimane a 0)
*/
if($reverse_charge) {
$id_conto = setting('Conto per Iva su acquisti');
$iva_predefinita = floatval(Aliquota::find(setting('Iva predefinita'))->percentuale);
$iva_reverse_charge = $reverse_charge * $iva_predefinita / 100;
$movimenti[] = [
'id_conto' => $id_conto,
'avere' => $iva_reverse_charge,
];
}
/*
* 5) Rivalsa INPS sul relativo conto
* Rivalsa INPS (senza IVA) -> AVERE per Vendita, DARE per Acquisto

View File

@ -1,76 +0,0 @@
<?php
/*
* OpenSTAManager: il software gestionale open source per l'assistenza tecnica e la fatturazione
* Copyright (C) DevCode s.r.l.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
include_once __DIR__.'/../../core.php';
$path = base_dir().'/files/impianti/';
switch (post('op')) {
case 'update':
$nomefile = post('nomefile');
$contenuto = post('contenuto');
if (!file_put_contents($path.$nomefile, $contenuto)) {
flash()->error(tr('Impossibile modificare il file!'));
} else {
flash()->info(tr('Informazioni salvate correttamente!'));
}
break;
case 'add':
$nomefile = str_replace('.ini', '', post('nomefile')).'.ini';
$contenuto = post('contenuto');
$cmp = \Util\Ini::getList($path);
$duplicato = false;
for ($c = 0; $c < count($cmp); ++$c) {
if ($nomefile == $cmp[$c][0]) {
$duplicato = true;
}
}
if ($duplicato) {
flash()->error(tr('Il file componente _FILE_ esiste già, nessun nuovo componente è stato creato!', [
'_FILE_' => "'".$nomefile."'",
]));
} elseif (!file_put_contents($path.$nomefile, $contenuto)) {
flash()->error(tr('Impossibile creare il file!'));
} else {
flash()->info(tr('Componente _FILE_ aggiunto correttamente!', [
'_FILE_' => "'".$nomefile."'",
]));
}
break;
case 'delete':
$nomefile = post('nomefile');
if (!empty($nomefile)) {
delete($path.$nomefile);
flash()->info(tr('File _FILE_ rimosso correttamente!', [
'_FILE_' => "'".$nomefile."'",
]));
}
break;
}

View File

@ -1,79 +0,0 @@
<?php
/*
* OpenSTAManager: il software gestionale open source per l'assistenza tecnica e la fatturazione
* Copyright (C) DevCode s.r.l.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
include_once __DIR__.'/../../core.php';
if (empty($id_record)) {
echo '
<table width="100%" class="datatables table table-striped table-hover table-condensed table-bordered">
<thead>
<tr>
<th width="10%">'.tr('Numero').'</th>
<th>'.tr('Nome del file').'</th>
</tr>
</thead>
<tbody>';
for ($c = 1; $c <= count($cmp); ++$c) {
echo '
<tr class="clickable" onclick="openLink(event, \''.base_path().'/editor.php?id_module='.$id_module.'&id_record='.$c.'\')">
<td>'.$c.'</td>
<td>'.$cmp[$c - 1][0].'</td>
</tr>';
}
echo '
</tbody>
</table>';
} else {
?>
<form action="" method="post" id="edit-form" enctype="multipart/form-data">
<input type="hidden" name="backto" value="record-edit">
<input type="hidden" name="op" value="update">
<!-- DATI ANAGRAFICI -->
<div class="panel panel-primary">
<div class="panel-heading">
<h3 class="panel-title"><?php echo tr('Componente'); ?></h3>
</div>
<div class="panel-body">
<div class="row">
<div class="col-md-6">
{[ "type": "text", "label": "<?php echo tr('Nome file'); ?>", "name": "nomefile", "required": 1, "value": "$nomefile$", "readonly": 1 ]}
</div>
</div>
<div class="row">
<div class="col-md-12">
{[ "type": "textarea", "label": "<?php echo tr('Contenuto'); ?>", "name": "contenuto", "required": 1, "class": "autosize", "value": "$contenuto$" ]}
</div>
</div>
</div>
</div>
</form>
<a class="btn btn-danger ask" data-backto="record-list" data-nomefile="<?php echo $record['nomefile']; ?>">
<i class="fa fa-trash"></i> <?php echo tr('Elimina'); ?>
</a>
<?php
}

View File

@ -70,15 +70,60 @@ switch (post('op')) {
$intervento->codice_cig = post('codice_cig');
$intervento->save();
// Assegnazione dei tecnici all'intervento
$tecnici_assegnati = (array) post('tecnici_assegnati');
$tecnici_presenti_array = $dbo->select('in_interventi_tecnici_assegnati', 'id_tecnico', ['id_intervento' => $intervento->id]);
foreach($tecnici_presenti_array as $tecnico_presente) {
$tecnici_presenti[] = $tecnico_presente['id_tecnico'];
// Notifica rimozione tecnico assegnato
if (setting('Notifica al tecnico la rimozione dell\'assegnazione dall\'attività')) {
if (!in_array($tecnico_presente['id_tecnico'], $tecnici_assegnati)){
$tecnico = Anagrafica::find($tecnico_presente['id_tecnico']);
if (!empty($tecnico['email'])) {
$template = Template::pool('Notifica rimozione intervento');
if (!empty($template)) {
$mail = Mail::build(auth()->getUser(), $template, $intervento->id);
$mail->addReceiver($tecnico['email']);
$mail->save();
}
}
}
}
}
foreach ($tecnici_assegnati as $tecnico_assegnato){
// Notifica aggiunta tecnico assegnato
if (setting('Notifica al tecnico l\'assegnazione all\'attività')) {
if (!in_array($tecnico_assegnato, $tecnici_presenti)){
$tecnico = Anagrafica::find($tecnico_assegnato);
if (!empty($tecnico['email'])) {
$template = Template::pool('Notifica intervento');
if (!empty($template)) {
$mail = Mail::build(auth()->getUser(), $template, $intervento->id);
$mail->addReceiver($tecnico['email']);
$mail->save();
}
}
}
}
}
// Assegnazione dei tecnici all'intervento
$dbo->sync('in_interventi_tecnici_assegnati', [
'id_intervento' => $id_record,
], [
'id_tecnico' => $tecnici_assegnati,
]);
// Notifica chiusura intervento
// Notifica cambio stato intervento
$stato = $dbo->selectOne('in_statiintervento', '*', ['idstatointervento' => post('idstatointervento')]);
if (!empty($stato['notifica']) && $stato['idstatointervento'] != $record['idstatointervento']) {
$template = Template::find($stato['id_email']);
@ -98,18 +143,22 @@ switch (post('op')) {
}
}
if (!empty($stato['notifica_tecnici'])) {
if (!empty($stato['notifica_tecnico_sessione'])) {
$tecnici_intervento = $dbo->select('in_interventi_tecnici', 'idtecnico', ['idintervento' => $id_record]);
$tecnici_assegnati = $dbo->select('in_interventi_tecnici_assegnati', 'id_tecnico AS idtecnico', ['id_intervento' => $id_record]);
$tecnici = array_unique(array_merge($tecnici_intervento, $tecnici_assegnati), SORT_REGULAR);
}
foreach ($tecnici as $tecnico) {
$mail_tecnico = $dbo->selectOne('an_anagrafiche', '*', ['idanagrafica' => $tecnico]);
if (!empty($mail_tecnico['email'])) {
$mail = Mail::build(auth()->getUser(), $template, $id_record);
$mail->addReceiver($mail_tecnico['email']);
$mail->save();
}
if (!empty($stato['notifica_tecnico_assegnato'])) {
$tecnici_assegnati = $dbo->select('in_interventi_tecnici_assegnati', 'id_tecnico AS idtecnico', ['id_intervento' => $id_record]);
}
$tecnici = array_unique(array_merge($tecnici_intervento, $tecnici_assegnati), SORT_REGULAR);
foreach ($tecnici as $tecnico) {
$mail_tecnico = $dbo->selectOne('an_anagrafiche', '*', ['idanagrafica' => $tecnico]);
if (!empty($mail_tecnico['email'])) {
$mail = Mail::build(auth()->getUser(), $template, $id_record);
$mail->addReceiver($mail_tecnico['email']);
$mail->save();
}
}
}
@ -214,6 +263,23 @@ switch (post('op')) {
'id_tecnico' => $tecnici_assegnati,
]);
foreach ($tecnici_assegnati as $tecnico_assegnato){
$tecnico = Anagrafica::find($tecnico_assegnato);
// Notifica al tecnico
if (setting('Notifica al tecnico l\'assegnazione all\'attività')) {
if (!empty($tecnico['email'])) {
$template = Template::pool('Notifica intervento');
if (!empty($template)) {
$mail = Mail::build(auth()->getUser(), $template, $intervento->id);
$mail->addReceiver($tecnico['email']);
$mail->save();
}
}
}
}
if (!empty(post('ricorsiva'))) {
$periodicita = post('periodicita');
$data = post('data_inizio_ricorrenza');
@ -636,7 +702,7 @@ switch (post('op')) {
$dbo->query('DELETE FROM in_interventi_tecnici WHERE id='.prepare($id_sessione));
// Notifica rimozione dell' intervento al tecnico
if (setting('Notifica al tecnico la rimozione dall\'attività')) {
if (setting('Notifica al tecnico la rimozione della sessione dall\'attività')) {
if (!empty($tecnico['email'])) {
$template = Template::pool('Notifica rimozione intervento');

View File

@ -29,6 +29,7 @@ $id_tipo = filter('id_tipo');
$origine_dashboard = get('ref') !== null;
$module_anagrafiche = Modules::get('Anagrafiche');
$id_plugin_sedi = Plugins::get('Sedi')['id'];
// Calcolo dell'orario di inizio e di fine sulla base delle informazioni fornite
$orario_inizio = filter('orario_inizio');
@ -168,7 +169,7 @@ echo '
</div>
<div class="col-md-4">
{[ "type": "select", "label": "'.tr('Sede destinazione').'", "name": "idsede_destinazione", "value": "'.$id_sede.'", "ajax-source": "sedi" ]}
{[ "type": "select", "label": "'.tr('Sede destinazione').'", "name": "idsede_destinazione", "value": "'.$id_sede.'", "ajax-source": "sedi", "icon-after": "add|'.$module_anagrafiche['id'].'|id_plugin='.$id_plugin_sedi.'&id_parent='.$id_anagrafica.'" ]}
</div>
<div class="col-md-4">
@ -509,6 +510,12 @@ echo '
} else {
$("#dettagli_cliente").html("'.tr('Seleziona prima un cliente').'...");
}
plus_sede = $("#idsede_destinazione").parent().find(".btn");
plus_sede.attr("onclick", plus_sede.attr("onclick").replace(/id_parent=[0-9]*/, "id_parent=" + value));
plus_impianto = $("#idimpianti").parent().find(".btn");
plus_impianto.attr("onclick", plus_impianto.attr("onclick").replace(/id_anagrafica=[0-9]*/, "id_anagrafica=" + value));
});
// Gestione della modifica della sede selezionato

View File

@ -97,7 +97,7 @@ function add_tecnico($id_intervento, $idtecnico, $inizio, $fine, $idcontratto =
$sessione = Sessione::build($intervento, $anagrafica, $inizio, $fine);
// Notifica nuovo intervento al tecnico
if (setting('Notifica al tecnico l\'assegnazione all\'attività')) {
if (setting('Notifica al tecnico l\'aggiunta della sessione nell\'attività')) {
if (!empty($anagrafica['email'])) {
$template = Template::pool('Notifica intervento');

View File

@ -25,21 +25,46 @@ if (!empty($rs)) {
echo '
<table class="table table-hover">
<tr>
<th width="50%">'.tr('Attività').'</th>
<th width="15%">'.tr('Data richiesta').'</th>
<th width="100">'.tr('Codice').'</th>
<th width="180">'.tr('Cliente').'</th>
<th width="80"><small>'.tr('Data richiesta').'</small></th>
<th width="17%" class="text-center">'.tr('Tecnici assegnati').'</th>
<th width="210">'.tr('Tipo intervento').'</th>
<th>'.tr('Descrizione').'</th>
</tr>';
foreach ($rs as $r) {
$data_richiesta = !empty($r['data_richiesta']) ? Translator::dateToLocale($r['data_richiesta']) : '';
$rs_tecnici = $dbo->fetchArray("SELECT GROUP_CONCAT(ragione_sociale SEPARATOR ',') AS tecnici FROM an_anagrafiche INNER JOIN in_interventi_tecnici_assegnati ON in_interventi_tecnici_assegnati.id_tecnico=an_anagrafiche.idanagrafica WHERE id_intervento=".prepare($r['id']).' GROUP BY id_intervento');
echo '
<tr >
<td>
'.Modules::link('Interventi', $r['id'], 'Intervento n. '.$r['codice'].' del '.$data_richiesta).'<br>
<small class="help-block">'.$r['ragione_sociale'].'</small>
</td>
<td class="text-center">'.$data_richiesta.'</td>
</tr>';
<tr id="int_'.$r['id'].'">
<td><a target="_blank" >'.Modules::link(Modules::get('Interventi')['id'], $r['id'], $r['codice']).'</a></td>
<td><a target="_blank" >'.Modules::link(Modules::get('Anagrafiche')['id'], $r['idanagrafica'], $dbo->fetchOne('SELECT ragione_sociale FROM an_anagrafiche WHERE idanagrafica='.prepare($r['idanagrafica']))['ragione_sociale']).'<br><small>Presso: ';
// Sede promemoria
if ($r['idsede'] == '-1') {
echo '- '.('Nessuna').' -';
} elseif (empty($r['idsede'])) {
echo tr('Sede legale');
} else {
$rsp2 = $dbo->fetchArray("SELECT id, CONCAT( CONCAT_WS( ' (', CONCAT_WS(', ', nomesede, citta), indirizzo ), ')') AS descrizione FROM an_sedi WHERE id=".prepare($r['idsede']));
echo $rsp2[0]['descrizione'];
}
echo '
</small>
</td>
<td>'.Translator::dateToLocale($r['data_richiesta']).' '.((empty($r['data_scadenza'])) ? '' : '<br><small>Entro il '.Translator::dateToLocale($r['data_scadenza']).'</small>').'</td>
<td>
'.$rs_tecnici[0]['tecnici'].'
</td>
<td>'.$dbo->fetchOne("SELECT CONCAT_WS(' - ', codice,descrizione) AS descrizione FROM in_tipiintervento WHERE idtipointervento=".prepare($r['idtipointervento']))['descrizione'].'</td>
<td>'.nl2br($r['richiesta']).'</td>
';
echo '
</tr>';
}
echo '
</table>';

View File

@ -0,0 +1,69 @@
<?php
/*
* OpenSTAManager: il software gestionale open source per l'assistenza tecnica e la fatturazione
* Copyright (C) DevCode s.r.l.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
include_once __DIR__.'/../../core.php';
switch (post('op')) {
case 'update':
$nome = post('nome');
if ($dbo->fetchNum('SELECT * FROM `an_mansioni` WHERE `nome`='.prepare($nome).' AND `id`!='.prepare($id_record)) == 0) {
$dbo->query('UPDATE `an_mansioni` SET `nome`='.prepare($nome).' WHERE `id`='.prepare($id_record));
flash()->info(tr('Salvataggio completato.'));
} else {
flash()->error(tr("E' già presente una _TYPE_ con lo stesso nome", [
'_TYPE_' => 'mansione',
]));
}
break;
case 'add':
$nome = post('nome');
if ($dbo->fetchNum('SELECT * FROM `an_mansioni` WHERE `nome`='.prepare($nome)) == 0) {
$dbo->query('INSERT INTO `an_mansioni` (`nome`) VALUES ('.prepare($nome).')');
$id_record = $dbo->lastInsertedID();
flash()->info(tr('Aggiunta nuova _TYPE_', [
'_TYPE_' => 'mansione',
]));
} else {
flash()->error(tr("E' già presente una _TYPE_ con lo stesso nome", [
'_TYPE_' => 'mansione',
]));
}
break;
case 'delete':
$referenti = $dbo->fetchNum('SELECT id FROM an_referenti WHERE idmansione='.prepare($id_record));
if (isset($id_record) && empty($referenti)) {
$dbo->query('DELETE FROM `an_mansioni` WHERE `id`='.prepare($id_record));
flash()->info(tr('_TYPE_ eliminata con successo.', [
'_TYPE_' => 'Mansione',
]));
} else {
flash()->error(tr('Sono presenti dei referenti collegati a questa mansione.'));
}
break;
}

View File

@ -21,17 +21,11 @@ include_once __DIR__.'/../../core.php';
?><form action="" method="post" id="add-form">
<input type="hidden" name="op" value="add">
<input type="hidden" name="backto" value="record-list">
<input type="hidden" name="backto" value="record-edit">
<div class="row">
<div class="col-md-12">
{[ "type": "text", "label": "<?php echo tr('Nome file'); ?>", "name": "nomefile", "required": 1 ]}
</div>
<div class="col-md-12">
<a href="#" class="pull-right" id="default">[Default]</a>
{[ "type": "textarea", "label": "<?php echo tr('Contenuto'); ?>", "name": "contenuto", "id": "contenuto_add", "required": 1, "class": "autosize", "extra": "rows='10'" ]}
{[ "type": "text", "label": "<?php echo tr('Mansione'); ?>", "name": "nome", "required": 1 ]}
</div>
</div>
@ -42,16 +36,3 @@ include_once __DIR__.'/../../core.php';
</div>
</div>
</form>
<script type="text/javascript">
$(document).ready( function() {
$('#modals > div #default').click( function() {
if (confirm ('Generare un componente di default?')){
var ini = '[Nome]\ntipo = span\nvalore = "Componente di esempio"\n\n[Marca]\ntipo = input\nvalore =\n\n[Tipo]\ntipo = select\nvalore =\nopzioni = "Tipo 1", "Tipo 2"\n\n[Data di installazione]\ntipo = date\nvalore =\n\n[Note]\ntipo = textarea\nvalore =\n';
$("#modals > div #contenuto_add").val(ini);
}
});
});
</script>

View File

@ -0,0 +1,35 @@
<?php
/*
* OpenSTAManager: il software gestionale open source per l'assistenza tecnica e la fatturazione
* Copyright (C) DevCode s.r.l.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
include_once __DIR__.'/../../../core.php';
switch ($resource) {
case 'mansioni':
$query = 'SELECT id, nome AS descrizione FROM an_mansioni |where| ORDER BY nome ASC';
foreach ($elements as $element) {
$filter[] = 'id='.prepare($element);
}
if (!empty($search)) {
$search_fields[] = 'nome LIKE '.prepare('%'.$search.'%');
}
break;
}

60
modules/mansioni/edit.php Normal file
View File

@ -0,0 +1,60 @@
<?php
/*
* OpenSTAManager: il software gestionale open source per l'assistenza tecnica e la fatturazione
* Copyright (C) DevCode s.r.l.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
include_once __DIR__.'/../../core.php';
?>
<form action="" method="post" id="edit-form">
<input type="hidden" name="backto" value="record-edit">
<input type="hidden" name="op" value="update">
<!-- DATI -->
<div class="panel panel-primary">
<div class="panel-heading">
<h3 class="panel-title"><?php echo tr('Dati'); ?></h3>
</div>
<div class="panel-body">
<div class="row">
<div class="col-md-12">
{[ "type": "text", "label": "<?php echo tr('Nome'); ?>", "name": "nome", "required": 1, "value": "$nome$" ]}
</div>
</div>
</div>
</div>
</form>
<?php
// Collegamenti diretti (numerici)
$mansioni_collegate = $dbo->fetchNum('SELECT id FROM an_referenti WHERE idmansione='.prepare($id_record));
if (!empty($mansioni_collegate)) {
echo '
<div class="alert alert-danger">
'.tr('Ci sono _NUM_ referenti collegati', [
'_NUM_' => $mansioni_collegate,
]).'.
</div>';
}
?>
<a class="btn btn-danger ask" data-backto="record-list">
<i class="fa fa-trash"></i> <?php echo tr('Elimina'); ?>
</a>

View File

@ -19,9 +19,6 @@
include_once __DIR__.'/../../core.php';
$cmp = \Util\Ini::getList(base_dir().'/files/impianti/');
if (!empty($id_record) && isset($cmp[$id_record - 1])) {
$record['nomefile'] = $cmp[$id_record - 1][0];
$record['contenuto'] = file_get_contents(base_dir().'/files/impianti/'.$record['nomefile']);
if (isset($id_record)) {
$record = $dbo->fetchOne('SELECT * FROM `an_mansioni` WHERE id='.prepare($id_record));
}

View File

@ -31,10 +31,16 @@ if ($bilancio_gia_aperto) {
}
echo '
<div class="text-right">
<button type="button" class="btn btn-lg '.$btn_class.'" data-op="apri-bilancio" data-title="'.tr('Apertura bilancio').'" data-backto="record-list" data-msg="'.$msg.'" data-button="'.tr('Riprendi saldi').'" data-class="btn btn-lg btn-warning" onclick="message( this );">
<i class="fa fa-folder-open"></i> '.tr('Apertura bilancio').'
</button>
<div class="row">
<div class="col-md-offset-4 col-md-4">
<input type="text" class="form-control input-lg text-center" id="input-cerca" placeholder="'.tr('Cerca').'...">
</div>
<div class="col-md-4 text-right">
<button type="button" class="btn btn-lg '.$btn_class.'" data-op="apri-bilancio" data-title="'.tr('Apertura bilancio').'" data-backto="record-list" data-msg="'.$msg.'" data-button="'.tr('Riprendi saldi').'" data-class="btn btn-lg btn-warning" onclick="message( this );">
<i class="fa fa-folder-open"></i> '.tr('Apertura bilancio').'
</button>
</div>
</div>';
// Livello 1
@ -51,7 +57,7 @@ foreach ($primo_livello as $conto_primo) {
echo '
<hr>
<div class="box">
<div class="box conto1">
<div class="box-header">
<h3 class="box-title">
'.$titolo.'
@ -70,158 +76,160 @@ foreach ($primo_livello as $conto_primo) {
foreach ($secondo_livello as $conto_secondo) {
// Livello 2
echo '
<div class="pull-right">
'.Prints::getLink('Mastrino', $conto_secondo['id'], 'btn-info btn-xs', '', null, 'lev=2').'
<div class="conto2">
<div class="pull-right">
'.Prints::getLink('Mastrino', $conto_secondo['id'], 'btn-info btn-xs', '', null, 'lev=2').'
<button type="button" class="btn btn-warning btn-xs" onclick="modificaConto('.$conto_secondo['id'].', 2)">
<i class="fa fa-edit"></i>
</button>
</div>
<button type="button" class="btn btn-warning btn-xs" onclick="modificaConto('.$conto_secondo['id'].', 2)">
<i class="fa fa-edit"></i>
</button>
</div>
<h5>
<b>'.$conto_secondo['numero'].' '.$conto_secondo['descrizione'].'</b>
<button type="button" class="btn btn-xs btn-primary" data-toggle="tooltip" title="'.tr('Aggiungi un nuovo conto...').'" onclick="aggiungiConto('.$conto_secondo['id'].')">
<i class="fa fa-plus-circle"></i>
</button>
</h5>
<h5>
<b>'.$conto_secondo['numero'].' '.$conto_secondo['descrizione'].'</b>
<button type="button" class="btn btn-xs btn-primary" data-toggle="tooltip" title="'.tr('Aggiungi un nuovo conto...').'" onclick="aggiungiConto('.$conto_secondo['id'].')">
<i class="fa fa-plus-circle"></i>
</button>
</h5>
<div class="table-responsive">
<table class="table table-striped table-hover table-condensed">
<thead>
<tr>
<th>'.tr('Descrizione').'</th>
<th style="width: 10%" class="text-center">'.tr('Importo').'</th>';
if ($conto_primo['descrizione'] == 'Economico') {
echo '
<th style="width: 10%" class="text-center">'.tr('Importo reddito').'</th>';
}
echo '
</tr>
</thead>
<tbody>';
// Livello 3
$query3 = 'SELECT `co_pianodeiconti3`.*, movimenti.numero_movimenti, movimenti.totale, movimenti.totale_reddito, anagrafica.idanagrafica, anagrafica.deleted_at
FROM `co_pianodeiconti3`
LEFT OUTER JOIN (
SELECT idanagrafica,
idconto_cliente,
idconto_fornitore,
deleted_at
FROM an_anagrafiche
) AS anagrafica ON co_pianodeiconti3.id IN (anagrafica.idconto_cliente, anagrafica.idconto_fornitore)
LEFT OUTER JOIN (
SELECT COUNT(idconto) AS numero_movimenti,
idconto,
SUM(totale) AS totale,
SUM(totale_reddito) AS totale_reddito
FROM co_movimenti
WHERE data BETWEEN '.prepare($_SESSION['period_start']).' AND '.prepare($_SESSION['period_end']).' GROUP BY idconto
) movimenti ON co_pianodeiconti3.id=movimenti.idconto
WHERE `idpianodeiconti2` = '.prepare($conto_secondo['id']).' ORDER BY numero ASC';
$terzo_livello = $dbo->fetchArray($query3);
foreach ($terzo_livello as $conto_terzo) {
// Se il conto non ha documenti collegati posso eliminarlo
$numero_movimenti = $conto_terzo['numero_movimenti'];
$totale_conto = $conto_terzo['totale'];
$totale_reddito = $conto_terzo['totale_reddito'];
if ($conto_primo['descrizione'] != 'Patrimoniale') {
$totale_conto = -$totale_conto;
$totale_reddito = -$totale_reddito;
}
$totale_conto2 += $totale_conto;
$totale_reddito2 += $totale_reddito;
echo '
<tr style="'.(!empty($numero_movimenti) ? '' : 'opacity: 0.5;').'">
<td>';
// Possibilità di esplodere i movimenti del conto
if (!empty($numero_movimenti)) {
echo '
<button type="button" id="movimenti-'.$conto_terzo['id'].'" class="btn btn-default btn-xs plus-btn"><i class="fa fa-plus"></i></button>';
}
// Span con i pulsanti
echo '
<span class="hide tools pull-right">';
// Possibilità di visionare l'anagrafica
$id_anagrafica = $conto_terzo['idanagrafica'];
$anagrafica_deleted = $conto_terzo['deleted_at'];
if (isset($id_anagrafica)) {
echo Modules::link('Anagrafiche', $id_anagrafica, ' <i title="'.(isset($anagrafica_deleted) ? tr('Anagrafica eliminata') : tr('Visualizza anagrafica')).'" class="btn btn-'.(isset($anagrafica_deleted) ? 'danger' : 'primary').' btn-xs fa fa-user" ></i>');
}
// Stampa mastrino
if (!empty($numero_movimenti)) {
echo '
'.Prints::getLink('Mastrino', $conto_terzo['id'], 'btn-info btn-xs', '', null, 'lev=3');
}
// Pulsante per aggiornare il totale reddito del conto di livello 3
echo '
<button type="button" class="btn btn-info btn-xs" onclick="aggiornaReddito('.$conto_terzo['id'].')">
<i class="fa fa-refresh"></i>
</button>';
// Pulsante per modificare il nome del conto di livello 3
echo '
<button type="button" class="btn btn-warning btn-xs" onclick="modificaConto('.$conto_terzo['id'].')">
<i class="fa fa-edit"></i>
</button>';
// Possibilità di eliminare il conto se non ci sono movimenti collegati
if ($numero_movimenti <= 0) {
echo '
<a class="btn btn-danger btn-xs ask" data-toggle="tooltip" title="'.tr('Elimina').'" data-backto="record-list" data-op="del" data-idconto="'.$conto_terzo['id'].'">
<i class="fa fa-trash"></i>
</a>';
}
echo '
</span>';
// Span con info del conto
echo '
<span class="clickable" id="movimenti-'.$conto_terzo['id'].'">
&nbsp;'.$conto_secondo['numero'].'.'.$conto_terzo['numero'].' '.$conto_terzo['descrizione'].($conto_terzo['percentuale_deducibile'] < 100 ? ' <span class="text-muted">('.tr('deducibile al _PERC_%', ['_PERC_' => Translator::numberToLocale($conto_terzo['percentuale_deducibile'], 0)]).')</span>' : '').'
</span>
<div id="conto_'.$conto_terzo['id'].'" style="display:none;"></div>
</td>
<td class="text-right">
'.moneyFormat($totale_conto, 2).'
</td>';
<div class="table-responsive">
<table class="table table-striped table-hover table-condensed">
<thead>
<tr>
<th>'.tr('Descrizione').'</th>
<th style="width: 10%" class="text-center">'.tr('Importo').'</th>';
if ($conto_primo['descrizione'] == 'Economico') {
echo '
<td class="text-right">
'.moneyFormat($totale_reddito, 2).'
</td>';
<th style="width: 10%" class="text-center">'.tr('Importo reddito').'</th>';
}
echo '
</tr>';
}
</tr>
</thead>
echo '
</tbody>
<tbody>';
<tfoot>
<tr>
<th class="text-right">'.tr('Totale').'</th>
<th class="text-right">'.moneyFormat($totale_conto2).'</th>';
if ($conto_primo['descrizione'] == 'Economico') {
echo '<th class="text-right">'.moneyFormat($totale_reddito2).'</th>';
}
echo '
</tr>
</tfoot>
</table>
// Livello 3
$query3 = 'SELECT `co_pianodeiconti3`.*, movimenti.numero_movimenti, movimenti.totale, movimenti.totale_reddito, anagrafica.idanagrafica, anagrafica.deleted_at
FROM `co_pianodeiconti3`
LEFT OUTER JOIN (
SELECT idanagrafica,
idconto_cliente,
idconto_fornitore,
deleted_at
FROM an_anagrafiche
) AS anagrafica ON co_pianodeiconti3.id IN (anagrafica.idconto_cliente, anagrafica.idconto_fornitore)
LEFT OUTER JOIN (
SELECT COUNT(idconto) AS numero_movimenti,
idconto,
SUM(totale) AS totale,
SUM(totale_reddito) AS totale_reddito
FROM co_movimenti
WHERE data BETWEEN '.prepare($_SESSION['period_start']).' AND '.prepare($_SESSION['period_end']).' GROUP BY idconto
) movimenti ON co_pianodeiconti3.id=movimenti.idconto
WHERE `idpianodeiconti2` = '.prepare($conto_secondo['id']).' ORDER BY numero ASC';
$terzo_livello = $dbo->fetchArray($query3);
foreach ($terzo_livello as $conto_terzo) {
// Se il conto non ha documenti collegati posso eliminarlo
$numero_movimenti = $conto_terzo['numero_movimenti'];
<br><br>
$totale_conto = $conto_terzo['totale'];
$totale_reddito = $conto_terzo['totale_reddito'];
if ($conto_primo['descrizione'] != 'Patrimoniale') {
$totale_conto = -$totale_conto;
$totale_reddito = -$totale_reddito;
}
$totale_conto2 += $totale_conto;
$totale_reddito2 += $totale_reddito;
echo '
<tr class="conto3" style="'.(!empty($numero_movimenti) ? '' : 'opacity: 0.5;').'">
<td>';
// Possibilità di esplodere i movimenti del conto
if (!empty($numero_movimenti)) {
echo '
<button type="button" id="movimenti-'.$conto_terzo['id'].'" class="btn btn-default btn-xs plus-btn"><i class="fa fa-plus"></i></button>';
}
// Span con i pulsanti
echo '
<span class="hide tools pull-right">';
// Possibilità di visionare l'anagrafica
$id_anagrafica = $conto_terzo['idanagrafica'];
$anagrafica_deleted = $conto_terzo['deleted_at'];
if (isset($id_anagrafica)) {
echo Modules::link('Anagrafiche', $id_anagrafica, ' <i title="'.(isset($anagrafica_deleted) ? tr('Anagrafica eliminata') : tr('Visualizza anagrafica')).'" class="btn btn-'.(isset($anagrafica_deleted) ? 'danger' : 'primary').' btn-xs fa fa-user" ></i>');
}
// Stampa mastrino
if (!empty($numero_movimenti)) {
echo '
'.Prints::getLink('Mastrino', $conto_terzo['id'], 'btn-info btn-xs', '', null, 'lev=3');
}
// Pulsante per aggiornare il totale reddito del conto di livello 3
echo '
<button type="button" class="btn btn-info btn-xs" onclick="aggiornaReddito('.$conto_terzo['id'].')">
<i class="fa fa-refresh"></i>
</button>';
// Pulsante per modificare il nome del conto di livello 3
echo '
<button type="button" class="btn btn-warning btn-xs" onclick="modificaConto('.$conto_terzo['id'].')">
<i class="fa fa-edit"></i>
</button>';
// Possibilità di eliminare il conto se non ci sono movimenti collegati
if ($numero_movimenti <= 0) {
echo '
<a class="btn btn-danger btn-xs ask" data-toggle="tooltip" title="'.tr('Elimina').'" data-backto="record-list" data-op="del" data-idconto="'.$conto_terzo['id'].'">
<i class="fa fa-trash"></i>
</a>';
}
echo '
</span>';
// Span con info del conto
echo '
<span class="clickable" id="movimenti-'.$conto_terzo['id'].'">
&nbsp;'.$conto_secondo['numero'].'.'.$conto_terzo['numero'].' '.$conto_terzo['descrizione'].($conto_terzo['percentuale_deducibile'] < 100 ? ' <span class="text-muted">('.tr('deducibile al _PERC_%', ['_PERC_' => Translator::numberToLocale($conto_terzo['percentuale_deducibile'], 0)]).')</span>' : '').'
</span>
<div id="conto_'.$conto_terzo['id'].'" style="display:none;"></div>
</td>
<td class="text-right">
'.moneyFormat($totale_conto, 2).'
</td>';
if ($conto_primo['descrizione'] == 'Economico') {
echo '
<td class="text-right">
'.moneyFormat($totale_reddito, 2).'
</td>';
}
echo '
</tr>';
}
echo '
</tbody>
<tfoot>
<tr class="totali">
<th class="text-right">'.tr('Totale').'</th>
<th class="text-right">'.moneyFormat($totale_conto2).'</th>';
if ($conto_primo['descrizione'] == 'Economico') {
echo '<th class="text-right">'.moneyFormat($totale_reddito2).'</th>';
}
echo '
</tr>
</tfoot>
</table>
<br><br>
</div>
</div>';
// Somma dei totali
if ($conto_primo['descrizione'] == 'Patrimoniale') {
@ -245,7 +253,7 @@ foreach ($primo_livello as $conto_primo) {
echo '
</div>
<table class="table table-condensed table-hover">';
<table class="table table-condensed table-hover totali">';
// Riepiloghi
if ($conto_primo['descrizione'] == 'Patrimoniale') {
@ -348,7 +356,7 @@ foreach ($primo_livello as $conto_primo) {
</td>
</tr>
<tr>
<tr class="totali">
<th class="text-right">
<big>'.tr('Utile/perdita').':</big>
</th>
@ -460,4 +468,29 @@ echo '
function aggiornaReddito(id_conto){
openModal("'.tr('Ricalcola importo deducibile').'", "'.$structure->fileurl('aggiorna_reddito.php').'?id=" + id_conto)
}
$("#input-cerca").keyup(function(){
var text = $(this).val();
if( text == "" ){
$(".conto1").show();
$(".conto2").show();
$(".conto3").show();
$(".totali").show();
} else {
$(".conto1").hide();
$(".conto2").hide();
$(".conto3").hide();
$(".totali").hide();
$(".conto1:contains(" + text + ")").show();
$(".conto2:contains(" + text + ")").show();
$(".conto3:contains(" + text + ")").show();
}
});
$.expr[":"].contains = $.expr.createPseudo(function(arg) {
return function( elem ) {
return $(elem).text().toUpperCase().indexOf(arg.toUpperCase()) >= 0;
};
});
</script>';

View File

@ -29,7 +29,8 @@ switch (post('op')) {
'is_fatturabile' => post('is_fatturabile'),
'notifica' => post('notifica'),
'notifica_cliente' => post('notifica_cliente'),
'notifica_tecnici' => post('notifica_tecnici'),
'notifica_tecnico_sessione' => post('notifica_tecnico_sessione'),
'notifica_tecnico_assegnato' => post('notifica_tecnico_sessione'),
'id_email' => post('email') ?: null,
'destinatari' => post('destinatari'),
], ['idstatointervento' => $id_record]);

View File

@ -49,28 +49,36 @@ if ($record['can_delete']) {
<div class="row">
<div class="col-md-6">
<div class="col-md-3">
{[ "type": "checkbox", "label": "<?php echo tr('Abilita notifiche'); ?>", "name": "notifica", "help": "<?php echo tr('Quando l\'attività passa in questo stato viene inviata una notifica ai destinatari designati.'); ?>.", "value": "$notifica$" ]}
</div>
</div>
<hr>
<div class="row">
<div class="col-md-6">
{[ "type": "select", "label": "<?php echo tr('Template email'); ?>", "name": "email", "value": "$id_email$", "values": "query=SELECT id, name AS descrizione FROM em_templates WHERE id_module = <?php echo Modules::get('Interventi')['id']; ?> AND deleted_at IS NULL", "disabled": <?php echo intval(empty($record['notifica'])); ?> ]}
</div>
<div class="col-md-6">
{[ "type": "email", "label": "<?php echo tr('Destinatario aggiuntivo'); ?>", "name": "destinatari", "value": "$destinatari$", "icon-before": "<i class='fa fa-envelope'></i>", "disabled": <?php echo intval(empty($record['notifica'])); ?>, "class": "email-mask" ]}
</div>
</div>
<div class="row">
<div class="col-md-3">
<div class="col-md-4">
{[ "type": "checkbox", "label": "<?php echo tr('Notifica al cliente'); ?>", "name": "notifica_cliente", "help": "<?php echo tr('Quando l\'attività passa in questo stato viene inviata una notifica al cliente.'); ?>.", "value": "$notifica_cliente$" ]}
</div>
<div class="col-md-3">
{[ "type": "checkbox", "label": "<?php echo tr('Notifica ai tecnici'); ?>", "name": "notifica_tecnici", "help": "<?php echo tr('Quando l\'attività passa in questo stato viene inviata una notifica ai tecnici assegnati.'); ?>.", "value": "$notifica_tecnici$" ]}
<div class="col-md-4">
{[ "type": "checkbox", "label": "<?php echo tr('Notifica ai tecnici assegnati'); ?>", "name": "notifica_tecnico_sessione", "help": "<?php echo tr('Quando l\'attività passa in questo stato viene inviata una notifica ai tecnici assegnati.'); ?>.", "value": "$notifica_tecnico_sessione$" ]}
</div>
<div class="col-md-6">
{[ "type": "text", "label": "<?php echo tr('Destinatari aggiuntivi'); ?>", "name": "destinatari", "value": "$destinatari$", "disabled": <?php echo intval(empty($record['notifica'])); ?> ]}
<div class="col-md-4">
{[ "type": "checkbox", "label": "<?php echo tr('Notifica ai tecnici delle sessioni'); ?>", "name": "notifica_tecnico_assegnato", "help": "<?php echo tr('Quando l\'attività passa in questo stato viene inviata una notifica ai tecnici delle sessioni.'); ?>.", "value": "$notifica_tecnico_assegnato$" ]}
</div>
</div>
@ -108,25 +116,32 @@ if ($record['can_delete']) {
});
$('#colore').parent().find('.square').css( 'background', $('#colore').val() );
notifica();
});
$("#notifica").change(function() {
if ($(this).is(":checked")) {
notifica();
});
function notifica() {
if ($("#notifica").is(":checked")) {
$("#email").attr("required", true);
$("#email").attr("disabled", false);
$("#destinatari").attr("disabled", false);
$("#notifica_cliente").attr("disabled", false);
$("#notifica_tecnici").attr("disabled", false);
$("#notifica_tecnico_sessione").attr("disabled", false);
$("#notifica_tecnico_assegnato").attr("disabled", false);
}else{
$("#email").attr("required", false);
$("#email").attr("disabled", true);
$("#destinatari").attr("disabled", true);
$("#destinatari").val("");
$("#notifica_cliente").attr("disabled", true);
$("#notifica_tecnici").attr("disabled", true);
$("#notifica_tecnico_sessione").attr("disabled", true);
$("#notifica_tecnico_assegnato").attr("disabled", true);
$("#notifica_cliente").val([0]);
$("#notifica_tecnici").val([0]);
$("#notifica_tecnico_sessione").val([0]);
$("#notifica_tecnico_assegnato").val([0]);
}
});
});
}
</script>

View File

@ -29,7 +29,7 @@ class EliminaMailTask extends Manager
public function needsExecution()
{
if(setting('Numero di giorni mantenimento coda di invio')>0){
$rs = database()->fetchArray("SELECT * FROM em_emails WHERE sent_at<DATE_SUB(NOW(), INTERVAL ".setting('Numero di giorni mantenimento coda di invio')." DAY)");
$rs = database()->fetchArray("SELECT * FROM em_emails WHERE sent_at<DATE_SUB(NOW(), INTERVAL ".setting('Numero di giorni mantenimento coda di invio')." DAY) AND id_newsletter IS NOT NULL");
if(sizeof($rs)>0){
return true;
@ -44,7 +44,7 @@ class EliminaMailTask extends Manager
public function execute()
{
if(setting('Numero di giorni mantenimento coda di invio')>0){
$rs = database()->fetchArray("SELECT * FROM em_emails WHERE sent_at<DATE_SUB(NOW(), INTERVAL ".setting('Numero di giorni mantenimento coda di invio')." DAY)");
$rs = database()->fetchArray("SELECT * FROM em_emails WHERE sent_at<DATE_SUB(NOW(), INTERVAL ".setting('Numero di giorni mantenimento coda di invio')." DAY) AND id_newsletter IS NOT NULL");
foreach($rs AS $r){
database()->query("DELETE FROM em_emails WHERE id=".prepare($r['id']));

View File

@ -372,6 +372,7 @@ if (!empty($righe)) {
$qta = $riga['Quantita'];
$um = $riga['UnitaMisura'];
$prezzo_unitario = $riga['PrezzoUnitario'] ?: $riga['Importo'];
$is_descrizione = empty((float)$riga['Quantita']) && empty((float)$prezzo_unitario);
echo '
<tr data-id="'.$key.'" data-qta="'.$qta.'" data-prezzo_unitario="'.$prezzo_unitario.'" data-iva_percentuale="'.$riga['AliquotaIVA'].'">
@ -404,8 +405,11 @@ if (!empty($righe)) {
]).'
<span id="riferimento_'.$key.'_iva"></span>
</td>
</tr>
</tr>';
if (!$is_descrizione) {
echo '
<tr id="dati_'.$key.'">
<td colspan="4" class="row">
<span class="hide" id="aliquota['.$key.']">'.$riga['AliquotaIVA'].'</span>
@ -462,6 +466,24 @@ if (!empty($righe)) {
</div>
</td>
</tr>';
} else {
echo '
<input type="hidden" name="qta_riferimento['.$key.']" id="qta_riferimento_'.$key.'" value="'.$riga['Quantita'].'">
<input type="hidden" name="tipo_riferimento['.$key.']" id="tipo_riferimento_'.$key.'" value="">
<input type="hidden" name="id_riferimento['.$key.']" id="id_riferimento_'.$key.'" value="">
<input type="hidden" name="id_riga_riferimento['.$key.']" id="id_riga_riferimento_'.$key.'" value="">
<input type="hidden" name="tipo_riga_riferimento['.$key.']" id="tipo_riga_riferimento_'.$key.'" value="">
<input type="hidden" name="tipo_riferimento_vendita['.$key.']" id="tipo_riferimento_vendita_'.$key.'" value="">
<input type="hidden" name="id_riferimento_vendita['.$key.']" id="id_riferimento_vendita_'.$key.'" value="">
<input type="hidden" name="id_riga_riferimento_vendita['.$key.']" id="id_riga_riferimento_vendita_'.$key.'" value="">
<input type="hidden" name="tipo_riga_riferimento_vendita['.$key.']" id="tipo_riga_riferimento_vendita_'.$key.'" value="">
<input type="hidden" name="conto['.$key.']" value="">
<input type="hidden" name="iva['.$key.']" value="">
<input type="hidden" name="update_info['.$key.']" value="">';
}
}
echo '

View File

@ -24,6 +24,7 @@ use Modules\Anagrafiche\Anagrafica;
use Modules\Articoli\Articolo as ArticoloOriginale;
use Modules\Articoli\Categoria;
use Modules\Fatture\Components\Articolo;
use Modules\Fatture\Components\Descrizione;
use Modules\Fatture\Components\Riga;
use Modules\Fatture\Fattura;
use Plugins\ListinoClienti\DettaglioPrezzo;
@ -123,6 +124,7 @@ class FatturaOrdinaria extends FatturaElettronica
$id_rivalsa = $info['id_rivalsa'];
$calcolo_ritenuta_acconto = $info['rivalsa_in_ritenuta'] ? 'IMP+RIV' : 'IMP';
$ritenuta_contributi = !empty($fattura->id_ritenuta_contributi);
$conto_arrotondamenti = null;
foreach ($righe as $key => $riga) {
$articolo = ArticoloOriginale::find($articoli[$key]);
@ -130,6 +132,8 @@ class FatturaOrdinaria extends FatturaElettronica
$riga['PrezzoUnitario'] = floatval($riga['PrezzoUnitario']);
$riga['Quantita'] = floatval($riga['Quantita']);
$is_descrizione = empty($riga['Quantita']) && empty($riga['PrezzoUnitario']);
$codici = $riga['CodiceArticolo'] ?: [];
$codici = !empty($codici) && !isset($codici[0]) ? [$codici] : $codici;
@ -161,6 +165,10 @@ class FatturaOrdinaria extends FatturaElettronica
$obj->movimentazione($movimentazione);
$target_type = Articolo::class;
} elseif($is_descrizione) {
$obj = Descrizione::build($fattura);
$target_type = Descrizione::class;
} else {
$obj = Riga::build($fattura);
@ -190,113 +198,121 @@ class FatturaOrdinaria extends FatturaElettronica
]);
}
$obj->id_iva = $iva[$key];
$obj->idconto = $conto[$key];
if (!$is_descrizione) {
$obj->id_iva = $iva[$key];
$obj->idconto = $conto[$key];
$obj->id_rivalsa_inps = $id_rivalsa;
$obj->ritenuta_contributi = $ritenuta_contributi;
if (!empty($riga['Ritenuta'])) {
$obj->id_ritenuta_acconto = $id_ritenuta_acconto;
$obj->calcolo_ritenuta_acconto = $calcolo_ritenuta_acconto;
}
// Nel caso il prezzo sia negativo viene gestito attraverso l'inversione della quantità (come per le note di credito)
// TODO: per migliorare la visualizzazione, sarebbe da lasciare negativo il prezzo e invertire gli sconti.
$prezzo = $riga['PrezzoUnitario'];
$qta = $riga['Quantita'] ?: 1;
// Prezzo e quantità
$obj->prezzo_unitario = $prezzo;
$obj->qta = $qta;
if (!empty($riga['UnitaMisura'])) {
$obj->um = $riga['UnitaMisura'];
}
// Sconti e maggiorazioni
$sconti = $riga['ScontoMaggiorazione'];
if (!empty($sconti)) {
$sconto_unitario = 0;
$sconti = $sconti[0] ? $sconti : [$sconti];
// Determina il tipo di sconto in caso di sconti misti UNT e PRC
foreach ($sconti as $sconto) {
$tipo_sconto = !empty($sconto['Importo']) ? 'UNT' : 'PRC';
if (!empty($tipo) && $tipo_sconto != $tipo) {
$tipo = 'UNT';
} else {
$tipo = $tipo_sconto;
}
if (empty($conto_arrotondamenti) && !empty($conto[$key]) ){
$conto_arrotondamenti = $conto[$key];
}
foreach ($sconti as $sconto) {
$unitario = $sconto['Importo'] ?: $sconto['Percentuale'];
$obj->id_rivalsa_inps = $id_rivalsa;
$obj->ritenuta_contributi = $ritenuta_contributi;
// Sconto o Maggiorazione
$sconto_riga = ($sconto['Tipo'] == 'SC') ? $unitario : -$unitario;
// Inserisco la ritenuta se è specificata nella riga o se non è specificata nella riga ma è presente in Dati ritenuta (quindi comprende tutte le righe)
if (!empty($riga['Ritenuta']) || $info['ritenuta_norighe']==true) {
$obj->id_ritenuta_acconto = $id_ritenuta_acconto;
$obj->calcolo_ritenuta_acconto = $calcolo_ritenuta_acconto;
}
$tipo_sconto = !empty($sconto['Importo']) ? 'UNT' : 'PRC';
if ($tipo_sconto == 'PRC') {
$sconto_calcolato = calcola_sconto([
'sconto' => $sconto_riga,
'prezzo' => $sconto_unitario ? $obj->prezzo_unitario - ($sconto_calcolato / $obj->qta) : $obj->prezzo_unitario,
'tipo' => 'PRC',
'qta' => $obj->qta,
]);
// Nel caso il prezzo sia negativo viene gestito attraverso l'inversione della quantità (come per le note di credito)
// TODO: per migliorare la visualizzazione, sarebbe da lasciare negativo il prezzo e invertire gli sconti.
$prezzo = $riga['PrezzoUnitario'];
$qta = $riga['Quantita'] ?: 1;
if ($tipo == 'PRC') {
$tot_sconto = $sconto_calcolato * 100 / $obj->imponibile;
// Prezzo e quantità
$obj->prezzo_unitario = $prezzo;
$obj->qta = $qta;
if (!empty($riga['UnitaMisura'])) {
$obj->um = $riga['UnitaMisura'];
}
// Sconti e maggiorazioni
$sconti = $riga['ScontoMaggiorazione'];
if (!empty($sconti)) {
$sconto_unitario = 0;
$sconti = $sconti[0] ? $sconti : [$sconti];
// Determina il tipo di sconto in caso di sconti misti UNT e PRC
foreach ($sconti as $sconto) {
$tipo_sconto = !empty($sconto['Importo']) ? 'UNT' : 'PRC';
if (!empty($tipo) && $tipo_sconto != $tipo) {
$tipo = 'UNT';
} else {
$tot_sconto = $sconto_calcolato;
$tipo = $tipo_sconto;
}
} else {
$tot_sconto = $sconto_riga;
}
$sconto_unitario += $tot_sconto;
foreach ($sconti as $sconto) {
$unitario = $sconto['Importo'] ?: $sconto['Percentuale'];
// Sconto o Maggiorazione
$sconto_riga = ($sconto['Tipo'] == 'SC') ? $unitario : -$unitario;
$tipo_sconto = !empty($sconto['Importo']) ? 'UNT' : 'PRC';
if ($tipo_sconto == 'PRC') {
$sconto_calcolato = calcola_sconto([
'sconto' => $sconto_riga,
'prezzo' => $sconto_unitario ? $obj->prezzo_unitario - ($sconto_calcolato / $obj->qta) : $obj->prezzo_unitario,
'tipo' => 'PRC',
'qta' => $obj->qta,
]);
if ($tipo == 'PRC') {
$tot_sconto = $sconto_calcolato * 100 / $obj->imponibile;
} else {
$tot_sconto = $sconto_calcolato;
}
} else {
$tot_sconto = $sconto_riga;
}
$sconto_unitario += $tot_sconto;
}
$obj->setSconto($sconto_unitario, $tipo);
}
$obj->setSconto($sconto_unitario, $tipo);
}
// Aggiornamento prezzo di acquisto e fornitore predefinito in base alle impostazioni
if (!empty($articolo)) {
if ($update_info[$key] == 'update_price' || $update_info[$key] == 'update_all') {
$dettaglio_predefinito = DettaglioPrezzo::dettaglioPredefinito($articolo->id, $anagrafica->idanagrafica, $direzione)
->first();
// Aggiornamento prezzo di acquisto e fornitore predefinito in base alle impostazioni
if (!empty($articolo)) {
if ($update_info[$key] == 'update_price' || $update_info[$key] == 'update_all') {
$dettaglio_predefinito = DettaglioPrezzo::dettaglioPredefinito($articolo->id, $anagrafica->idanagrafica, $direzione)
->first();
// Aggiungo associazione fornitore-articolo se non presente
if (empty($dettaglio_predefinito)) {
$dettaglio_predefinito = DettaglioPrezzo::build($articolo, $anagrafica, $direzione);
}
// Aggiungo associazione fornitore-articolo se non presente
if (empty($dettaglio_predefinito)) {
$dettaglio_predefinito = DettaglioPrezzo::build($articolo, $anagrafica, $direzione);
}
// Imposto lo sconto nel listino solo se è una percentuale, se è un importo lo sottraggo dal prezzo
if ($tipo == 'PRC') {
$dettaglio_predefinito->sconto_percentuale = $sconto_unitario;
$prezzo_unitario = $obj->prezzo_unitario;
$prezzo_acquisto = $obj->prezzo_unitario - ($obj->prezzo_unitario * $sconto_unitario / 100);
} else {
$prezzo_unitario = $obj->prezzo_unitario - $sconto_unitario;
$prezzo_acquisto = $prezzo_unitario;
}
// Imposto lo sconto nel listino solo se è una percentuale, se è un importo lo sottraggo dal prezzo
if ($tipo == 'PRC') {
$dettaglio_predefinito->sconto_percentuale = $sconto_unitario;
$prezzo_unitario = $obj->prezzo_unitario;
$prezzo_acquisto = $obj->prezzo_unitario - ($obj->prezzo_unitario * $sconto_unitario / 100);
} else {
$prezzo_unitario = $obj->prezzo_unitario - $sconto_unitario;
$prezzo_acquisto = $prezzo_unitario;
}
// Aggiornamento listino
$dettaglio_predefinito->setPrezzoUnitario($prezzo_unitario);
$dettaglio_predefinito->save();
// Aggiornamento listino
$dettaglio_predefinito->setPrezzoUnitario($prezzo_unitario);
$dettaglio_predefinito->save();
// Aggiornamento fornitore predefinito
if ($update_info[$key] == 'update_all') {
// Aggiornamento prezzo di acquisto e fornitore predefinito
$articolo->prezzo_acquisto = $prezzo_acquisto;
$articolo->id_fornitore = $anagrafica->idanagrafica;
$articolo->save();
// Aggiornamento fornitore predefinito
if ($update_info[$key] == 'update_all') {
// Aggiornamento prezzo di acquisto e fornitore predefinito
$articolo->prezzo_acquisto = $prezzo_acquisto;
$articolo->id_fornitore = $anagrafica->idanagrafica;
$articolo->save();
}
}
}
$tipo = null;
$sconto_unitario = null;
}
$tipo = null;
$sconto_unitario = null;
$obj->save();
}
@ -317,7 +333,7 @@ class FatturaOrdinaria extends FatturaElettronica
$obj->descrizione = tr('Arrotondamento calcolato in automatico');
$obj->id_iva = $iva_arrotondamento['id'];
$obj->idconto = $conto[0];
$obj->idconto = $conto_arrotondamenti;
$obj->prezzo_unitario = round($diff, 4);
$obj->qta = 1;
@ -415,9 +431,11 @@ class FatturaOrdinaria extends FatturaElettronica
$ritenuta = $dati_generali['DatiRitenuta'];
if (!empty($ritenuta)) {
$totali = [];
$ritenuta_norighe = true;
foreach ($righe as $riga) {
if (!empty($riga['Ritenuta'])) {
$totali[] = $riga['PrezzoTotale'];
$ritenuta_norighe = false;
}
}
$totale = sum($totali);
@ -448,6 +466,7 @@ class FatturaOrdinaria extends FatturaElettronica
'id_ritenuta_acconto' => $id_ritenuta_acconto,
'id_rivalsa' => $id_rivalsa,
'rivalsa_in_ritenuta' => $rivalsa_in_ritenuta,
'ritenuta_norighe' => $ritenuta_norighe,
];
}
}

View File

@ -36,6 +36,11 @@ switch (filter('op')) {
$modifica_prezzi = filter('modifica_prezzi');
if (empty($modifica_prezzi)) {
$dbo->query('DELETE FROM mg_prezzi_articoli WHERE id_articolo='.prepare($id_articolo).' AND id_anagrafica='.prepare($id_anagrafica).' AND minimo IS NULL AND massimo IS NULL');
if ($id_anagrafica == $articolo->id_fornitore && $direzione == 'uscita') {
$articolo->id_fornitore = null;
$articolo->save();
}
} else {
// Salvataggio del prezzo predefinito
$prezzo_unitario = filter('prezzo_unitario_fisso');

View File

@ -0,0 +1,67 @@
<?php
/*
* OpenSTAManager: il software gestionale open source per l'assistenza tecnica e la fatturazione
* Copyright (C) DevCode s.r.l.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
include_once __DIR__.'/../../core.php';
include_once __DIR__.'/../init.php';
use Modules\Fatture\Fattura;
$modulo = Modules::get($id_module)['name'];
if ($modulo == 'Anagrafiche') {
$movimenti = $dbo->fetchArray('SELECT co_movimenti.*, SUM(totale) AS totale, co_pianodeiconti3.descrizione, co_pianodeiconti3.numero AS conto3, co_pianodeiconti2.numero AS conto2 FROM co_movimenti LEFT JOIN co_pianodeiconti3 ON co_movimenti.idconto=co_pianodeiconti3.id LEFT JOIN co_pianodeiconti2 ON co_pianodeiconti3.idpianodeiconti2=co_pianodeiconti2.id WHERE id_anagrafica='.prepare($id_record).' GROUP BY idmastrino, idconto ORDER BY data, idmastrino');
} else {
$movimenti = $dbo->fetchArray('SELECT co_movimenti.*, SUM(totale) AS totale, co_pianodeiconti3.descrizione, co_pianodeiconti3.numero AS conto3, co_pianodeiconti2.numero AS conto2 FROM co_movimenti LEFT JOIN co_pianodeiconti3 ON co_movimenti.idconto=co_pianodeiconti3.id LEFT JOIN co_pianodeiconti2 ON co_pianodeiconti3.idpianodeiconti2=co_pianodeiconti2.id WHERE iddocumento='.prepare($id_record).' GROUP BY idmastrino, idconto ORDER BY data, idmastrino');
}
if (!empty($movimenti)) {
echo '
<table class="table table-hover table-condensed table-bordered table-striped" style="font-size:11pt;">
<thead>
<tr>
<th width="160">'.tr('Data').'</th>
<th>'.tr('Conto').'</th>
<th width="170">'.tr('Dare').'</th>
<th width="170">'.tr('Avere').'</th>
<th width="170">'.tr('Scalare').'</th>
</tr>
</thead>
<tbody>';
foreach ($movimenti as $movimento) {
$documento = $modulo == 'Anagrafiche' ? Fattura::find($movimento['iddocumento']) : null;
$scalare += $movimento['totale'];
echo '
<tr>
<td class="text-center">'.Translator::dateToLocale($movimento['data']).'</td>
<td>'.$movimento['conto2'].'.'.$movimento['conto3'].' - '.$movimento['descrizione'].'<small class="pull-right text-right text-muted" style="font-size:8pt;">'.($documento ? $documento->getReference() : '').'</small></td>
<td class="text-right">'.($movimento['totale']>0 ? moneyFormat(abs($movimento['totale'])) : "").'</td>
<td class="text-right">'.($movimento['totale']<0 ? moneyFormat(abs($movimento['totale'])) : "").'</td>
<td class="text-right">'.moneyFormat($scalare).'</td>
</tr>';
}
echo '
</tbody>
</table>';
} else {
echo '
<h3 class="text-center">
<small class="help-block">'.tr('Non sono presenti movimenti contabili').'</small>
</h3>';
}

View File

@ -0,0 +1,93 @@
<?php
use Carbon\Carbon;
use Plugins\PresentazioniBancarie\Gestore;
use Modules\Scadenzario\Scadenza;
include_once __DIR__.'/init.php';
switch (filter('op')) {
case 'generate':
$id_scadenze = filter('scadenze');
$sequenze = (array)filter('sequenze');
$codice_sequenza = [];
foreach($sequenze AS $sequenza){
$id_scadenza = explode('-', $sequenza)[0];
$codice = explode('-', $sequenza)[1];
$codice_sequenza[$id_scadenza] = $codice;
}
$data = new Carbon();
$azienda = Gestore::getAzienda();
// Individuazione delle scadenze indicate
$scadenze = Scadenza::with('documento')->whereIn('id', $id_scadenze)->get();
if ($scadenze->isEmpty()) {
echo json_encode([
'files' => [],
'scadenze' => [],
]);
}
// Iterazione tra le scadenze selezionate
$scadenze_completate = [];
$gestori_esportazione = [];
foreach ($scadenze as $key => $scadenza) {
$documento = $scadenza->documento;
if (empty($documento)) {
continue;
}
// Individuazione altre scadenze del documento
$scadenze_documento = $documento->scadenze->sortBy('scadenza');
$pos = $scadenze_documento->search(function ($item, $key) use ($scadenza) {
return $item->id == $scadenza->id;
});
// Generazione della descrizione del pagamento
$descrizione = $documento->getReference();
if ($scadenze_documento->count() > 1) {
$descrizione .= tr('_DOC_, pagamento _NUM_/_TOT_', [
'_DOC_' => $descrizione,
'_NUM_' => $pos + 1,
'_TOT_' => $scadenze_documento->count(),
]);
}
// Controllo sulla banca aziendale collegata alla scadenza
$banca_azienda = Gestore::getBancaAzienda($scadenza);
if (!isset($gestori_esportazione[$banca_azienda->id])) {
$gestori_esportazione[$banca_azienda->id] = new Gestore($azienda, $banca_azienda);
}
// Delegazione per la gestione
$completato = $gestori_esportazione[$banca_azienda->id]->aggiungi($scadenza, $scadenza->id, $descrizione, $codice_sequenza[$scadenza->id]);
// Salvataggio dell'esportazione
if ($completato) {
$scadenza->presentazioni_exported_at = $data;
$scadenza->save();
$scadenze_completate[] = $scadenza->id;
}
}
/**
* Salvataggio dei file nei diversi formati.
*/
$files = [];
foreach ($gestori_esportazione as $gestore) {
$files = array_merge($files, $gestore->esporta($plugin->upload_directory));
}
echo json_encode([
'files' => $files,
'scadenze' => $scadenze_completate,
]);
break;
}

View File

@ -0,0 +1,50 @@
<?php
include_once __DIR__.'/init.php';
if (!empty($records)) {
include $structure->filepath('generate.php');
return;
}
echo '
<div class="row">
<div class="col-md-3">
{[ "type": "checkbox", "label": "'.tr('Esporta già pagati').'", "name": "pagati", "help": "'.tr('Seleziona per esportare le scadenze già pagate tra quelle selezionate').'" ]}
</div>
<div class="col-md-3">
{[ "type": "checkbox", "label": "'.tr('Esporta già processati').'", "name": "processati", "help": "'.tr('Seleziona per esportare nuovamente le scadenze esportate in precedenze tra quelle selezionate').'" ]}
</div>
</div>
<div class="row">
<div class="col-md-12 text-right">
<button type="button" class="btn btn-warning" onclick="esporta(this)">
<i class="fa fa-download"></i> '.tr('Esporta').'
</button>
</div>
</div>
<script>
function getRecords() {
let table = $(".main-records[id^=main]").first();
let datatable = getTable("#" + table.attr("id"));
return datatable.getSelectedRows();
}
function esporta(button) {
let records = getRecords();
if (!records.length) {
swal("'.tr('Errore').'", "'.tr('Selezione assente!').'", "error");
return;
}
let pagati = input("pagati").get();
let processati = input("processati").get();
redirect("'.base_path().'/editor.php?id_module='.$id_module.'&id_plugin='.$id_plugin.'&records=" + records + "&pagati=" + pagati + "&processati=" + processati);
}
</script>';

View File

@ -0,0 +1,309 @@
<?php
use Plugins\PresentazioniBancarie\Gestore;
use Modules\Anagrafiche\Anagrafica;
use Modules\Banche\Banca;
use Modules\Scadenzario\Scadenza;
include_once __DIR__.'/init.php';
echo '
<style>
.select2-selection__rendered {
line-height: 21px !important;
}
.select2-container .select2-selection--single {
height: 25px !important;
}
.select2-selection__arrow {
height: 24px !important;
position: absolute !important;
top: -1px !important;
}
</style>
<script>
$(document).ready(function () {
$("#pulsanti .pull-right").hide();
})
</script>
<p>'.tr('Riepilogo di esportazione per i pagamenti ai fornitori').'.</p>';
// Azienda predefinita
$azienda = Anagrafica::find(setting('Azienda predefinita'));
$banca_azienda = Gestore::getBancaPredefinitaAzienda();
if (empty($banca_azienda)) {
echo '
<div class="alert alert-warning">
<i class="fa fa-warning"></i>
'.tr("L'anagrafica Azienda non ha impostati i campi Codice IBAN e BIC per l'esecuzione dei pagamenti").'.
'.Modules::link('Anagrafiche', $azienda->id, tr('Imposta'), null, 'class="btn btn-warning pull-right"').'
<div class="clearfix"></div>
</div>';
}
$scadenze = Scadenza::with('documento')->whereIn('id', $records);
// Filtro per scadenze pagate
$esporta_pagati = get('pagati');
if (!$esporta_pagati) {
$scadenze = $scadenze->whereRaw('ABS(pagato) < ABS(da_pagare)');
}
// Filtro per scadenze esportate in precedenza
$esporta_processati = get('processati');
if (!$esporta_processati) {
$scadenze = $scadenze->whereNull('presentazioni_exported_at');
}
// Lettura delle informazioni
$scadenze = $scadenze->get();
$id_scadenze = $scadenze->pluck('id');
$raggruppamento = $scadenze->groupBy('documento.idanagrafica');
if ($raggruppamento->isEmpty()) {
echo '
<p>'.tr('Nessun pagamento disponibile secondo la selezione effettuata').'.</p>';
return;
}
foreach ($raggruppamento as $id_anagrafica => $scadenze_anagrafica) {
$anagrafica = $scadenze_anagrafica->first()->documento->anagrafica;
echo '
<h3>
'.$anagrafica->ragione_sociale;
$banca_controparte = Banca::where('id_anagrafica', $anagrafica->id)
->where('predefined', 1)
->first();
if (empty($banca_controparte)) {
echo '
</h3>
<p>'.tr('Banca predefinita non impostata').'.</p>';
continue;
}
echo '
</h3>
<table class="table table-condensed table-striped">
<thead>
<tr>
<th>'.tr('Causale').'</th>
<th class="text-center">'.tr('Data').'</th>
<th class="text-center">'.tr('Totale').'</th>
</tr>
</thead>
<tbody>';
$scadenze = $scadenze_anagrafica->sortBy('scadenza');
foreach ($scadenze as $scadenza) {
$totale = abs($scadenza->da_pagare) - abs($scadenza->pagato);
echo '
<tr>
<td>
<span>
'.$scadenza->descrizione.'
</span>';
$data_esportazione = $scadenza->presentazioni_exported_at;
if (!empty($data_esportazione)) {
echo '
<span class="badge pull-right">'.tr('Esportato in data: _DATE_', [
'_DATE_' => timestampFormat($data_esportazione),
]).'</span>';
}
$banca_controparte = Gestore::getBancaControparte($scadenza);
if ($database->tableExists('co_mandati_sepa')) {
$rs_mandato = $dbo->fetchArray('SELECT * FROM co_mandati_sepa WHERE id_banca = '.prepare($banca_controparte->id));
} else{
$rs_mandato = false;
}
$is_rid = in_array($scadenza->documento->pagamento['codice_modalita_pagamento_fe'],["MP09", "MP10", "MP11"]);
$is_riba = in_array($scadenza->documento->pagamento['codice_modalita_pagamento_fe'],["MP12"]);
$is_sepa = in_array($scadenza->documento->pagamento['codice_modalita_pagamento_fe'],["MP19", "MP20", "MP21"]);
$documento = $scadenza->documento;
$pagamento = $documento->pagamento;
if ($is_rid) {
if(!$rs_mandato){
echo '
<span class="label label-danger">'.tr('Id mandato mancante').'</span>';
}
if(!$banca_azienda->creditor_id){
echo '
<span class="label label-danger">'.tr('Id creditore mancante').'</span>';
}
} else if($is_riba && empty($banca_azienda->codice_sia)){
echo '
<span class="label label-danger">'.tr('Codice SIA banca emittente mancante').'</span>';
}
if ($is_sepa) {
//Prima, successiva, singola
$scadenze_antecedenti = $dbo->fetchArray("SELECT * FROM co_scadenziario INNER JOIN co_documenti ON co_scadenziario.iddocumento=co_documenti.id INNER JOIN co_pagamenti ON co_documenti.idpagamento=co_pagamenti.id WHERE co_documenti.idanagrafica=".prepare($id_anagrafica)." AND codice_modalita_pagamento_fe IN('MP19','MP20','MP21') AND data_emissione<".prepare($scadenza->data_emissione));
$check_successiva = '';
$check_prima = '';
$check_singola = '';
if(sizeof($scadenze_antecedenti)>0){
$check_successiva = 'selected';
}else{
$check_prima = 'selected';
}
if (sizeof($rs_mandato)>0) {
if($rs_mandato[0]['singola_disposizione']=='1'){
$check_singola = 'selected';
$check_successiva = '';
$check_prima = '';
}
}
echo '
<span class="pull-right" style="margin-right:15px;">
<select class="sequenza" name="sequenza[]" data-idscadenza="'.$scadenza->id.'" style="width:300px;">
<option value="">- Seleziona una sequenza -</option>
<option value="FRST" '.$check_prima.'>Prima di una serie di disposizioni</option>
<option value="RCUR" '.$check_successiva.'>Successiva di una serie di disposizioni di incasso</option>
<option value="FNAL">Ultima di una serie di disposizioni</option>
<option value="OOFF" '.$check_singola.'>Singola diposizione non ripetuta</option>
</select>
</span>';
}
echo '
</td>
<td class="text-center">
'.dateFormat($scadenza->scadenza).'
</td>
<td class="text-right">
'.moneyFormat($totale).'
</td>
</tr>';
}
echo '
</tbody>
</table>';
}
echo '
<div class="row">
<div class="col-md-12 text-right">
<button type="button" class="btn btn-primary '.(!empty($banca_azienda) ? '' : 'disabled').'" onclick="esporta(this)">
<i class="fa fa-download"></i> '.tr('Esporta').'
</button>
</div>
</div>
<div class="row hidden" id="info">
<div class="col-md-12">
<p>'.tr('Le scadenze selezionate sono state esportate nei seguenti file').':</p>
<ul id="files"></ul>
</div>
<div class="col-md-12 text-right">
<button type="button" id="registrazione_contabile" class="btn btn-primary" onclick="registraPagamenti(this)">
<i class="fa fa-save"></i> '.tr('Registrazione contabile').'
</button>
</div>
</div>';
$modulo_prima_nota = Modules::get('Prima nota');
echo '
<script>
$(".sequenza").select2();
function esporta(button) {
let restore = buttonLoading(button);
//Creo un array con i valori di sequenza
var inputs = $(".sequenza");
var sequenze = new Array();
for(var i = 0; i < inputs.length; i++){
if($(inputs[i]).val()){
sequenze[i] = $(inputs[i]).data("idscadenza")+"-"+$(inputs[i]).val();
}
}
$.ajax({
url: globals.rootdir + "/actions.php",
cache: false,
type: "POST",
dataType: "json",
data: {
id_module: globals.id_module,
id_plugin: "'.$id_plugin.'",
scadenze: ['.implode(',', $id_scadenze->toArray()).'],
sequenze: sequenze,
op: "generate",
},
}).then(function(response) {
buttonRestore(button, restore);
if (response.scadenze.length) {
$(button).addClass("hidden");
$("#info").removeClass("hidden");
// Salvataggio delle scadenze esportate correttamente
$("#registrazione_contabile").data("scadenze", response.scadenze);
// Creazione dei link per il download dei file
let fileList = $("#files");
for(const file of response.files){
fileList.append(`<li>
<a href="` + file + `" target="_blank">` + file + `</a>
<button type="button" class="btn btn-xs btn-info" onclick="scaricaFile(\'` + file + `\')">
<i class="fa fa-download"></i>
</button>
</li>`)
}
} else {
swal({
title: "'.tr('Impossibile esportare le scadenze indicate!').'",
type: "error",
})
}
});
}
function scaricaFile(file) {
fetch(file)
.then(resp => resp.blob())
.then(blob => {
const url = window.URL.createObjectURL(blob);
const a = document.createElement("a");
a.style.display = "none";
a.href = url;
// the filename you want
a.download = file.split("/").pop();
document.body.appendChild(a);
a.click();
window.URL.revokeObjectURL(url);
})
.catch(() => swal("'.tr('Errore').'", "'.tr('Errore durante il download').'", "error"));
}
function registraPagamenti(button) {
let scadenze = $(button).data("scadenze");
openModal("'.tr('Registrazione contabile pagamento').'", globals.rootdir + "/add.php?id_module='.$modulo_prima_nota['id'].'&id_records=" + scadenze.join(";"));
}
</script>';

View File

@ -0,0 +1,7 @@
<?php
include_once __DIR__.'/../../core.php';
$records = get('records', true);
$records = $records ? explode(',', $records) : [];
$record = $records[0] ?: null;

View File

@ -0,0 +1,416 @@
<?php
namespace Plugins\PresentazioniBancarie;
use Carbon\Carbon;
use DateTime;
use Plugins\PresentazioniBancarie\RiBa\Intestazione;
use Plugins\PresentazioniBancarie\RiBa\RiBa;
use Plugins\PresentazioniBancarie\RiBa\Ricevuta;
use Digitick\Sepa\PaymentInformation;
use Digitick\Sepa\TransferFile\Factory\TransferFileFacadeFactory;
use Exception;
use Modules\Anagrafiche\Anagrafica;
use Modules\Banche\Banca;
use Modules\Scadenzario\Scadenza;
use Sdd\DirectDebit as DirectDebitCBI;
use Sdd\DirectDebit\GroupHeader as HeaderCBI;
use Sdd\DirectDebit\Payment as PaymentCBI;
use Sdd\DirectDebit\PaymentInformation as PaymentInformationCBI;
class Gestore
{
/**
* @var Anagrafica|null
*/
protected static $azienda_predefinita;
/**
* @var Banca|null
*/
protected static $banca_predefinita_azienda;
protected $id_riba;
protected $id_debito_diretto;
protected $id_credito_diretto;
protected $riba;
protected $debito_diretto;
protected $credito_diretto;
protected $numero_transazioni_debito_diretto = 0;
protected $totale_debito_diretto = 0;
/**
* @var Anagrafica
*/
private $azienda;
/**
* @var Banca
*/
private $banca_azienda;
public function __construct(Anagrafica $azienda, Banca $banca_azienda)
{
$this->azienda = $azienda;
$this->banca_azienda = $banca_azienda;
$this->id_riba = random_string();
$this->initRiBa();
$this->id_credito_diretto = random_string();
$this->initCreditoDiretto();
$this->id_debito_diretto = random_string();
$this->initDebitoDiretto();
}
/**
* Inizializzazione del formato per il sistema RiBa.
*/
public function initRiBa()
{
$iban = $this->banca_azienda->iban;
$conto = substr($iban, 15, 12);
$abi_assuntrice = substr($iban, 5, 5);
$cab_assuntrice = substr($iban, 10, 5);
$data = new Carbon();
$supporto = $data->format('dmYHis');
// Generazione intestazione
$intestazione = new Intestazione();
$intestazione->codice_sia = $this->banca_azienda['codice_sia'];
$intestazione->conto = $conto;
$intestazione->abi = $abi_assuntrice;
$intestazione->cab = $cab_assuntrice;
$intestazione->data_creazione = $data->format('dmy');
$intestazione->nome_supporto = $supporto;
$intestazione->cap_citta_prov_creditore = strtoupper($this->azienda['cap'].' '.$this->azienda['citta'].' '.$this->azienda['provincia']);
$intestazione->ragione_soc1_creditore = strtoupper($this->azienda->ragione_sociale);
$intestazione->indirizzo_creditore = strtoupper($this->azienda['indirizzo']);
$intestazione->identificativo_creditore = !empty($this->azienda->partita_iva) ? $this->azienda->partita_iva : $this->azienda->codice_fiscale;
$this->riba = new RiBa($intestazione);
}
/**
* Inizializzazione del formato per il credito diretto.
*
* @source https://github.com/php-sepa-xml/php-sepa-xml/blob/master/doc/direct_credit.md
*/
public function initCreditoDiretto()
{
$this->credito_diretto = TransferFileFacadeFactory::createCustomerCredit($this->id_credito_diretto, $this->azienda->ragione_sociale);
}
/**
* Inizializzazione del formato per il debito diretto.
*
* @source https://github.com/php-sepa-xml/php-sepa-xml/blob/master/doc/direct_debit.md
*/
public function initDebitoDirettoSEPA()
{
$this->debito_diretto = TransferFileFacadeFactory::createDirectDebit($this->id_debito_diretto, $this->azienda->ragione_sociale);
}
/**
* Inizializzazione del formato per il debito diretto.
*
* @source https://github.com/wdog/sdd_ita/blob/master/tests/DirectDebitTest.php
*/
public function initDebitoDiretto()
{
$this->debito_diretto = new DirectDebitCBI();
}
public function aggiungi(Scadenza $scadenza, int $identifier, string $descrizione, string $codice_sequenza = null)
{
$documento = $scadenza->documento;
$controparte = $documento->anagrafica;
$banca_controparte = self::getBancaControparte($scadenza);
if (empty($banca_controparte)) {
return false;
}
$pagamento = $documento->pagamento;
$direzione = $documento->direzione;
$totale = (abs($scadenza->da_pagare) - abs($scadenza->pagato));
$is_credito_diretto = $direzione == 'uscita' && in_array($pagamento->codice_modalita_pagamento_fe, ['MP09', 'MP10', 'MP11', 'MP19', 'MP20', 'MP21']);
$is_debito_diretto = $direzione == 'entrata' && in_array($pagamento->codice_modalita_pagamento_fe, ['MP09', 'MP10', 'MP11', 'MP19', 'MP20', 'MP21']) && !empty($this->banca_azienda->creditor_id); // Mandato SEPA disponibile
$is_riba = $direzione == 'entrata' && in_array($pagamento->codice_modalita_pagamento_fe, ['MP12']) && !empty($this->banca_azienda->codice_sia);
if(in_array($pagamento->codice_modalita_pagamento_fe, ['MP19', 'MP21'])){
$method = 'B2B';
}else if(in_array($pagamento->codice_modalita_pagamento_fe, ['MP20'])){
$method = 'CORE';
}
if ($is_credito_diretto) {
return $this->aggiungiCreditoDiretto($identifier, $controparte, $banca_controparte, $descrizione, $totale, $scadenza->scadenza);
} elseif ($is_debito_diretto) {
return $this->aggiungiDebitoDiretto($identifier, $controparte, $banca_controparte, $descrizione, $totale, $scadenza->scadenza, $method, $codice_sequenza);
} elseif ($is_riba) {
$totale = $totale*100;
return $this->aggiungiRiBa($identifier, $controparte, $banca_controparte, $descrizione, $totale, $scadenza->scadenza);
}
return false;
}
public function aggiungiRiBa(int $identifier, Anagrafica $controparte, Banca $banca_controparte, string $descrizione, int $totale, DateTime $data_prevista)
{
$data_scadenza = $data_prevista->format('dmy');
// Dati banca cliente
$abi_cliente = substr($banca_controparte['iban'], 5, 5);
$cab_cliente = substr($banca_controparte['iban'], 10, 5);
$descrizione_banca = $banca_controparte['nome'].' '.$banca_controparte['filiale'];
// Aggiunta codice CIG CUP se presenti
if (!empty($controparte['cig'])) {
$descrizione .= ' CIG:'.$controparte['cig'];
}
if (!empty($controparte['cup'])) {
$descrizione .= ' CUP:'.$controparte['cup'];
}
// Salvataggio della singola ricevuta nel RiBa
$ricevuta = new Ricevuta();
$ricevuta->numero_ricevuta = $identifier;
$ricevuta->scadenza = $data_scadenza;
$ricevuta->importo = $totale;
$ricevuta->abi_banca = $abi_cliente;
$ricevuta->cab_banca = $cab_cliente;
$ricevuta->codice_cliente = $controparte['codice'];
//controlli sulla ragione sociale
$ragione_sociale = utf8_decode($controparte['ragione_sociale']);
// Sostituzione di alcuni simboli noti
$replaces = [
'&#039;' => "'",
'&quot;' => "'",
'&amp;' => '&',
];
$ragione_sociale = str_replace(array_keys($replaces), array_values($replaces), $ragione_sociale);
$ricevuta->nome_debitore = strtoupper($ragione_sociale);
$ricevuta->identificativo_debitore = !empty($controparte->partita_iva) ? $controparte->partita_iva : $controparte->codice_fiscale;
$ricevuta->indirizzo_debitore = strtoupper($controparte['indirizzo']);
$ricevuta->cap_debitore = $controparte['cap'];
$ricevuta->comune_debitore = strtoupper($controparte['citta']);
$ricevuta->provincia_debitore = $controparte['provincia'];
$ricevuta->descrizione_banca = $descrizione_banca;
$ricevuta->descrizione = strtoupper($descrizione);
$this->riba->addRicevuta($ricevuta);
return true;
}
public function aggiungiCreditoDiretto(int $identifier, Anagrafica $controparte, Banca $banca_controparte, string $descrizione, $totale, DateTime $data_prevista)
{
$id = 'pagamento_'.$identifier;
// Esportazione del pagamento
$this->credito_diretto->addPaymentInfo($id, [
'id' => $identifier,
'dueDate' => $data_prevista->format('dmy'),
'debtorName' => $this->azienda->ragione_sociale,
'debtorAccountIBAN' => $this->banca_azienda->iban,
'debtorAgentBIC' => $this->banca_azienda->bic,
]);
$this->credito_diretto->addTransfer($id, [
'amount' => $totale,
'creditorIban' => $banca_controparte->iban,
'creditorBic' => $banca_controparte->bic,
'creditorName' => $controparte->ragione_sociale,
'remittanceInformation' => $descrizione,
]);
return true;
}
public function aggiungiDebitoDirettoSEPA(int $identifier, Anagrafica $controparte, Banca $banca_controparte, string $descrizione, $totale, DateTime $data_prevista)
{
$id = 'pagamento_'.$identifier;
$this->debito_diretto->addPaymentInfo($id, [
'id' => $identifier,
'dueDate' => $data_prevista->format('Y-m-d'),
'creditorName' => $this->azienda->ragione_sociale,
'creditorAccountIBAN' => $this->banca_azienda->iban,
'creditorAgentBIC' => $this->banca_azienda->bic,
'seqType' => PaymentInformation::S_ONEOFF,
'creditorId' => $this->banca_azienda->creditor_id,
'localInstrumentCode' => 'CORE', // default. optional.
]);
// Add a Single Transaction to the named payment
$mandato = $this->getMandato($banca_controparte);
$this->debito_diretto->addTransfer($id, [
'amount' => $totale,
'debtorName' => $controparte->ragione_sociale,
'debtorIban' => $banca_controparte->iban,
'debtorBic' => $banca_controparte->bic,
'debtorMandate' => $mandato['id_mandato'],
'debtorMandateSignDate' => $mandato['data_firma_mandato'],
'remittanceInformation' => $descrizione,
]);
return true;
}
public function aggiungiDebitoDiretto(int $identifier, Anagrafica $controparte, Banca $banca_controparte, string $descrizione, $totale, DateTime $data_prevista, $method, $codice_sequenza)
{
$paymentInformation = new PaymentInformationCBI();
$paymentInformation
->setCreditorName($this->azienda->ragione_sociale)
->setCreditorIBAN($this->banca_azienda->iban)
->setCreditorId($this->banca_azienda->creditor_id)
->setPaymentInformationIdentification($identifier)
->setRequestedExecutionDate($data_prevista->format('Y-m-d'))
->setLocalMethod($method)
->setServiceLevel('SEPA')
->setSeqType(($codice_sequenza!=''?$codice_sequenza:'RCUR'));
$mandato = $this->getMandato($banca_controparte);
$payment = new PaymentCBI();
$payment
->setInstrId($identifier)
->setAmount($totale)
->setEndToEndId($identifier.$this->numero_transazioni_debito_diretto)
->setDebtorIBAN($banca_controparte->iban)
->setDebtorName(htmlentities($controparte->ragione_sociale))
->setMndt($mandato['id_mandato'])
->setMndtDate($mandato['data_firma_mandato'])
->setRemittanceInformation($descrizione);
$paymentInformation->addPayments([$payment]);
$this->debito_diretto->addPaymentInformation($paymentInformation);
++$this->numero_transazioni_debito_diretto;
$this->totale_debito_diretto += $totale;
return true;
}
public static function getBancaControparte(Scadenza $scadenza): ?Banca
{
$documento = $scadenza->documento;
$anagrafica = $documento->anagrafica;
$banca_controparte = $documento->id_banca_controparte ? Banca::find($documento->id_banca_controparte) : null;
if (empty($banca_controparte)) {
$banca_controparte = Banca::where('id_anagrafica', $anagrafica->id)
->where('predefined', 1)
->first();
}
return $banca_controparte;
}
public static function getBancaAzienda(Scadenza $scadenza): Banca
{
$documento = $scadenza->documento;
return $documento->id_banca_azienda ? Banca::find($documento->id_banca_azienda) : self::getBancaPredefinitaAzienda();
}
public static function getBancaPredefinitaAzienda(): Banca
{
if (!isset(self::$banca_predefinita_azienda)) {
self::$banca_predefinita_azienda = Banca::where('id_anagrafica', self::getAzienda()->id)
->where('predefined', 1)
->first();
}
return self::$banca_predefinita_azienda;
}
public static function getAzienda(): Anagrafica
{
if (!isset(self::$azienda_predefinita)) {
self::$azienda_predefinita = Anagrafica::find(setting('Azienda predefinita'));
}
return self::$azienda_predefinita;
}
public function esporta(string $path): array
{
/**
* Salvataggio dei file nei diversi formati.
*/
$files = [];
// File per il pagamento delle vendite RiBa
try {
$content = $this->riba->asCBI();
// Generazione filename
$filename = $this->id_riba.'.txt';
$file = $path.'/'.$filename;
$files[] = base_url().'/'.$file;
// Salvataggio del file
file_put_contents(base_dir().'/'.$file, $content);
} catch (Exception $e) {
}
// File per il pagamento degli acquisti SEPA
try {
$xml = $this->credito_diretto->asXML();
// Generazione filename
$filename = $this->id_credito_diretto.'.xml';
$file = $path.'/'.$filename;
$files[] = base_url().'/'.$file;
// Salvataggio del file
file_put_contents(base_dir().'/'.$file, $xml);
} catch (Exception $e) {
}
// File per il pagamento delle vendite SEPA CBI
try {
$groupHeader = new HeaderCBI();
$groupHeader->setControlSum($this->totale_debito_diretto)
->setInitiatingPartyName($this->azienda->ragione_sociale)
->setOrgHeaderId('ABC') // Codice Unico CBI
->setOrgHeaderIssr('CBI')
->setMessageIdentification($this->id_debito_diretto)
->setNumberOfTransactions($this->numero_transazioni_debito_diretto);
$this->debito_diretto->setGroupHeader($groupHeader);
$xml = $this->debito_diretto->xml();
// Generazione filename
$filename = $this->id_debito_diretto.'.xml';
$file = $path.'/'.$filename;
$files[] = base_url().'/'.$file;
// Salvataggio del file
file_put_contents(base_dir().'/'.$file, $xml);
} catch (Exception $e) {
}
return $files;
}
protected function getMandato(Banca $banca)
{
if (database()->tableExists('co_mandati_sepa')) {
return database()->fetchOne('SELECT * FROM co_mandati_sepa WHERE id_banca = '.prepare($banca->id));
} else{
return [];
}
}
}

View File

@ -0,0 +1,47 @@
<?php
namespace Plugins\PresentazioniBancarie\RiBa;
abstract class Elemento
{
protected $dati = [];
public function __get($name)
{
$method = $this->getCamelCase($name);
if (method_exists($this, 'get'.$method)) {
return $this->{'get'.$name}();
}
return $this->{$name};
}
public function __set($name, $value)
{
$method = $this->getCamelCase($name);
if (method_exists($this, 'set'.$method)) {
$this->{'set'.$name}($value);
} else {
$this->{$name} = $value;
}
}
/**
* @return array
*/
abstract public function toCbiFormat();
/**
* @param string $string
*
* @return string
*/
protected function getCamelCase($string)
{
$words = str_replace('_', ' ', $string);
$upper = ucwords($words);
$name = str_replace(' ', '', $upper);
return $name;
}
}

View File

@ -0,0 +1,101 @@
<?php
namespace Plugins\PresentazioniBancarie\RiBa;
/**
* Classe per gestire l'intestazione del RiBa.
*
* @property int $abi
* @property int $cab
* @property string $conto
* @property string $data_creazione
* @property string $nome_supporto
* @property string $codice_divisa
* @property string $ragione_soc1_creditore
* @property string $ragione_soc2_creditore
* @property string $indirizzo_creditore
* @property string $cap_citta_prov_creditore
* @property string $identificativo_creditore
* @property string $codice_sia
* @property bool $eol
*/
class Intestazione extends Elemento
{
/**
* Codice ABI della banca del creditore.
*
* @var int Valore numerico di 5 cifre
*/
protected $abi;
/**
* Codice CAB della banca del creditore.
*
* @var int Valore numerico di 5 cifre
*
* @property
*/
protected $cab;
/**
* @var string Valore alfanumerico di 12 cifre
*/
protected $conto;
/**
* @var string Valore numerico di 6 cifre in formato ggmmaa
*/
protected $data_creazione;
/**
* @var string Valore alfanumerico di 20 cifre
*/
protected $nome_supporto;
/**
* @var string Valore alfanumerico di 1 cifra, opzionale (default "E")
*/
protected $codice_divisa = 'E';
/**
* @var string Valore alfanumerico di 24 cifre
*/
protected $ragione_soc1_creditore;
/**
* @var string Valore alfanumerico di 24 cifre
*/
protected $ragione_soc2_creditore;
/**
* @var string Valore alfanumerico di 24 cifre
*/
protected $indirizzo_creditore;
/**
* @var string Valore alfanumerico di 24 cifre
*/
protected $cap_citta_prov_creditore;
/**
* @var string Valore alfanumerico di 16 cifre, opzionale (default "")
*/
protected $identificativo_creditore = '';
/**
* @var string Valore alfanumerico di 5 cifre
*/
protected $codice_sia;
/**
* @var bool true per aggiungere i caratteri di fine rigo
*/
protected $eol = true;
public function toCbiFormat()
{
return [
$this->abi,
$this->cab,
$this->conto,
$this->data_creazione,
$this->nome_supporto,
$this->codice_divisa,
$this->ragione_soc1_creditore,
$this->ragione_soc2_creditore,
$this->indirizzo_creditore,
$this->cap_citta_prov_creditore,
$this->identificativo_creditore,
$this->codice_sia,
$this->eol,
];
}
}

View File

@ -0,0 +1,151 @@
<?php
namespace Plugins\PresentazioniBancarie\RiBa\Records;
abstract class BaseRecord implements RecordInterface
{
protected $dati = [];
/**
* Costruttore predefinito, che inizializza le informazioni interne al record in modo autonomo secondo la relativa struttura.
*/
public function __construct()
{
$struttura = static::getStruttura();
// Inizializzazione di tutti i campi
foreach ($struttura as $nome => $campo) {
$this->{$nome} = $campo['valore'] ?: '';
}
}
public function __get($name)
{
$method = $this->getCamelCase($name);
if (method_exists($this, 'get'.$method)) {
return $this->{'get'.$name}();
}
return $this->get($name);
}
public function __set($name, $value)
{
$method = $this->getCamelCase($name);
if (method_exists($this, 'set'.$method)) {
$this->{'set'.$name}($value);
} else {
$this->set($name, $value);
}
}
public function toCBI(): string
{
$contenuto = ' '.static::getCodice();
$struttura = static::getStruttura();
// Informazioni sui campi disponibili
$contenuti = [];
foreach ($struttura as $nome => $campo) {
$contenuti[$campo['inizio']] = $this->{$nome};
}
// Sort per indici
ksort($contenuti);
// Completamento dei filler
foreach ($contenuti as $inizio => $string) {
$dimensione_contenuto = strlen($contenuto) + 1;
if ($dimensione_contenuto != $inizio) {
$contenuto .= str_repeat(' ', $inizio - $dimensione_contenuto);
}
$contenuto .= $string;
}
// Filler finale per la riga
$contenuto .= str_repeat(' ', 120 - strlen($contenuto));
return $contenuto;
}
public function fromCBI(string $contenuto): void
{
$struttura = static::getStruttura();
// Informazioni sui campi disponibili
foreach ($struttura as $nome => $campo) {
$string = substr($contenuto, $campo['inizio'] - 1, $campo['dimensione']);
// Aggiunta del contenuto al record
$this->{$nome} = trim($string);
}
}
public function get(string $name): ?string
{
return isset($this->dati[$name]) ? $this->dati[$name] : null;
}
public function set(string $name, ?string $value): void
{
$struttura = static::getStruttura();
$record = $struttura[$name];
if (empty($record)) {
return;
}
// Pad automatico sulla base del tipo
if ($record['tipo'] == 'string') {
$value = $this->padString($value, $record['dimensione']);
} elseif ($record['tipo'] == 'numeric') {
$value = $this->padNumber($value, $record['dimensione']);
} elseif ($record['tipo'] == 'constant') {
$value = $record['valore'];
}
$this->dati[$name] = $value;
}
/**
* @return string
*/
protected function padString(?string $string, int $length)
{
// Sostituzione di alcuni simboli noti
$replaces = [
'&#039;' => "'",
'&quot;' => "'",
'&amp;' => '&',
];
$string = str_replace(array_keys($replaces), array_values($replaces), $string);
$string = substr($string, 0, $length);
return str_pad($string, $length);
}
/**
* @return string
*/
protected function padNumber(?string $string, int $length)
{
$string = substr($string, 0, $length);
return str_pad($string, $length, '0', STR_PAD_LEFT);
}
/**
* @return string
*/
protected function getCamelCase(string $string)
{
$words = str_replace('_', ' ', $string);
$upper = ucwords($words);
$name = str_replace(' ', '', $upper);
return $name;
}
}

View File

@ -0,0 +1,118 @@
<?php
namespace Plugins\PresentazioniBancarie\RiBa\Records;
/**
* Classe dedicata alla gestione dei dati per il record 14 del formato CBI.
*
* @property string numero_progressivo Numero della disposizione all'interno del flusso. Inizia con 1 ed è progressivo di 1.
* @property string data_pagamento Data di scadenza, nel formato GGMMAA,
* @property string causale Assume valore fisso "30000".
* @property string importo Importo della ricevuta in centesimi di Euro.
* @property string segno assume valore fisso " - ".
* @property string abi_assuntrice Codice ABI della banca assuntrice delle ricevute; deve corrispondere a quello presente sul record di testa.
* @property string cab_assuntrice Codice CAB dello sportello della banca.
* @property string conto_assuntrice Conto corrente che il cliente chiede di
* @property string abi_domiciliataria Codice ABI della banca domiciliataria.
* @property string cab_domiciliataria Codice CAB dello sportello della banca.
* @property string codice_azienda_creditrice Codice SIA del cliente ordinante; tale codice, se presente, deve essere valorizzato su tutte le singole disposizioni contenute nel medesimo supporto logico, e deve contenere sempre il medesimo valore. Questo può essere diverso dal codice SIA dellazienda mittente indicato sul record di testa, e non necessariamente è censito tra i codici SIA riportati nelle tabelle di routing dei Centri Applicativi (cfr. par.3.6.4 sez. I).
* @property string tipo_codice_creditrice Assume il valore fisso "4".
* @property string codice_cliente_debitore Codice con il quale il debitore è conosciuto dal creditore.
* @property string flag_tipo_debitore Nel caso il debitore sia una Banca deve assumere il valore "B" (il codice ABI è indicato in pos. 70-74).
* @property string codice_divisa Questo campo deve coincidere con quello
omonimo del record di testa.
*/
class Record14 extends BaseRecord
{
public static $struttura = [
'numero_progressivo' => [
'inizio' => 4,
'dimensione' => 7,
'tipo' => 'numeric',
],
'data_pagamento' => [
'inizio' => 23,
'dimensione' => 6,
'tipo' => 'string',
],
'causale' => [
'inizio' => 29,
'dimensione' => 5,
'tipo' => 'constant',
'valore' => '30000',
],
'importo' => [
'inizio' => 34,
'dimensione' => 13,
'tipo' => 'numeric',
],
'segno' => [
'inizio' => 47,
'dimensione' => 1,
'tipo' => 'constant',
'valore' => '-',
],
'abi_assuntrice' => [
'inizio' => 48,
'dimensione' => 5,
'tipo' => 'numeric',
],
'cab_assuntrice' => [
'inizio' => 53,
'dimensione' => 5,
'tipo' => 'numeric',
],
'conto_assuntrice' => [
'inizio' => 58,
'dimensione' => 12,
'tipo' => 'numeric',
],
'abi_domiciliataria' => [
'inizio' => 70,
'dimensione' => 5,
'tipo' => 'numeric',
],
'cab_domiciliataria' => [
'inizio' => 75,
'dimensione' => 5,
'tipo' => 'numeric',
],
'codice_azienda_creditrice' => [
'inizio' => 92,
'dimensione' => 5,
'tipo' => 'string',
],
'tipo_codice_creditrice' => [
'inizio' => 97,
'dimensione' => 1,
'tipo' => 'constant',
'valore' => '4',
],
'codice_cliente_debitore' => [
'inizio' => 98,
'dimensione' => 16,
'tipo' => 'string',
],
'flag_tipo_debitore' => [
'inizio' => 114,
'dimensione' => 1,
'tipo' => 'string',
],
'codice_divisa' => [
'inizio' => 120,
'dimensione' => 1,
'tipo' => 'constant',
'valore' => 'E',
],
];
public static function getStruttura(): array
{
return static::$struttura;
}
public static function getCodice(): string
{
return '14';
}
}

View File

@ -0,0 +1,53 @@
<?php
namespace Plugins\PresentazioniBancarie\RiBa\Records;
/**
* Classe dedicata alla gestione dei dati per il record 20 del formato CBI.
*
* @property string numero_progressivo Numero progressivo della ricevuta, uguale a quello indicato per il record 14 della disposizione.
* @property string descrizione_creditore_1 Descrizione del creditore (24 caratteri alfanumerici).
* @property string descrizione_creditore_2 Descrizione del creditore (24 caratteri alfanumerici).
* @property string descrizione_creditore_3 Descrizione del creditore (24 caratteri alfanumerici).
* @property string descrizione_creditore_4 Descrizione del creditore (24 caratteri alfanumerici).
*/
class Record20 extends BaseRecord
{
public static $struttura = [
'numero_progressivo' => [
'inizio' => 4,
'dimensione' => 7,
'tipo' => 'numeric',
],
'descrizione_creditore_1' => [
'inizio' => 11,
'dimensione' => 24,
'tipo' => 'string',
],
'descrizione_creditore_2' => [
'inizio' => 35,
'dimensione' => 24,
'tipo' => 'string',
],
'descrizione_creditore_3' => [
'inizio' => 59,
'dimensione' => 24,
'tipo' => 'string',
],
'descrizione_creditore_4' => [
'inizio' => 83,
'dimensione' => 24,
'tipo' => 'string',
],
];
public static function getStruttura(): array
{
return static::$struttura;
}
public static function getCodice(): string
{
return '20';
}
}

View File

@ -0,0 +1,47 @@
<?php
namespace Plugins\PresentazioniBancarie\RiBa\Records;
/**
* Classe dedicata alla gestione dei dati per il record 30 del formato CBI.
*
* @property string numero_progressivo Numero progressivo della ricevuta, uguale a quello indicato per il record 14 della disposizione.
* @property string descrizione_debitore_1 Descrizione del debitore (30 caratteri alfanumerici).
* @property string descrizione_debitore_2 Descrizione del debitore (30 caratteri alfanumerici).
* @property string codice_fiscale_debitore Codice fiscale del cliente debitore; il controllo è di validità; pertanto va verificata la presenza del CIN e la sua correttezza. Il campo non è sottoposto ad alcun controllo di presenza formale sulla validità nel caso in cui il codice ABI della Banca domiciliataria (pos. 70-74, rec. 14) sia uno dei seguenti: 03034 03145 03171 - 03178 - 03195 03225 - 03530 06067 08540 - 3262 1.
*/
class Record30 extends BaseRecord
{
public static $struttura = [
'numero_progressivo' => [
'inizio' => 4,
'dimensione' => 7,
'tipo' => 'numeric',
],
'descrizione_debitore_1' => [
'inizio' => 11,
'dimensione' => 30,
'tipo' => 'string',
],
'descrizione_debitore_2' => [
'inizio' => 41,
'dimensione' => 30,
'tipo' => 'string',
],
'codice_fiscale_debitore' => [
'inizio' => 71,
'dimensione' => 16,
'tipo' => 'string',
],
];
public static function getStruttura(): array
{
return static::$struttura;
}
public static function getCodice(): string
{
return '30';
}
}

View File

@ -0,0 +1,59 @@
<?php
namespace Plugins\PresentazioniBancarie\RiBa\Records;
/**
* Classe dedicata alla gestione dei dati per il record 40 del formato CBI.
*
* @property string numero_progressivo Numero progressivo della ricevuta, uguale a quello indicato per il record 14 della disposizione.
* @property string indirizzo_debitore Via, numero civico e/o nome della frazione.
* @property string cap_debitore Codice di avviamento postale.
* @property string comune_debitore Comune del debitore.
* @property string provincia_debitore Sigla della provincia del debitore.
* @property string banca_domiciliataria Banca/sportello domiciliataria: eventuale denominazione in chiaro della banca/sportello domiciliataria/o.
*/
class Record40 extends BaseRecord
{
public static $struttura = [
'numero_progressivo' => [
'inizio' => 4,
'dimensione' => 7,
'tipo' => 'numeric',
],
'indirizzo_debitore' => [
'inizio' => 11,
'dimensione' => 30,
'tipo' => 'string',
],
'cap_debitore' => [
'inizio' => 41,
'dimensione' => 5,
'tipo' => 'string',
],
'comune_debitore' => [
'inizio' => 46,
'dimensione' => 23,
'tipo' => 'string',
],
'provincia_debitore' => [
'inizio' => 69,
'dimensione' => 2,
'tipo' => 'string',
],
'banca_domiciliataria' => [
'inizio' => 71,
'dimensione' => 50,
'tipo' => 'string',
],
];
public static function getStruttura(): array
{
return static::$struttura;
}
public static function getCodice(): string
{
return '40';
}
}

View File

@ -0,0 +1,47 @@
<?php
namespace Plugins\PresentazioniBancarie\RiBa\Records;
/**
* Classe dedicata alla gestione dei dati per il record 50 del formato CBI.
*
* @property string numero_progressivo Numero progressivo della ricevuta, uguale a quello indicato per il record 14 della disposizione.
* @property string riferimento_debito_1 Riferimenti al debito.
* @property string riferimento_debito_2 Riferimenti al debito.
* @property string codice_fiscale_creditore Codice fiscale/Partita IVA del creditore. Se il campo è valorizzato, il controllo è di validità pertanto va verificata la presenza del CIN e la sua correttezza. Lobbligatorietà viene meno nel caso in cui il campo 82 del tipo record 70 delle “Riba presentate da clientela non residente” sia valorizzato a 1.
*/
class Record50 extends BaseRecord
{
public static $struttura = [
'numero_progressivo' => [
'inizio' => 4,
'dimensione' => 7,
'tipo' => 'numeric',
],
'riferimento_debito_1' => [
'inizio' => 11,
'dimensione' => 40,
'tipo' => 'string',
],
'riferimento_debito_2' => [
'inizio' => 51,
'dimensione' => 40,
'tipo' => 'string',
],
'codice_fiscale_creditore' => [
'inizio' => 101,
'dimensione' => 16,
'tipo' => 'string',
],
];
public static function getStruttura(): array
{
return static::$struttura;
}
public static function getCodice(): string
{
return '50';
}
}

View File

@ -0,0 +1,59 @@
<?php
namespace Plugins\PresentazioniBancarie\RiBa\Records;
/**
* Classe dedicata alla gestione dei dati per il record 51 del formato CBI.
*
* @property string numero_progressivo Numero progressivo della ricevuta, uguale a quello indicato per il record 14 della disposizione.
* @property string numero_ricevuta Numero ricevuta attribuito dal creditore.
* @property string denominazione_creditore Denominazione sociale del creditore in forma abbreviata.
* @property string provincia_bollo_virtuale Provincia dell'Intendenza di Finanza che ha autorizzato il pagamento del bollo in modo virtuale.
* @property string numero_autorizzazione_bollo_virtuale Numero dell'autorizzazione concessa dall'Intendenza di Finanza.
* @property string data_autorizzazione_bollo_virtuale Data (nel formato GGMMAA) di concessione dell'autorizzazione da parte della Intendenza di Finanza.
*/
class Record51 extends BaseRecord
{
public static $struttura = [
'numero_progressivo' => [
'inizio' => 4,
'dimensione' => 7,
'tipo' => 'numeric',
],
'numero_ricevuta' => [
'inizio' => 11,
'dimensione' => 10,
'tipo' => 'numeric',
],
'denominazione_creditore' => [
'inizio' => 21,
'dimensione' => 20,
'tipo' => 'string',
],
'provincia_bollo_virtuale' => [
'inizio' => 41,
'dimensione' => 15,
'tipo' => 'string',
],
'numero_autorizzazione_bollo_virtuale' => [
'inizio' => 56,
'dimensione' => 10,
'tipo' => 'string',
],
'data_autorizzazione_bollo_virtuale' => [
'inizio' => 66,
'dimensione' => 6,
'tipo' => 'string',
],
];
public static function getStruttura(): array
{
return static::$struttura;
}
public static function getCodice(): string
{
return '51';
}
}

View File

@ -0,0 +1,59 @@
<?php
namespace Plugins\PresentazioniBancarie\RiBa\Records;
/**
* Classe dedicata alla gestione dei dati per il record 70 del formato CBI.
*
* @property string numero_progressivo Numero progressivo della ricevuta, uguale a quello indicato per il record 14 della disposizione.
* @property string indicatori_circuito Campo a disposizione per altri circuiti (Teleincassi, Reteincassi, ecc.) da valorizzare secondo gli standard propri di ogni circuito.
* @property string tipo_documento_per_debitore Indica il tipo di documento da rilasciare al debitore al momento dell'esazione dell'incasso; assume i seguenti valori: 1 = ricevuta bancaria; 2 = Conferma d'ordine di bonifico; 0 o blank = il cliente chiede alla Banca di comportarsi secondo accordi bilaterali predefiniti.
* @property string flag_richiesta_esito Assume i seguenti valori: 1 = é richiesta la notifica del pagato; 2 = non é richiesta la notifica del pagato; 0 o blank = il cliente chiede alla Banca di comportarsi secondo accordi bilaterali predefiniti.
* @property string flag_stampa_avviso Indica chi é incaricato della stampa e invio dell'avviso di pagamento; può assumere i
* @property string chiavi_controllo Campo a disposizione, valorizzabile dall'Azienda previ accordi diretti con la Banca Assuntrice.
*/
class Record70 extends BaseRecord
{
public static $struttura = [
'numero_progressivo' => [
'inizio' => 4,
'dimensione' => 7,
'tipo' => 'numeric',
],
'indicatori_circuito' => [
'inizio' => 89,
'dimensione' => 12,
'tipo' => 'string',
],
'tipo_documento_per_debitore' => [
'inizio' => 101,
'dimensione' => 1,
'tipo' => 'string',
],
'flag_richiesta_esito' => [
'inizio' => 102,
'dimensione' => 1,
'tipo' => 'string',
],
'flag_stampa_avviso' => [
'inizio' => 103,
'dimensione' => 1,
'tipo' => 'string',
],
'chiavi_controllo' => [
'inizio' => 104,
'dimensione' => 17,
'tipo' => 'string',
],
];
public static function getStruttura(): array
{
return static::$struttura;
}
public static function getCodice(): string
{
return '70';
}
}

View File

@ -0,0 +1,90 @@
<?php
namespace Plugins\PresentazioniBancarie\RiBa\Records;
/**
* Classe dedicata alla gestione dei dati per il record EF del formato CBI.
*
* @property string codice_sia_mittente Codice assegnato dalla Sia all'Azienda Mittente; deve essere censito in associazione alla Banca Proponente presso il Centro Applicativo mittente.
* @property string abi_assuntrice Codice ABI della banca assuntrice cui devono essere inviate le disposizioni; deve essere presente nella tabella Centri Applicativi in associazione al Centro Applicativo destinatario del flusso.
* @property string data_creazione Data di creazione del 'flusso' da parte dell'Azienda mittente nel formato GGMMAA.
* @property string nome_supporto Campo di libera composizione da parte dell'Azienda Mittente; dev'essere univoco nell'ambito della data di creazione e a parità di mittente e ricevente.
* @property string campo_a_disposizione Campo a disposizione dell'Azienda mittente.
* @property string numero_disposizioni Numero delle disposizioni (ricevute Ri.Ba. contenute nel flusso).
* @property string totale_importi_negativi Importo totale in centesimi di Euro - delle disposizioni contenute nel flusso.
* @property string totale_importi_positivi Valorizzato con "zeri" per RiBa.
* @property string numero_record Numero dei record che compongono il flusso (comprensivo dei record di testa e di coda).
* @property string codice_divisa Assume il valore fisso "E" (Euro).
* @property string giornata_applicativa Questo campo è di interesse soltanto nella tratta tra Centri Applicativi. Data della giornata applicativa in cui il supporto logico é stato elaborato presso il Centro Applicativo mittente (nel formato GGMMAA).
*/
class RecordEF extends BaseRecord
{
public static $struttura = [
'codice_sia_mittente' => [
'inizio' => 4,
'dimensione' => 5,
'tipo' => 'numeric',
],
'abi_assuntrice' => [
'inizio' => 9,
'dimensione' => 5,
'tipo' => 'numeric',
],
'data_creazione' => [
'inizio' => 14,
'dimensione' => 6,
'tipo' => 'string',
],
'nome_supporto' => [
'inizio' => 20,
'dimensione' => 20,
'tipo' => 'string',
],
'campo_a_disposizione' => [
'inizio' => 40,
'dimensione' => 6,
'tipo' => 'string',
],
'numero_disposizioni' => [
'inizio' => 46,
'dimensione' => 7,
'tipo' => 'numeric',
],
'totale_importi_negativi' => [
'inizio' => 53,
'dimensione' => 15,
'tipo' => 'numeric',
],
'totale_importi_positivi' => [
'inizio' => 68,
'dimensione' => 15,
'tipo' => 'numeric',
],
'numero_record' => [
'inizio' => 83,
'dimensione' => 7,
'tipo' => 'numeric',
],
'codice_divisa' => [
'inizio' => 114,
'dimensione' => 1,
'tipo' => 'constant',
'valore' => 'E',
],
'giornata_applicativa' => [
'inizio' => 115,
'dimensione' => 6,
'tipo' => 'string',
],
];
public static function getStruttura(): array
{
return static::$struttura;
}
public static function getCodice(): string
{
return 'EF';
}
}

View File

@ -0,0 +1,85 @@
<?php
namespace Plugins\PresentazioniBancarie\RiBa\Records;
/**
* Classe dedicata alla gestione dei dati per il record IB del formato CBI.
*
* @property string codice_sia_mittente Codice assegnato dalla Sia all'Azienda Mittente; deve essere censito in associazione alla Banca Proponente presso il Centro Applicativo codice_sia_mittente.
* @property string abi_assuntrice Codice ABI della banca assuntrice cui devono essere inviate le disposizioni; deve essere presente nella tabella Centri Applicativi in associazione al Centro Applicativo destinatario del flusso.
* @property string data_creazione Data di creazione del 'flusso' da parte dell'Azienda codice_sia_mittente nel formato GGMMAA.
* @property string nome_supporto Campo di libera composizione da parte dell'Azienda Mittente; dev'essere univoco nell'ambito della data di creazione e a parità di codice_sia_mittente e abi_assuntrice.
* @property string campo_a_disposizione Campo a disposizione dell'Azienda codice_sia_mittente.
* @property string tipo_flusso Assume il valore: "1" = operazioni generate nellambito di attività Market Place.
* @property string qualificatore_flusso Assume il valore fisso "$".
* @property string soggetto_veicolare Se i due campi tipo_flusso e qualificatore_flusso sono valorizzati con i valori previsti, deve essere indicato il codice ABI della Banca Gateway MP.
* @property string codice_divisa Assume il valore fisso "E" (Euro).
* @property string centro_applicativo Questo campo è di interesse soltanto della tratta tra Centri Applicativi. Codice ABI del Centro Applicativo destinatario del supporto.
*/
class RecordIB extends BaseRecord
{
public static $struttura = [
'codice_sia_mittente' => [
'inizio' => 4,
'dimensione' => 5,
'tipo' => 'numeric',
],
'abi_assuntrice' => [
'inizio' => 9,
'dimensione' => 5,
'tipo' => 'numeric',
],
'data_creazione' => [
'inizio' => 14,
'dimensione' => 6,
'tipo' => 'string',
],
'nome_supporto' => [
'inizio' => 20,
'dimensione' => 20,
'tipo' => 'string',
],
'campo_a_disposizione' => [
'inizio' => 40,
'dimensione' => 6,
'tipo' => 'string',
],
'tipo_flusso' => [
'inizio' => 105,
'dimensione' => 1,
'tipo' => 'string',
],
'qualificatore_flusso' => [
'inizio' => 106,
'dimensione' => 1,
'tipo' => 'constant',
'valore' => '$',
],
'soggetto_veicolare' => [
'inizio' => 107,
'dimensione' => 5,
'tipo' => 'string',
],
'codice_divisa' => [
'inizio' => 114,
'dimensione' => 1,
'tipo' => 'constant',
'valore' => 'E',
],
'centro_applicativo' => [
'inizio' => 116,
'dimensione' => 5,
'tipo' => 'string',
],
];
public static function getStruttura(): array
{
return static::$struttura;
}
public static function getCodice(): string
{
return 'IB';
}
}

View File

@ -0,0 +1,18 @@
<?php
namespace Plugins\PresentazioniBancarie\RiBa\Records;
interface RecordInterface
{
public static function getStruttura(): array;
public static function getCodice(): string;
public function get(string $name): ?string;
public function set(string $name, ?string $value): void;
public function toCBI(): string;
public function fromCBI(string $contenuto): void;
}

View File

@ -0,0 +1,206 @@
<?php
namespace Plugins\PresentazioniBancarie\RiBa;
use Plugins\PresentazioniBancarie\RiBa\Records\Record14;
use Plugins\PresentazioniBancarie\RiBa\Records\Record20;
use Plugins\PresentazioniBancarie\RiBa\Records\Record30;
use Plugins\PresentazioniBancarie\RiBa\Records\Record40;
use Plugins\PresentazioniBancarie\RiBa\Records\Record50;
use Plugins\PresentazioniBancarie\RiBa\Records\Record51;
use Plugins\PresentazioniBancarie\RiBa\Records\Record70;
use Plugins\PresentazioniBancarie\RiBa\Records\RecordEF;
use Plugins\PresentazioniBancarie\RiBa\Records\RecordIB;
use InvalidArgumentException;
class RiBa
{
/**
* @var Intestazione
*/
protected $intestazione;
/**
* @var Ricevuta[]
*/
protected $ricevute = [];
public function __construct(Intestazione $intestazione)
{
$this->intestazione = $intestazione;
}
public function addRicevuta(Ricevuta $ricevuta)
{
$this->ricevute[] = $ricevuta;
}
/**
* @return Intestazione
*/
public function getIntestazione()
{
return $this->intestazione;
}
/**
* @return RiBa
*/
public function setIntestazione(Intestazione $intestazione)
{
$this->intestazione = $intestazione;
return $this;
}
/**
* @return Ricevuta[]
*/
public function getRicevute()
{
return $this->ricevute;
}
/**
* @param Ricevuta[] $ricevute
*
* @return RiBa
*/
public function setRicevute($ricevute)
{
$this->ricevute = $ricevute;
return $this;
}
public function asCBI()
{
$eol = "\r\n";
$intestazione = $this->intestazione;
$ricevute = $this->ricevute;
$contenuto = '';
// Verifica sulla presenza di ricevute
if (empty($ricevute)) {
throw new \Exception();
}
// Record IB
$ib = new RecordIB();
$ib->codice_sia_mittente = $intestazione->codice_sia;
$ib->abi_assuntrice = $intestazione->abi;
$ib->nome_supporto = $intestazione->nome_supporto;
$ib->data_creazione = $intestazione->data_creazione;
$ib->tipo_flusso = 1;
$ib->soggetto_veicolare = $intestazione->abi;
$contenuto .= $ib->toCBI().$eol;
// Iterazione tra le ricevute interne al RiBa
$progressivo = 0;
$totale = 0;
foreach ($ricevute as $ricevuta) {
++$progressivo;
$totale += $ricevuta->importo;
// Record 14
$r14 = new Record14();
$r14->numero_progressivo = $progressivo;
$r14->data_pagamento = $ricevuta->scadenza;
$r14->abi_assuntrice = $intestazione->abi;
$r14->cab_assuntrice = $intestazione->cab;
$r14->conto_assuntrice = $intestazione->conto;
$r14->codice_azienda_creditrice = $intestazione->codice_sia;
$r14->abi_domiciliataria = $ricevuta->abi_banca;
$r14->cab_domiciliataria = $ricevuta->cab_banca;
$r14->importo = $ricevuta->importo;
$r14->codice_cliente_debitore = $ricevuta->codice_cliente;
$contenuto .= $r14->toCBI().$eol;
// Record 20
$r20 = new Record20();
$r20->numero_progressivo = $progressivo;
$r20->descrizione_creditore_1 = $intestazione->ragione_soc1_creditore;
$r20->descrizione_creditore_2 = $intestazione->ragione_soc2_creditore;
$r20->descrizione_creditore_3 = $intestazione->indirizzo_creditore;
$r20->descrizione_creditore_4 = $intestazione->cap_citta_prov_creditore;
$contenuto .= $r20->toCBI().$eol;
// Record 30
$r30 = new Record30();
$r30->numero_progressivo = $progressivo;
$r30->descrizione_debitore_1 = $ricevuta->nome_debitore;
//$r30->descrizione_debitore_2 = $ricevuta->indirizzo_debitore;
$r30->codice_fiscale_debitore = $ricevuta->identificativo_debitore;
$contenuto .= $r30->toCBI().$eol;
// Record 40
$r40 = new Record40();
$r40->numero_progressivo = $progressivo;
$r40->indirizzo_debitore = $ricevuta->indirizzo_debitore;
$r40->cap_debitore = $ricevuta->cap_debitore;
$r40->comune_debitore = $ricevuta->comune_debitore;
$r40->provincia_debitore = $ricevuta->provincia_debitore;
$r40->banca_domiciliataria = $ricevuta->descrizione_banca;
$contenuto .= $r40->toCBI().$eol;
// Record 50
$r50 = new Record50();
$r50->numero_progressivo = $progressivo;
$r50->codice_fiscale_creditore = $intestazione->identificativo_creditore;
$r50->riferimento_debito_1 = $ricevuta->descrizione;
$r50->riferimento_debito_2 = $ricevuta->descrizione_origine;
$contenuto .= $r50->toCBI().$eol;
// Record 51
$r51 = new Record51();
$r51->numero_progressivo = $progressivo;
$r51->numero_ricevuta = $ricevuta->numero_ricevuta;
$r51->denominazione_creditore = $intestazione->ragione_soc1_creditore;
$contenuto .= $r51->toCBI().$eol;
// Record 70
$r70 = new Record70();
$r70->numero_progressivo = $progressivo;
$contenuto .= $r70->toCBI().$eol;
}
// Record 70
$ef = new RecordEF();
$ef->codice_sia_mittente = $intestazione->codice_sia;
$ef->abi_assuntrice = $intestazione->abi;
$ef->nome_supporto = $intestazione->nome_supporto;
$ef->data_creazione = $intestazione->data_creazione;
$ef->numero_disposizioni = $progressivo;
$ef->totale_importi_negativi = $totale;
$ef->numero_record = $progressivo * 7 + 2;
$contenuto .= $ef->toCBI().$eol;
return $contenuto;
}
public function asRibaAbiCbi()
{
$formato_intestazione = $this->intestazione->toCbiFormat();
// Trasformazione delle ricevute nel formato relativo
$formato_ricevute = [];
foreach ($this->ricevute as $ricevuta) {
$formato_ricevute[] = $ricevuta->toCbiFormat();
}
// Eccezione in caso di assenza di ricevute interne
if (empty($formato_ricevute)) {
throw new InvalidArgumentException();
}
$cbi = new RibaAbiCbi();
return $cbi->creaFile($formato_intestazione, $formato_ricevute);
}
}

View File

@ -0,0 +1,265 @@
<?php
namespace Plugins\PresentazioniBancarie\RiBa;
/**
* Questa classe genera il file RiBa standard ABI-CBI passando alla funzione "creaFile".
*
* @source GAzie - Gestione Azienda <http://gazie.sourceforge.net>
*
* @license GPL-2.0
* @copyright Copyright (C) 2004-2020 - Antonio De Vincentiis Montesilvano (PE) (http://www.devincentiis.it)
*/
class RibaAbiCbi
{
protected $progressivo = 0;
protected $assuntrice;
protected $data;
protected $valuta;
protected $supporto;
protected $totale;
protected $creditore;
protected $sia_code;
protected $cab_ass;
/**
* @param array $intestazione = [
* [0] => abi_assuntrice variabile lunghezza 5 numerico
* [1] => cab_assuntrice variabile lunghezza 5 numerico
* [2] => conto variabile lunghezza 12 alfanumerico
* [3] => data_creazione variabile lunghezza 6 numerico formato GGMAA
* [4] => nome_supporto variabile lunghezza 20 alfanumerico
* [5] => codice_divisa variabile lunghezza 1 alfanumerico opzionale default "E"
* [6] => ragione_soc1_creditore variabile lunghezza 24 alfanumerico
* [7] => ragione_soc2_creditore variabile lunghezza 24 alfanumerico
* [8] => indirizzo_creditore variabile lunghezza 24 alfanumerico
* [9] => cap_citta_prov_creditore variabile lunghezza 24 alfanumerico
* [10] => codice_fiscale_creditore variabile lunghezza 16 alfanumerico opzionale default ""
* [11] => codice SIA 5 caratteri alfanumerici
* [12] => carry booleano true per aggiungere i caratteri di fine rigo chr(13) e chr(10)
* ]
* @param array $ricevute_bancarie = [
* [0] => numero ricevuta lunghezza 10 numerico
* [1] => scadenza lunghezza 6 numerico
* [2] => importo in centesimi di euro lunghezza 13 numerico
* [3] => nome debitore lunghezza 60 alfanumerico
* [4] => codice fiscale/partita iva debitore lunghezza 16 alfanumerico
* [5] => indirizzo debitore lunghezza 30 alfanumerico
* [6] => cap debitore lunghezza 5 numerico
* [7] => comune debitore lunghezza 25 alfanumerico
* [8] => abi banca domiciliataria lunghezza 5 numerico
* [9] => cab banca domiciliataria lunghezza 5 numerico
* [10] => descrizione banca domiciliataria lunghezza 50 alfanumerico
* [11] => codice cliente attribuito dal creditore lunghezza 16 numerico
* [12] => descrizione del debito lunghezza 40 alfanumerico (CIG CUP)
* [13] => provincia debitore lunghezza 2 alfanumerico
* [14] => descrizione del debito lunghezza 40 alfanumerico (Numero e data riferimento della fattura che ha generato l'effetto)
* ]
*
* @return string
*/
public function creaFile($intestazione, $ricevute_bancarie)
{
$eol = '';
if (isset($intestazione[12])) {
$eol = chr(13).chr(10);
}
$contenuto = $this->RecordIB($intestazione[0], $intestazione[3], $intestazione[4], $intestazione[5], $intestazione[11], $intestazione[1]).$eol;
foreach ($ricevute_bancarie as $ricevuta) { //estraggo le ricevute dall'array
++$this->progressivo;
$contenuto .= $this->Record14($ricevuta[1], $ricevuta[2], $intestazione[0], $intestazione[1], $intestazione[2], $ricevuta[8], $ricevuta[9], $ricevuta[11]).$eol;
$contenuto .= $this->Record20($intestazione[6], $intestazione[7], $intestazione[8], $intestazione[9]).$eol;
$contenuto .= $this->Record30($ricevuta[3], $ricevuta[4]).$eol;
$contenuto .= $this->Record40($ricevuta[5], $ricevuta[6], $ricevuta[7], $ricevuta[10], $ricevuta[13]).$eol;
$contenuto .= $this->Record50($ricevuta[12].' '.$ricevuta[14], $intestazione[10]).$eol;
$contenuto .= $this->Record51($ricevuta[0]).$eol;
$contenuto .= $this->Record70().$eol;
}
$contenuto .= $this->RecordEF().$eol;
return $contenuto;
}
/**
* @param string $string
* @param int $length
*
* @return string
*/
protected function padString($string, $length)
{
// Sostituzione di alcuni simboli noti
$replaces = [
'&#039;' => "'",
'&quot;' => "'",
'&amp;' => '&',
];
$string = str_replace(array_keys($replaces), array_values($replaces), $string);
return substr(str_pad($string, $length), 0, $length);
}
/**
* @param string $string
* @param int $length
*
* @return string
*/
protected function padNumber($string, $length)
{
return str_pad($string, $length, '0', STR_PAD_LEFT);
}
/**
* Record di testa.
*
* @param $abi_assuntrice
* @param $data_creazione
* @param $nome_supporto
* @param $codice_divisa
* @param $sia_code
* @param $cab_assuntrice
*
* @return string
*/
protected function RecordIB($abi_assuntrice, $data_creazione, $nome_supporto, $codice_divisa, $sia_code, $cab_assuntrice)
{
$this->assuntrice = $this->padNumber($abi_assuntrice, 5);
$this->cab_ass = $this->padNumber($cab_assuntrice, 5);
$this->data = str_pad($data_creazione, 6, '0');
$this->valuta = substr($codice_divisa, 0, 1);
$this->supporto = str_pad($nome_supporto, 20, '*', STR_PAD_LEFT);
$this->sia_code = $this->padNumber($sia_code, 5);
return ' IB'.$this->sia_code.$this->assuntrice.$this->data.$this->supporto.str_repeat(' ', 65).'1$'.$this->assuntrice.str_repeat(' ', 2).$this->valuta.str_repeat(' ', 6);
}
/**
* @param string $scadenza
* @param float $importo
* @param string $abi_assuntrice
* @param string $cab_assuntrice
* @param string $conto
* @param string $abi_domiciliataria
* @param string $cab_domiciliataria
* @param string $codice_cliente
*
* @return string
*/
protected function Record14($scadenza, $importo, $abi_assuntrice, $cab_assuntrice, $conto, $abi_domiciliataria, $cab_domiciliataria, $codice_cliente)
{
$this->totale += $importo;
return ' 14'.$this->padNumber($this->progressivo, 7)
.str_repeat(' ', 12).$scadenza.'30000'.$this->padNumber($importo, 13).'-'.$this->padNumber($abi_assuntrice, 5).$this->padNumber($cab_assuntrice, 5).str_pad($conto, 12)
.$this->padNumber($abi_domiciliataria, 5)
.$this->padNumber($cab_domiciliataria, 5)
.str_repeat(' ', 12).$this->sia_code.'4'.str_pad($codice_cliente, 16)
.str_repeat(' ', 6).$this->valuta;
}
/**
* @param string $ragione_soc1_creditore
* @param string $ragione_soc2_creditore
* @param string $indirizzo_creditore
* @param string $cap_citta_prov_creditore
*
* @return string
*/
protected function Record20($ragione_soc1_creditore, $ragione_soc2_creditore, $indirizzo_creditore, $cap_citta_prov_creditore)
{
$this->creditore = str_pad($ragione_soc1_creditore, 24);
return ' 20'.$this->padNumber($this->progressivo, 7)
.substr($this->creditore, 0, 24)
.$this->padString($ragione_soc2_creditore, 24)
.$this->padString($indirizzo_creditore, 24)
.$this->padString($cap_citta_prov_creditore, 24)
.str_repeat(' ', 14);
}
/**
* @param string $nome_debitore
* @param string $codice_fiscale_debitore
*
* @return string
*/
protected function Record30($nome_debitore, $codice_fiscale_debitore)
{
return ' 30'.$this->padNumber($this->progressivo, 7)
.$this->padString($nome_debitore, 60)
.str_pad($codice_fiscale_debitore, 16, ' ')
.str_repeat(' ', 34);
}
/**
* @param string $indirizzo_debitore
* @param string $cap_debitore
* @param string $comune_debitore
* @param string $descrizione_domiciliataria
* @param string $provincia_debitore
*
* @return string
*/
protected function Record40($indirizzo_debitore, $cap_debitore, $comune_debitore, $descrizione_domiciliataria = '', $provincia_debitore = '')
{
return ' 40'.$this->padNumber($this->progressivo, 7)
.$this->padString($indirizzo_debitore, 30)
.$this->padNumber(intval($cap_debitore), 5)
.$this->padString($comune_debitore, 22).' '.$this->padString($provincia_debitore, 2)
.$this->padString($descrizione_domiciliataria, 50);
}
/**
* @param string $descrizione_debito
* @param string $codice_fiscale_creditore
*
* @return string
*/
protected function Record50($descrizione_debito, $codice_fiscale_creditore)
{
return ' 50'.$this->padNumber($this->progressivo, 7)
.$this->padString($descrizione_debito, 80)
.str_repeat(' ', 10)
.str_pad($codice_fiscale_creditore, 16, ' ')
.str_repeat(' ', 4);
}
/**
* @param string $numero_ricevuta_creditore
*
* @return string
*/
protected function Record51($numero_ricevuta_creditore)
{
return ' 51'.$this->padNumber($this->progressivo, 7)
.$this->padNumber($numero_ricevuta_creditore, 10)
.substr($this->creditore, 0, 20)
.str_repeat(' ', 80);
}
/**
* @return string
*/
protected function Record70()
{
return ' 70'.$this->padNumber($this->progressivo, 7)
.str_repeat(' ', 110);
}
/**
* Record di coda.
*
* @return string
*/
protected function RecordEF()
{
return ' EF'.$this->sia_code.$this->assuntrice.$this->data.$this->supporto.str_repeat(' ', 6)
.$this->padNumber($this->progressivo, 7)
.$this->padNumber($this->totale, 15)
.str_repeat('0', 15)
.$this->padNumber($this->progressivo * 7 + 2, 7)
.str_repeat(' ', 24).$this->valuta.str_repeat(' ', 6);
}
}

View File

@ -0,0 +1,113 @@
<?php
namespace Plugins\PresentazioniBancarie\RiBa;
/**
* Classe per gestire i dati della ricevuta bancaria del RiBa.
*
* @property int $numero_ricevuta
* @property string $scadenza
* @property float $importo
* @property string $nome_debitore
* @property string $identificativo_debitore
* @property string $indirizzo_debitore
* @property int $cap_debitore
* @property string $comune_debitore
* @property int $abi_banca
* @property int $cab_banca
* @property string $descrizione_banca
* @property int $codice_cliente
* @property string $descrizione
* @property string $provincia_debitore
* @property string $descrizione_origine
*/
class Ricevuta extends Elemento
{
/**
* @var int Valore numerico di 10 cifre
*/
protected $numero_ricevuta;
/**
* @var string Valore numerico di 6 cifre
*/
protected $scadenza;
/**
* @var float Valore numerico di 13 cifre, con 2 cifre decimali
*/
protected $importo;
/**
* @var string Valore alfanumerico di 60 cifre
*/
protected $nome_debitore;
/**
* Codice fiscale oppure Partita IVA.
*
* @var string Valore alfanumerico di massimo 16 cifre
*/
protected $identificativo_debitore;
/**
* @var string Valore alfanumerico di 30 cifre
*/
protected $indirizzo_debitore;
/**
* @var int Valore numerico di 5 cifre
*/
protected $cap_debitore;
/**
* @var string Valore alfanumerico di 25 cifre
*/
protected $comune_debitore;
/**
* @var int Valore numerico di 5 cifre
*/
protected $abi_banca;
/**
* @var int Valore numerico di 5 cifre
*/
protected $cab_banca;
/**
* @var string Valore alfanumerico di 50 cifre
*/
protected $descrizione_banca;
/**
* Codice cliente attribuito dal creditore.
*
* @var int Valore numerico di 16 cifre
*/
protected $codice_cliente;
/**
* @var string Valore alfanumerico di 40 cifre, con i campi (CIG CUP)
*/
protected $descrizione;
/**
* @var string Valore alfanumerico di 2 cifre
*/
protected $provincia_debitore;
/**
* Numero e data riferimento della fattura che ha generato l'effetto.
*
* @var string Valore alfanumerico di 40 cifre
*/
protected $descrizione_origine;
public function toCbiFormat()
{
return [
$this->numero_ricevuta,
$this->scadenza,
$this->importo,
$this->nome_debitore,
$this->identificativo_debitore,
$this->indirizzo_debitore,
$this->cap_debitore,
$this->comune_debitore,
$this->abi_banca,
$this->cab_banca,
$this->descrizione_banca,
$this->codice_cliente,
$this->descrizione,
$this->provincia_debitore,
$this->descrizione_origine,
];
}
}

View File

@ -27,7 +27,7 @@ switch ($operazione) {
$dbo->insert('an_referenti', [
'idanagrafica' => $id_parent,
'nome' => post('nome'),
'mansione' => post('mansione'),
'idmansione' => post('idmansione'),
'telefono' => post('telefono'),
'email' => post('email'),
'idsede' => post('idsede'),
@ -51,7 +51,7 @@ switch ($operazione) {
$dbo->update('an_referenti', [
'idanagrafica' => $id_parent,
'nome' => post('nome'),
'mansione' => post('mansione'),
'idmansione' => post('idmansione'),
'telefono' => post('telefono'),
'email' => post('email'),
'idsede' => post('idsede'),

View File

@ -34,7 +34,7 @@ echo '
</div>
<div class="col-md-6">
{[ "type": "text", "label": "'.tr('Mansione').'", "name": "mansione", "required": 1 ]}
{[ "type": "select", "label": "'.tr('Mansione').'", "name": "idmansione", "ajax-source": "mansioni", "required": 1 ]}
</div>
</div>
@ -44,7 +44,7 @@ echo '
</div>
<div class="col-md-6">
{[ "type": "text", "label": "'.tr('Indirizzo email').'", "name": "email" ]}
{[ "type": "text", "label": "'.tr('Indirizzo email').'", "name": "email", "class": "email-mask", "validation": "email"]}
</div>
</div>
@ -65,11 +65,3 @@ echo '
</div>
</div>
</form>';
?>
<script>
$(document).ready( function(){
$(document).load("ajax_complete.php?op=get_mansioni", function(response){
$("#mansione").autocomplete({source: response.split("|")});
} );
});
</script>

View File

@ -33,7 +33,7 @@ echo '
</div>
<div class="col-md-6">
{[ "type": "text", "label": "'.tr('Mansione').'", "name": "mansione", "required": 1, "value" : "$mansione$" ]}
{[ "type": "select", "label": "'.tr('Mansione').'", "name": "idmansione", "ajax-source": "mansioni", "required": 1, "value" : "$idmansione$" ]}
</div>
</div>
@ -43,7 +43,7 @@ echo '
</div>
<div class="col-md-6">
{[ "type": "text", "label": "'.tr('Indirizzo email').'", "name": "email", "value" : "$email$" ]}
{[ "type": "text", "label": "'.tr('Indirizzo email').'", "name": "email", "class": "email-mask", "value" : "$email$", "validation": "email" ]}
</div>
</div>
@ -68,11 +68,3 @@ echo '
</div>
</div>
</form>';
?>
<script>
$(document).ready( function(){
$(document).load("ajax_complete.php?op=get_mansioni", function(response){
$("#mansione").autocomplete({source: response.split("|")});
} );
});
</script>

View File

@ -82,7 +82,7 @@ echo '
</div>
<div class="col-md-4">
{[ "type": "text", "label": "'.tr('Indirizzo email').'", "name": "email" ]}
{[ "type": "text", "label": "'.tr('Indirizzo email').'", "name": "email", "class": "email-mask", "validation": "email" ]}
</div>
</div>

View File

@ -92,7 +92,7 @@ echo '
<div class="row">
<div class="col-md-6">
{[ "type": "text", "label": "'.tr('Indirizzo email').'", "name": "email", "value": "$email$" ]}
{[ "type": "text", "label": "'.tr('Indirizzo email').'", "name": "email", "value": "$email$", "class": "email-mask", "validation": "email" ]}
</div>
<div class="col-md-3">

View File

@ -50,14 +50,15 @@ class Referenti extends AppResource implements RetrieveInterface
public function retrieveRecord($id)
{
// Gestione della visualizzazione dei dettagli del record
$query = 'SELECT id,
$query = 'SELECT an_referenti.id,
idanagrafica AS id_cliente,
IF(idsede = 0, NULL, idsede) AS id_sede,
nome,
mansione,
an_referenti.nome,
an_mansioni.nome AS mansione,
telefono,
email
FROM an_referenti
FROM an_referenti
LEFT JOIN an_mansioni ON an_referenti.idmansione=an_mansioni.id
WHERE an_referenti.id = '.prepare($id);
$record = database()->fetchOne($query);

View File

@ -26,15 +26,17 @@ $date_end = $_SESSION['period_end'];
// Raggruppamento
$query = "SELECT data,
DATE_FORMAT(data, '%m-%Y') AS periodo,
SUM(co_righe_documenti.subtotale - co_righe_documenti.sconto) as imponibile,
SUM(iva) as iva,
SUM(co_righe_documenti.subtotale - co_righe_documenti.sconto + iva) as totale
SUM((co_righe_documenti.subtotale - co_righe_documenti.sconto)* IF(co_tipidocumento.reversed, -1, 1)) as imponibile,
SUM((iva)* IF(co_tipidocumento.reversed, -1, 1)) as iva,
SUM((co_righe_documenti.subtotale - co_righe_documenti.sconto + iva)* IF(co_tipidocumento.reversed, -1, 1)) as totale
FROM co_documenti
INNER JOIN co_tipidocumento ON co_documenti.idtipodocumento = co_tipidocumento.id
INNER JOIN co_righe_documenti ON co_righe_documenti.iddocumento = co_documenti.id
INNER JOIN co_statidocumento ON co_documenti.idstatodocumento = co_statidocumento.id
WHERE
(data >= ".prepare($date_start).' AND data <= '.prepare($date_end).')
AND dir = '.prepare($dir).'
AND co_statidocumento.descrizione!="Bozza"
'.$add_where.'
GROUP BY periodo
ORDER BY data ASC';

12
update/2_4_28.php Normal file
View File

@ -0,0 +1,12 @@
<?php
// File e cartelle deprecate
$files = [
'modules/gestione_componenti',
];
foreach ($files as $key => $value) {
$files[$key] = realpath(base_dir().'/'.$value);
}
delete($files);

View File

@ -30,4 +30,78 @@ UPDATE `zz_prints` SET `id_module` = (SELECT `id` FROM `zz_modules` WHERE `name`
UPDATE `zz_prints` SET `id_module` = (SELECT `id` FROM `zz_modules` WHERE `name`='Stampe contabili') WHERE `zz_prints`.`name` = 'Bilancio';
-- Aggiunta stampa libro giornale
INSERT INTO `zz_prints` (`id`, `id_module`, `is_record`, `name`, `title`, `filename`, `directory`, `previous`, `options`, `icon`, `version`, `compatibility`, `order`, `predefined`, `default`, `enabled`) VALUES (NULL, (SELECT `id` FROM `zz_modules` WHERE `name`='Stampe contabili'), '1', 'Libro giornale', 'Libro giornale', 'Libro giornale', 'libro_giornale', 'idconto', '', 'fa fa-print', '', '', '0', '0', '1', '1');
INSERT INTO `zz_prints` (`id`, `id_module`, `is_record`, `name`, `title`, `filename`, `directory`, `previous`, `options`, `icon`, `version`, `compatibility`, `order`, `predefined`, `default`, `enabled`) VALUES (NULL, (SELECT `id` FROM `zz_modules` WHERE `name`='Stampe contabili'), '1', 'Libro giornale', 'Libro giornale', 'Libro giornale', 'libro_giornale', 'idconto', '', 'fa fa-print', '', '', '0', '0', '1', '1');
-- Aggiunta tabella mansioni
CREATE TABLE IF NOT EXISTS `an_mansioni` ( `id` INT NOT NULL AUTO_INCREMENT , `nome` VARCHAR(100) NOT NULL , `created_at` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP , `updated_at` TIMESTAMP on update CURRENT_TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP , PRIMARY KEY (`id`));
INSERT INTO `an_mansioni`(
`nome`
)(
SELECT DISTINCT `mansione` FROM `an_referenti`
);
ALTER TABLE `an_referenti` ADD `idmansione` INT NOT NULL AFTER `idsede`;
UPDATE `an_referenti`, `an_mansioni` SET `idmansione`=`an_mansioni`.`id` WHERE `an_mansioni`.`nome`=`an_referenti`.`mansione`;
ALTER TABLE `an_referenti` DROP `mansione`;
-- Aggiunto modulo mansioni referenti
INSERT INTO `zz_modules` (`id`, `name`, `title`, `directory`, `options`, `options2`, `icon`, `version`, `compatibility`, `order`, `parent`, `default`, `enabled`) VALUES
(NULL, 'Mansioni referenti', 'Mansioni referenti', 'mansioni', 'SELECT |select| FROM an_mansioni ORDER BY `nome`', NULL, 'fa fa-angle-right', '1.0', '2.*', '100', '40', '1', '1');
INSERT INTO `zz_views` (`id`, `id_module`, `name`, `query`, `order`, `visible`, `format`, `default`) VALUES
(NULL, (SELECT `id` FROM `zz_modules` WHERE `name` = 'Mansioni referenti'), 'id', 'an_mansioni.id', 1, 0, 0, 1),
(NULL, (SELECT `id` FROM `zz_modules` WHERE `name` = 'Mansioni referenti'), 'Nome', 'an_mansioni.nome', 2, 1, 0, 1);
UPDATE `zz_plugins` SET `options` = ' { \"main_query\": [ { \"type\": \"table\", \"fields\": \"Nominativo, Mansione, Telefono, Indirizzo email, Sede\", \"query\": \"SELECT an_referenti.id, an_referenti.nome AS Nominativo, an_mansioni.nome AS Mansione, an_referenti.telefono AS Telefono, an_referenti.email AS \'Indirizzo email\', IF(idsede = 0, \'Sede legale\', an_sedi.nomesede) AS Sede FROM an_referenti LEFT OUTER JOIN an_sedi ON idsede = an_sedi.id LEFT OUTER JOIN an_mansioni ON idmansione = an_mansioni.id WHERE 1=1 AND an_referenti.idanagrafica=|id_parent| HAVING 2=2 ORDER BY an_referenti.id DESC\"} ]}' WHERE `zz_plugins`.`name` = 'Referenti';
CREATE TABLE IF NOT EXISTS `em_mansioni_template` ( `id` INT NOT NULL AUTO_INCREMENT , `idmansione` INT NOT NULL , `id_template` INT NOT NULL , `created_at` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP , `updated_at` TIMESTAMP on update CURRENT_TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, PRIMARY KEY (`id`));
-- Aggiunta notifiche ai tecnici assegnati
ALTER TABLE `in_statiintervento` CHANGE `notifica_tecnici` `notifica_tecnico_sessione` TINYINT(4) NOT NULL;
ALTER TABLE `in_statiintervento` ADD `notifica_tecnico_assegnato` TINYINT(4) NOT NULL AFTER `notifica_tecnico_sessione`;
UPDATE `in_statiintervento` SET `notifica_tecnico_assegnato`=`notifica_tecnico_sessione`;
UPDATE `zz_settings` SET `nome` = 'Notifica al tecnico l\'aggiunta della sessione nell\'attività', `order`=15 WHERE `zz_settings`.`nome` = 'Notifica al tecnico l\'assegnazione all\'attività';
UPDATE `zz_settings` SET `nome` = 'Notifica al tecnico la rimozione della sessione dall\'attività', `order`=16 WHERE `zz_settings`.`nome` = 'Notifica al tecnico la rimozione dall\'attività';
INSERT INTO `zz_settings` (`id`, `nome`, `valore`, `tipo`, `editable`, `sezione`, `order`, `help`) VALUES (NULL, 'Notifica al tecnico l''assegnazione all''attività', '0', 'boolean', '1', 'Attività', 17, 'Notifica via email al tecnico l''assegnazione di una nuova attività (l''indirizzo email deve essere specificato nella sua anagrafica)');
INSERT INTO `zz_settings` (`id`, `nome`, `valore`, `tipo`, `editable`, `sezione`, `order`, `help`) VALUES (NULL, 'Notifica al tecnico la rimozione dell''assegnazione dall''attività', '0', 'boolean', '1', 'Attività', 18, 'Notifica via email al tecnico la rimozione dell''assegnazione dall''attività (l''indirizzo email deve essere specificato nella sua anagrafica)');
UPDATE `zz_settings` SET `valore` = '2' WHERE `zz_settings`.`nome` = 'Numero massimo di tentativi';
-- Cambio segno subtotale e iva per righe negative
UPDATE `co_righe_documenti` SET `subtotale`=-`subtotale` WHERE `subtotale`>0 AND `prezzo_unitario`<0;
UPDATE `co_righe_documenti` SET `iva`=-`iva` WHERE `iva`>0 AND `iva_unitaria`<0;
-- Modifica impostazione eliminazione automatica coda d'invio
UPDATE `zz_settings` SET `help` = 'L\'impostazione è valida solamente per l\'eliminazione della coda d\'invio delle newsletter.' WHERE `zz_settings`.`nome` = 'Numero di giorni mantenimento coda di invio';
-- Migliorie modulo Coda di invio
INSERT INTO `zz_segments` (`id_module`, `name`, `clause`, `position`, `pattern`, `note`, `predefined`, `predefined_accredito`, `predefined_addebito`, `is_fiscale`) VALUES
((SELECT `id` FROM `zz_modules` WHERE `name` = 'Stato email'), 'Tutte', '1=1', 'WHR', '####', '', 1, 0, 0, 0),
((SELECT `id` FROM `zz_modules` WHERE `name` = 'Stato email'), 'Non inviate', '1=1 AND sent_at IS NULL', 'WHR', '####', '', 0, 0, 0, 0);
INSERT INTO `zz_views` (`id_module`, `name`, `query`, `order`, `search`, `slow`, `format`, `search_inside`, `order_by`, `visible`, `summable`, `default`) VALUES
((SELECT `id` FROM `zz_modules` WHERE `name` = 'Stato email'), 'Tentativi', '`em_emails`.`attempt`', 7, 1, 0, 0, '', '', 1, 0, 0),
((SELECT `id` FROM `zz_modules` WHERE `name` = 'Stato email'), 'Data creazione', '`em_emails`.`created_at`', 9, 1, 0, 1, '', '', 1, 0, 0);
UPDATE `zz_views` SET `format` = '0' WHERE `zz_views`.`name` = 'Utente' AND id_module=(SELECT `id` FROM `zz_modules` WHERE `name` = 'Stato email');
-- Aggiunto plugin Movimenti in fatture di acquisto, vendita e anagrafiche
INSERT INTO `zz_plugins` (`id`, `name`, `title`, `idmodule_from`, `idmodule_to`, `position`, `script`, `enabled`, `default`, `order`, `compatibility`, `version`, `options2`, `options`, `directory`, `help`) VALUES (NULL, 'Movimenti contabili', 'Movimenti contabili', (SELECT `id` FROM `zz_modules` WHERE `name` = 'Fatture di acquisto'), (SELECT `id` FROM `zz_modules` WHERE `name` = 'Fatture di acquisto'), 'tab', '', '1', '1', '0', '', '', NULL, 'custom', 'movimenti_contabili', '');
INSERT INTO `zz_plugins` (`id`, `name`, `title`, `idmodule_from`, `idmodule_to`, `position`, `script`, `enabled`, `default`, `order`, `compatibility`, `version`, `options2`, `options`, `directory`, `help`) VALUES (NULL, 'Movimenti contabili', 'Movimenti contabili', (SELECT `id` FROM `zz_modules` WHERE `name` = 'Fatture di vendita'), (SELECT `id` FROM `zz_modules` WHERE `name` = 'Fatture di vendita'), 'tab', '', '1', '1', '0', '', '', NULL, 'custom', 'movimenti_contabili', '');
INSERT INTO `zz_plugins` (`id`, `name`, `title`, `idmodule_from`, `idmodule_to`, `position`, `script`, `enabled`, `default`, `order`, `compatibility`, `version`, `options2`, `options`, `directory`, `help`) VALUES (NULL, 'Movimenti contabili', 'Movimenti contabili', (SELECT `id` FROM `zz_modules` WHERE `name` = 'Anagrafiche'), (SELECT `id` FROM `zz_modules` WHERE `name` = 'Anagrafiche'), 'tab', '', '1', '1', '0', '', '', NULL, 'custom', 'movimenti_contabili', '');
-- Aggiunto plugin Presentazioni bancarie
ALTER TABLE `co_scadenziario` ADD `presentazioni_exported_at` TIMESTAMP NULL DEFAULT NULL;
INSERT INTO `zz_plugins` (`id`, `name`, `title`, `idmodule_from`, `idmodule_to`, `position`, `script`, `enabled`, `default`, `order`, `compatibility`, `version`, `options2`, `options`, `directory`, `help`) VALUES (NULL, 'Presentazioni Bancarie', 'Presentazioni Bancarie', (SELECT `id` FROM `zz_modules` WHERE `name` = 'Scadenzario'), (SELECT `id` FROM `zz_modules` WHERE `name` = 'Scadenzario'), 'tab_main', '', '1', '1', '0', '', '', NULL, 'custom', 'presentazioni_bancarie', '');
-- Aggiunte note interne in template email
ALTER TABLE `em_templates` ADD `note_aggiuntive` TEXT NOT NULL AFTER `predefined`;
-- Eliminazione modulo gestione componenti
DELETE FROM `zz_modules` WHERE `zz_modules`.`name` = 'Gestione componenti';