diff --git a/.github/CONTRIBUTING.md b/.github/CONTRIBUTING.md index 724fa6ffe..273f74a1f 100644 --- a/.github/CONTRIBUTING.md +++ b/.github/CONTRIBUTING.md @@ -79,18 +79,18 @@ Cerchiamo di essere disponibili quanto possibile, ma non sempre riusciamo a risp Il progetto presenta, a partire dalla versione 2.4.2, un insieme di test per facilitare il controllo sul corretto funzionamento del gestionale. -Per eseguire i test è necessario seguire le seguenti istruzioni (https://codeception.com/docs/modules/WebDriver): -- Scaricare (Selenium Server)[https://docs.seleniumhq.org/download/] e salvarlo come `selenium-server-standalone.jar` nella cartella principale -- Scaricare (ChromeDriver)[https://sites.google.com/a/chromium.org/chromedriver/getting-started], rendendolo eseguibile da riga di comando (su Windows, aggiungerlo al PATH) -- Configurare localmente Codeception nel file `codeception.yml` con l'URL del web server locale +E' innanzitutto necessario configurare correttamente l'ambiente locale per l'esecuzione dei test: +- Impostare l'URL del web server locale nel file `codeception.yml` per Codeception ```yml modules: config: WebDriver: url: http://localhost/openstamanager ``` -- Eseguire su shell differenti i seguenti comandi: +- Scaricare (ChromeDriver)[https://sites.google.com/a/chromium.org/chromedriver/getting-started], rendendolo eseguibile da riga di comando (su Windows, aggiungerlo al PATH) + +E' quindi possibile eseguire i tests avviando dapprima il server ChromeDriver e poi Codeception in shell differenti: ```bash -npm run tests-server # Avvia i server per i test di funzionamento grafico -npm run tests-OSM # Avvia i test +chromedriver --url-base=/wd/hub +php codecept.phar run --steps ``` diff --git a/CHANGELOG.md b/CHANGELOG.md index 73b36c095..f20dab468 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,54 +4,60 @@ 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.8 (2019-03-01)](#248-2019-03-01) +- [2.4.7 (2019-02-21)](#247-2019-02-21) - [2.4.6 (2019-02-12)](#246-2019-02-12) - - [Aggiunto (Added)](#aggiunto-added) - - [Modificato (Changed)](#modificato-changed) - - [Fixed](#fixed) - [2.4.5 (2019-01-10)](#245-2019-01-10) - - [Aggiunto (Added)](#aggiunto-added-1) - - [Modificato (Changed)](#modificato-changed-1) - - [Fixed](#fixed-1) - [2.4.4 (2018-12-12)](#244-2018-12-12) - - [Aggiunto (Added)](#aggiunto-added-2) - - [Fixed](#fixed-2) - [2.4.3 (2018-12-07)](#243-2018-12-07) - - [Aggiunto (Added)](#aggiunto-added-3) - - [Fixed](#fixed-3) - [2.4.2 (2018-11-14)](#242-2018-11-14) - - [Aggiunto (Added)](#aggiunto-added-4) - - [Modificato (Changed)](#modificato-changed-2) - - [Deprecato (Deprecated)](#deprecato-deprecated) - - [Rimosso (Removed)](#rimosso-removed) - - [Sicurezza (Security)](#sicurezza-security) - [2.4.1 (2018-08-01)](#241-2018-08-01) - - [Aggiunto (Added)](#aggiunto-added-5) - - [Modificato (Changed)](#modificato-changed-3) - - [Fixed](#fixed-4) - [2.4 (2018-03-30)](#24-2018-03-30) - - [Aggiunto (Added)](#aggiunto-added-6) - - [Modificato (Changed)](#modificato-changed-4) - - [Fixed](#fixed-5) - [2.3.1 (2018-02-19)](#231-2018-02-19) - - [Aggiunto (Added)](#aggiunto-added-7) - - [Modificato (Changed)](#modificato-changed-5) - - [Fixed](#fixed-6) - [2.3 (2018-02-16)](#23-2018-02-16) - - [Aggiunto (Added)](#aggiunto-added-8) - - [Modificato (Changed)](#modificato-changed-6) - - [Deprecato (Deprecated)](#deprecato-deprecated-1) - - [Rimosso (Removed)](#rimosso-removed-1) - - [Fixed](#fixed-7) - - [Sicurezza (Security)](#sicurezza-security-1) - [2.2 (2016-11-10)](#22-2016-11-10) - - [Aggiunto (Added)](#aggiunto-added-9) - - [Fixed](#fixed-8) - [2.1 (2015-04-02)](#21-2015-04-02) - - [Aggiunto (Added)](#aggiunto-added-10) - - [Modificato (Changed)](#modificato-changed-7) - - [Fixed](#fixed-9) +## 2.4.8 (2019-03-01) + +### Aggiunto (Added) + + - Possibilità di scorporare l'IVA dal prezzo di vendita nel modulo **Articoli** + - Ritenuta contributi nella stampa di **Fatture di vendita** + - Supporto al campo *NumItem* nella Fatture Elettronica + - Aggiunta la data di scadenza per le **Attività** + +### Modificato (Changed) + + - Miglioramento del caricamento delle opzioni Ajax per i select + - Miglioramento della procedura di importazione: i contenuti vengono importati un po' alla volta, evitando così problemi di *timeout* del server + +### Fixed + + - Fix della procedura di passaggio tra documenti (con supporto agli *sconti incondizionati*) + - Fix di un bug nella movimentazione articoli nel passaggio tra documenti + - Fix della creazione delle categorie articoli e impianti + - Risolti altri bug generali + +## 2.4.7 (2019-02-21) + +### Aggiunto (Added) + + - Aggiunto possibilità per evitare i movimenti causati da Fatture Elettroniche importate + - Supporto delle fatture alle ritenute contributi + - Solleciti di pagamento nel modulo **Scadenzario** + +### Modificato (Changed) + + - Miglioramento del sistema di importazione dei diversi documenti in fattura + +### Fixed + + - Fix di diversi bug nella procedura di importazione XML + - Fix degli sconti nelle note di credito + - Risolti alcuni bug distribuiti + ## 2.4.6 (2019-02-12) ### Aggiunto (Added) diff --git a/actions.php b/actions.php index 7c37ac3d4..18f23d5b0 100644 --- a/actions.php +++ b/actions.php @@ -156,12 +156,9 @@ if ($structure->permission == 'rw') { // Operazioni generiche per i campi personalizzati if (post('op') != null) { - $query = 'SELECT `id`, `name` FROM `zz_fields` WHERE '; - if (!empty($id_plugin)) { - $query .= '`id_plugin` = '.prepare($id_plugin); - } else { - $query .= '`id_module` = '.prepare($id_module); - } + $custom_where = !empty($id_plugin) ? '`id_plugin` = '.prepare($id_plugin) : '`id_module` = '.prepare($id_module); + + $query = 'SELECT `id`, `html_name` AS `name` FROM `zz_fields` WHERE '.$custom_where; $customs = $dbo->fetchArray($query); if (!starts_with(post('op'), 'delete')) { @@ -188,13 +185,25 @@ if ($structure->permission == 'rw') { // Aggiornamento elseif (starts_with(post('op'), 'update')) { + $query = 'SELECT `zz_field_record`.`id_field` FROM `zz_field_record` JOIN `zz_fields` ON `zz_fields`.`id` = `zz_field_record`.`id_field` WHERE id_record = '.prepare($id_record).' AND '.$custom_where; + $customs_present = $dbo->fetchArray($query); + $customs_present = array_column($customs_present, 'id_field'); + foreach ($values as $key => $value) { - $dbo->update('zz_field_record', [ - 'value' => $value, - ], [ - 'id_record' => $id_record, - 'id_field' => $key, - ]); + if (in_array($key, $customs_present)) { + $dbo->update('zz_field_record', [ + 'value' => $value, + ], [ + 'id_record' => $id_record, + 'id_field' => $key, + ]); + } else { + $dbo->insert('zz_field_record', [ + 'id_record' => $id_record, + 'id_field' => $key, + 'value' => $value, + ]); + } } } } diff --git a/ajax_dataload.php b/ajax_dataload.php index b53ae590f..e85d193f3 100644 --- a/ajax_dataload.php +++ b/ajax_dataload.php @@ -2,6 +2,8 @@ include_once __DIR__.'/core.php'; +use Util\Query; + // Informazioni fondamentali $columns = filter('columns'); $order = filter('order')[0]; @@ -32,27 +34,23 @@ $results = [ 'summable' => [], ]; -$query = Util\Query::getQuery($structure); +$query = Query::getQuery($structure); if (!empty($query)) { // CONTEGGIO TOTALE $results['recordsTotal'] = $dbo->fetchNum($query); // RISULTATI VISIBILI - $query = Util\Query::getQuery($structure, $search, $order, $limit); + $query = Query::getQuery($structure, $search, $order, $limit); // Filtri derivanti dai permessi (eventuali) if (empty($id_plugin)) { $query = Modules::replaceAdditionals($id_module, $query); } - $query = str_replace_once('SELECT', 'SELECT SQL_CALC_FOUND_ROWS', $query); - $rows = $dbo->fetchArray($query); - // Conteggio dei record filtrati - $count = $dbo->fetchArray('SELECT FOUND_ROWS()'); - if (!empty($count)) { - $results['recordsFiltered'] = $count[0]['FOUND_ROWS()']; - } + $data = Query::executeAndCount($query); + $rows = $data['results']; + $results['recordsFiltered'] = $data['count']; // SOMME $results['summable'] = Util\Query::getSums($structure, $search); diff --git a/ajax_select.php b/ajax_select.php index 6ef1bf4f5..473f522a4 100644 --- a/ajax_select.php +++ b/ajax_select.php @@ -4,14 +4,16 @@ include_once __DIR__.'/core.php'; if (!isset($resource)) { $op = empty($op) ? filter('op') : $op; - $search = filter('q'); + $search = filter('search'); + $page = filter('page') ?: 0; + $length = filter('length') ?: 100; if (!isset($elements)) { $elements = []; } $elements = (!is_array($elements)) ? explode(',', $elements) : $elements; - $results = AJAX::select($op, $elements, $search); + $results = AJAX::select($op, $elements, $search, $page, $length); echo json_encode($results); } diff --git a/assets/src/xml/fe-stylesheet-1.2.1.xsl b/assets/src/xml/fe-stylesheet-1.2.1.xsl deleted file mode 100644 index 66331dd4e..000000000 --- a/assets/src/xml/fe-stylesheet-1.2.1.xsl +++ /dev/null @@ -1,2543 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + - - - - - - - - - - - - % - - - - - - - - - - - - - - - - - - - - - - - + - - - - - - - - - - - - % - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- - - - - - () - -
-
- - - - - - - - - () - - - - - - - - -
- Tipo dato: - - - (dati relativi a lotti e scadenze) - - -
- - -
- - - - Lotto: - - - Rif. testo: - - - -
-
- - - - -
- - - - Scadenza: - - - Rif. data: - - - - - - - -
-
- - -
- - - - Quantità del suddetto lotto: - - - Rif. numero: - - - -
-
- - - -
- -
- - -
- RIF.AMM. -
-
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- - - - - - - - -
-
- - - - - - - - - - - - - - - - - - -
- -
-
- - - -
- -
-
-
- - - - - - - - - - -
-
- - - - - - - - -
- - - - - - - - - ------------------------ - - - - -
- - - -
- -
- -
- - - - - - - - - - - - - - - - - - - -
- - - - - - - - - -
- -
- - - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Dati ritenuta d'accontoAliquota ritenutaCausale Importo
- - - - - - - - - - - - (ritenuta persone fisiche) - - - (ritenuta persone giuridiche) - - - - - (!!! codice non previsto !!!) - - - - - - - - - - - - - - - - - - - - (decodifica come da modello 770S) - - - - - - - - - -
-
- - - - - - - - - - - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - -
- - - - - - - -
- - -
- - - - - - - - - - -
- - - Identificativo fiscale ai fini IVA: - - - - - - -
- -
- - - - Codice fiscale: - - - - - - -
- -
- - - - Denominazione: - - - - - - -
- -
- - - - Cognome nome: - - - - - - - - - - - - - - - -
- - -
- - - - Regime fiscale: - - - - - - - - - - (ordinario) - - - (contribuenti minimi) - - - (nuove iniziative produttive) - - - (agricoltura e attività connesse e pesca) - - - (vendita sali e tabacchi) - - - (commercio fiammiferi) - - - (editoria) - - - (gestione servizi telefonia pubblica) - - - (rivendita documenti di trasporto pubblico e di sosta) - - - (intrattenimenti, giochi e altre attività di cui alla tariffa allegata al DPR 640/72) - - - (agenzie viaggi e turismo) - - - (agriturismo) - - - (vendite a domicilio) - - - (rivendita beni usati, oggetti d’arte, - d’antiquariato o da collezione) - - - (agenzie di vendite all’asta di oggetti d’arte, - antiquariato o da collezione) - - - (IVA per cassa P.A.) - - - (IVA per cassa - art. 32-bis, D.L. 83/2012) - - - (Regime forfettario) - - - (altro) - - - - - (!!! codice non previsto !!!) - - - - - -
- -
- - - -
- - - - Indirizzo: - - - - - - - - -
- -
- - - - Comune: - - - - - - - - - Provincia: - - - - - - - - - -
-
- - - - Cap: - - - - - - - - - Nazione: - - - - - - - - -
-
-
- - - - Telefono: - - - - - - - - -
- -
- - - - Email: - - - - - - - - - -
- -
- - - - Riferimento Amministrazione: - - - - - - - - - -
- -
- - -
- - - Identificativo fiscale ai fini IVA: - - - - - - -
- -
- - - - Codice fiscale: - - - - - - -
- -
- - - - Cognome nome: - - - - - - - - - - - - - - - -
- -
- - - - Regime fiscale: - - - - - - - - - - (ordinario) - - - (contribuenti minimi) - - - (nuove iniziative produttive) - - - (agricoltura e attività connesse e pesca) - - - (vendita sali e tabacchi) - - - (commercio fiammiferi) - - - (editoria) - - - (gestione servizi telefonia pubblica) - - - (rivendita documenti di trasporto pubblico e di sosta) - - - (intrattenimenti, giochi e altre attività di cui alla tariffa allegata al DPR 640/72) - - - (agenzie viaggi e turismo) - - - (agriturismo) - - - (vendite a domicilio) - - - (rivendita beni usati, oggetti d’arte, - d’antiquariato o da collezione) - - - (agenzie di vendite all’asta di oggetti d’arte, - antiquariato o da collezione) - - - (IVA per cassa P.A.) - - - (IVA per cassa - art. 32-bis, D.L. 83/2012) - - - (Regime forfettario) - - - (altro) - - - - - (!!! codice non previsto !!!) - - - - - -
- - - -
- - - - Indirizzo: - - - - - - - - -
- -
- - - - Comune: - - - - - - - - - Provincia: - - - - - - - - - -
-
- - - - Cap: - - - - - - - - - Nazione: - - - - - - - - -
-
-
-
- -
-
- - - -
- - - -
- - - - - - -
- - -
- - - - - - - -
- - - Identificativo fiscale ai fini IVA: - - - - - - -
- -
- - - - Codice fiscale: - - - - - - -
- -
- - - - Denominazione: - - - - - - -
- -
- - - - Cognome nome: - - - - - - - - - - - - - - - -
- - -
- - - -
- - - - Indirizzo: - - - - - - - - -
- - - -
- - - - Comune: - - - - - - - - - Provincia: - - - - - - - - - -
-
- - - - Cap: - - - - - - - - - Nazione: - - - - - - - - -
-
- - - - Pec: - - - - - -
- - -
-
- - - -
- - - Identificativo fiscale ai fini IVA: - - - - - - -
- -
- - - - Codice fiscale: - - - - - - -
-
- -
- - - - Denominazione: - - - - - - -
- -
- - - - Cognome nome: - - - - - - - - - - - - - - - -
- - - -
- - - - Indirizzo: - - - - - - - - -
- - - -
- - - - Comune: - - - - - - - - - Provincia: - - - - - - - - - -
-
- - - - Cap: - - - - - - - - - Nazione: - - - - - - - - -
-
- - - - Pec: - - - - - -
- - -
- -
-
-
-
- -
- - - - - -
- - - - -
- - -
-
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Tipologia documentoArt. 73Numero documentoData documentoCodice destinatario
- - - - - - - - - - - (fattura) - - - (acconto/anticipo su fattura) - - - (acconto/anticipo su parcella) - - - (nota di credito) - - - (nota di debito) - - - (parcella) - - - (autofattura) - - - - (fattura semplificata) - - - (nota di credito semplificata) - - - (nota di debito semplificata) - - - - - (!!! codice non previsto !!!) - - - - - - - - - - - - - - - - - - - - - - - - - Indicata PEC - - - - - - - - -
- - -
- - - - - - - - - - - - - - - - - -
Causale
- - - - - - - -
-
- -
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
DescrizioneImposta%IVAPrezzo totale
- - - - - - -
- RIF.NORM. -
-
- -
- - - - - - - - - - - - - - - -
- -
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Cod. articoloDescrizioneQuantitàPrezzo unitarioUMSconto o magg.%IVAPrezzo totale
- - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Dati Cassa PrevidenzialeImponibile%Contr.Ritenuta%IVAImporto
- - - - - - - - - - - (Cassa Nazionale Previdenza e Assistenza Avvocati - e Procuratori legali) - - - (Cassa Previdenza Dottori Commercialisti) - - - (Cassa Previdenza e Assistenza Geometri) - - - (Cassa Nazionale Previdenza e Assistenza - Ingegneri e Architetti liberi profess.) - - - (Cassa Nazionale del Notariato) - - - (Cassa Nazionale Previdenza e Assistenza - Ragionieri e Periti commerciali) - - - (Ente Nazionale Assistenza Agenti e Rappresentanti - di Commercio-ENASARCO) - - - (Ente Nazionale Previdenza e Assistenza Consulenti - del Lavoro-ENPACL) - - - (Ente Nazionale Previdenza e Assistenza - Medici-ENPAM) - - - (Ente Nazionale Previdenza e Assistenza - Farmacisti-ENPAF) - - - (Ente Nazionale Previdenza e Assistenza - Veterinari-ENPAV) - - - (Ente Nazionale Previdenza e Assistenza Impiegati - dell'Agricoltura-ENPAIA) - - - (Fondo Previdenza Impiegati Imprese di Spedizione - e Agenzie Marittime) - - - (Istituto Nazionale Previdenza Giornalisti - Italiani-INPGI) - - - (Opera Nazionale Assistenza Orfani Sanitari - Italiani-ONAOSI) - - - (Cassa Autonoma Assistenza Integrativa - Giornalisti Italiani-CASAGIT) - - - (Ente Previdenza Periti Industriali e Periti - Industriali Laureati-EPPI) - - - (Ente Previdenza e Assistenza - Pluricategoriale-EPAP) - - - (Ente Nazionale Previdenza e Assistenza - Biologi-ENPAB) - - - (Ente Nazionale Previdenza e Assistenza - Professione Infermieristica-ENPAPI) - - - (Ente Nazionale Previdenza e Assistenza - Psicologi-ENPAP) - - - (INPS) - - - - - (!!! codice non previsto !!!) - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- - -
- - - -
- - - - - - - - -
RIEPILOGHI IVA E TOTALI
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
esigibilità iva / riferimenti normativi%IVASpese accessorieTotale imponibileTotale imposta
- - - - - - - - - - - - (esigibilità immediata) - - - (esigibilità differita) - - - (scissione dei pagamenti) - - - (!!! codice non previsto !!!) - - - - - - - Esigib. non dich. (si presume immediata) - - - - - -
- -
-
-
- - - - - - - - - - - - - - - - - - - - - - - - 0 - - - - - - - - - -
- Importo bollo - - Sconto/Maggiorazione - - Valuta - - Totale documento -
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- - - - - -
- -
- - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Modalità pagamentoIBANIstitutoData scadenzaImporto
- - - - - - - - - - - Contanti - - - Assegno - - - Assegno circolare - - - Contanti presso Tesoreria - - - Bonifico - - - Vaglia cambiario - - - Bollettino bancario - - - Carta di pagamento - - - RID - - - RID utenze - - - RID veloce - - - RIBA - - - MAV - - - Quietanza erario - - - Giroconto su conti di contabilità speciale - - - Domiciliazione bancaria - - - Domiciliazione postale - - - Bollettino di c/c postale - - - SEPA Direct Debit - - - SEPA Direct Debit CORE - - - SEPA Direct Debit B2B - - - Trattenuta su somme già riscosse - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- - -
- - -
- * -
- -
- -
-
- -
- -
- - - - -
Allegati:
- -
    - -
  • -
    - - - - -
    -
  • - - -
    - -
- -
- - - - -
- - - -
- -
- - - - - -
- - -
- - - -
-
- - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- - -
-
\ No newline at end of file diff --git a/codeception.dist.yml b/codeception.dist.yml index 63e714b01..e268f61b0 100644 --- a/codeception.dist.yml +++ b/codeception.dist.yml @@ -11,3 +11,4 @@ actor_suffix: Tester extensions: enabled: - Codeception\Extension\RunFailed + #- Codeception\Extension\Recorder diff --git a/composer.json b/composer.json index d045ee1e7..671d4bfb6 100644 --- a/composer.json +++ b/composer.json @@ -60,7 +60,7 @@ "symfony/var-dumper": "^3.3" }, "require-dev": { - "codeception/codeception": "2.4.*", + "codeception/codeception": "^2.4", "friendsofphp/php-cs-fixer": "^2.10", "phpmd/phpmd": "2.6.0" }, diff --git a/config/namespaces.php b/config/namespaces.php index e649cfb4b..07cc75097 100644 --- a/config/namespaces.php +++ b/config/namespaces.php @@ -5,6 +5,7 @@ return [ 'modules/anagrafiche' => 'Modules\Anagrafiche', 'modules/articoli' => 'Modules\Articoli', 'modules/ritenute' => 'Modules\Ritenute', + 'modules/ritenute_contributi' => 'Modules\RitenuteContributi', 'modules/rivalse' => 'Modules\Rivalse', 'modules/iva' => 'Modules\Iva', 'modules/ddt' => 'Modules\DDT', @@ -13,6 +14,7 @@ return [ 'modules/preventivi' => 'Modules\Preventivi', 'modules/contratti' => 'Modules\Contratti', 'modules/interventi' => 'Modules\Interventi', + 'modules/pagamenti' => 'Modules\Pagamenti', 'plugins/exportFE' => 'Plugins\ExportFE', 'plugins/importFE' => 'Plugins\ImportFE', 'plugins/receiptFE' => 'Plugins\ReceiptFE', diff --git a/core.php b/core.php index a900822b2..cab7c3788 100644 --- a/core.php +++ b/core.php @@ -87,6 +87,17 @@ if (!API::isAPIRequest()) { } $whoops->register(); + + // Aggiunta di Monolog a Whoops + $whoops->pushHandler(function ($exception, $inspector, $run) use ($logger) { + $logger->addError($exception->getMessage(), [ + 'code' => $exception->getCode(), + 'message' => $exception->getMessage(), + 'file' => $exception->getFile(), + 'line' => $exception->getLine(), + 'trace' => $exception->getTraceAsString(), + ]); + }); } else { $handlers[] = new StreamHandler($docroot.'/logs/api.log', Monolog\Logger::ERROR); } @@ -109,19 +120,6 @@ foreach ($handlers as $handler) { // Imposta Monolog come gestore degli errori Monolog\ErrorHandler::register($logger, [], Monolog\Logger::ERROR, Monolog\Logger::ERROR); -// Aggiunta di Monolog a Whoops -if (App::debug()) { - $whoops->pushHandler(function ($exception, $inspector, $run) use ($logger) { - $logger->addError($exception->getMessage(), [ - 'code' => $exception->getCode(), - 'message' => $exception->getMessage(), - 'file' => $exception->getFile(), - 'line' => $exception->getLine(), - 'trace' => $exception->getTraceAsString(), - ]); - }); -} - // Database $dbo = $database = database(); diff --git a/editor.php b/editor.php index 09ed6041b..fc801e47c 100755 --- a/editor.php +++ b/editor.php @@ -13,12 +13,12 @@ if (empty($id_record) && !empty($id_module)) { include_once App::filepath('include|custom|', 'top.php'); Util\Query::setSegments(false); -$query = Util\Query::getQuery($structure, [ +$query = Util\Query::getQuery($module, [ 'id' => $id_record, ]); Util\Query::setSegments(true); -$has_access = !empty($query) ? $dbo->fetchNum($query) : true; +$has_access = !empty($query) ? $dbo->fetchNum($query) !== 0 : true; if ($has_access) { // Inclusione gli elementi fondamentali @@ -392,7 +392,6 @@ if ($read_only || !empty($block_edit)) { }; window.addEventListener("unload", function(e) { - //console.log(e); $("#main_loading").show(); }); diff --git a/include/common/conti.php b/include/common/conti.php index 329d2796e..c15f060d3 100644 --- a/include/common/conti.php +++ b/include/common/conti.php @@ -47,7 +47,7 @@ if ($show_rivalsa == 1 || $show_ritenuta_acconto == 1) { if ($show_rivalsa == 1) { echo '
- {[ "type": "select", "label": "'.tr('Rivalsa').'", "name": "id_rivalsa_inps", "value": "'.$id_rivalsa_inps.'", "values": "query=SELECT * FROM co_rivalse", "help": "'.(($options['dir'] == 'entrata') ? setting("Tipo Cassa") : null).'" ]} + {[ "type": "select", "label": "'.tr('Rivalsa').'", "name": "id_rivalsa_inps", "value": "'.$id_rivalsa_inps.'", "values": "query=SELECT * FROM co_rivalse", "help": "'.(($options['dir'] == 'entrata') ? setting('Tipo Cassa') : null).'" ]}
'; } @@ -71,12 +71,28 @@ if ($show_rivalsa == 1 || $show_ritenuta_acconto == 1) { '; } -// Conto -if (empty($options['hide_conto'])) { +if (!empty($options['show-ritenuta-contributi']) || empty($options['hide_conto'])) { + $width = !empty($options['show-ritenuta-contributi']) && empty($options['hide_conto']) ? 6 : 12; + echo ' -
-
- {[ "type": "select", "label": "'.tr('Conto').'", "name": "idconto", "required": 1, "value": "'.$result['idconto'].'", "ajax-source": "'.$options['conti'].'" ]} -
+
'; + + // Ritenuta contributi + if (!empty($options['show-ritenuta-contributi'])) { + echo ' +
+ {[ "type": "checkbox", "label": "'.tr('Ritenuta contributi').'", "name": "ritenuta_contributi", "value": "'.$result['ritenuta_contributi'].'" ]}
'; + } + + // Conto + if (empty($options['hide_conto'])) { + echo ' +
+ {[ "type": "select", "label": "'.tr('Conto').'", "name": "idconto", "required": 1, "value": "'.$result['idconto'].'", "ajax-source": "'.$options['conti'].'" ]} +
'; + } + + echo ' +
'; } diff --git a/include/common/form.php b/include/common/form.php index e59fb6c65..51c9f27b3 100644 --- a/include/common/form.php +++ b/include/common/form.php @@ -2,9 +2,7 @@ $result['id'] = isset($result['id']) ? $result['id'] : null; -/* - Form di inserimento riga documento -*/ +// Form di inserimento riga documento echo '
diff --git a/include/common/importa.php b/include/common/importa.php new file mode 100644 index 000000000..2403bcd44 --- /dev/null +++ b/include/common/importa.php @@ -0,0 +1,309 @@ +fetchOne('SELECT * FROM '.$table.' WHERE id = '.prepare($id_record)); +$numero = !empty($documento['numero_esterno']) ? $documento['numero_esterno'] : $documento['numero']; +$id_anagrafica = $documento['idanagrafica']; +$id_pagamento = $documento['idpagamento']; +$id_conto = $documento['idconto']; + +if (empty($documento)) { + return; +} + +$id_iva = $id_iva ?: setting('Iva predefinita'); +if (empty($id_conto)) { + $id_conto = ($dir == 'entrata') ? setting('Conto predefinito fatture di vendita') : setting('Conto predefinito fatture di acquisto'); +} + +// Selezione articoli dell'ordine da portare nel ddt +$righe = $dbo->fetchArray('SELECT *, IFNULL((SELECT codice FROM mg_articoli WHERE id=idarticolo),"") AS codice, (qta - qta_evasa) AS qta_rimanente FROM '.$table.' INNER JOIN '.$rows.' ON '.$table.'.id='.$rows.'.'.$id_rows.' WHERE '.$table.'.id='.prepare($id_record).' HAVING qta_rimanente > 0 OR is_descrizione = 1 ORDER BY `order`'); + +if (!empty($righe)) { + echo ' + + + + + + + + + + + + '; + + // Creazione fattura dal documento + if (!empty($options['create_document'])) { + echo ' +
+ + +
+ {[ "type": "date", "label": "'.tr('Data del documento').'", "name": "data", "required": 1, "value": "-now-" ]} +
'; + + if ($final_module['name'] == 'Fatture di vendita' || $final_module['name'] == 'Fatture di acquisto') { + if ($op == 'nota_accredito' && !empty($segmenti)) { + $segmento = $dbo->fetchOne("SELECT * FROM zz_segments WHERE predefined_accredito='1'"); + + $id_segment = $segmento['id']; + } else { + $id_segment = $_SESSION['module_'.$final_module['id']]['id_segment']; + } + + echo ' +
+ {[ "type": "select", "label": "'.tr('Sezionale').'", "name": "id_segment", "required": 1, "values": "query=SELECT id, name AS descrizione FROM zz_segments WHERE id_module='.prepare($final_module['id']).' ORDER BY name", "value": "'.$id_segment.'" ]} +
'; + } + + echo ' +
'; + } + + // Conto + if (($final_module['name'] == 'Fatture di vendita' || $final_module['name'] == 'Fatture di acquisto') && !($original_module['name'] == 'Fatture di vendita' || $original_module['name'] == 'Fatture di acquisto')) { + echo ' +
+
+ {[ "type": "select", "label": "'.tr('Conto').'", "name": "id_conto", "required": 1, "value": "'.$id_conto.'", "ajax-source": "'.($dir == 'entrata' ? 'conti-vendite' : 'conti-acquisti').'" ]} +
+
'; + } + + echo ' +
+
+ +

'.tr('Seleziona le righe e le relative quantità da inserire nel documento').'.

+ + + + + + + '; + + if (!empty($options['serials'])) { + echo ' + '; + } + + echo ' + '; + + $totale = 0.00; + + foreach ($righe as $i => $r) { + // Descrizione + echo ' + + '; + + // Q.tà rimanente + echo ' + '; + + // Q.tà da evadere + echo ' + '; + + // Subtotale + $subtotale = $r['subtotale'] / $r['qta'] * ($r['qta'] - $r['qta_evasa']); + $sconto = $r['sconto'] / $r['qta'] * ($r['qta'] - $r['qta_evasa']); + $iva = $r['iva'] / $r['qta'] * ($r['qta'] - $r['qta_evasa']); + + echo ' + '; + + // Seriali + if (!empty($options['serials'])) { + echo ' + '; + } + + echo ' + '; + + $totale += $subtotale - $sconto + $iva; + } + + // Totale + echo ' + + + + +
'.tr('Descrizione').''.tr('Q.tà').''.tr('Q.tà da evadere').''.tr('Subtot.').''.tr('Seriali').'
+ + + + '; + + // Checkbox - da evadere? + echo ' + '; + + $descrizione = (!empty($r['codice']) ? $r['codice'].' - ' : '').$r['descrizione']; + + echo ' '.nl2br($descrizione); + + echo ' + + + +

'.Translator::numberToLocale($r['qta_rimanente']).'

+
+ {[ "type": "number", "name": "qta_da_evadere['.$r['id'].']", "id": "qta_'.$i.'", "required": 1, "value": "'.$r['qta_rimanente'].'", "extra" : "onkeyup=\"ricalcola_subtotale_riga('.$i.');\"", "decimals": "qta", "min-value": "0", "extra": "'.(($r['is_descrizione']) ? 'readonly' : '').'" ]} + + + + + + + '.Translator::numberToLocale($subtotale - $sconto + $iva).' €
+ + '.Translator::numberToLocale($subtotale - $sconto).' + '.Translator::numberToLocale($iva).' +
'; + + if (!empty($r['abilita_serial'])) { + $query = 'SELECT DISTINCT serial AS id, serial AS descrizione FROM mg_prodotti WHERE dir='.prepare($dir).' AND '.$options['serials']['id_riga'].' = '.prepare($r['id']).' AND serial IS NOT NULL AND serial NOT IN (SELECT serial FROM mg_prodotti AS t WHERE serial IS NOT NULL AND dir='.prepare($dir).' AND '.$options['serials']['condition'].')'; + + $values = $dbo->fetchArray($query); + if (!empty($values)) { + echo ' + {[ "type": "select", "name": "serial['.$r['id'].'][]", "id": "serial_'.$i.'", "multiple": 1, "values": "query='.$query.'", "value": "'.implode(',', array_column($values, 'id')).'", "extra": "data-maximum=\"'.intval($r['qta_rimanente']).'\"" ]}'; + } + } + + if (empty($r['abilita_serial']) || empty($values)) { + echo '-'; + } + + echo ' +
+ '.tr('Totale').': + + '.Translator::numberToLocale($totale).' € +
'; + + echo ' + + +
+
+ +
+
+
'; +} else { + echo ' +

'.tr('Non ci sono elementi da evadere').'...

'; +} + +echo ' +'; + +?> + + diff --git a/include/common/riga.php b/include/common/riga.php index 4a96a96dc..115a65f91 100644 --- a/include/common/riga.php +++ b/include/common/riga.php @@ -81,7 +81,7 @@ echo ' // Sconto unitario echo '
- {[ "type": "number", "label": "'.tr('Sconto unitario').'", "name": "sconto", "value": "'.$result['sconto_unitario'].'", "icon-after": "choice|untprc|'.$result['tipo_sconto'].'" ]} + {[ "type": "number", "label": "'.tr('Sconto unitario').'", "name": "sconto", "value": "'.$result['sconto_unitario'].'", "icon-after": "choice|untprc|'.$result['tipo_sconto'].'", "help": "'.tr('Il valore positivo indica uno sconto. Per applicare un rincaro inserire un valore negativo.').'" ]}
'; diff --git a/include/init/init.php b/include/init/init.php index 5e1435f12..71a0db3a4 100644 --- a/include/init/init.php +++ b/include/init/init.php @@ -67,6 +67,7 @@ if (post('action') == 'init') { 'nome' => 'Amministratori', ]); + // Creazione utente Amministratore $dbo->insert('zz_users', [ 'username' => post('admin_username'), 'password' => Auth::hashPassword(post('admin_password')), @@ -75,6 +76,12 @@ if (post('action') == 'init') { 'idanagrafica' => isset($id_record) ? $id_record : 0, 'enabled' => 1, ]); + + // Creazione token API per l'amministratore + $dbo->insert('zz_tokens', [ + 'id_utente' => $dbo->lastInsertedID(), + 'token' => secure_random_string(), + ]); } if (!$has_settings) { diff --git a/include/init/update.php b/include/init/update.php index 78401ed2f..118ccc40e 100644 --- a/include/init/update.php +++ b/include/init/update.php @@ -233,7 +233,7 @@ if (filter('action') == 'do_update') { $("#progress .info").html($("#progress .info").html() + "

'.tr('Aggiornamento _DONE_ di _TODO_ (_VERSION_)', [ '_DONE_' => '" + current + "', '_TODO_' => '" + count + "', - '_VERSION_' => '" + version + "', + '_VERSION_' => '" + version.trim() + "', ]).'

"); } } diff --git a/include/src/Components/Article.php b/include/src/Components/Article.php index 6670e6261..45e9b9779 100644 --- a/include/src/Components/Article.php +++ b/include/src/Components/Article.php @@ -9,7 +9,7 @@ use UnexpectedValueException; abstract class Article extends Row { - protected $serialRowID = 'documento'; + protected $serialRowID = null; protected $abilita_movimentazione = true; protected $qta_movimentazione = 0; diff --git a/include/src/Components/Description.php b/include/src/Components/Description.php index ea0ea411c..af224110d 100644 --- a/include/src/Components/Description.php +++ b/include/src/Components/Description.php @@ -127,6 +127,7 @@ abstract class Description extends Model */ protected function customInitCopiaIn($original) { + $this->is_descrizione = $original->is_descrizione; } /** diff --git a/include/src/Components/Row.php b/include/src/Components/Row.php index 0e3eb202f..f2cfbcda2 100644 --- a/include/src/Components/Row.php +++ b/include/src/Components/Row.php @@ -5,13 +5,16 @@ namespace Common\Components; use Common\Document; use Illuminate\Database\Eloquent\Builder; use Modules\Iva\Aliquota; -use Modules\Ritenute\RitenutaAcconto; -use Modules\Rivalse\RivalsaINPS; abstract class Row extends Description { protected $prezzo_unitario_vendita_riga = null; + protected $casts = [ + 'qta' => 'float', + //'qta_evasa' => 'float', + ]; + public static function build(Document $document, $bypass = false) { return parent::build($document, true); @@ -44,23 +47,13 @@ abstract class Row extends Description } /** - * Restituisce il totale (imponibile + iva + rivalsa_inps + iva_rivalsainps) dell'elemento. + * Restituisce il totale (imponibile + iva) dell'elemento. * * @return float */ public function getTotaleAttribute() { - return $this->imponibile_scontato + $this->iva + $this->rivalsa_inps + $this->iva_rivalsa_inps; - } - - /** - * Restituisce il netto a pagare (totale - ritenuta_acconto) dell'elemento. - * - * @return float - */ - public function getNettoAttribute() - { - return $this->totale - $this->ritenuta_acconto; + return $this->imponibile_scontato + $this->iva; } /** @@ -85,27 +78,6 @@ abstract class Row extends Description // Attributi della componente - public function getRivalsaINPSAttribute() - { - return $this->imponibile_scontato / 100 * $this->rivalsa->percentuale; - } - - public function getIvaRivalsaINPSAttribute() - { - return $this->rivalsa_inps / 100 * $this->aliquota->percentuale; - } - - public function getRitenutaAccontoAttribute() - { - $result = $this->imponibile_scontato; - - if ($this->calcolo_ritenuta_acconto == 'IMP+RIV') { - $result += $this->rivalsainps; - } - - return $result / 100 * $this->ritenuta->percentuale; - } - public function getIvaIndetraibileAttribute() { return $this->iva / 100 * $this->aliquota->indetraibile; @@ -141,28 +113,6 @@ abstract class Row extends Description ]); } - /** - * Imposta l'identificatore della Rivalsa INPS. - * - * @param int $value - */ - public function setIdRivalsaINPSAttribute($value) - { - $this->attributes['idrivalsainps'] = $value; - $this->load('rivalsa'); - } - - /** - * Imposta l'identificatore della Ritenuta d'Acconto. - * - * @param int $value - */ - public function setIdRitenutaAccontoAttribute($value) - { - $this->attributes['idritenutaacconto'] = $value; - $this->load('ritenuta'); - } - /** * Imposta l'identificatore dell'IVA. * @@ -210,8 +160,6 @@ abstract class Row extends Description $this->fixSconto(); $this->fixIva(); - $this->fixRitenutaAcconto(); - $this->fixRivalsaINPS(); return parent::save($options); } @@ -221,16 +169,6 @@ abstract class Row extends Description return $this->belongsTo(Aliquota::class, 'idiva'); } - public function rivalsa() - { - return $this->belongsTo(RivalsaINPS::class, 'idrivalsainps'); - } - - public function ritenuta() - { - return $this->belongsTo(RitenutaAcconto::class, 'idritenutaacconto'); - } - protected static function boot($bypass = false) { parent::boot(true); @@ -250,22 +188,6 @@ abstract class Row extends Description $this->attributes['subtotale'] = $this->imponibile; } - /** - * Effettua i conti per la Rivalsa INPS. - */ - protected function fixRivalsaINPS() - { - $this->attributes['rivalsainps'] = $this->rivalsa_inps; - } - - /** - * Effettua i conti per la Ritenuta d'Acconto, basandosi sul valore del campo calcolo_ritenuta_acconto. - */ - protected function fixRitenutaAcconto() - { - $this->attributes['ritenutaacconto'] = $this->ritenuta_acconto; - } - /** * Effettua i conti per l'IVA. */ diff --git a/include/src/Document.php b/include/src/Document.php index 8e0f679d5..07a2d07d5 100644 --- a/include/src/Document.php +++ b/include/src/Document.php @@ -27,7 +27,7 @@ abstract class Document extends Model abstract public function scontoGlobale(); /** - * Calcola l'imponibile della fattura. + * Calcola l'imponibile del documento. * * @return float */ @@ -37,7 +37,7 @@ abstract class Document extends Model } /** - * Calcola lo sconto totale della fattura. + * Calcola lo sconto totale del documento. * * @return float */ @@ -47,7 +47,7 @@ abstract class Document extends Model } /** - * Calcola l'imponibile scontato della fattura. + * Calcola l'imponibile scontato del documento. * * @return float */ @@ -57,47 +57,17 @@ abstract class Document extends Model } /** - * Calcola l'IVA totale della fattura. + * Calcola l'IVA totale del documento. * * @return float */ public function getIvaAttribute() { - return $this->calcola('iva', 'iva_rivalsa_inps'); + return $this->calcola('iva'); } /** - * Calcola la rivalsa INPS totale della fattura. - * - * @return float - */ - public function getRivalsaINPSAttribute() - { - return $this->calcola('rivalsa_inps'); - } - - /** - * Calcola l'iva della rivalsa INPS totale della fattura. - * - * @return float - */ - public function getIvaRivalsaINPSAttribute() - { - return $this->calcola('iva_rivalsa_inps'); - } - - /** - * Calcola la ritenuta d'acconto totale della fattura. - * - * @return float - */ - public function getRitenutaAccontoAttribute() - { - return $this->calcola('ritenuta_acconto'); - } - - /** - * Calcola il totale della fattura. + * Calcola il totale del documento. * * @return float */ @@ -106,16 +76,6 @@ abstract class Document extends Model return $this->calcola('totale'); } - /** - * Calcola il netto a pagare della fattura. - * - * @return float - */ - public function getNettoAttribute() - { - return $this->calcola('netto'); - } - /** * Calcola la spesa totale relativa alla fattura. * @@ -127,7 +87,7 @@ abstract class Document extends Model } /** - * Calcola il guadagno della fattura. + * Calcola il guadagno del documento. * * @return float */ diff --git a/lib/common.php b/lib/common.php index 6657713dc..570680376 100644 --- a/lib/common.php +++ b/lib/common.php @@ -213,18 +213,8 @@ function doc_references($info, $dir, $ignore = []) $module = null; $id = null; - // Ordine - if (!empty($info['idordine'])) { - $data = $dbo->fetchArray("SELECT IF(numero_esterno != '', numero_esterno, numero) AS numero, data FROM or_ordini WHERE id=".prepare($info['idordine'])); - - $module = ($dir == 'entrata') ? 'Ordini cliente' : 'Ordini fornitore'; - $id = $info['idordine']; - - $document = tr('Ordine'); - } - // DDT - elseif (!empty($info['idddt'])) { + if (!empty($info['idddt'])) { $data = $dbo->fetchArray("SELECT IF(numero_esterno != '', numero_esterno, numero) AS numero, data FROM dt_ddt WHERE id=".prepare($info['idddt'])); $module = ($dir == 'entrata') ? 'Ddt di vendita' : 'Ddt di acquisto'; @@ -233,6 +223,16 @@ function doc_references($info, $dir, $ignore = []) $document = tr('Ddt'); } + // Ordine + elseif (!empty($info['idordine'])) { + $data = $dbo->fetchArray("SELECT IF(numero_esterno != '', numero_esterno, numero) AS numero, data FROM or_ordini WHERE id=".prepare($info['idordine'])); + + $module = ($dir == 'entrata') ? 'Ordini cliente' : 'Ordini fornitore'; + $id = $info['idordine']; + + $document = tr('Ordine'); + } + // Preventivo elseif (!empty($info['idpreventivo'])) { $data = $dbo->fetchArray('SELECT numero, data_bozza AS data FROM co_preventivi WHERE id='.prepare($info['idpreventivo'])); diff --git a/lib/functions.js b/lib/functions.js index bbcc2c911..e83fa85f5 100644 --- a/lib/functions.js +++ b/lib/functions.js @@ -506,8 +506,7 @@ function launch_modal(title, href, init_modal, id) { } } -// Datatable -function start_datatables() { +function start_local_datatables(){ $('.datatables').each(function () { if (!$.fn.DataTable.isDataTable($(this))) { $(this).DataTable({ @@ -524,6 +523,11 @@ function start_datatables() { }); } }); +} + +// Datatable +function start_datatables() { + start_local_datatables(); $('.main-records').each(function () { var $this = $(this); @@ -972,13 +976,23 @@ function start_superselect() { delay: 250, data: function (params) { return { - q: params.term // search term + search: params.term, + page: params.page || 0, + length: params.length || 100, } }, - processResults: function (data) { - return { - results: data - } + processResults: function (data, params) { + params.page = params.page || 0; + params.length = params.length || 100; + + var response = { + results: data.results, + pagination: { + more: (params.page + 1) * params.length < data.recordsFiltered, + } + }; + + return response; }, cache: false }, diff --git a/lib/helpers.php b/lib/helpers.php index d4569f87e..00579de71 100644 --- a/lib/helpers.php +++ b/lib/helpers.php @@ -175,3 +175,60 @@ function logger() { return Monolog\Registry::getInstance('logs'); } + +/** + * Restituisce il numero indicato formattato secondo la configurazione del sistema. + * + * @param float $number + * @param int $decimals + * + * @return string + * + * @since 2.4.8 + */ +function numberFormat($number, $decimals) +{ + return Translator::numberToLocale($number, $decimals); +} + +/** + * Restituisce il timestamp indicato formattato secondo la configurazione del sistema. + * + * @param string $timestamp ++ * + * @return string + * + * @since 2.4.8 + */ +function timestampFormat($timestamp) +{ + return Translator::timestampToLocale($timestamp); +} + +/** + * Restituisce la data indicata formattato secondo la configurazione del sistema. + * + * @param string $date + * + * @return string + * + * @since 2.4.8 + */ +function dateFormat($date) +{ + return Translator::dateToLocale($date); +} + +/** + * Restituisce l'orario indicato formattato secondo la configurazione del sistema. + * + * @param string $time + * + * @return string + * + * @since 2.4.8 + */ +function timeFormat($time) +{ + return Translator::timeToLocale($time); +} diff --git a/lib/util.php b/lib/util.php index 49055a533..74a355441 100644 --- a/lib/util.php +++ b/lib/util.php @@ -77,30 +77,6 @@ if (!function_exists('ends_with')) { } } -if (!function_exists('str_replace_once')) { - /** - * Sostituisce la prima occorenza di una determinata stringa. - * - * @param string $str_pattern - * @param string $str_replacement - * @param string $string - * - * @since 2.3 - * - * @return string - */ - function str_replace_once($str_pattern, $str_replacement, $string) - { - if (strpos($string, $str_pattern) !== false) { - $occurrence = strpos($string, $str_pattern); - - return substr_replace($string, $str_replacement, strpos($string, $str_pattern), strlen($str_pattern)); - } - - return $string; - } -} - if (!function_exists('str_contains')) { /** * Check if a string contains the given string. diff --git a/mail.php b/mail.php index a826d1eb1..836474367 100644 --- a/mail.php +++ b/mail.php @@ -98,7 +98,7 @@ echo ' $attachments = []; if ($template['name'] == 'Fattura Elettronica') { - $attachments = $dbo->fetchArray('SELECT id FROM zz_files WHERE id_module = '.prepare($module['id']).' AND id_record = '.prepare($id_record).' AND category = \'Fattura elettronica\''); + $attachments = $dbo->fetchArray('SELECT id FROM zz_files WHERE id_module = '.prepare($module['id']).' AND id_record = '.prepare($id_record).' AND category = \'Fattura Elettronica\''); $attachments = array_column($attachments, 'id'); } diff --git a/modules/aggiornamenti/upload_modules.php b/modules/aggiornamenti/upload_modules.php index bc993829f..d07d12f8d 100644 --- a/modules/aggiornamenti/upload_modules.php +++ b/modules/aggiornamenti/upload_modules.php @@ -50,7 +50,7 @@ if (file_exists($extraction_dir.'/VERSION')) { $table = 'zz_modules'; $installed = Modules::get($info['name']); - $insert['parent'] = Modules::get($info['parent']); + $insert['parent'] = Modules::get($info['parent'])['id']; $insert['icon'] = $info['icon']; } diff --git a/modules/anagrafiche/actions.php b/modules/anagrafiche/actions.php index 31ed8dfb6..5759d8e0a 100644 --- a/modules/anagrafiche/actions.php +++ b/modules/anagrafiche/actions.php @@ -91,7 +91,7 @@ switch (post('op')) { // Validazione della Partita IVA $partita_iva = $anagrafica->partita_iva; - $partita_iva = strlen($partita_iva) == 11 ? $anagrafica->nazione->iso2.$partita_iva : $partita_iva; + $partita_iva = is_numeric($partita_iva) ? $anagrafica->nazione->iso2.$partita_iva : $partita_iva; $check_vat_number = Validate::isValidVatNumber($partita_iva); if (empty($check_vat_number)) { diff --git a/modules/anagrafiche/add.php b/modules/anagrafiche/add.php index a159b7a6a..308058618 100644 --- a/modules/anagrafiche/add.php +++ b/modules/anagrafiche/add.php @@ -23,13 +23,16 @@ echo '
+ +
+ {[ "type": "text", "label": "'.tr('Cognome').'", "name": "cognome", "required": 0 ]} +
+
{[ "type": "text", "label": "'.tr('Nome').'", "name": "nome", "required": 0 ]}
-
- {[ "type": "text", "label": "'.tr('Cognome').'", "name": "cognome", "required": 0 ]} -
+
'; echo ' diff --git a/modules/anagrafiche/ajax/select.php b/modules/anagrafiche/ajax/select.php index d2b85fd24..a37bee004 100644 --- a/modules/anagrafiche/ajax/select.php +++ b/modules/anagrafiche/ajax/select.php @@ -87,7 +87,7 @@ switch ($resource) { $search_fields[] = 'provincia LIKE '.prepare('%'.$search.'%'); } - $results = AJAX::completeResults($query, $where, $filter, $search, $custom); + $results = AJAX::selectResults($query, $where, $filter, $search, $limit, $custom); // Evidenzia l'agente di default if ($superselect['idanagrafica']) { diff --git a/modules/anagrafiche/edit.php b/modules/anagrafiche/edit.php index 70dfab6d8..c0e2fc6f4 100644 --- a/modules/anagrafiche/edit.php +++ b/modules/anagrafiche/edit.php @@ -335,9 +335,9 @@ if (!empty($google)) { {[ "type": "select", "label": "", "name": "idlistino_vendite", "values": "query=SELECT id, nome AS descrizione FROM mg_listini ORDER BY nome ASC", "value": "$idlistino_vendite$", "extra": "" ]} -
- {[ "type": "select", "label": "", "name": "idsede_fatturazione", "values": "query=SELECT id, IF(citta = '', nomesede, CONCAT_WS(', ', nomesede, citta)) AS descrizione FROM an_sedi WHERE idanagrafica='' UNION SELECT '0' AS id, 'Sede legale' AS descrizione ORDER BY descrizione", "value": "$idsede_fatturazione$" , "extra": "" ]} -
+
+ {[ "type": "select", "label": "", "name": "idsede_fatturazione", "values": "query=SELECT id, IF(citta = '', nomesede, CONCAT_WS(', ', nomesede, citta)) AS descrizione FROM an_sedi WHERE idanagrafica='' UNION SELECT '0' AS id, 'Sede legale' AS descrizione ORDER BY descrizione", "value": "$idsede_fatturazione$" , "extra": "" ]} +
@@ -349,31 +349,27 @@ if (!empty($google)) { {[ "type": "select", "label": "", "name": "idagente", "values": "query=SELECT an_anagrafiche.idanagrafica AS id, IF(deleted_at IS NOT NULL, CONCAT(ragione_sociale, ' (Eliminato)'), ragione_sociale ) AS descrizione FROM an_anagrafiche INNER JOIN (an_tipianagrafiche_anagrafiche INNER JOIN an_tipianagrafiche ON an_tipianagrafiche_anagrafiche.idtipoanagrafica=an_tipianagrafiche.idtipoanagrafica) ON an_anagrafiche.idanagrafica=an_tipianagrafiche_anagrafiche.idanagrafica WHERE (descrizione='Agente' AND deleted_at IS NULL)ORDER BY ragione_sociale", "value": "$idagente$", "extra": "" ]}
+ +
-fetchOne('SELECT co_pianodeiconti2.numero as numero, co_pianodeiconti3.numero as numero_conto, co_pianodeiconti3.descrizione as descrizione FROM co_pianodeiconti3 INNER JOIN co_pianodeiconti2 ON co_pianodeiconti3.idpianodeiconti2=co_pianodeiconti2.id WHERE co_pianodeiconti3.id = '.prepare($record['idconto_cliente'])); + // Collegamento con il conto + $conto = $dbo->fetchOne('SELECT co_pianodeiconti2.numero as numero, co_pianodeiconti3.numero as numero_conto, co_pianodeiconti3.descrizione as descrizione FROM co_pianodeiconti3 INNER JOIN co_pianodeiconti2 ON co_pianodeiconti3.idpianodeiconti2=co_pianodeiconti2.id WHERE co_pianodeiconti3.id = '.prepare($record['idconto_cliente'])); - /*echo ' -

'.tr('Piano dei conti collegato: _NAME_', [ - '_NAME_' => $conto['numero'].'.'.$conto['numero_conto'].' '.$conto['descrizione'], - ]).Modules::link('Piano dei conti', null, '').'

';*/ if (!empty($conto['numero_conto'])) { $piano_dei_conti_cliente = tr('_NAME_', [ - '_NAME_' => $conto['numero'].'.'.$conto['numero_conto'].' '.$conto['descrizione'], - ]); + '_NAME_' => $conto['numero'].'.'.$conto['numero_conto'].' '.$conto['descrizione'], + ]); echo Modules::link('Piano dei conti', null, null, null, 'class="pull-right"'); } else { $piano_dei_conti_cliente = tr('Nessuno'); } ?> - {[ "type": "select", "label": "", "name": "piano_dei_conti_cliente", "values": "list=\"\": \"\"", "readonly": 1, "value": "", "extra": "" ]} - -
- -
+ {[ "type": "select", "label": "", "name": "piano_dei_conti_cliente", "values": "list=\"\": \"\"", "readonly": 1, "value": "", "extra": "" ]} + + @@ -545,7 +541,7 @@ if (!empty($google)) { if (setting('Azienda predefinita') == $id_record) { echo ' -
'.tr('Per impostare il logo delle stampe, caricare un file ".jpg" specificando come nome dell\'allegato "Logo stampe" (Risoluzione consigliata 302x111 pixel)').'.
'; +
'.tr('Per impostare il logo delle stampe, caricare un\'immagine specificando come nome "Logo stampe" (Risoluzione consigliata 302x111 pixel)').'.
'; } // Collegamenti diretti diff --git a/modules/anagrafiche/src/Anagrafica.php b/modules/anagrafiche/src/Anagrafica.php index 1967f6b41..8c45d93fe 100644 --- a/modules/anagrafiche/src/Anagrafica.php +++ b/modules/anagrafiche/src/Anagrafica.php @@ -46,6 +46,7 @@ class Anagrafica extends Model $codice = Generator::generate(setting('Formato codice anagrafica'), $ultimo['codice']); $model->codice = $codice; + $model->id_ritenuta_acconto_vendite = setting("Percentuale ritenuta d'acconto"); $model->save(); $model->tipologie = $tipologie; diff --git a/modules/articoli/actions.php b/modules/articoli/actions.php index dec37d893..4905cca60 100644 --- a/modules/articoli/actions.php +++ b/modules/articoli/actions.php @@ -151,7 +151,7 @@ switch (post('op')) { preg_match("/(.*?)([\d]*$)/", $serial__end, $m); $serial_end = intval($m[2]); $n_serial = abs($serial_end - $serial_start) + 1; - $serial_prefix = str_replace($serial_end, '', $serial__end); + $serial_prefix = rtrim($serial__end, $serial_end); $serial_pad_length = strlen($serial__end) - strlen($serial_prefix); // Altro diff --git a/modules/articoli/add.php b/modules/articoli/add.php index c03b36322..773732786 100644 --- a/modules/articoli/add.php +++ b/modules/articoli/add.php @@ -10,7 +10,7 @@ unset($_SESSION['superselect']['id_categoria']);
- {[ "type": "text", "label": "", "name": "codice", "class":"alphanumeric-mask", "required": 1 ]} + {[ "type": "text", "label": "", "name": "codice", "required": 1 ]}
diff --git a/modules/articoli/ajax/select.php b/modules/articoli/ajax/select.php index adbae2920..51099cb1b 100644 --- a/modules/articoli/ajax/select.php +++ b/modules/articoli/ajax/select.php @@ -4,7 +4,64 @@ include_once __DIR__.'/../../../core.php'; switch ($resource) { case 'articoli': - $query = 'SELECT mg_articoli.*, (SELECT CONCAT(co_pianodeiconti2.numero, ".", co_pianodeiconti3.numero, " ", co_pianodeiconti3.descrizione) FROM co_pianodeiconti3 INNER JOIN co_pianodeiconti2 ON co_pianodeiconti3.idpianodeiconti2=co_pianodeiconti2.id WHERE co_pianodeiconti3.id = idconto_vendita) AS idconto_vendita_title, (SELECT CONCAT(co_pianodeiconti2.numero, ".", co_pianodeiconti3.numero, " ", co_pianodeiconti3.descrizione) FROM co_pianodeiconti3 INNER JOIN co_pianodeiconti2 ON co_pianodeiconti3.idpianodeiconti2=co_pianodeiconti2.id WHERE co_pianodeiconti3.id = idconto_acquisto) AS idconto_acquisto_title, co_iva.descrizione AS iva_vendita FROM mg_articoli LEFT OUTER JOIN co_iva ON mg_articoli.idiva_vendita=co_iva.id |where| ORDER BY mg_articoli.id_categoria ASC, mg_articoli.id_sottocategoria ASC'; + $query = 'SELECT + mg_articoli.id, + mg_articoli.codice, + mg_articoli.descrizione, + mg_articoli.um, + mg_articoli.idiva_vendita, + mg_articoli.idconto_vendita, + mg_articoli.idconto_acquisto, + mg_articoli.prezzo_vendita, + mg_articoli.prezzo_acquisto, + categoria.`nome` AS categoria, + sottocategoria.`nome` AS sottocategoria, + co_iva.descrizione AS iva_vendita, + CONCAT(conto_vendita_categoria .numero, ".", conto_vendita_sottocategoria.numero, " ", conto_vendita_sottocategoria.descrizione) AS idconto_vendita_title, + CONCAT(conto_acquisto_categoria .numero, ".", conto_acquisto_sottocategoria.numero, " ", conto_acquisto_sottocategoria.descrizione) AS idconto_acquisto_title + FROM mg_articoli + LEFT JOIN co_iva ON mg_articoli.idiva_vendita = co_iva.id + LEFT JOIN `mg_categorie` AS categoria ON `categoria`.`id` = `mg_articoli`.`id_categoria` + LEFT JOIN `mg_categorie` AS sottocategoria ON `sottocategoria`.`id` = `mg_articoli`.`id_sottocategoria` + LEFT JOIN co_pianodeiconti3 AS conto_vendita_sottocategoria ON conto_vendita_sottocategoria.id=mg_articoli.idconto_vendita + LEFT JOIN co_pianodeiconti2 AS conto_vendita_categoria ON conto_vendita_sottocategoria.idpianodeiconti2=conto_vendita_categoria.id + LEFT JOIN co_pianodeiconti3 AS conto_acquisto_sottocategoria ON conto_acquisto_sottocategoria.id=mg_articoli.idconto_acquisto + LEFT JOIN co_pianodeiconti2 AS conto_acquisto_categoria ON conto_acquisto_sottocategoria.idpianodeiconti2=conto_acquisto_categoria.id + |where| ORDER BY mg_articoli.id_categoria ASC, mg_articoli.id_sottocategoria ASC'; + + foreach ($elements as $element) { + $filter[] = 'mg_articoli.id='.prepare($element); + } + + $where[] = 'attivo = 1'; + if (!empty($superselect['dir']) && $superselect['dir'] == 'entrata') { + //$where[] = '(qta > 0 OR servizio = 1)'; + } + + if (!empty($search)) { + $search_fields[] = 'mg_articoli.descrizione LIKE '.prepare('%'.$search.'%'); + $search_fields[] = 'mg_articoli.codice LIKE '.prepare('%'.$search.'%'); + } + + $custom = [ + 'id' => 'id', + 'codice' => 'codice', + 'descrizione' => 'descrizione', + 'um' => 'um', + 'categoria' => 'categoria', + 'sottocategoria' => 'sottocategoria', + 'idiva_vendita' => 'idiva_vendita', + 'iva_vendita' => 'iva_vendita', + 'idconto_vendita' => 'idconto_vendita', + 'idconto_vendita_title' => 'idconto_vendita_title', + 'idconto_acquisto' => 'idconto_acquisto', + 'idconto_acquisto_title' => 'idconto_acquisto_title', + 'prezzo_acquisto' => 'prezzo_acquisto', + 'prezzo_vendita' => 'prezzo_vendita', + ]; + + $data = AJAX::selectResults($query, $where, $filter, $search_fields, $limit, $custom); + $rs = $data['results']; // Individuazione di eventuali listini if (!empty($superselect['dir']) && !empty($superselect['idanagrafica'])) { @@ -21,45 +78,22 @@ switch ($resource) { $idiva_predefinita = get_var('Iva predefinita'); $iva_predefinita = $dbo->fetchOne('SELECT descrizione FROM co_iva WHERE id='.prepare($idiva_predefinita))['descrizione']; - foreach ($elements as $element) { - $filter[] = 'mg_articoli.id='.prepare($element); - } - - $where[] = 'attivo = 1'; - if (!empty($superselect['dir']) && $superselect['dir'] == 'entrata') { - //$where[] = '(qta > 0 OR servizio = 1)'; - } - - if (!empty($search)) { - $search_fields[] = 'mg_articoli.descrizione LIKE '.prepare('%'.$search.'%'); - $search_fields[] = 'mg_articoli.codice LIKE '.prepare('%'.$search.'%'); - } - - if (!empty($search_fields)) { - $where[] = '('.implode(' OR ', $search_fields).')'; - } - - if (!empty($filter)) { - $where[] = '('.implode(' OR ', $filter).')'; - } - - $wh = ''; - if (count($where) != 0) { - $wh = 'WHERE '.implode(' AND ', $where); - } - $query = str_replace('|where|', $wh, $query); - - $prev = -1; - $rs = $dbo->fetchArray($query); + $previous_category = -1; + $previous_subcategory = -1; foreach ($rs as $r) { - if ($prev != $r['id_sottocategoria']) { - $categoria = $dbo->fetchOne('SELECT `nome` FROM `mg_categorie` WHERE `id`='.prepare($r['id_categoria']))['nome']; + if ($previous_category != $r['categoria'] || $previous_subcategory != $r['sottocategoria']) { + $previous_category = $r['categoria']; + $previous_subcategory = $r['sottocategoria']; - $sottocategoria = $dbo->fetchOne('SELECT `nome` FROM `mg_categorie` WHERE `id`='.prepare($r['id_sottocategoria'])); - $sottocategoria = isset($sottocategoria['nome']) ? $sottocategoria['nome'] : null; + $text = ''.tr('Nessuna categoria').''; + if (!empty($r['categoria'])) { + $text = $r['categoria'].' ('.(!empty($r['sottocategoria']) ? $r['sottocategoria'] : '-').')'; + } - $prev = $r['id_sottocategoria']; - $results[] = ['text' => $categoria.' ('.(!empty($r['id_sottocategoria']) ? $sottocategoria : '-').')', 'children' => []]; + $results[] = [ + 'text' => $text, + 'children' => [], + ]; } // Iva dell'articolo @@ -101,6 +135,11 @@ switch ($resource) { ]; } + $results = [ + 'results' => $results, + 'recordsFiltered' => $data['recordsFiltered'], + ]; + break; case 'prodotti_lotti': diff --git a/modules/articoli/edit.php b/modules/articoli/edit.php index af0ca727e..8cd9df2c2 100644 --- a/modules/articoli/edit.php +++ b/modules/articoli/edit.php @@ -151,12 +151,19 @@ if (!empty($record['immagine'])) {
-

+

+ +

+ + +
+
+ {[ "type": "number", "label": "", "name": "prezzo_vendita", "value": "$prezzo_vendita$", "icon-after": "€" ]}
@@ -344,6 +351,28 @@ $("#categoria").change( function(){ session_set("superselect,id_categoria", $(this).val(), 0); $("#subcategoria").val(null).trigger("change"); }); + + +function scorpora_iva() { + if ($("#idiva_vendita").val()!=''){ + var percentuale = parseFloat($("#idiva_vendita").selectData().percentuale); + if(!percentuale) return; + + var input = $("#prezzo_vendita"); + var prezzo = input.val().toEnglish(); + + var scorporato = prezzo * 100 / (100 + percentuale); + + input.val(scorporato); + }else{ + swal("", "", "warning"); + } +} + +$("#scorpora_iva").click( function(){ + scorpora_iva(); +}); + diff --git a/modules/articoli/import.php b/modules/articoli/import.php index 7731b4d21..c78d2a8ea 100644 --- a/modules/articoli/import.php +++ b/modules/articoli/import.php @@ -75,6 +75,17 @@ switch (post('op')) { } } + // Codice --> ID IVA vendita + if (!empty($data[$key]['idiva_vendita'])) { + $rs_iva = $dbo->select('co_iva', 'id', [ + 'codice' => $data[$key]['idiva_vendita'], + ]); + + if (!empty($rs_iva[0]['id'])) { + $data[$key]['idiva_vendita'] = $rs_iva[0]['id']; + } + } + // Insert o update $insert = true; if (!empty($primary_key)) { @@ -166,6 +177,14 @@ return [ 'idcategoria', ], ], + [ + 'field' => 'idiva_vendita', + 'label' => 'Codice IVA vendita', + 'names' => [ + 'Codice IVA vendita', + 'idiva_vendita', + ], + ], [ 'field' => 'note', 'label' => 'Note', diff --git a/modules/articoli/src/Articolo.php b/modules/articoli/src/Articolo.php index dad08f54e..1a0dda8fa 100644 --- a/modules/articoli/src/Articolo.php +++ b/modules/articoli/src/Articolo.php @@ -3,7 +3,7 @@ namespace Modules\Articoli; use Common\Model; -use Modules\Interventi\Articolo as ArticoloIntervento; +use Modules\Interventi\Components\Articolo as ArticoloIntervento; class Articolo extends Model { diff --git a/modules/categorie_articoli/add.php b/modules/categorie_articoli/add.php index c8df55e32..458c53f9d 100644 --- a/modules/categorie_articoli/add.php +++ b/modules/categorie_articoli/add.php @@ -8,9 +8,13 @@ if (isset($id_record)) { include __DIR__.'/init.php'; } -?>
+?> - - - - - -
@@ -47,17 +31,7 @@ if (!isset($id_original)) {
- - - -
diff --git a/modules/contratti/actions.php b/modules/contratti/actions.php index eb946a383..7dafbe028 100644 --- a/modules/contratti/actions.php +++ b/modules/contratti/actions.php @@ -60,6 +60,7 @@ switch (post('op')) { $costo_diritto_chiamata = post('costo_diritto_chiamata'); $id_documento_fe = post('id_documento_fe'); + $num_item = post('num_item'); $codice_cig = post('codice_cig'); $codice_cup = post('codice_cup'); @@ -81,6 +82,7 @@ switch (post('op')) { giorni_preavviso_rinnovo='.prepare($giorni_preavviso_rinnovo).', esclusioni='.prepare($esclusioni).', descrizione='.prepare($descrizione).', id_documento_fe='.prepare($id_documento_fe).', + num_item='.prepare($num_item).', codice_cig='.prepare($codice_cig).', codice_cup='.prepare($codice_cup).' WHERE id='.prepare($id_record); diff --git a/modules/contratti/ajax/select.php b/modules/contratti/ajax/select.php index f2710e169..48b4c303d 100644 --- a/modules/contratti/ajax/select.php +++ b/modules/contratti/ajax/select.php @@ -10,13 +10,11 @@ switch ($resource) { $filter[] = 'id='.prepare($element); } - $where[] = 'an_anagrafiche.idanagrafica='.prepare($superselect['idanagrafica']); + if (empty($elements)) { + $where[] = 'an_anagrafiche.idanagrafica='.prepare($superselect['idanagrafica']); - $stato = !empty($superselect['stato']) ? $superselect['stato'] : 'pianificabile'; - $where[] = 'idstato IN (SELECT `id` FROM co_staticontratti WHERE '.$stato.' = 1)'; - - if (!empty($superselect['non_fatturato'])) { - $where[] = 'id NOT IN (SELECT idcontratto FROM co_righe_documenti WHERE idcontratto IS NOT NULL)'; + $stato = !empty($superselect['stato']) ? $superselect['stato'] : 'pianificabile'; + $where[] = 'idstato IN (SELECT `id` FROM co_staticontratti WHERE '.$stato.' = 1)'; } if (!empty($search)) { diff --git a/modules/contratti/buttons.php b/modules/contratti/buttons.php index 4f6b5cba5..5ef34e6d2 100644 --- a/modules/contratti/buttons.php +++ b/modules/contratti/buttons.php @@ -3,15 +3,18 @@ include_once __DIR__.'/../../core.php'; $rs_documento = $dbo->fetchArray('SELECT * FROM co_righe_contratti WHERE idcontratto='.prepare($id_record)); + /* permetto di fatturare il contratto solo se contiene righe e si trova in uno stato fatturabile */ echo ' -'; if ($record['rinnovabile']) { $rinnova = !empty($record['data_accettazione']) && !empty($record['data_conclusione']) && $record['data_accettazione'] != '0000-00-00' && $record['data_conclusione'] != '0000-00-00' && $record['pianificabile']; + $stati_pianificabili = $dbo->fetchOne('SELECT GROUP_CONCAT(`descrizione` SEPARATOR ", ") AS stati_pianificabili FROM `co_staticontratti` WHERE `pianificabile` = 1')['stati_pianificabili']; + echo '
-
+

-
+
{[ "type": "text", "label": "", "help": "Obbligatorio per valorizzare CIG/CUP. È possible inserire:
  • N. determina
  • RDO
  • Ordine MEPA
'); ?>","name": "id_documento_fe", "required": 0, "value": "$id_documento_fe$", "maxlength": 20 ]}
-
+
+ {[ "type": "text", "label": "", "name": "num_item", "required": 0, "value": "$num_item$", "maxlength": 15 ]} +
+
+
+
{[ "type": "text", "label": "", "name": "codice_cig", "required": 0, "value": "$codice_cig$", "maxlength": 15 ]}
-
+
{[ "type": "text", "label": "", "name": "codice_cup", "required": 0, "value": "$codice_cup$", "maxlength": 15 ]}
@@ -378,12 +383,6 @@ if (!empty($record['idcontratto_prev'])) { {( "name": "log_email", "id_module": "$id_module$", "id_record": "$id_record$" )} -
' method='post' id='form_creafattura'> - - - -
- fetchOne('SELECT *, (SELECT tipo FROM an_anagrafiche WHERE idanagrafica = co_contratti.idanagrafica) AS tipo_anagrafica, (SELECT fatturabile FROM co_staticontratti WHERE id=idstato) AS fatturabile, (SELECT pianificabile FROM co_staticontratti WHERE id=idstato) AS pianificabile, (SELECT descrizione FROM co_staticontratti WHERE id=idstato) AS stato, (SELECT GROUP_CONCAT(my_impianti_contratti.idimpianto) FROM my_impianti_contratti WHERE idcontratto = co_contratti.id) AS idimpianti FROM co_contratti WHERE id='.prepare($id_record)); + $record = $dbo->fetchOne('SELECT *, + (SELECT tipo FROM an_anagrafiche WHERE idanagrafica = co_contratti.idanagrafica) AS tipo_anagrafica, + (SELECT fatturabile FROM co_staticontratti WHERE id=idstato) AS fatturabile, + (SELECT pianificabile FROM co_staticontratti WHERE id=idstato) AS pianificabile, + (SELECT descrizione FROM co_staticontratti WHERE id=idstato) AS stato, + (SELECT GROUP_CONCAT(my_impianti_contratti.idimpianto) FROM my_impianti_contratti WHERE idcontratto = co_contratti.id) AS idimpianti + FROM co_contratti WHERE id='.prepare($id_record)); } diff --git a/modules/contratti/plugins/contratti.consuntivo.php b/modules/contratti/plugins/contratti.consuntivo.php index 0986a5aa1..a54ab6a37 100644 --- a/modules/contratti/plugins/contratti.consuntivo.php +++ b/modules/contratti/plugins/contratti.consuntivo.php @@ -21,7 +21,24 @@ $totale = 0; $totale_stato = []; // Tabella con riepilogo interventi -$rsi = $dbo->fetchArray('SELECT *, in_interventi.id, (SELECT MIN(orario_inizio) FROM in_interventi_tecnici WHERE idintervento=in_interventi.id) AS inizio, (SELECT SUM(ore) FROM in_interventi_tecnici WHERE idintervento=in_interventi.id) AS ore, (SELECT MIN(km) FROM in_interventi_tecnici WHERE idintervento=in_interventi.id) AS km FROM co_promemoria INNER JOIN in_interventi ON co_promemoria.idintervento=in_interventi.id WHERE co_promemoria.idcontratto='.prepare($id_record).' ORDER BY co_promemoria.idintervento DESC'); +$rsi = $dbo->fetchArray('SELECT in_interventi.id, in_interventi.codice, + (SELECT completato FROM in_statiintervento WHERE in_statiintervento.idstatointervento = in_interventi.idstatointervento) AS completato, + (SELECT MIN(orario_inizio) FROM in_interventi_tecnici WHERE idintervento=in_interventi.id) AS inizio, + (SELECT SUM(ore) FROM in_interventi_tecnici WHERE idintervento=in_interventi.id) AS ore, + (SELECT MIN(km) FROM in_interventi_tecnici WHERE idintervento=in_interventi.id) AS km + FROM co_promemoria + INNER JOIN in_interventi ON co_promemoria.idintervento=in_interventi.id + WHERE co_promemoria.idcontratto='.prepare($id_record).' +UNION + SELECT in_interventi.id, in_interventi.codice, + (SELECT completato FROM in_statiintervento WHERE in_statiintervento.idstatointervento = in_interventi.idstatointervento) AS completato, + (SELECT MIN(orario_inizio) FROM in_interventi_tecnici WHERE idintervento=in_interventi.id) AS inizio, + (SELECT SUM(ore) FROM in_interventi_tecnici WHERE idintervento=in_interventi.id) AS ore, + (SELECT MIN(km) FROM in_interventi_tecnici WHERE idintervento=in_interventi.id) AS km + FROM in_interventi + WHERE id_contratto = '.prepare($id_record).' +ORDER BY id DESC'); + if (!empty($rsi)) { echo ' @@ -195,7 +212,8 @@ if (!empty($rsi)) { '; - $totale_ore += $int['ore']; + $totale_ore_interventi += $int['ore']; + $totale_ore_completate += !empty($int['completato']) ? $int['ore'] : 0; $totale_km += $int['km']; $totale_costo += $int['totale_costo']; $totale_addebito += $int['totale_addebito']; @@ -211,7 +229,7 @@ if (!empty($rsi)) { echo ' '; echo ' @@ -269,7 +287,7 @@ $rs = $dbo->fetchArray('SELECT SUM(subtotale - sconto) AS budget FROM co_righe_c $budget = $rs[0]['budget']; $rs = $dbo->fetchArray("SELECT SUM(qta) AS totale_ore FROM `co_righe_contratti` WHERE um='ore' AND idcontratto=".prepare($id_record)); -$contratto_tot_ore = $rs[0]['totale_ore']; +$totale_ore_contratto = $rs[0]['totale_ore']; $diff = sum($budget, -$totale); @@ -289,24 +307,30 @@ echo '

'; -if (!empty($contratto_tot_ore)) { +if (!empty($totale_ore_contratto)) { echo '
- +
- '.Translator::numberToLocale($totale_ore).' + '.Translator::numberToLocale($totale_ore_interventi).'
+ + + + + + + + + + + + + + + + - - - - - - - - - - - +
'.tr('Ore in contratto').':'.Translator::numberToLocale($totale_ore_contratto).'
'.tr('Ore erogate totali').':'.Translator::numberToLocale($totale_ore_interventi).''.tr('Ore residue totali').':'.Translator::numberToLocale(floatval($totale_ore_contratto) - floatval($totale_ore_interventi)).'
'.tr('Ore erogate concluse').':'.Translator::numberToLocale($totale_ore_completate).''.tr('Ore residue').':'.Translator::numberToLocale(floatval($contratto_tot_ore) - floatval($totale_ore)).'
'.tr('Ore erogate').':'.Translator::numberToLocale($totale_ore).'
'.tr('Ore in contratto').':'.Translator::numberToLocale($contratto_tot_ore).''.Translator::numberToLocale(floatval($totale_ore_contratto) - floatval($totale_ore_completate)).'
diff --git a/modules/contratti/plugins/contratti.fatturaordiniservizio.php b/modules/contratti/plugins/contratti.fatturaordiniservizio.php index 28e84a4f3..6419a4ebe 100644 --- a/modules/contratti/plugins/contratti.fatturaordiniservizio.php +++ b/modules/contratti/plugins/contratti.fatturaordiniservizio.php @@ -130,7 +130,7 @@ elseif (get('op') == 'addfattura') { $iva_indetraibile = $importo / 100 * $rs2[0]['indetraibile']; // Inserimento riga in fattura - $dbo->query('INSERT INTO co_righe_documenti(iddocumento, descrizione, desc_iva, iva, iva_indetraibile, subtotale, um, qta, `order`) VALUES('.prepare($iddocumento).', '.prepare($descrizione).', '.prepare($desc_iva).', '.prepare($iva).', '.prepare($iva_indetraibile).', '.prepare($importo).", '-', 1, (SELECT IFNULL(MAX(`order`) + 1, 0) FROM co_righe_documenti AS t WHERE iddocumento=".prepare($iddocumento).'))'); + $dbo->query('INSERT INTO co_righe_documenti(iddocumento, idcontratto, descrizione, desc_iva, iva, iva_indetraibile, subtotale, um, qta, `order`) VALUES('.prepare($iddocumento).', '.prepare($id_record).', '.prepare($descrizione).', '.prepare($desc_iva).', '.prepare($iva).', '.prepare($iva_indetraibile).', '.prepare($importo).", '-', 1, (SELECT IFNULL(MAX(`order`) + 1, 0) FROM co_righe_documenti AS t WHERE iddocumento=".prepare($iddocumento).'))'); redirect($rootdir.'/editor.php?id_module='.Modules::get('Fatture di vendita')['id'].'&id_record='.$iddocumento.'&dir=entrata'); exit(); diff --git a/modules/contratti/row-list.php b/modules/contratti/row-list.php index 1d07183b1..964ab3767 100644 --- a/modules/contratti/row-list.php +++ b/modules/contratti/row-list.php @@ -38,10 +38,12 @@ foreach ($rs as $r) { // Q.tà echo ' - '; + '; + if (empty($r['is_descrizione'])) { echo ' - '.Translator::numberToLocale($r['qta'], 'qta'); + '.Translator::numberToLocale($r['qta'] - $r['qta_evasa'], 'qta').' +
('.tr('Q.tà iniziale').': '.Translator::numberToLocale($r['qta'], 'qta').')'; } echo ' '; diff --git a/modules/contratti/src/Components/Articolo.php b/modules/contratti/src/Components/Articolo.php index 718e14057..1e45ecb44 100644 --- a/modules/contratti/src/Components/Articolo.php +++ b/modules/contratti/src/Components/Articolo.php @@ -29,26 +29,7 @@ class Articolo extends Article public function movimenta($qta) { - $contratto = $this->contratto; - $tipo = $contratto->tipo; - - $numero = $contratto->numero_esterno ?: $contratto->numero; - $data = $contratto->data; - - $carico = ($tipo->dir == 'entrata') ? tr('Ripristino articolo da _TYPE_ _NUM_') : tr('Carico magazzino da _TYPE_ numero _NUM_'); - $scarico = ($tipo->dir == 'entrata') ? tr('Scarico magazzino per _TYPE_ numero _NUM_') : tr('Rimozione articolo da _TYPE_ _NUM_'); - - $qta = ($tipo->dir == 'uscita') ? -$qta : $qta; - $movimento = ($qta < 0) ? $carico : $scarico; - - $movimento = replace($movimento, [ - '_TYPE_' => $tipo->descrizione, - '_NUM_' => $numero, - ]); - - $this->articolo->movimenta(-$qta, $movimento, $data, false, [ - 'iddocumento' => $contratto->id, - ]); + return; } public function getDirection() diff --git a/modules/contratti/src/Contratto.php b/modules/contratti/src/Contratto.php index 7072005a9..c2be4c41f 100644 --- a/modules/contratti/src/Contratto.php +++ b/modules/contratti/src/Contratto.php @@ -5,6 +5,7 @@ namespace Modules\Contratti; use Carbon\Carbon; use Common\Document; use Modules\Anagrafiche\Anagrafica; +use Modules\Interventi\Intervento; use Modules\Interventi\TipoSessione; use Traits\RecordTrait; use Util\Generator; @@ -138,6 +139,11 @@ class Contratto extends Document return $this->hasOne(Components\Sconto::class, 'idcontratto'); } + public function interventi() + { + return $this->hasMany(Intervento::class, 'id_contratto'); + } + // Metodi statici /** diff --git a/modules/custom_fields/add.php b/modules/custom_fields/add.php index a47fa486c..00dd6545b 100644 --- a/modules/custom_fields/add.php +++ b/modules/custom_fields/add.php @@ -28,7 +28,13 @@ include_once __DIR__.'/../../core.php';
- +filepath('content-info.php'); + +?> + +
diff --git a/modules/custom_fields/content-info.php b/modules/custom_fields/content-info.php new file mode 100644 index 000000000..6e9eade62 --- /dev/null +++ b/modules/custom_fields/content-info.php @@ -0,0 +1,37 @@ + +
+
+

'.tr('Istruzioni per il campo _FIELD_', [ + '_FIELD_' => tr('Contenuto'), + ]).'

+
+ +
+

'.tr('Le seguenti sequenze di testo vengono sostituite nel seguente modo').':

+
    '; + +$list = [ + 'label' => tr('Nome'), + 'name' => tr('Nome HTML'), +]; + +foreach ($list as $key => $value) { + echo ' +
  • '.tr('_TEXT_ con il valore del campo "_FIELD_"', [ + '_TEXT_' => '|'.$key.'|', + '_FIELD_' => $value, + ]).'
  • '; +} + +echo ' +
  • '.tr('_TEXT_ con il valore impostato per il record', [ + '_TEXT_' => '|value|', + ]).'
  • '; + +echo ' +
+
+
'; diff --git a/modules/custom_fields/edit.php b/modules/custom_fields/edit.php index e4baa9ea3..f77f71b64 100644 --- a/modules/custom_fields/edit.php +++ b/modules/custom_fields/edit.php @@ -45,40 +45,11 @@ include_once __DIR__.'/../../core.php';
- -
-
-

tr('Contenuto'), - ]); ?>

-
- -
-

:

-
    tr('Nome'), - 'html_name' => tr('Nome HTML'), -]; -foreach ($list as $key => $value) { - echo ' -
  • '.tr('_TEXT_ con il valore del campo "_FIELD_"', [ - '_TEXT_' => '|'.$key.'|', - '_FIELD_' => $value, - ]).'
  • '; -} - -echo ' -
  • '.tr('_TEXT_ con il valore impostato per il record', [ - '_TEXT_' => '|value|', - ]).'
  • '; +include $module->filepath('content-info.php'); ?> -
-
-

diff --git a/modules/ddt/actions.php b/modules/ddt/actions.php index 807ed4587..89ca330fc 100644 --- a/modules/ddt/actions.php +++ b/modules/ddt/actions.php @@ -198,82 +198,67 @@ switch (post('op')) { break; - // Creazione ddt da ordine - case 'ddt_da_ordine': - $totale_ordine = 0.00; - $data = post('data'); - $idanagrafica = post('idanagrafica'); - $idsede = post('idsede'); - $idpagamento = post('idpagamento'); - $idconto = post('idconto'); - $idordine = post('idordine'); + // Aggiunta di un ordine in ddt + case 'add_ordine': + $ordine = \Modules\Ordini\Ordine::find(post('id_ordine')); - // Creazione DDT - $anagrafica = Anagrafica::find($idanagrafica); - $tipo = Tipo::where('dir', $dir)->first(); + // Creazione della fattura al volo + if (post('create_document') == 'on') { + $tipo = Tipo::where('dir', $dir)->first(); - $ddt = DDT::build($anagrafica, $tipo, $data); - $id_record = $ddt->id; + $ddt = DDT::build($ordine->anagrafica, $tipo, post('data')); + $ddt->idpagamento = $ordine->idpagamento; + $ddt->save(); - // Lettura di tutte le righe della tabella in arrivo - foreach (post('qta_da_evadere') as $idriga => $value) { - // Processo solo le righe da evadere - if (post('evadere')[$idriga] == 'on') { - $idarticolo = post('idarticolo')[$idriga]; - $descrizione = post('descrizione')[$idriga]; + $id_record = $ddt->id; + } - $qta = post('qta_da_evadere')[$idriga]; - $um = post('um')[$idriga]; - $abilita_serial = post('abilita_serial')[$idriga]; + $parziale = false; + $righe = $ordine->getRighe(); + foreach ($righe as $riga) { + if (post('evadere')[$riga->id] == 'on') { + $qta = post('qta_da_evadere')[$riga->id]; - $subtot = post('subtot')[$idriga] * $qta; - $sconto = post('sconto')[$idriga]; - $sconto = $sconto * $qta; - - $idiva = post('idiva')[$idriga]; - $iva = post('iva')[$idriga] * $qta; - - $qprc = 'SELECT tipo_sconto, sconto_unitario FROM or_righe_ordini WHERE id='.prepare($idriga); - $rsprc = $dbo->fetchArray($qprc); - - $sconto_unitario = $rsprc[0]['sconto_unitario']; - $tipo_sconto = $rsprc[0]['tipo_sconto']; - - // Calcolo l'iva indetraibile - $q = 'SELECT descrizione, indetraibile FROM co_iva WHERE id='.prepare($idiva); - $rs = $dbo->fetchArray($q); - $iva_indetraibile = $iva / 100 * $rs[0]['indetraibile']; - - // Inserisco la riga in ddt - $dbo->query('INSERT INTO dt_righe_ddt(idddt, idordine, idarticolo, idiva, desc_iva, iva, iva_indetraibile, descrizione, subtotale, sconto, sconto_unitario, tipo_sconto, um, qta, abilita_serial, `order`) VALUES('.prepare($id_record).', '.prepare($idordine).', '.prepare($idarticolo).', '.prepare($idiva).', '.prepare($rs[0]['descrizione']).', '.prepare($iva).', '.prepare($iva_indetraibile).', '.prepare($descrizione).', '.prepare($subtot).', '.prepare($sconto).', '.prepare($sconto_unitario).', '.prepare($tipo_sconto).', '.prepare($um).', '.prepare($qta).', '.prepare($abilita_serial).', (SELECT IFNULL(MAX(`order`) + 1, 0) FROM dt_righe_ddt AS t WHERE idddt='.prepare($id_record).'))'); - $riga = $dbo->lastInsertedID(); + $copia = $riga->copiaIn($ddt, $qta); // Aggiornamento seriali dalla riga dell'ordine - $serials = is_array(post('serial')[$idriga]) ? post('serial')[$idriga] : []; - $serials = array_clean($serials); + if ($copia->isArticolo()) { + $copia->movimenta($copia->qta); - $dbo->sync('mg_prodotti', ['id_riga_ddt' => $riga, 'dir' => $dir, 'id_articolo' => $idarticolo], ['serial' => $serials]); + $serials = is_array(post('serial')[$riga->id]) ? post('serial')[$riga->id] : []; - // Scalo la quantità dall'ordine - $dbo->query('UPDATE or_righe_ordini SET qta_evasa = qta_evasa+'.$qta.' WHERE id='.prepare($idriga)); - - // Movimento il magazzino - if (!empty($idarticolo)) { - // vendita - if ($dir == 'entrata') { - add_movimento_magazzino($idarticolo, -$qta, ['idddt' => $id_record]); - } - - // acquisto - else { - add_movimento_magazzino($idarticolo, $qta, ['idddt' => $id_record]); - } + $copia->serials = $serials; } + + $copia->save(); + } + + if ($riga->qta != $riga->qta_evasa) { + $parziale = true; } } + // Aggiornamento sconto + if (post('evadere')[$ordine->scontoGlobale->id] == 'on') { + $ddt->tipo_sconto_globale = $ordine->tipo_sconto_globale; + $ddt->sconto_globale = $ordine->tipo_sconto_globale == 'PRC' ? $ordine->sconto_globale : $ordine->sconto_globale; + $ddt->save(); + + $ddt->updateSconto(); + } + + // Impostazione del nuovo stato + $descrizione = $parziale ? 'Parzialmente evaso' : 'Evaso'; + $stato = \Modules\Ordini\Stato::where('descrizione', $descrizione)->first(); + $ordine->stato()->associate($stato); + $ordine->save(); + ricalcola_costiagg_ddt($id_record); - flash()->info(tr('Creato un nuovo ddt!')); + + flash()->info(tr('Ordine _NUM_ aggiunto!', [ + '_NUM_' => $ordine->numero, + ])); + break; // Scollegamento articolo da ddt @@ -489,71 +474,6 @@ switch (post('op')) { } break; - - // aggiungi righe da ordine - case 'add_ordine': - $idordine = post('iddocumento'); - - // Lettura di tutte le righe della tabella in arrivo - foreach (post('qta_da_evadere') as $i => $value) { - // Processo solo le righe da evadere - if (post('evadere')[$i] == 'on') { - $idrigaordine = $i; - $idarticolo = post('idarticolo')[$i]; - $descrizione = post('descrizione')[$i]; - - $qta = post('qta_da_evadere')[$i]; - $um = post('um')[$i]; - - $subtot = post('subtot')[$i] * $qta; - $sconto = post('sconto')[$i]; - $sconto = $sconto * $qta; - - $qprc = 'SELECT tipo_sconto, sconto_unitario FROM or_righe_ordini WHERE id='.prepare($idrigaordine); - $rsprc = $dbo->fetchArray($qprc); - - $sconto_unitario = $rsprc[0]['sconto_unitario']; - $tipo_sconto = $rsprc[0]['tipo_sconto']; - - $idiva = post('idiva')[$i]; - - // Calcolo l'iva indetraibile - $q = 'SELECT percentuale, indetraibile FROM co_iva WHERE id='.prepare($idiva); - $rs = $dbo->fetchArray($q); - $iva = ($subtot - $sconto) / 100 * $rs[0]['percentuale']; - $iva_indetraibile = $iva / 100 * $rs[0]['indetraibile']; - - // Leggo la descrizione iva - $query = 'SELECT * FROM co_iva WHERE id='.prepare($idiva); - $rs = $dbo->fetchArray($query); - $desc_iva = $rs[0]['descrizione']; - - // Se sto aggiungendo un articolo uso la funzione per inserirlo e incrementare la giacenza - if (!empty($idarticolo)) { - $idiva_acquisto = $idiva; - $prezzo_acquisto = $subtot; - $riga = add_articolo_inddt($id_record, $idarticolo, $descrizione, $idiva, $qta, $um, $prezzo_acquisto, $sconto, $sconto_unitario, $tipo_sconto); - - // Lettura lotto, serial, altro dalla riga dell'ordine - $dbo->query('INSERT INTO mg_prodotti (id_riga_documento, id_articolo, dir, serial, lotto, altro) SELECT '.prepare($riga).', '.prepare($idarticolo).', '.prepare($dir).', serial, lotto, altro FROM mg_prodotti AS t WHERE id_riga_ordine='.prepare($idrigaordine)); - } - - // Inserimento riga normale - elseif ($qta != 0) { - $query = 'INSERT INTO dt_righe_ddt(idddt, idarticolo, descrizione, idordine, idiva, desc_iva, iva, iva_indetraibile, subtotale, sconto, sconto_unitario, tipo_sconto, um, qta, `order`) VALUES('.prepare($id_record).', '.prepare($idarticolo).', '.prepare($descrizione).', '.prepare($idordine).', '.prepare($idiva).', '.prepare($desc_iva).', '.prepare($iva).', '.prepare($iva_indetraibile).', '.prepare($subtot).', '.prepare($sconto).', '.prepare($sconto_unitario).', '.prepare($tipo_sconto).', '.prepare($um).', '.prepare($qta).', (SELECT IFNULL(MAX(`order`) + 1, 0) FROM co_righe_documenti AS t WHERE iddocumento='.prepare($id_record).'))'; - $dbo->query($query); - } - - // Scalo la quantità dall ordine - $dbo->query('UPDATE or_righe_ordini SET qta_evasa = qta_evasa+'.$qta.' WHERE id='.prepare($idrigaordine)); - } - } - - ricalcola_costiagg_ddt($id_record); - - flash()->info(tr('Aggiunti nuovi articoli in ddt!')); - - break; } // Aggiornamento stato degli ordini presenti in questa fattura in base alle quantità totali evase diff --git a/modules/ddt/add_ordine.php b/modules/ddt/add_ordine.php index 17ef82bd9..93da2d4f2 100644 --- a/modules/ddt/add_ordine.php +++ b/modules/ddt/add_ordine.php @@ -4,41 +4,88 @@ include_once __DIR__.'/../../core.php'; $module = Modules::get($id_module); -if ($module['name'] == 'Ddt di vendita') { - $dir = 'entrata'; - $module_origin = 'Ordini cliente'; -} else { - $dir = 'uscita'; - $module_origin = 'Ordini fornitore'; +$dir = ($module['name'] == 'Ddt di vendita') ? 'entrata' : 'uscita'; + +if (get('op')) { + $options = [ + 'op' => 'add_ordine', + 'id_importazione' => 'id_ordine', + 'final_module' => $module['name'], + 'original_module' => $module['name'] == 'Ddt di vendita' ? 'Ordini cliente' : 'Ordini fornitore', + 'sql' => [ + 'table' => 'or_ordini', + 'rows' => 'or_righe_ordini', + 'id_rows' => 'idordine', + ], + 'serials' => [ + 'id_riga' => 'id_riga_ddt', + 'condition' => '(id_riga_documento IS NOT NULL)', + ], + 'button' => tr('Aggiungi'), + 'dir' => $dir, + ]; + + $result = [ + 'id_record' => $id_record, + 'id_documento' => get('iddocumento'), + ]; + + echo App::load('importa.php', $result, $options, true); + + return; } $info = $dbo->fetchOne('SELECT * FROM dt_ddt WHERE id='.prepare($id_record)); -$numero = ($info['numero_esterno'] != '') ? $info['numero_esterno'] : $info['numero']; -$idconto = $info['idconto']; $idanagrafica = $info['idanagrafica']; -// Preventivo echo ' -
-
- {[ "type": "select", "label": "'.tr('Ordine').'", "name": "id_ordine", "required": 1, "values": "query=SELECT or_ordini.id, CONCAT(IF(numero_esterno != \'\', numero_esterno, numero), \' del \', DATE_FORMAT(data, \'%d/%m/%Y\')) AS descrizione FROM or_ordini WHERE idanagrafica='.prepare($idanagrafica).' AND idstatoordine IN (SELECT id FROM or_statiordine WHERE descrizione IN(\'Bozza\', \'Evaso\', \'Parzialmente evaso\', \'Parzialmente fatturato\')) AND idtipoordine=(SELECT id FROM or_tipiordine WHERE dir='.prepare($dir).' LIMIT 0,1) AND or_ordini.id IN (SELECT idordine FROM or_righe_ordini WHERE or_righe_ordini.idordine = or_ordini.id AND (qta - qta_evasa) > 0) ORDER BY data DESC, numero DESC" ]} -
-
'; +
+
+ {[ "type": "select", "label": "'.tr('Ordine').'", "name": "id_documento", "values": "query=SELECT or_ordini.id, CONCAT(IF(numero_esterno != \'\', numero_esterno, numero), \' del \', DATE_FORMAT(data, \'%d-%m-%Y\')) AS descrizione FROM or_ordini WHERE idanagrafica='.prepare($idanagrafica).' AND idstatoordine IN (SELECT id FROM or_statiordine WHERE descrizione IN(\'Bozza\', \'Evaso\', \'Parzialmente evaso\', \'Parzialmente fatturato\')) AND idtipoordine=(SELECT id FROM or_tipiordine WHERE dir='.prepare($dir).' LIMIT 0,1) AND or_ordini.id IN (SELECT idordine FROM or_righe_ordini WHERE or_righe_ordini.idordine = or_ordini.id AND (qta - qta_evasa) > 0) ORDER BY data DESC, numero DESC" ]} +
+
+
+
+

'.tr('Informazioni di importazione').'

+
+
+
+
+ +
+ '.tr('Caricamento in corso').'... +
'; + +$file = basename(__FILE__); echo ' -
-
-
'; - -echo ' - '; - -?> - + + +'; diff --git a/modules/ddt/buttons.php b/modules/ddt/buttons.php index d2bee4232..21e03abb5 100644 --- a/modules/ddt/buttons.php +++ b/modules/ddt/buttons.php @@ -2,9 +2,7 @@ include_once __DIR__.'/../../core.php'; -if (!in_array($record['stato'], ['Bozza', 'Fatturato'])) { - echo ' - - '.tr('Crea fattura').' - '; -} +echo ' + + '.tr('Crea fattura').' +'; diff --git a/modules/ddt/crea_documento.php b/modules/ddt/crea_documento.php new file mode 100644 index 000000000..4813ca11e --- /dev/null +++ b/modules/ddt/crea_documento.php @@ -0,0 +1,34 @@ + 'add_ddt', + 'id_importazione' => 'id_ddt', + 'final_module' => $final_module, + 'original_module' => $module['name'], + 'sql' => [ + 'table' => 'dt_ddt', + 'rows' => 'dt_righe_ddt', + 'id_rows' => 'idddt', + ], + 'serials' => [ + 'id_riga' => 'id_riga_ddt', + 'condition' => '(id_riga_documento IS NOT NULL)', + ], + 'button' => tr('Aggiungi'), + 'dir' => $dir, + 'create_document' => true, +]; + +$result = [ + 'id_record' => $id_record, + 'id_documento' => get('iddocumento'), +]; + +echo App::load('importa.php', $result, $options, true); diff --git a/modules/ddt/init.php b/modules/ddt/init.php index 4aae1a5bb..5e8b4761c 100644 --- a/modules/ddt/init.php +++ b/modules/ddt/init.php @@ -2,8 +2,10 @@ include_once __DIR__.'/../../core.php'; +use Modules\DDT\DDT; + if (isset($id_record)) { - $ddt = Modules\DDT\DDT::with('tipo', 'stato')->find($id_record); + $ddt = DDT::with('tipo', 'stato')->find($id_record); $record = $dbo->fetchOne('SELECT *, dt_ddt.note, dt_ddt.idpagamento, dt_ddt.id AS idddt, dt_statiddt.descrizione AS `stato`, dt_tipiddt.descrizione AS `descrizione_tipodoc`, (SELECT completato FROM dt_statiddt WHERE dt_statiddt.id=dt_ddt.idstatoddt) AS flag_completato diff --git a/modules/ddt/src/Components/Articolo.php b/modules/ddt/src/Components/Articolo.php index 7eb3517f2..6f7a94c29 100644 --- a/modules/ddt/src/Components/Articolo.php +++ b/modules/ddt/src/Components/Articolo.php @@ -11,6 +11,7 @@ class Articolo extends Article use RelationTrait; protected $table = 'dt_righe_ddt'; + protected $serialRowID = 'ddt'; /** * Crea un nuovo articolo collegato ad una ddt. @@ -47,7 +48,7 @@ class Articolo extends Article ]); $this->articolo->movimenta(-$qta, $movimento, $data, false, [ - 'iddocumento' => $ddt->id, + 'idddt' => $ddt->id, ]); } diff --git a/modules/fatture/actions.php b/modules/fatture/actions.php index f2bb5e99f..b719944a0 100644 --- a/modules/fatture/actions.php +++ b/modules/fatture/actions.php @@ -63,6 +63,7 @@ switch (post('op')) { // Query di aggiornamento $dbo->update('co_documenti', array_merge([ 'data' => post('data'), + 'data_ricezione' => post('data_ricezione'), 'numero_esterno' => post('numero_esterno'), 'note' => post('note'), 'note_aggiuntive' => post('note_aggiuntive'), @@ -89,6 +90,7 @@ switch (post('op')) { 'ritenutaacconto' => 0, 'iva_rivalsainps' => 0, 'codice_stato_fe' => post('codice_stato_fe') ?: null, + 'id_ritenuta_contributi' => post('id_ritenuta_contributi') ?: null, ], $data), ['id' => $id_record]); $query = 'SELECT descrizione FROM co_statidocumento WHERE id='.prepare($idstatodocumento); @@ -143,6 +145,12 @@ switch (post('op')) { break; + // Ricalcolo scadenze + case 'ricalcola_scadenze': + $fattura->registraScadenze(false, true); + + break; + // eliminazione documento case 'delete': $rs = $dbo->fetchArray('SELECT id FROM co_righe_documenti WHERE iddocumento='.prepare($id_record)); @@ -247,8 +255,18 @@ switch (post('op')) { break; case 'addintervento': - if (!empty($id_record) && post('idintervento') !== null) { - aggiungi_intervento_in_fattura(post('idintervento'), $id_record, post('descrizione'), post('idiva'), post('idconto'), post('id_rivalsa_inps'), post('id_ritenuta_acconto'), post('calcolo_ritenuta_acconto')); + $id_intervento = post('idintervento'); + if (!empty($id_record) && $id_intervento !== null) { + $copia_descrizione = post('copia_descrizione'); + $intervento = $dbo->fetchOne('SELECT descrizione FROM in_interventi WHERE id = '.prepare($id_intervento)); + if (!empty($copia_descrizione) && !empty($intervento['descrizione'])) { + $riga = Descrizione::build($fattura); + $riga->descrizione = $intervento['descrizione']; + $riga->idintervento = $id_intervento; + $riga->save(); + } + + aggiungi_intervento_in_fattura($id_intervento, $id_record, post('descrizione'), post('idiva'), post('idconto'), post('id_rivalsa_inps'), post('id_ritenuta_acconto'), post('calcolo_ritenuta_acconto')); flash()->info(tr('Intervento _NUM_ aggiunto!', [ '_NUM_' => $idintervento, @@ -256,279 +274,6 @@ switch (post('op')) { } break; - case 'addpreventivo': - if (!empty($id_record) && post('idpreventivo') !== null) { - $idpreventivo = post('idpreventivo'); - $descrizione = post('descrizione'); - $idiva = post('idiva'); - $idconto = post('idconto'); - - $prezzo = post('prezzo'); - $qta = 1; - - // Calcolo dello sconto - $sconto_unitario = post('sconto'); - $tipo_sconto = post('tipo_sconto'); - $sconto = calcola_sconto([ - 'sconto' => $sconto_unitario, - 'prezzo' => $prezzo, - 'tipo' => $tipo_sconto, - 'qta' => $qta, - ]); - - $subtot = 0; - $aggiorna_budget = (post('aggiorna_budget') == 'on') ? 1 : 0; - - // Leggo l'anagrafica del cliente - $rs = $dbo->fetchArray('SELECT idanagrafica, numero FROM `co_preventivi` WHERE id='.prepare($idpreventivo)); - $idanagrafica = $rs[0]['idanagrafica']; - $numero = $rs[0]['numero']; - - // Calcolo iva - $query = 'SELECT * FROM co_iva WHERE id='.prepare($idiva); - $rs = $dbo->fetchArray($query); - $iva = ($prezzo - $sconto) / 100 * $rs[0]['percentuale']; - $iva_indetraibile = $iva / 100 * $rs[0]['indetraibile']; - $desc_iva = $rs[0]['descrizione']; - - // Calcolo rivalsa inps - $query = 'SELECT * FROM co_rivalse WHERE id='.prepare(setting('Percentuale rivalsa')); - $rs = $dbo->fetchArray($query); - $rivalsainps = ($prezzo - $sconto) / 100 * $rs[0]['percentuale']; - - // Calcolo ritenuta d'acconto TOTALE - $query = 'SELECT * FROM co_ritenutaacconto WHERE id = '.prepare(setting("Percentuale ritenuta d'acconto")); - $rs = $dbo->fetchArray($query); - if (setting("Metodologia calcolo ritenuta d'acconto predefinito") == 'Imponibile') { - $ritenutaacconto = ($prezzo - $sconto) / 100 * $rs[0]['percentuale']; - } else { - $ritenutaacconto = ($prezzo - $sconto + $rivalsainps) / 100 * $rs[0]['percentuale']; - } - - if (!empty(post('import'))) { - // Replicazione delle righe del preventivo sul documento - $righe = $dbo->fetchArray('SELECT idarticolo, idiva, desc_iva, iva, iva_indetraibile, descrizione, subtotale, um, qta, sconto, sconto_unitario, tipo_sconto, is_descrizione, IFNULL( (SELECT mg_articoli.abilita_serial FROM mg_articoli WHERE mg_articoli.id=co_righe_preventivi.idarticolo), 0 ) AS abilita_serial FROM co_righe_preventivi WHERE idpreventivo='.prepare($idpreventivo)); - - foreach ($righe as $key => $riga) { - $subtot = $riga['subtotale']; - - $sconto = $riga['sconto']; - - // Ricalcolo ritenuta per ogni singola riga - if (setting("Metodologia calcolo ritenuta d'acconto predefinito") == 'Imponibile') { - $ritenutaacconto = ($subtot - $sconto) / 100 * $rs[0]['percentuale']; - } else { - $ritenutaacconto = ($subtot - $sconto + $rivalsainps) / 100 * $rs[0]['percentuale']; - } - - $dbo->insert('co_righe_documenti', [ - 'iddocumento' => $id_record, - 'idpreventivo' => $idpreventivo, - 'idconto' => $idconto, - 'idarticolo' => $riga['idarticolo'], - 'idiva' => $riga['idiva'], - 'desc_iva' => $riga['desc_iva'], - 'iva' => $riga['iva'], - 'iva_indetraibile' => $riga['iva_indetraibile'], - 'descrizione' => str_replace('SCONTO', 'SCONTO '.$descrizione, $riga['descrizione']), - 'subtotale' => $riga['subtotale'], - 'um' => $riga['um'], - 'qta' => $riga['qta'], - 'is_descrizione' => $riga['is_descrizione'], - 'sconto' => $riga['sconto'], - 'sconto_unitario' => $riga['sconto_unitario'], - 'tipo_sconto' => $riga['tipo_sconto'], - 'order' => orderValue('co_righe_documenti', 'iddocumento', $id_record), - 'idritenutaacconto' => setting("Percentuale ritenuta d'acconto"), - 'ritenutaacconto' => $ritenutaacconto, - 'idrivalsainps' => setting('Percentuale rivalsa'), - 'rivalsainps' => $rivalsainps, - 'abilita_serial' => $riga['abilita_serial'], - 'calcolo_ritenuta_acconto' => setting("Metodologia calcolo ritenuta d'acconto predefinito"), - ]); - - if (!empty($riga['idarticolo'])) { - add_movimento_magazzino($riga['idarticolo'], -$riga['qta'], ['iddocumento' => $id_record]); - } - } - } else { - // Aggiunta riga preventivo sul documento - $query = 'INSERT INTO co_righe_documenti(iddocumento, idpreventivo, is_preventivo, idconto, idiva, desc_iva, iva, iva_indetraibile, descrizione, subtotale, sconto, sconto_unitario, tipo_sconto, um, qta, idritenutaacconto, ritenutaacconto, idrivalsainps, rivalsainps, `order`) VALUES('.prepare($id_record).', '.prepare($idpreventivo).', "1", '.prepare($idconto).', '.prepare($idiva).', '.prepare($desc_iva).', '.prepare($iva).', '.prepare($iva_indetraibile).', '.prepare($descrizione).', '.prepare($prezzo).', '.prepare($sconto).', '.prepare($sconto_unitario).', '.prepare($tipo_sconto).", '-', 1, ".prepare(setting("Percentuale ritenuta d'acconto")).', '.prepare($ritenutaacconto).', '.prepare(setting('Percentuale rivalsa')).', '.prepare($rivalsainps).', (SELECT IFNULL(MAX(`order`) + 1, 0) FROM co_righe_documenti AS t WHERE iddocumento='.prepare($id_record).'))'; - $dbo->query($query); - - // Scarico gli articoli nel preventivo - $righe = $dbo->fetchArray('SELECT * FROM co_righe_preventivi WHERE idpreventivo='.prepare($idpreventivo)); - foreach ($righe as $key => $riga) { - if (!empty($riga['idarticolo'])) { - add_movimento_magazzino($riga['idarticolo'], -$riga['qta'], ['iddocumento' => $id_record]); - } - } - } - - // Aggiorno lo stato degli interventi collegati al preventivo se ce ne sono - $query2 = 'SELECT idpreventivo FROM co_righe_documenti WHERE iddocumento='.prepare($id_record).' AND NOT idpreventivo=0 AND idpreventivo IS NOT NULL'; - $rs2 = $dbo->fetchArray($query2); - - for ($j = 0; $j < sizeof($rs2); ++$j) { - $dbo->query("UPDATE in_interventi SET idstatointervento=(SELECT idstatointervento FROM in_statiintervento WHERE descrizione='Fatturato') WHERE id_preventivo=".prepare($rs2[$j]['idpreventivo'])); - } - - flash()->info(tr('Preventivo _NUM_ aggiunto!', [ - '_NUM_' => $numero, - ])); - - // Aggiorno il budget sul preventivo con l'importo inserito in fattura e imposto lo stato del preventivo "In attesa di pagamento" (se selezionato) - if ($aggiorna_budget) { - $dbo->query('UPDATE co_preventivi SET budget='.prepare($prezzo).' WHERE id='.prepare($idpreventivo)); - } - $dbo->query("UPDATE co_preventivi SET idstato=(SELECT id FROM co_statipreventivi WHERE descrizione='In attesa di pagamento') WHERE id=".prepare($idpreventivo)); - - // Ricalcolo inps, ritenuta e bollo - if ($dir == 'entrata') { - ricalcola_costiagg_fattura($id_record); - } else { - ricalcola_costiagg_fattura($id_record); - } - } - - break; - - case 'addcontratto': - if (!empty($id_record) && post('idcontratto') !== null) { - $idcontratto = post('idcontratto'); - $descrizione = post('descrizione'); - $idiva = post('idiva'); - $idconto = post('idconto'); - - $prezzo = post('prezzo'); - $qta = 1; - - // Calcolo dello sconto - $sconto_unitario = post('sconto'); - $tipo_sconto = post('tipo_sconto'); - $sconto = calcola_sconto([ - 'sconto' => $sconto_unitario, - 'prezzo' => $prezzo, - 'tipo' => $tipo_sconto, - 'qta' => $qta, - ]); - - $subtot = 0; - $aggiorna_budget = (post('aggiorna_budget') == 'on') ? 1 : 0; - - // Leggo l'anagrafica del cliente - $rs = $dbo->fetchArray('SELECT idanagrafica, numero FROM `co_contratti` WHERE id='.prepare($idcontratto)); - $idanagrafica = $rs[0]['idanagrafica']; - $numero = $rs[0]['numero']; - - // Calcolo iva - $query = 'SELECT * FROM co_iva WHERE id='.prepare($idiva); - $rs = $dbo->fetchArray($query); - $iva = ($prezzo - $sconto) / 100 * $rs[0]['percentuale']; - $iva_indetraibile = $iva / 100 * $rs[0]['indetraibile']; - $desc_iva = $rs[0]['descrizione']; - - // Calcolo rivalsa inps - $query = 'SELECT * FROM co_rivalse WHERE id='.prepare(setting('Percentuale rivalsa')); - $rs = $dbo->fetchArray($query); - $rivalsainps = ($prezzo - $sconto) / 100 * $rs[0]['percentuale']; - - // Calcolo ritenuta d'acconto - $query = 'SELECT * FROM co_ritenutaacconto WHERE id='.prepare(setting("Percentuale ritenuta d'acconto")); - $rs = $dbo->fetchArray($query); - if (setting("Metodologia calcolo ritenuta d'acconto predefinito") == 'Imponibile') { - $ritenutaacconto = ($prezzo - $sconto) / 100 * $rs[0]['percentuale']; - } else { - $ritenutaacconto = ($prezzo - $sconto + $rivalsainps) / 100 * $rs[0]['percentuale']; - } - - if (!empty(post('import'))) { - // Replicazione delle righe del contratto sul documento - $righe = $dbo->fetchArray('SELECT *, IFNULL( (SELECT mg_articoli.abilita_serial FROM mg_articoli WHERE mg_articoli.id=co_righe_contratti.idarticolo), 0 ) AS abilita_serial FROM co_righe_contratti WHERE idcontratto='.prepare($idcontratto)); - - foreach ($righe as $key => $riga) { - $subtot = $riga['subtotale']; - - $sconto = $riga['sconto']; - - // Ricalcolo ritenuta per ogni singola riga - if (setting("Metodologia calcolo ritenuta d'acconto predefinito") == 'Imponibile') { - $ritenutaacconto = ($subtot - $sconto) / 100 * $rs[0]['percentuale']; - } else { - $ritenutaacconto = ($subtot - $sconto + $rivalsainps) / 100 * $rs[0]['percentuale']; - } - - $dbo->insert('co_righe_documenti', [ - 'iddocumento' => $id_record, - 'idcontratto' => $idcontratto, - 'idconto' => $idconto, - 'idarticolo' => $riga['idarticolo'], - 'idiva' => $riga['idiva'], - 'desc_iva' => $riga['desc_iva'], - 'iva' => $riga['iva'], - 'iva_indetraibile' => $riga['iva_indetraibile'], - 'descrizione' => str_replace('SCONTO', 'SCONTO '.$descrizione, $riga['descrizione']), - 'subtotale' => $riga['subtotale'], - 'um' => $riga['um'], - 'qta' => $riga['qta'], - 'sconto' => $riga['sconto'], - 'sconto_unitario' => $riga['sconto_unitario'], - 'tipo_sconto' => $riga['tipo_sconto'], - 'order' => orderValue('co_righe_documenti', 'iddocumento', $id_record), - 'idritenutaacconto' => setting("Percentuale ritenuta d'acconto"), - 'ritenutaacconto' => $ritenutaacconto, - 'idrivalsainps' => setting('Percentuale rivalsa'), - 'rivalsainps' => $rivalsainps, - 'abilita_serial' => $riga['abilita_serial'], - 'calcolo_ritenuta_acconto' => setting("Metodologia calcolo ritenuta d'acconto predefinito"), - ]); - - if (!empty($riga['idarticolo'])) { - add_movimento_magazzino($riga['idarticolo'], -$riga['qta'], ['iddocumento' => $id_record]); - } - } - } else { - // Aggiunta riga contratto sul documento - $query = 'INSERT INTO co_righe_documenti(iddocumento, idcontratto, is_contratto, idconto, idiva, desc_iva, iva, iva_indetraibile, descrizione, subtotale, sconto, sconto_unitario, tipo_sconto, um, qta, idrivalsainps, rivalsainps, idritenutaacconto, ritenutaacconto, calcolo_ritenuta_acconto, `order`) VALUES('.prepare($id_record).', '.prepare($idcontratto).', "1", '.prepare($idconto).', '.prepare($idiva).', '.prepare($desc_iva).', '.prepare($iva).', '.prepare($iva_indetraibile).', '.prepare($descrizione).', '.prepare($prezzo).', '.prepare($sconto).', '.prepare($sconto_unitario).', '.prepare($tipo_sconto).", '-', 1, ".prepare(setting('Percentuale rivalsa')).', '.prepare($rivalsainps).', '.prepare(setting("Percentuale ritenuta d'acconto")).', '.prepare($ritenutaacconto).', '.prepare(setting("Metodologia calcolo ritenuta d'acconto predefinito")).', (SELECT IFNULL(MAX(`order`) + 1, 0) FROM co_righe_documenti AS t WHERE iddocumento='.prepare($id_record).'))'; - $dbo->query($query); - - // Scalo le qta degli articoli nel contratto - $righe = $dbo->fetchArray('SELECT * FROM co_righe_contratti WHERE idcontratto='.prepare($idcontratto)); - foreach ($righe as $key => $riga) { - if (!empty($riga['idarticolo'])) { - add_movimento_magazzino($riga['idarticolo'], -$riga['qta'], ['iddocumento' => $id_record]); - } - } - } - - flash()->info(tr('Contratto _NUM_ aggiunto!', [ - '_NUM_' => $numero, - ])); - - // Aggiorno lo stato degli interventi collegati al contratto se ce ne sono - $query2 = 'SELECT idcontratto FROM co_righe_documenti WHERE iddocumento='.prepare($id_record).' AND NOT idcontratto=0 AND idcontratto IS NOT NULL'; - $rs2 = $dbo->fetchArray($query2); - - for ($j = 0; $j < sizeof($rs2); ++$j) { - $dbo->query("UPDATE in_interventi SET idstatointervento=(SELECT idstatointervento FROM in_statiintervento WHERE descrizione='Fatturato') WHERE id_contratto=".prepare($rs2[$j]['idcontratto'])); - } - - // Aggiorno il budget sul contratto con l'importo inserito in fattura e imposto lo stato del contratto "In attesa di pagamento" (se selezionato) - if ($aggiorna_budget) { - $dbo->query('UPDATE co_contratti SET budget='.prepare($prezzo).' WHERE id='.prepare($idcontratto)); - } - - $dbo->query("UPDATE co_contratti SET idstato=(SELECT id FROM co_staticontratti WHERE descrizione='In attesa di pagamento') WHERE id=".prepare($idcontratto)); - - // Ricalcolo inps, ritenuta e bollo - if ($dir == 'entrata') { - ricalcola_costiagg_fattura($id_record); - } else { - ricalcola_costiagg_fattura($id_record); - } - } - break; - case 'manage_articolo': if (post('idriga') != null) { $articolo = Articolo::find(post('idriga')); @@ -550,12 +295,10 @@ switch (post('op')) { $articolo->calcolo_ritenuta_acconto = post('calcolo_ritenuta_acconto') ?: null; $articolo->id_ritenuta_acconto = post('id_ritenuta_acconto') ?: null; - + $articolo->ritenuta_contributi = post('ritenuta_contributi'); $articolo->id_rivalsa_inps = post('id_rivalsa_inps') ?: null; - if (post('prezzo_acquisto')) { - $riga->prezzo_unitario_acquisto = post('prezzo_acquisto'); - } + $articolo->prezzo_unitario_acquisto = post('prezzo_acquisto') ?: 0; $articolo->prezzo_unitario_vendita = post('prezzo'); $articolo->sconto_unitario = post('sconto'); $articolo->tipo_sconto = post('tipo_sconto'); @@ -599,14 +342,12 @@ switch (post('op')) { $riga->id_iva = post('idiva'); $riga->idconto = post('idconto'); - $articolo->calcolo_ritenuta_acconto = post('calcolo_ritenuta_acconto') ?: null; - $articolo->id_ritenuta_acconto = post('id_ritenuta_acconto') ?: null; + $riga->calcolo_ritenuta_acconto = post('calcolo_ritenuta_acconto') ?: null; + $riga->id_ritenuta_acconto = post('id_ritenuta_acconto') ?: null; + $riga->ritenuta_contributi = post('ritenuta_contributi'); + $riga->id_rivalsa_inps = post('id_rivalsa_inps') ?: null; - $articolo->id_rivalsa_inps = post('id_rivalsa_inps') ?: null; - - if (post('prezzo_acquisto')) { - $riga->prezzo_unitario_acquisto = post('prezzo_acquisto'); - } + $riga->prezzo_unitario_acquisto = post('prezzo_acquisto') ?: 0; $riga->prezzo_unitario_vendita = post('prezzo'); $riga->sconto_unitario = post('sconto'); $riga->tipo_sconto = post('tipo_sconto'); @@ -651,294 +392,6 @@ switch (post('op')) { break; - // Creazione fattura da ddt - case 'fattura_da_ddt': - $totale_fattura = 0.00; - $data = post('data'); - $idanagrafica = post('idanagrafica'); - $idarticolo = post('idarticolo'); - $idpagamento = post('idpagamento'); - $idddt = post('idddt'); - - $id_segment = post('id_segment'); - $numero = get_new_numerofattura($data); - - if ($dir == 'entrata') { - $numero_esterno = get_new_numerosecondariofattura($data); - } else { - $numero_esterno = ''; - } - - if ($dir == 'entrata') { - $tipo_documento = 'Fattura differita di vendita'; - $idconto = setting('Conto predefinito fatture di vendita'); - } else { - $tipo_documento = 'Fattura differita di acquisto'; - $idconto = setting('Conto predefinito fatture di acquisto'); - } - - // Creazione nuova fattura - $dbo->query('INSERT INTO co_documenti(numero, numero_esterno, data, idanagrafica, idtipodocumento, idstatodocumento, idpagamento, idconto, id_segment) VALUES('.prepare($numero).', '.prepare($numero_esterno).', '.prepare($data).', '.prepare($idanagrafica).', (SELECT id FROM co_tipidocumento WHERE descrizione='.prepare($tipo_documento)."), (SELECT id FROM co_statidocumento WHERE descrizione='Bozza'), ".prepare($idpagamento).', '.prepare($idconto).', '.prepare($id_segment).' )'); - $id_record = $dbo->lastInsertedID(); - - // Lettura di tutte le righe della tabella in arrivo - foreach (post('qta_da_evadere') as $i => $value) { - // Processo solo le righe da evadere - if (post('evadere')[$i] == 'on') { - $idrigaddt = $i; - $idarticolo = post('idarticolo')[$i]; - $descrizione = post('descrizione')[$i]; - $qta = post('qta_da_evadere')[$i]; - $um = post('um')[$i]; - $subtot = post('subtot')[$i] * $qta; - $sconto = post('sconto')[$i]; - $sconto = $sconto * $qta; - $idiva = post('idiva')[$i]; - - $qprc = 'SELECT tipo_sconto, sconto_unitario FROM dt_righe_ddt WHERE id='.prepare($idrigaddt); - $rsprc = $dbo->fetchArray($qprc); - - $sconto_unitario = $rsprc[0]['sconto_unitario']; - $tipo_sconto = $rsprc[0]['tipo_sconto']; - - // Leggo la descrizione iva - $query = 'SELECT * FROM co_iva WHERE id='.prepare($idiva); - $rs = $dbo->fetchArray($query); - $perc_iva = $rs[0]['percentuale']; - $desc_iva = $rs[0]['descrizione']; - $iva = ($subtot - $sconto) / 100 * $perc_iva; - - // Calcolo l'iva indetraibile - $q = 'SELECT indetraibile FROM co_iva WHERE id='.prepare($idiva); - $rs = $dbo->fetchArray($q); - $iva_indetraibile = $iva / 100 * $rs[0]['indetraibile']; - - $qdesc = 'SELECT is_descrizione FROM dt_righe_ddt WHERE id='.prepare($idrigaddt); - $rsdesc = $dbo->fetchArray($qdesc); - - // Se sto aggiungendo un articolo uso la funzione per inserirlo e incrementare la giacenza - if (!empty($idarticolo)) { - $idiva_acquisto = $idiva; - $prezzo_acquisto = $subtot; - $idriga = add_articolo_infattura($id_record, $idarticolo, $descrizione, $idiva_acquisto, $qta, $prezzo_acquisto, $sconto, $sconto_unitario, $tipo_sconto); - - // Aggiornamento seriali dalla riga dell'ordine - $serials = is_array(post('serial')[$i]) ? post('serial')[$i] : []; - $serials = array_clean($serials); - - $dbo->sync('mg_prodotti', ['id_riga_documento' => $idriga, 'dir' => $dir, 'id_articolo' => $idarticolo], ['serial' => $serials]); - } - - // Inserimento riga normale - else { - $query = 'INSERT INTO co_righe_documenti(iddocumento, idarticolo, descrizione, is_descrizione, idddt, idiva, desc_iva, iva, iva_indetraibile, subtotale, sconto, sconto_unitario, tipo_sconto, um, qta, `order`) VALUES('.prepare($id_record).', '.prepare($idarticolo).', '.prepare($descrizione).', '.prepare($rsdesc[0]['is_descrizione']).', '.prepare($idddt).', '.prepare($idiva).', '.prepare($desc_iva).', '.prepare($iva).', '.prepare($iva_indetraibile).', '.prepare($subtot).', '.prepare($sconto).', '.prepare($sconto_unitario).', '.prepare($tipo_sconto).', '.prepare($um).', '.prepare($qta).', (SELECT IFNULL(MAX(`order`) + 1, 0) FROM co_righe_documenti AS t WHERE iddocumento='.prepare($id_record).'))'; - - $dbo->query($query); - } - - // Scalo la quantità dal ddt - $dbo->query('UPDATE dt_righe_ddt SET qta_evasa = qta_evasa+'.$qta.' WHERE id='.prepare($idrigaddt)); - } - } - - ricalcola_costiagg_fattura($id_record); - - flash()->info(tr('Creata una nuova fattura!')); - - break; - - // Creazione fattura da ordine - case 'fattura_da_ordine': - $totale_fattura = 0.00; - $data = post('data'); - $idanagrafica = post('idanagrafica'); - $idarticolo = post('idarticolo'); - $idpagamento = post('idpagamento'); - $idconto = post('idconto'); - $idordine = post('idordine'); - $id_segment = post('id_segment'); - $numero = get_new_numerofattura($data); - $numero_esterno = get_new_numerosecondariofattura($data); - - $tipo_documento = ($dir == 'entrata') ? 'Fattura immediata di vendita' : 'Fattura immediata di acquisto'; - - // Creazione nuova fattura - $dbo->query('INSERT INTO co_documenti(numero, numero_esterno, data, idanagrafica, idtipodocumento, idstatodocumento, idpagamento, idconto, id_segment) VALUES('.prepare($numero).', '.prepare($numero_esterno).', '.prepare($data).', '.prepare($idanagrafica).', (SELECT id FROM co_tipidocumento WHERE descrizione='.prepare($tipo_documento)."), (SELECT id FROM co_statidocumento WHERE descrizione='Bozza'), ".prepare($idpagamento).', '.prepare($idconto).','.prepare($id_segment).')'); - $id_record = $dbo->lastInsertedID(); - - // Lettura di tutte le righe della tabella in arrivo - foreach (post('qta_da_evadere') as $i => $value) { - // Processo solo le righe da evadere - if (post('evadere')[$i] == 'on') { - $idriga = $i; - $idarticolo = post('idarticolo')[$i]; - $descrizione = post('descrizione')[$i]; - $qta = post('qta_da_evadere')[$i]; - $um = post('um')[$i]; - $subtot = post('subtot')[$i] * $qta; - $idiva = post('idiva')[$i]; - $iva = post('iva')[$i] * $qta; - $sconto = post('sconto')[$i]; - $sconto = $sconto * $qta; - - $qprc = 'SELECT tipo_sconto, sconto_unitario FROM or_righe_ordini WHERE id='.prepare($idriga); - $rsprc = $dbo->fetchArray($qprc); - - $sconto_unitario = $rsprc[0]['sconto_unitario']; - $tipo_sconto = $rsprc[0]['tipo_sconto']; - - // Calcolo l'iva indetraibile - $q = 'SELECT indetraibile FROM co_iva WHERE id='.prepare($idiva); - $rs = $dbo->fetchArray($q); - $iva_indetraibile = $iva / 100 * $rs[0]['indetraibile']; - - // Leggo la descrizione iva - $query = 'SELECT * FROM co_iva WHERE id='.prepare($idiva); - $rs = $dbo->fetchArray($query); - $desc_iva = $rs[0]['descrizione']; - - $qdesc = 'SELECT is_descrizione FROM dt_righe_ddt WHERE id='.prepare($idriga); - $rsdesc = $dbo->fetchArray($qdesc); - - // Se sto aggiungendo un articolo uso la funzione per inserirlo e incrementare la giacenza - if (!empty($idarticolo)) { - $idiva_acquisto = $idiva; - $prezzo_acquisto = $subtot; - $riga = add_articolo_infattura($id_record, $idarticolo, $descrizione, $idiva_acquisto, $qta, $prezzo_acquisto, $sconto, $sconto_unitario, $tipo_sconto); - - // Aggiornamento seriali dalla riga dell'ordine - $serials = is_array(post('serial')[$i]) ? post('serial')[$i] : []; - $serials = array_clean($serials); - - $dbo->sync('mg_prodotti', ['id_riga_documento' => $riga, 'dir' => $dir, 'id_articolo' => $idarticolo], ['serial' => $serials]); - - // Imposto la provenienza dell'ordine - $dbo->query('UPDATE co_righe_documenti SET idordine='.prepare($idordine).' WHERE id='.prepare($idriga)); - } - - // Inserimento riga normale - else { - $dbo->query('INSERT INTO co_righe_documenti(iddocumento, idarticolo, idordine, idiva, desc_iva, iva, iva_indetraibile, descrizione, is_descrizione, subtotale, sconto, sconto_unitario, tipo_sconto, um, qta, `order`) VALUES('.prepare($id_record).', '.prepare($idarticolo).', '.prepare($idordine).', '.prepare($idiva).', '.prepare($desc_iva).', '.prepare($iva).', '.prepare($iva_indetraibile).', '.prepare($descrizione).', '.prepare($rdesc[0]['is_descrizione']).', '.prepare($subtot).', '.prepare($sconto).', '.prepare($sconto_unitario).', '.prepare($tipo_sconto).', '.prepare($um).', '.prepare($qta).', (SELECT IFNULL(MAX(`order`) + 1, 0) FROM co_righe_documenti AS t WHERE iddocumento='.prepare($id_record).'))'); - } - - // Scalo la quantità dall'ordine - $dbo->query('UPDATE or_righe_ordini SET qta_evasa = qta_evasa+'.$qta.' WHERE id='.prepare($idriga)); - } - } - - ricalcola_costiagg_fattura($id_record); - flash()->info(tr('Creata una nuova fattura!')); - - break; - - // Creazione fattura da contratto - case 'fattura_da_contratto': - $idcontratto = post('id_record'); - $data = date('Y-m-d'); - - $rs_segment = $dbo->fetchArray('SELECT * FROM zz_segments WHERE id_module='.prepare($id_module)." AND predefined='1'"); - $id_segment = $rs_segment[0]['id']; - - $numero = get_new_numerofattura($data); - $numero_esterno = get_new_numerosecondariofattura($data); - $tipo_documento = 'Fattura immediata di vendita'; - - // Info contratto - $rs_contratto = $dbo->fetchArray('SELECT * FROM co_contratti WHERE id='.prepare($idcontratto)); - $idanagrafica = $rs_contratto[0]['idanagrafica']; - $idpagamento = $rs_contratto[0]['idpagamento']; - $idconto = setting('Conto predefinito fatture di vendita'); - - // Creazione nuova fattura - $dbo->query('INSERT INTO co_documenti(numero, numero_esterno, data, idanagrafica, idtipodocumento, idstatodocumento, idpagamento, idconto, id_segment) VALUES('.prepare($numero).', '.prepare($numero_esterno).', '.prepare($data).', '.prepare($idanagrafica).', (SELECT id FROM co_tipidocumento WHERE descrizione='.prepare($tipo_documento)."), (SELECT id FROM co_statidocumento WHERE descrizione='Bozza'), ".prepare($idpagamento).', '.prepare($idconto).','.prepare($id_segment).')'); - $id_record = $dbo->lastInsertedID(); - - // Righe contratto - $rs_righe = $dbo->fetchArray('SELECT * FROM co_righe_contratti WHERE idcontratto='.prepare($idcontratto)); - - for ($i = 0; $i < sizeof($rs_righe); ++$i) { - // Se sto aggiungendo un articolo uso la funzione per inserirlo e incrementare la giacenza - if ($rs_righe[$i]['idarticolo'] != 0) { - add_articolo_infattura($id_record, $rs_righe[$i]['idarticolo'], $rs_righe[$i]['descrizione'], $rs_righe[$i]['idiva'], $rs_righe[$i]['qta'], $rs_righe[$i]['subtotale'], $rs_righe[$i]['sconto'], $rs_righe[$i]['sconto_unitario'], $rs_righe[$i]['tipo_sconto']); - } - - // Inserimento riga normale - else { - $dbo->query('INSERT INTO co_righe_documenti(iddocumento, idcontratto, is_descrizione, descrizione, subtotale, sconto, sconto_unitario, tipo_sconto, sconto_globale, idiva, desc_iva, iva, iva_indetraibile, um, qta, idconto, `order`) values('.prepare($id_record).', '.prepare($idcontratto).', '.prepare($rs_righe[$i]['is_descrizione']).', '.prepare($rs_righe[$i]['descrizione']).', '.prepare($rs_righe[$i]['subtotale']).', '.prepare($rs_righe[$i]['sconto']).', '.prepare($rs_righe[$i]['sconto_unitario']).', '.prepare($rs_righe[$i]['tipo_sconto']).', '.prepare($rs_righe[$i]['sconto_globale']).', '.prepare($rs_righe[$i]['idiva']).', '.prepare($rs_righe[$i]['desc_iva']).', '.prepare($rs_righe[$i]['iva']).', '.prepare($rs_righe[$i]['iva_indetraibile']).', '.prepare($rs_righe[$i]['um']).', '.prepare($rs_righe[$i]['qta']).', '.prepare($idconto).', '.prepare($rs_righe[$i]['order']).')'); - } - } - - flash()->info(tr('Creata una nuova fattura!')); - break; - - // aggiungi righe da ddt - case 'add_ddt': - $idddt = post('iddocumento'); - - $rs = $dbo->fetchArray('SELECT * FROM co_documenti WHERE id='.prepare($id_record)); - $idconto = $rs[0]['idconto']; - - // Lettura di tutte le righe della tabella in arrivo - foreach (post('qta_da_evadere') as $i => $value) { - // Processo solo le righe da evadere - if (post('evadere')[$i] == 'on') { - $idrigaddt = $i; - $idarticolo = post('idarticolo')[$i]; - $descrizione = post('descrizione')[$i]; - - $qta = post('qta_da_evadere')[$i]; - $um = post('um')[$i]; - - $subtot = post('subtot')[$i] * $qta; - $sconto = post('sconto')[$i]; - $sconto = $sconto * $qta; - - $qprc = 'SELECT tipo_sconto, sconto_unitario FROM dt_righe_ddt WHERE id='.prepare($idrigaddt); - $rsprc = $dbo->fetchArray($qprc); - - $sconto_unitario = $rsprc[0]['sconto_unitario']; - $tipo_sconto = $rsprc[0]['tipo_sconto']; - - $idiva = post('idiva')[$i]; - - // Calcolo l'iva indetraibile - $q = 'SELECT percentuale, indetraibile FROM co_iva WHERE id='.prepare($idiva); - $rs = $dbo->fetchArray($q); - $iva = ($subtot - $sconto) / 100 * $rs[0]['percentuale']; - $iva_indetraibile = $iva / 100 * $rs[0]['indetraibile']; - - // Leggo la descrizione iva - $query = 'SELECT * FROM co_iva WHERE id='.prepare($idiva); - $rs = $dbo->fetchArray($query); - $desc_iva = $rs[0]['descrizione']; - - // Se sto aggiungendo un articolo uso la funzione per inserirlo e incrementare la giacenza - if (!empty($idarticolo)) { - $idiva_acquisto = $idiva; - $prezzo_acquisto = $subtot; - $riga = add_articolo_infattura($id_record, $idarticolo, $descrizione, $idiva_acquisto, $qta, $prezzo_acquisto, 0, 0, 'UNT', 0, $idconto, $um); - - // Lettura lotto, serial, altro dalla riga dell'ddt - $dbo->query('INSERT INTO mg_prodotti (id_riga_documento, id_articolo, dir, serial, lotto, altro) SELECT '.prepare($riga).', '.prepare($idarticolo).', '.prepare($dir).', serial, lotto, altro FROM mg_prodotti AS t WHERE id_riga_ddt='.prepare($idrigaddt)); - } - - // Inserimento riga normale - else { - $query = 'INSERT INTO co_righe_documenti(iddocumento, idarticolo, descrizione, idconto, idddt, idiva, desc_iva, iva, iva_indetraibile, subtotale, sconto, sconto_unitario, tipo_sconto, um, qta, `order`) VALUES('.prepare($id_record).', '.prepare($idarticolo).', '.prepare($descrizione).', '.prepare($idconto).', '.prepare($idddt).', '.prepare($idiva).', '.prepare($desc_iva).', '.prepare($iva).', '.prepare($iva_indetraibile).', '.prepare($subtot).', '.prepare($sconto).', '.prepare($sconto_unitario).', '.prepare($tipo_sconto).', '.prepare($um).', '.prepare($qta).', (SELECT IFNULL(MAX(`order`) + 1, 0) FROM co_righe_documenti AS t WHERE iddocumento='.prepare($id_record).'))'; - $dbo->query($query); - } - - // Scalo la quantità dal ddt - $dbo->query('UPDATE dt_righe_ddt SET qta_evasa = qta_evasa+'.$qta.' WHERE id='.prepare($idrigaddt)); - } - } - - ricalcola_costiagg_fattura($id_record); - - flash()->info(tr('Aggiunti nuovi articoli in fattura!')); - - break; - // Scollegamento intervento da documento case 'unlink_intervento': if (!empty($id_record) && post('idriga') !== null) { @@ -1182,71 +635,319 @@ switch (post('op')) { break; - // aggiungi righe da ordine + // Aggiunta di un ordine in fattura case 'add_ordine': - $idordine = post('iddocumento'); + $ordine = \Modules\Ordini\Ordine::find(post('id_ordine')); - // Lettura di tutte le righe della tabella in arrivo - foreach (post('qta_da_evadere') as $i => $value) { - // Processo solo le righe da evadere - if (post('evadere')[$i] == 'on') { - $idriga = $i; - $idarticolo = post('idarticolo')[$i]; - $descrizione = post('descrizione')[$i]; + // Creazione della fattura al volo + if (post('create_document') == 'on') { + $descrizione = ($dir == 'entrata') ? 'Fattura immediata di vendita' : 'Fattura immediata di acquisto'; + $tipo = Tipo::where('descrizione', $descrizione)->first(); - $qta = post('qta_da_evadere')[$i]; - $um = post('um')[$i]; + $fattura = Fattura::build($ordine->anagrafica, $tipo, post('data'), post('id_segment')); + $fattura->idpagamento = $ordine->idpagamento; + $fattura->save(); - $subtot = post('subtot')[$i] * $qta; - $sconto = post('sconto')[$i]; - $sconto = $sconto * $qta; + $id_record = $fattura->id; + } - $qprc = 'SELECT tipo_sconto, sconto_unitario FROM or_righe_ordini WHERE id='.prepare($idriga); - $rsprc = $dbo->fetchArray($qprc); + $id_rivalsa_inps = setting('Percentuale rivalsa'); + if ($dir == 'uscita') { + $id_ritenuta_acconto = $fattura->anagrafica->id_ritenuta_acconto_acquisti; + } else { + $id_ritenuta_acconto = $fattura->anagrafica->id_ritenuta_acconto_vendite ?: setting("Percentuale ritenuta d'acconto"); + } + $calcolo_ritenuta_acconto = setting("Metodologia calcolo ritenuta d'acconto predefinito"); + $id_conto = post('id_conto'); - $sconto_unitario = $rsprc[0]['sconto_unitario']; - $tipo_sconto = $rsprc[0]['tipo_sconto']; + $parziale = false; + $righe = $ordine->getRighe(); + foreach ($righe as $riga) { + if (post('evadere')[$riga->id] == 'on') { + $qta = post('qta_da_evadere')[$riga->id]; - $idiva = post('idiva')[$i]; + $copia = $riga->copiaIn($fattura, $qta); + $copia->id_conto = $id_conto; - // Calcolo l'iva indetraibile - $q = 'SELECT percentuale, indetraibile FROM co_iva WHERE id='.prepare($idiva); - $rs = $dbo->fetchArray($q); - $iva = ($subtot - $sconto) / 100 * $rs[0]['percentuale']; - $iva_indetraibile = $iva / 100 * $rs[0]['indetraibile']; + $copia->calcolo_ritenuta_acconto = $calcolo_ritenuta_acconto; + $copia->id_ritenuta_acconto = $id_ritenuta_acconto; + $copia->id_rivalsa_inps = $id_rivalsa_inps; - // Leggo la descrizione iva - $query = 'SELECT * FROM co_iva WHERE id='.prepare($idiva); - $rs = $dbo->fetchArray($query); - $desc_iva = $rs[0]['descrizione']; + // Aggiornamento seriali dalla riga dell'ordine + if ($copia->isArticolo()) { + $copia->movimenta($copia->qta); - $rs = $dbo->fetchArray('SELECT * FROM co_righe_documenti WHERE id='.prepare($idriga)); - $idconto = $rs[0]['idconto']; + $serials = is_array(post('serial')[$riga->id]) ? post('serial')[$riga->id] : []; - // Se sto aggiungendo un articolo uso la funzione per inserirlo e incrementare la giacenza - if (!empty($idarticolo)) { - $idiva_acquisto = $idiva; - $prezzo_acquisto = $subtot; - $riga = add_articolo_infattura($id_record, $idarticolo, $descrizione, $idiva_acquisto, $qta, $prezzo_acquisto, $sconto, $sconto_unitario, $tipo_sconto, 0, $idconto); - - // Lettura lotto, serial, altro dalla riga dell'ordine - $dbo->query('INSERT INTO mg_prodotti (id_riga_documento, id_articolo, dir, serial, lotto, altro) SELECT '.prepare($riga).', '.prepare($idarticolo).', '.prepare($dir).', serial, lotto, altro FROM mg_prodotti AS t WHERE id_riga_ordine='.prepare($idriga)); + $copia->serials = $serials; } - // Inserimento riga normale - elseif ($qta != 0) { - $query = 'INSERT INTO co_righe_documenti(iddocumento, idarticolo, descrizione, idconto, idordine, idiva, desc_iva, iva, iva_indetraibile, subtotale, sconto, sconto_unitario, tipo_sconto, um, qta, `order`) VALUES('.prepare($id_record).', '.prepare($idarticolo).', '.prepare($descrizione).', '.prepare($idconto).', '.prepare($idordine).', '.prepare($idiva).', '.prepare($desc_iva).', '.prepare($iva).', '.prepare($iva_indetraibile).', '.prepare($subtot).', '.prepare($sconto).', '.prepare($sconto_unitario).', '.prepare($tipo_sconto).', '.prepare($um).', '.prepare($qta).', (SELECT IFNULL(MAX(`order`) + 1, 0) FROM co_righe_documenti AS t WHERE iddocumento='.prepare($id_record).'))'; - $dbo->query($query); - } - - // Scalo la quantità dall ordine - $dbo->query('UPDATE or_righe_ordini SET qta_evasa = qta_evasa+'.$qta.' WHERE id='.prepare($idriga)); + $copia->save(); } + + if ($riga->qta != $riga->qta_evasa) { + $parziale = true; + } + } + + // Aggiornamento sconto + if (post('evadere')[$ordine->scontoGlobale->id] == 'on') { + $fattura->tipo_sconto_globale = $ordine->tipo_sconto_globale; + $fattura->sconto_globale = $ordine->tipo_sconto_globale == 'PRC' ? $ordine->sconto_globale : $ordine->sconto_globale; + $fattura->save(); + + $fattura->updateSconto(); + } + + // Impostazione del nuovo stato + $descrizione = $parziale ? 'Parzialmente fatturato' : 'Fatturato'; + $stato = \Modules\Ordini\Stato::where('descrizione', $descrizione)->first(); + $ordine->stato()->associate($stato); + $ordine->save(); + + ricalcola_costiagg_fattura($id_record); + + flash()->info(tr('Ordine _NUM_ aggiunto!', [ + '_NUM_' => $ordine->numero, + ])); + + break; + + // Aggiunta di un ddt in fattura + case 'add_ddt': + $ddt = \Modules\DDT\DDT::find(post('id_ddt')); + + // Creazione della fattura al volo + if (post('create_document') == 'on') { + $descrizione = ($dir == 'entrata') ? 'Fattura differita di vendita' : 'Fattura differita di acquisto'; + $tipo = Tipo::where('descrizione', $descrizione)->first(); + + $fattura = Fattura::build($ddt->anagrafica, $tipo, post('data'), post('id_segment')); + $fattura->idpagamento = $ddt->idpagamento; + $fattura->save(); + + $id_record = $fattura->id; + } + + $id_rivalsa_inps = setting('Percentuale rivalsa'); + if ($dir == 'uscita') { + $id_ritenuta_acconto = $fattura->anagrafica->id_ritenuta_acconto_acquisti; + } else { + $id_ritenuta_acconto = $fattura->anagrafica->id_ritenuta_acconto_vendite ?: setting("Percentuale ritenuta d'acconto"); + } + $calcolo_ritenuta_acconto = setting("Metodologia calcolo ritenuta d'acconto predefinito"); + $id_conto = post('id_conto'); + + $parziale = false; + $righe = $ddt->getRighe(); + foreach ($righe as $riga) { + if (post('evadere')[$riga->id] == 'on') { + $qta = post('qta_da_evadere')[$riga->id]; + + $copia = $riga->copiaIn($fattura, $qta); + $copia->id_conto = $id_conto; + + $copia->calcolo_ritenuta_acconto = $calcolo_ritenuta_acconto; + $copia->id_ritenuta_acconto = $id_ritenuta_acconto; + $copia->id_rivalsa_inps = $id_rivalsa_inps; + + // Aggiornamento seriali dalla riga dell'ordine + if ($copia->isArticolo()) { + $serials = is_array(post('serial')[$riga->id]) ? post('serial')[$riga->id] : []; + + $copia->serials = $serials; + } + + $copia->save(); + } + + if ($riga->qta != $riga->qta_evasa) { + $parziale = true; + } + } + + // Aggiornamento sconto + if (post('evadere')[$ddt->scontoGlobale->id] == 'on') { + $fattura->tipo_sconto_globale = $ddt->tipo_sconto_globale; + $fattura->sconto_globale = $ddt->tipo_sconto_globale == 'PRC' ? $ddt->sconto_globale : $ddt->sconto_globale; + $fattura->save(); + + $fattura->updateSconto(); + } + + // Impostazione del nuovo stato + $descrizione = $parziale ? 'Parzialmente fatturato' : 'Fatturato'; + $stato = \Modules\DDT\Stato::where('descrizione', $descrizione)->first(); + $ddt->stato()->associate($stato); + $ddt->save(); + + ricalcola_costiagg_fattura($id_record); + + flash()->info(tr('DDT _NUM_ aggiunto!', [ + '_NUM_' => $ddt->numero, + ])); + + break; + + // Aggiunta di un preventivo in fattura + case 'add_preventivo': + $preventivo = \Modules\Preventivi\Preventivo::find(post('id_preventivo')); + + // Creazione della fattura al volo + if (post('create_document') == 'on') { + $tipo = Tipo::where('descrizione', 'Fattura immediata di vendita')->first(); + + $fattura = Fattura::build($preventivo->anagrafica, $tipo, post('data'), post('id_segment')); + $fattura->idpagamento = $preventivo->idpagamento; + $fattura->save(); + + $id_record = $fattura->id; + } + + $id_rivalsa_inps = setting('Percentuale rivalsa'); + if ($dir == 'uscita') { + $id_ritenuta_acconto = $fattura->anagrafica->id_ritenuta_acconto_acquisti; + } else { + $id_ritenuta_acconto = $fattura->anagrafica->id_ritenuta_acconto_vendite ?: setting("Percentuale ritenuta d'acconto"); + } + $calcolo_ritenuta_acconto = setting("Metodologia calcolo ritenuta d'acconto predefinito"); + $id_conto = post('id_conto'); + + $parziale = false; + $righe = $preventivo->getRighe(); + foreach ($righe as $riga) { + if (post('evadere')[$riga->id] == 'on') { + $qta = post('qta_da_evadere')[$riga->id]; + + $copia = $riga->copiaIn($fattura, $qta); + $copia->id_conto = $id_conto; + + $copia->calcolo_ritenuta_acconto = $calcolo_ritenuta_acconto; + $copia->id_ritenuta_acconto = $id_ritenuta_acconto; + $copia->id_rivalsa_inps = $id_rivalsa_inps; + + // Aggiornamento seriali dalla riga dell'ordine + if ($copia->isArticolo()) { + $copia->movimenta($copia->qta); + } + + $copia->save(); + } + + if ($riga->qta != $riga->qta_evasa) { + $parziale = true; + } + } + + // Aggiornamento sconto + if (post('evadere')[$preventivo->scontoGlobale->id] == 'on') { + $fattura->tipo_sconto_globale = $preventivo->tipo_sconto_globale; + $fattura->sconto_globale = $preventivo->tipo_sconto_globale == 'PRC' ? $preventivo->sconto_globale : $preventivo->sconto_globale; + $fattura->save(); + + $fattura->updateSconto(); + } + + // Impostazione del nuovo stato + $descrizione = $parziale ? 'Parzialmente fatturato' : 'Fatturato'; + $stato = \Modules\Preventivi\Stato::where('descrizione', $descrizione)->first(); + $preventivo->stato()->associate($stato); + $preventivo->save(); + + // Trasferimento degli interventi collegati + $interventi = $preventivo->interventi; + $stato_intervento = \Modules\Interventi\Stato::where('descrizione', 'Fatturato')->first(); + foreach ($interventi as $intervento) { + $intervento->stato()->associate($stato_intervento); + $intervento->save(); } ricalcola_costiagg_fattura($id_record); - flash()->info(tr('Aggiunti nuovi articoli in fattura!')); + flash()->info(tr('Preventivo _NUM_ aggiunto!', [ + '_NUM_' => $preventivo->numero, + ])); + + break; + + // Aggiunta di un contratto in fattura + case 'add_contratto': + $contratto = \Modules\Contratti\Contratto::find(post('id_contratto')); + + // Creazione della fattura al volo + if (post('create_document') == 'on') { + $tipo = Tipo::where('descrizione', 'Fattura immediata di vendita')->first(); + + $fattura = Fattura::build($contratto->anagrafica, $tipo, post('data'), post('id_segment')); + $fattura->idpagamento = $contratto->idpagamento; + $fattura->save(); + + $id_record = $fattura->id; + } + + $id_rivalsa_inps = setting('Percentuale rivalsa'); + if ($dir == 'uscita') { + $id_ritenuta_acconto = $fattura->anagrafica->id_ritenuta_acconto_acquisti; + } else { + $id_ritenuta_acconto = $fattura->anagrafica->id_ritenuta_acconto_vendite ?: setting("Percentuale ritenuta d'acconto"); + } + $calcolo_ritenuta_acconto = setting("Metodologia calcolo ritenuta d'acconto predefinito"); + $id_conto = post('id_conto'); + + $parziale = false; + $righe = $contratto->getRighe(); + foreach ($righe as $riga) { + if (post('evadere')[$riga->id] == 'on') { + $qta = post('qta_da_evadere')[$riga->id]; + + $copia = $riga->copiaIn($fattura, $qta); + $copia->id_conto = $id_conto; + + $copia->calcolo_ritenuta_acconto = $calcolo_ritenuta_acconto; + $copia->id_ritenuta_acconto = $id_ritenuta_acconto; + $copia->id_rivalsa_inps = $id_rivalsa_inps; + + // Aggiornamento seriali dalla riga dell'ordine + if ($copia->isArticolo()) { + $copia->movimenta($copia->qta); + } + + $copia->save(); + } + + if ($riga->qta != $riga->qta_evasa) { + $parziale = true; + } + } + + // Aggiornamento sconto + if (post('evadere')[$contratto->scontoGlobale->id] == 'on') { + $fattura->tipo_sconto_globale = $contratto->tipo_sconto_globale; + $fattura->sconto_globale = $contratto->tipo_sconto_globale == 'PRC' ? $contratto->sconto_globale : $contratto->sconto_globale; + $fattura->save(); + + $fattura->updateSconto(); + } + + // Impostazione del nuovo stato + $descrizione = $parziale ? 'Parzialmente fatturato' : 'Fatturato'; + $stato = \Modules\Contratti\Stato::where('descrizione', $descrizione)->first(); + $contratto->stato()->associate($stato); + $contratto->save(); + + // Trasferimento degli interventi collegati + $interventi = $contratto->interventi; + $stato_intervento = \Modules\Interventi\Stato::where('descrizione', 'Fatturato')->first(); + foreach ($interventi as $intervento) { + $intervento->stato()->associate($stato_intervento); + $intervento->save(); + } + + ricalcola_costiagg_fattura($id_record); + + flash()->info(tr('Contratto _NUM_ aggiunto!', [ + '_NUM_' => $contratto->numero, + ])); break; @@ -1283,6 +984,8 @@ switch (post('op')) { $copia->serials = $serials; $riga->removeSerials($serials); } + + $copia->save(); } } diff --git a/modules/fatture/add_contratto.php b/modules/fatture/add_contratto.php index 1e1102ac1..bb38859e3 100644 --- a/modules/fatture/add_contratto.php +++ b/modules/fatture/add_contratto.php @@ -4,93 +4,82 @@ include_once __DIR__.'/../../core.php'; $module = Modules::get($id_module); -if ($module['name'] == 'Fatture di vendita') { - $dir = 'entrata'; - $conti = 'conti-vendite'; -} else { - $dir = 'uscita'; - $conti = 'conti-acquisti'; +$dir = ($module['name'] == 'Fatture di vendita') ? 'entrata' : 'uscita'; + +if (get('op')) { + $options = [ + 'op' => 'add_contratto', + 'id_importazione' => 'id_contratto', + 'final_module' => $module['name'], + 'original_module' => 'Contratti', + 'sql' => [ + 'table' => 'co_contratti', + 'rows' => 'co_righe_contratti', + 'id_rows' => 'idcontratto', + ], + 'serials' => false, + 'button' => tr('Aggiungi'), + 'dir' => $dir, + ]; + + $result = [ + 'id_record' => $id_record, + 'id_documento' => get('iddocumento'), + ]; + + echo App::load('importa.php', $result, $options, true); + + return; } -$info = $dbo->fetchOne('SELECT * FROM co_documenti WHERE id='.prepare($id_record)); -$numero = ($info['numero_esterno'] != '') ? $info['numero_esterno'] : $info['numero']; -$idconto = $info['idconto']; -$idanagrafica = $info['idanagrafica']; - -/* - Form di inserimento riga documento -*/ echo ' -

'.tr('Documento numero _NUM_', [ - '_NUM_' => $numero, -]).'

- -
- - - '; - -// Contratto -$_SESSION['superselect']['stato'] = 'fatturabile'; -$_SESSION['superselect']['non_fatturato'] = 1; -echo ' -
-
- {[ "type": "select", "label": "'.tr('Contratto').'", "name": "idcontratto", "required": 1, "ajax-source": "contratti", "extra": "onchange=\"$data = $(this).selectData(); $(\'#descrizione\').val($data.text); $(\'#prezzo\').val($data.totale); $(\'#sconto\').val($data.sconto); if ($data.n_righe>0) { $(\'#import\').prop(\'checked\', true); $(\'input[name=import]\').val(\'1\'); $(\'#import\').removeAttr(\'disabled\'); }else{ $(\'#import\').prop(\'checked\', false); $(\'input[name=import]\').val(\'0\'); $(\'#import\').prop(\'disabled\', true); } \"" ]} -
- -
- {[ "type": "checkbox", "label": "'.tr('Importa righe').'", "name": "import", "value": "1", "placeholder": "'.tr('Replica righe del contratto in fattura').'" ]} -
-
'; - -// Descrizione -echo ' -
-
- {[ "type": "textarea", "label": "'.tr('Descrizione').'", "name": "descrizione", "required": 1 ]} -
-
'; - -// Leggo l'iva predefinita dall'articolo e se non c'è leggo quella predefinita generica -$idiva = $idiva ?: setting('Iva predefinita'); - -// Iva -echo ' -
-
- {[ "type": "select", "label": "'.tr('Iva').'", "name": "idiva", "required": 1, "value": "'.$idiva.'", "ajax-source": "iva" ]} -
'; - -echo ' -
- {[ "type": "select", "label": "'.tr('Conto').'", "name": "idconto", "required": 1, "value": "'.$idconto.'", "ajax-source": "'.$conti.'" ]} -
-
'; - -// Costo unitario -echo ' -
-
- {[ "type": "number", "label": "'.tr('Costo unitario').'", "name": "prezzo", "required": 1, "icon-after": "€" ]} -
'; - -// Sconto unitario -echo ' -
- {[ "type": "number", "label": "'.tr('Sconto unitario').'", "name": "sconto", "icon-after": "choice|untprc" ]} -
-
'; - -echo ' - - -
-
- -
+
+
+ {[ "type": "select", "label": "'.tr('Contratto').'", "name": "id_documento", "ajax-source": "contratti" ]}
-'; +
+
+
+

'.tr('Informazioni di importazione').'

+
+
+
+
+ +
+ '.tr('Caricamento in corso').'... +
'; + +$file = basename(__FILE__); echo ' - '; + + +'; diff --git a/modules/fatture/add_ddt.php b/modules/fatture/add_ddt.php index a760a1ab2..ba257f97b 100644 --- a/modules/fatture/add_ddt.php +++ b/modules/fatture/add_ddt.php @@ -4,40 +4,88 @@ include_once __DIR__.'/../../core.php'; $module = Modules::get($id_module); -if ($module['name'] == 'Fatture di vendita') { - $dir = 'entrata'; - $module_origin = 'Ddt di vendita'; -} else { - $dir = 'uscita'; - $module_origin = 'Ddt di acquisto'; +$dir = ($module['name'] == 'Fatture di vendita') ? 'entrata' : 'uscita'; + +if (get('op')) { + $options = [ + 'op' => 'add_ddt', + 'id_importazione' => 'id_ddt', + 'final_module' => $module['name'], + 'original_module' => $module['name'] == 'Fatture di vendita' ? 'Ddt di vendita' : 'Ddt di acquisto', + 'sql' => [ + 'table' => 'dt_ddt', + 'rows' => 'dt_righe_ddt', + 'id_rows' => 'idddt', + ], + 'serials' => [ + 'id_riga' => 'id_riga_ddt', + 'condition' => '(id_riga_documento IS NOT NULL)', + ], + 'button' => tr('Aggiungi'), + 'dir' => $dir, + ]; + + $result = [ + 'id_record' => $id_record, + 'id_documento' => get('iddocumento'), + ]; + + echo App::load('importa.php', $result, $options, true); + + return; } $info = $dbo->fetchOne('SELECT * FROM co_documenti WHERE id='.prepare($id_record)); -$numero = ($info['numero_esterno'] != '') ? $info['numero_esterno'] : $info['numero']; $idanagrafica = $info['idanagrafica']; -// Ddt echo ' -
-
- {[ "type": "select", "label": "'.tr('Ddt').'", "name": "id_ddt", "required": 1, "values": "query=SELECT dt_ddt.id, CONCAT(\'nr. \', IF(numero_esterno != \'\', numero_esterno, numero), \' del \', DATE_FORMAT(data, \'%d-%m-%Y\')) AS descrizione FROM dt_ddt WHERE idanagrafica='.prepare($idanagrafica).' AND idstatoddt IN (SELECT id FROM dt_statiddt WHERE descrizione IN(\'Bozza\', \'Evaso\', \'Parzialmente evaso\', \'Parzialmente fatturato\')) AND idtipoddt=(SELECT id FROM dt_tipiddt WHERE dir='.prepare($dir).') AND dt_ddt.id IN (SELECT idddt FROM dt_righe_ddt WHERE dt_righe_ddt.idddt = dt_ddt.id AND (qta - qta_evasa) > 0) ORDER BY data DESC, numero DESC" ]} -
-
'; +
+
+ {[ "type": "select", "label": "'.tr('Ddt').'", "name": "id_documento", "values": "query=SELECT dt_ddt.id, CONCAT(\'DDT num. \', IF(numero_esterno != \'\', numero_esterno, numero), \' del \', DATE_FORMAT(data, \'%d-%m-%Y\')) AS descrizione FROM dt_ddt WHERE idanagrafica='.prepare($idanagrafica).' AND idstatoddt IN (SELECT id FROM dt_statiddt WHERE descrizione IN(\'Bozza\', \'Evaso\', \'Parzialmente evaso\', \'Parzialmente fatturato\')) AND idtipoddt=(SELECT id FROM dt_tipiddt WHERE dir='.prepare($dir).') AND dt_ddt.id IN (SELECT idddt FROM dt_righe_ddt WHERE dt_righe_ddt.idddt = dt_ddt.id AND (qta - qta_evasa) > 0) ORDER BY data DESC, numero DESC" ]} +
+
+
+
+

'.tr('Informazioni di importazione').'

+
+
+
+
+ +
+ '.tr('Caricamento in corso').'... +
'; + +$file = basename(__FILE__); echo ' -
-
-
'; - -echo ' - '; - -?> - + + +'; diff --git a/modules/fatture/add_intervento.php b/modules/fatture/add_intervento.php index db564c9fc..19f180d0c 100644 --- a/modules/fatture/add_intervento.php +++ b/modules/fatture/add_intervento.php @@ -46,7 +46,7 @@ $rs = $dbo->fetchArray('SELECT AND in_interventi.id_preventivo IS NULL AND NOT in_interventi.id IN (SELECT idintervento FROM co_promemoria WHERE idintervento IS NOT NULL)'); foreach ($rs as $key => $value) { - $rs[$key]['prezzo'] = get_costi_intervento($value['id'])['totale']; + $rs[$key]['prezzo'] = Translator::numberToLocale(get_costi_intervento($value['id'])['totale']); } // Intervento diff --git a/modules/fatture/add_ordine.php b/modules/fatture/add_ordine.php index 20e959962..aed3f4db2 100644 --- a/modules/fatture/add_ordine.php +++ b/modules/fatture/add_ordine.php @@ -4,40 +4,88 @@ include_once __DIR__.'/../../core.php'; $module = Modules::get($id_module); -if ($module['name'] == 'Fatture di vendita') { - $dir = 'entrata'; - $module_origin = 'Ordini cliente'; -} else { - $dir = 'uscita'; - $module_origin = 'Ordini fornitore'; +$dir = ($module['name'] == 'Fatture di vendita') ? 'entrata' : 'uscita'; + +if (get('op')) { + $options = [ + 'op' => 'add_ordine', + 'id_importazione' => 'id_ordine', + 'final_module' => $module['name'], + 'original_module' => $module['name'] == 'Fatture di vendita' ? 'Ordini cliente' : 'Ordini fornitore', + 'sql' => [ + 'table' => 'or_ordini', + 'rows' => 'or_righe_ordini', + 'id_rows' => 'idordine', + ], + 'serials' => [ + 'id_riga' => 'id_riga_ddt', + 'condition' => '(id_riga_documento IS NOT NULL)', + ], + 'button' => tr('Aggiungi'), + 'dir' => $dir, + ]; + + $result = [ + 'id_record' => $id_record, + 'id_documento' => get('iddocumento'), + ]; + + echo App::load('importa.php', $result, $options, true); + + return; } $info = $dbo->fetchOne('SELECT * FROM co_documenti WHERE id='.prepare($id_record)); -$numero = ($info['numero_esterno'] != '') ? $info['numero_esterno'] : $info['numero']; $idanagrafica = $info['idanagrafica']; -// Ordine echo ' -
-
- {[ "type": "select", "label": "'.tr('Ordine').'", "name": "id_ordine", "required": 1, "values": "query=SELECT or_ordini.id, CONCAT(IF(numero_esterno != \'\', numero_esterno, numero), \' del \', DATE_FORMAT(data, \'%d-%m-%Y\')) AS descrizione FROM or_ordini WHERE idanagrafica='.prepare($idanagrafica).' AND idstatoordine IN (SELECT id FROM or_statiordine WHERE descrizione IN(\'Bozza\', \'Evaso\', \'Parzialmente evaso\', \'Parzialmente fatturato\')) AND idtipoordine=(SELECT id FROM or_tipiordine WHERE dir='.prepare($dir).' LIMIT 0,1) AND or_ordini.id IN (SELECT idordine FROM or_righe_ordini WHERE or_righe_ordini.idordine = or_ordini.id AND (qta - qta_evasa) > 0) ORDER BY data DESC, numero DESC" ]} -
-
'; +
+
+ {[ "type": "select", "label": "'.tr('Ordine').'", "name": "id_documento", "values": "query=SELECT or_ordini.id, CONCAT(IF(numero_esterno != \'\', numero_esterno, numero), \' del \', DATE_FORMAT(data, \'%d-%m-%Y\')) AS descrizione FROM or_ordini WHERE idanagrafica='.prepare($idanagrafica).' AND idstatoordine IN (SELECT id FROM or_statiordine WHERE descrizione IN(\'Bozza\', \'Evaso\', \'Parzialmente evaso\', \'Parzialmente fatturato\')) AND idtipoordine=(SELECT id FROM or_tipiordine WHERE dir='.prepare($dir).' LIMIT 0,1) AND or_ordini.id IN (SELECT idordine FROM or_righe_ordini WHERE or_righe_ordini.idordine = or_ordini.id AND (qta - qta_evasa) > 0) ORDER BY data DESC, numero DESC" ]} +
+
+
+
+

'.tr('Informazioni di importazione').'

+
+
+
+
+ +
+ '.tr('Caricamento in corso').'... +
'; + +$file = basename(__FILE__); echo ' -
-
-
'; - -echo ' - '; - -?> - + + +'; diff --git a/modules/fatture/add_preventivo.php b/modules/fatture/add_preventivo.php index 4d95c0a8d..e93882797 100644 --- a/modules/fatture/add_preventivo.php +++ b/modules/fatture/add_preventivo.php @@ -4,93 +4,80 @@ include_once __DIR__.'/../../core.php'; $module = Modules::get($id_module); -if ($module['name'] == 'Fatture di vendita') { - $dir = 'entrata'; - $conti = 'conti-vendite'; -} else { - $dir = 'uscita'; - $conti = 'conti-acquisti'; +if (get('op')) { + $options = [ + 'op' => 'add_preventivo', + 'id_importazione' => 'id_preventivo', + 'final_module' => $module['name'], + 'original_module' => 'Preventivi', + 'sql' => [ + 'table' => 'co_preventivi', + 'rows' => 'co_righe_preventivi', + 'id_rows' => 'idpreventivo', + ], + 'serials' => false, + 'button' => tr('Aggiungi'), + 'dir' => $dir, + ]; + + $result = [ + 'id_record' => $id_record, + 'id_documento' => get('iddocumento'), + ]; + + echo App::load('importa.php', $result, $options, true); + + return; } -$info = $dbo->fetchOne('SELECT * FROM co_documenti WHERE id='.prepare($id_record)); -$numero = ($info['numero_esterno'] != '') ? $info['numero_esterno'] : $info['numero']; -$idanagrafica = $info['idanagrafica']; - -$idconto = ($dir == 'entrata') ? setting('Conto predefinito fatture di vendita') : setting('Conto predefinito fatture di acquisto'); - -/* - Form di inserimento riga documento -*/ echo ' -

'.tr('Documento numero _NUM_', [ - '_NUM_' => $numero, -]).'

- -
- - - '; - -// Preventivo -$_SESSION['superselect']['stati'] = [ - 'Accettato', - 'In lavorazione', - 'In attesa di conferma', -]; -$_SESSION['superselect']['non_fatturato'] = 1; - -echo ' -
-
- {[ "type": "select", "label": "'.tr('Preventivo').'", "name": "idpreventivo", "required": 1, "ajax-source": "preventivi", "extra": "onchange=\"$data = $(this).selectData(); $(\'#descrizione\').val($data.text); $(\'#prezzo\').val($data.totale - $data.sconto);console.log($data.totale)\"" ]} -
- -
- {[ "type": "checkbox", "label": "'.tr('Importa righe').'", "name": "import", "value": "1", "placeholder": "'.tr('Replica righe del preventivo in fattura').'" ]} -
-
'; - -// Descrizione -echo ' -
-
- {[ "type": "textarea", "label": "'.tr('Descrizione').'", "name": "descrizione", "required": 1 ]} -
-
'; - -// Leggo l'iva predefinita dall'articolo e se non c'è leggo quella predefinita generica -$idiva = $idiva ?: setting('Iva predefinita'); - -// Iva -echo ' -
-
- {[ "type": "select", "label": "'.tr('Iva').'", "name": "idiva", "required": 1, "value": "'.$idiva.'", "ajax-source": "iva" ]} -
'; - -echo ' -
- {[ "type": "select", "label": "'.tr('Conto').'", "name": "idconto", "required": 1, "value": "'.$idconto.'", "ajax-source": "'.$conti.'" ]} -
-
'; - -// Costo unitario -echo ' -
-
- {[ "type": "number", "label": "'.tr('Costo unitario').'", "name": "prezzo", "required": 1, "icon-after": "€", "disabled": 1 ]} -
-
'; - -echo ' - - -
-
- -
+
+
+ {[ "type": "select", "label": "'.tr('Preventivo').'", "name": "id_documento", "ajax-source": "preventivi" ]}
-'; +
+
+
+

'.tr('Informazioni di importazione').'

+
+
+
+
+ +
+ '.tr('Caricamento in corso').'... +
'; + +$file = basename(__FILE__); echo ' - '; + + +'; diff --git a/modules/fatture/bulk.php b/modules/fatture/bulk.php index a889b1087..20f96bbe3 100644 --- a/modules/fatture/bulk.php +++ b/modules/fatture/bulk.php @@ -2,6 +2,7 @@ include_once __DIR__.'/../../core.php'; +use Modules\Fatture\Fattura; use Util\Zip; switch (post('op')) { @@ -9,6 +10,9 @@ switch (post('op')) { $dir = DOCROOT.'/files/export_fatture/'; directory($dir.'tmp/'); + $dir = slashes($dir); + $zip = slashes($dir.'fatture_'.time().'.zip'); + // Rimozione dei contenuti precedenti $files = glob($dir.'/*.zip'); foreach ($files as $file) { @@ -32,15 +36,12 @@ switch (post('op')) { Prints::render($print['id'], $r['id'], $filename); } - $dir = slashes($dir); - $file = slashes($dir.'fatture_'.time().'.zip'); - // Creazione zip if (extension_loaded('zip')) { - Zip::create($dir.'tmp/', $file); + Zip::create($dir.'tmp/', $zip); // Invio al browser dello zip - download($file); + download($zip); // Rimozione dei contenuti delete($dir.'tmp/'); @@ -49,28 +50,94 @@ switch (post('op')) { break; - case 'delete-bulk': - - if (App::debug()) { - foreach ($id_records as $id) { - $dbo->query('DELETE FROM co_documenti WHERE id = '.prepare($id).Modules::getAdditionalsQuery($id_module)); - $dbo->query('DELETE FROM co_righe_documenti WHERE iddocumento='.prepare($id).Modules::getAdditionalsQuery($id_module)); - $dbo->query('DELETE FROM co_scadenziario WHERE iddocumento='.prepare($id).Modules::getAdditionalsQuery($id_module)); - $dbo->query('DELETE FROM mg_movimenti WHERE iddocumento='.prepare($id).Modules::getAdditionalsQuery($id_module)); - } - - flash()->info(tr('Fatture eliminate!')); - } else { - flash()->warning(tr('Procedura in fase di sviluppo. Nessuna modifica apportata.')); + case 'delete-bulk': + if (App::debug()) { + foreach ($id_records as $id) { + $dbo->query('DELETE FROM co_documenti WHERE id = '.prepare($id).Modules::getAdditionalsQuery($id_module)); + $dbo->query('DELETE FROM co_righe_documenti WHERE iddocumento='.prepare($id).Modules::getAdditionalsQuery($id_module)); + $dbo->query('DELETE FROM co_scadenziario WHERE iddocumento='.prepare($id).Modules::getAdditionalsQuery($id_module)); + $dbo->query('DELETE FROM mg_movimenti WHERE iddocumento='.prepare($id).Modules::getAdditionalsQuery($id_module)); } + flash()->info(tr('Fatture eliminate!')); + } else { + flash()->warning(tr('Procedura in fase di sviluppo. Nessuna modifica apportata.')); + } + break; + + case 'export-xml-bulk': + $dir = DOCROOT.'/files/export_fatture/'; + directory($dir.'tmp/'); + + $dir = slashes($dir); + $zip = slashes($dir.'fatture_'.time().'.zip'); + + // Rimozione dei contenuti precedenti + $files = glob($dir.'/*.zip'); + foreach ($files as $file) { + delete($file); + } + + // Selezione delle fatture da stampare + $fatture = $dbo->fetchArray('SELECT co_documenti.id, numero_esterno, data, ragione_sociale, co_tipidocumento.descrizione FROM co_documenti INNER JOIN an_anagrafiche ON co_documenti.idanagrafica=an_anagrafiche.idanagrafica INNER JOIN co_tipidocumento ON co_documenti.idtipodocumento=co_tipidocumento.id WHERE co_documenti.id IN('.implode(',', $id_records).')'); + + $failed = []; + if (!empty($fatture)) { + foreach ($fatture as $r) { + $fattura = Fattura::find($r['id']); + $include = true; + + try { + $fe = new \Plugins\ExportFE\FatturaElettronica($fattura->id); + + $include = $fe->isGenerated(); + } catch (UnexpectedValueException $e) { + $include = false; + } + + if (!$include) { + $failed[] = $fattura->numero_esterno; + } else { + $filename = $fe->getFilename(); + + $file = slashes($module->upload_directory.'/'.$filename); + $dest = slashes($dir.'/tmp/'.$filename); + + $result = copy($file, $dest); + if ($result) { + operationLog('export-xml-bulk', ['id_record' => $r['id']]); + } else { + $failed[] = $fattura->numero_esterno; + } + } + } + + // Creazione zip + if (extension_loaded('zip')) { + Zip::create($dir.'tmp/', $zip); + + // Invio al browser il file zip + download($zip); + + // Rimozione dei contenuti + delete($dir.'tmp/'); + } + + if (!empty($failed)) { + flash()->warning(tr('Le fatture elettroniche _LIST_ non sono state incluse poichè non ancora generate', [ + '_LIST_' => implode(', ', $failed), + ])); + } + } break; } -return [ +$bulk = [ 'delete-bulk' => tr('Elimina selezionati'), +]; - 'export-bulk' => [ +if ($module->name == 'Fatture di vendita') { + $bulk['export-bulk'] = [ 'text' => tr('Esporta stampe'), 'data' => [ 'msg' => tr('Vuoi davvero esportare tutte le stampe in un archivio?'), @@ -78,5 +145,17 @@ return [ 'class' => 'btn btn-lg btn-warning', 'blank' => true, ], - ], -]; + ]; + + $bulk['export-xml-bulk'] = [ + 'text' => tr('Esporta XML'), + 'data' => [ + 'msg' => tr('Vuoi davvero esportare tutte le fatture elettroniche in un archivio?'), + 'button' => tr('Procedi'), + 'class' => 'btn btn-lg btn-warning', + 'blank' => true, + ], + ]; +} + +return $bulk; diff --git a/modules/fatture/buttons.php b/modules/fatture/buttons.php index 4308304c0..59c9f4f88 100644 --- a/modules/fatture/buttons.php +++ b/modules/fatture/buttons.php @@ -13,10 +13,10 @@ echo ' '.tr('Duplica fattura').' '; -if ($dir == 'entrata' && empty($record['ref_documento']) && $record['stato'] == 'Emessa') { +if ($dir == 'entrata') { echo '
- @@ -41,3 +41,29 @@ if (empty($record['is_fiscale'])) { '.tr('Trasforma in fattura fiscale').' '; } + +?> + +fetchNum('SELECT id FROM co_movimenti WHERE iddocumento='.prepare($id_record).' AND primanota=1'); + + $rs3 = $dbo->fetchArray('SELECT SUM(da_pagare-pagato) AS differenza, SUM(da_pagare) FROM co_scadenziario GROUP BY iddocumento HAVING iddocumento='.prepare($id_record)); + $differenza = isset($rs3[0]) ? $rs3[0]['differenza'] : null; + $da_pagare = isset($rs3[0]) ? $rs3[0]['da_pagare'] : null; + + if (($n2 <= 0 && $record['stato'] == 'Emessa') || $differenza != 0) { + ?> + + + + \ No newline at end of file diff --git a/modules/fatture/crea_documento.php b/modules/fatture/crea_documento.php index 528dca6e6..10b1ee359 100644 --- a/modules/fatture/crea_documento.php +++ b/modules/fatture/crea_documento.php @@ -4,340 +4,29 @@ include_once __DIR__.'/../../core.php'; $module = Modules::get($id_module); -$data = [ - 'ddt' => [ - 'table' => 'dt_ddt', // Tabella del documento - 'rows' => 'dt_righe_ddt', // Tabella delle righe - 'id' => 'idddt', // ID nella tabella delle righe - 'condition' => '(id_riga_documento IS NOT NULL)', // Condizione per i seriali - ], - 'ord' => [ - 'table' => 'or_ordini', - 'rows' => 'or_righe_ordini', - 'id' => 'idordine', - 'condition' => '(id_riga_ddt IS NOT NULL OR id_riga_documento IS NOT NULL)', - ], - 'fat' => [ +$options = [ + 'op' => 'nota_credito', + 'id_importazione' => 'id_documento', + 'final_module' => $module['name'], + 'original_module' => $module['name'], + 'sql' => [ 'table' => 'co_documenti', 'rows' => 'co_righe_documenti', - 'id' => 'iddocumento', - 'condition' => '(1 = 2)', - 'allow-empty' => true, + 'id_rows' => 'iddocumento', ], + 'serials' => [ + 'id_riga' => 'id_riga_documento', + 'condition' => '(1 = 2)', + ], + 'button' => tr('Aggiungi'), + 'dir' => $dir, + 'create_document' => true, + 'allow-empty' => true, ]; -$documento = get('documento'); +$result = [ + 'id_record' => $id_record, + 'id_documento' => get('iddocumento'), +]; -if ($module['name'] == 'Ordini cliente' || $module['name'] == 'Ordini fornitore') { - $pos = 'ord'; - $op = ($documento == 'ddt') ? 'ddt_da_ordine' : 'fattura_da_ordine'; - - $head = tr('Ordine numero _NUM_'); - - $dir = ($module['name'] == 'Ordini cliente') ? 'entrata' : 'uscita'; -} elseif ($module['name'] == 'Ddt di vendita' || $module['name'] == 'Ddt di acquisto') { - $pos = 'ddt'; - $op = 'fattura_da_ddt'; - - $head = tr('Ddt numero _NUM_'); - - $dir = ($module['name'] == 'Ddt di vendita') ? 'entrata' : 'uscita'; -} else { - $pos = 'fat'; - $op = 'nota_credito'; - - $head = tr('Fattura numero _NUM_'); - - $dir = 'entrata'; -} - -$table = $data[$pos]['table']; -$rows = $data[$pos]['rows']; -$id = $data[$pos]['id']; -$row = str_replace('id', 'id_riga_', $id); - -if ($module['name'] == 'Ordini cliente') { - $module_name = ($documento == 'ddt') ? 'Ddt di vendita' : 'Fatture di vendita'; -} elseif ($module['name'] == 'Ordini fornitore') { - $module_name = ($documento == 'ddt') ? 'Ddt di acquisto' : 'Fatture di acquisto'; -} elseif ($module['name'] == 'Ddt di acquisto') { - $module_name = 'Fatture di acquisto'; -} else { - $module_name = 'Fatture di vendita'; -} - -$op = !empty(get('op')) ? get('op') : $op; - -$button = ($documento == 'ddt') ? tr('Crea ddt') : tr('Crea fattura'); -$button = !empty(get('op')) ? tr('Aggiungi') : $button; - -// Info documento -$rs = $dbo->fetchArray('SELECT * FROM '.$table.' WHERE id='.prepare($id_record)); -$numero = !empty($rs[0]['numero_esterno']) ? $rs[0]['numero_esterno'] : $rs[0]['numero']; -$idanagrafica = $rs[0]['idanagrafica']; -$idpagamento = $rs[0]['idpagamento']; -$idconto = $rs[0]['idconto']; - -if (empty($idconto)) { - $idconto = ($dir == 'entrata') ? setting('Conto predefinito fatture di vendita') : setting('Conto predefinito fatture di acquisto'); -} - -/* - Form di inserimento riga documento -*/ -echo ' -

'.str_replace('_NUM_', $numero, $head).'.

'; - -// Selezione articoli dell'ordine da portare nel ddt -$rs = $dbo->fetchArray('SELECT *, IFNULL((SELECT codice FROM mg_articoli WHERE id=idarticolo),"") AS codice, (qta - qta_evasa) AS qta_rimanente FROM '.$table.' INNER JOIN '.$rows.' ON '.$table.'.id='.$rows.'.'.$id.' WHERE '.$table.'.id='.prepare($id_record).' HAVING qta_rimanente > 0 OR is_descrizione = 1 ORDER BY `order`'); - -if (!empty($rs)) { - echo ' -

'.tr('Seleziona le righe e le relative quantità da inserire nel documento').'.

- -
- - - - - - - - - '; - - if (empty(get('op'))) { - echo ' -
- -
- {[ "type": "date", "label": "'.tr('Data del documento').'", "name": "data", "required": 1, "value": "-now-" ]} -
'; - - if ($module_name == 'Fatture di vendita' || $module_name == 'Fatture di acquisto') { - $rs_segment = $dbo->fetchArray("SELECT * FROM zz_segments WHERE predefined_accredito='1'"); - if ($op == 'nota_accredito' && sizeof($rs_segment) > 0) { - echo ' -
- {[ "type": "select", "label": "'.tr('Sezionale').'", "name": "id_segment", "required": 1, "values": "query=SELECT id, name AS descrizione FROM zz_segments WHERE id_module='.prepare(Modules::get($module_name)['id']).' ORDER BY name", "value": "'.$rs_segment[0]['id'].'" ]} -
'; - } else { - echo ' -
- {[ "type": "select", "label": "'.tr('Sezionale').'", "name": "id_segment", "required": 1, "values": "query=SELECT id, name AS descrizione FROM zz_segments WHERE id_module='.prepare(Modules::get($module_name)['id']).' ORDER BY name", "value": "'.$_SESSION['module_'.Modules::get($module_name)['id']]['id_segment'].'" ]} -
'; - } - } - - echo - '
'; - } - - echo ' -
-
- - - - - - - - - '; - - $totale = 0.00; - - foreach ($rs as $i => $r) { - // Descrizione - echo ' - - '; - - // Q.tà rimanente - echo ' - '; - - // Q.tà da evadere - echo ' - '; - - // Subtotale - $subtotale = $r['subtotale'] / $r['qta'] * ($r['qta'] - $r['qta_evasa']); - $sconto = $r['sconto'] / $r['qta'] * ($r['qta'] - $r['qta_evasa']); - $iva = $r['iva'] / $r['qta'] * ($r['qta'] - $r['qta_evasa']); - - echo ' - '; - - // Seriali - echo ' - - '; - - $totale += $subtotale - $sconto + $iva; - } - - // Totale - echo ' - - - - -
'.tr('Descrizione').''.tr('Q.tà').''.tr('Q.tà da evadere').''.tr('Subtot.').''.tr('Seriali').'
- - - - '; - - // Checkbox - da evadere? - echo ' - '; - - $descrizione = (!empty($r['codice']) ? $r['codice'].' - ' : '').$r['descrizione']; - - echo ' '.nl2br($descrizione); - - echo ' - - - -

'.Translator::numberToLocale($r['qta_rimanente']).'

-
- {[ "type": "number", "name": "qta_da_evadere['.$r['id'].']", "id": "qta_'.$i.'", "required": 1, "value": "'.$r['qta_rimanente'].'", "extra" : "onkeyup=\"ricalcola_subtotale_riga('.$i.');\"", "decimals": "qta", "min-value": "0", "extra": "'.(($r['is_descrizione']) ? 'readonly' : '').'" ]} - - - - - - - '.Translator::numberToLocale($subtotale - $sconto + $iva).' €
- - '.Translator::numberToLocale($subtotale - $sconto).' + '.Translator::numberToLocale($iva).' -
'; - if (!empty($r['abilita_serial'])) { - $query = 'SELECT DISTINCT serial AS id, serial AS descrizione FROM mg_prodotti WHERE dir='.prepare($dir).' AND '.$row.' = '.prepare($r['id']).' AND serial IS NOT NULL AND serial NOT IN (SELECT serial FROM mg_prodotti AS t WHERE serial IS NOT NULL AND dir='.prepare($dir).' AND '.$data[$pos]['condition'].')'; - - $values = $dbo->fetchArray($query); - if (!empty($values)) { - echo ' - {[ "type": "select", "name": "serial['.$r['id'].'][]", "id": "serial_'.$i.'", "multiple": 1, "values": "query='.$query.'", "value": "'.implode(',', array_column($values, 'id')).'", "extra": "data-maximum=\"'.intval($r['qta_rimanente']).'\"" ]}'; - } else { - echo '-'; - } - } else { - echo '-'; - } - echo ' -
- '.tr('Totale').': - - '.Translator::numberToLocale($totale).' € -
'; - - echo ' - - -
-
- -
-
-
'; -} else { - echo ' -

'.tr('Non ci sono articoli da evadere').'...

'; -} - -echo ' - '; - -?> - - +echo App::load('importa.php', $result, $options, true); diff --git a/modules/fatture/edit.php b/modules/fatture/edit.php index fcd500bd2..b1da75986 100644 --- a/modules/fatture/edit.php +++ b/modules/fatture/edit.php @@ -85,7 +85,7 @@ if ($dir == 'entrata') { {[ "type": "hidden", "label": "Segmento", "name": "id_segment", "class": "text-center", "value": "$id_segment$" ]}
- {[ "type": "text", "label": "", "name": "numero_esterno", "class": "alphanumeric-mask text-center", "value": "$numero_esterno$" ]} + {[ "type": "text", "label": "", "name": "numero_esterno", "class": "text-center", "value": "$numero_esterno$" ]}
@@ -113,7 +113,7 @@ if (empty($record['is_fiscale'])) { - {[ "type": "select", "label": "", "name": "codice_stato_fe", "required": 0, "values": "query=SELECT codice as id, descrizione as text FROM fe_stati_documento", "value": "$codice_stato_fe$", "disabled": , "class": "unblockable" ]} + {[ "type": "select", "label": "", "name": "codice_stato_fe", "required": 0, "values": "query=SELECT codice as id, CONCAT_WS(' - ',codice,descrizione) as text FROM fe_stati_documento", "value": "$codice_stato_fe$", "disabled": , "class": "unblockable", "help": "" ]} @@ -128,7 +128,7 @@ if (empty($record['is_fiscale'])) { if ($dir == 'entrata') { ?> - {[ "type": "select", "label": "", "name": "idanagrafica", "required": 1, "ajax-source": "clienti", "help": "fetchOne('SELECT ragione_sociale FROM an_anagrafiche WHERE idanagrafica = '.prepare(setting('Azienda predefinita')))['ragione_sociale']; ?>", "value": "$idanagrafica$" ]} + {[ "type": "select", "label": "", "name": "idanagrafica", "required": 1, "ajax-source": "clienti", "help": "fetchOne('SELECT ragione_sociale FROM an_anagrafiche WHERE idanagrafica = '.prepare(setting('Azienda predefinita')))['ragione_sociale']); ?>", "value": "$idanagrafica$" ]} @@ -141,6 +141,14 @@ if (empty($record['is_fiscale'])) {
{[ "type": "select", "label": "", "name": "idsede", "ajax-source": "sedi", "placeholder": "Sede legale", "value": "$idsede$" ]}
+ + + +
+ {[ "type": "date", "label": "", "name": "data_ricezione", "required": 0, "value": "$data_ricezione$" ]} +
+ + @@ -152,14 +160,41 @@ if (empty($record['is_fiscale'])) { fetchArray('SELECT * FROM co_scadenziario WHERE iddocumento = '.prepare($id_record)); echo '

'.tr('Scadenze').'

'; foreach ($scadenze as $scadenza) { echo ' -

'.Translator::dateToLocale($scadenza['scadenza']).': '.Translator::numberToLocale($scadenza['da_pagare']).'€

'; +

'.Translator::dateToLocale($scadenza['scadenza']).': '; + + if ($scadenza['pagato'] == $scadenza['da_pagare']) { + echo ' + '; + } + + echo Translator::numberToLocale($scadenza['da_pagare']).'€'; + + if ($scadenza['pagato'] == $scadenza['da_pagare']) { + echo ' + '; + } + + echo ' +

'; + + $ricalcola = empty(floatval($scadenza['pagato'])) && $ricalcola; } + + if ($fattura->isFE() && $ricalcola && $module['name'] == 'Fatture di acquisto') { + echo ' + '; + } + echo '
'; } @@ -171,7 +206,7 @@ if (empty($record['is_fiscale'])) {
- + {[ "type": "select", "label": "", "name": "idtipodocumento", "required": 1, "values": "query=SELECT id, descrizione FROM co_tipidocumento WHERE dir='' AND (reversed = 0 OR id = )", "value": "$idtipodocumento$", "readonly": , "help": "fetchOne('SELECT tipo FROM an_anagrafiche WHERE idanagrafica = '.prepare($record['idanagrafica']))['tipo'] == 'Ente pubblico') ? 'FPA12 - fattura verso PA' : 'FPR12 - fattura verso privati'; ?>" ]}
@@ -182,35 +217,6 @@ if (empty($record['is_fiscale'])) {
{[ "type": "select", "label": "", "name": "idbanca", "values": "query=SELECT id, CONCAT (nome, ' - ' , iban) AS descrizione FROM co_banche WHERE deleted_at IS NULL ORDER BY nome ASC", "value": "$idbanca$", "icon-after": "add|||", "extra": " " ]}
- - -
-
-fetchNum('SELECT id FROM co_movimenti WHERE iddocumento='.prepare($id_record).' AND primanota=1'); - - $rs3 = $dbo->fetchArray('SELECT SUM(da_pagare-pagato) AS differenza, SUM(da_pagare) FROM co_scadenziario GROUP BY iddocumento HAVING iddocumento='.prepare($id_record)); - $differenza = isset($rs3[0]) ? $rs3[0]['differenza'] : null; - $da_pagare = isset($rs3[0]) ? $rs3[0]['da_pagare'] : null; - - if (($n2 <= 0 && $record['stato'] == 'Emessa') || $differenza != 0) { - ?> - ...

- - ... - - -
- +
- +
- {[ "type": "number", "label": "", "name": "sconto_generico", "value": "$sconto_globale$", "help": "", "icon-after": "choice|untprc|$tipo_sconto_globale$" ]} + {[ "type": "number", "label": "", "name": "sconto_generico", "value": "$sconto_globale$", "help": "", "icon-after": "choice|untprc|$tipo_sconto_globale$" ]}
- +
{[ "type": "checkbox", "label": "", "name": "split_payment", "value": "$split_payment$", "help": "", "placeholder": "" ]}
- +
- {[ "type": "checkbox", "label": "", "name": "is_fattura_conto_terzi", "value": "$is_fattura_conto_terzi$", "help": "fetchOne('SELECT ragione_sociale FROM an_anagrafiche WHERE idanagrafica = '.prepare(setting('Azienda predefinita')))['ragione_sociale'].') come cessionario e il cliente come cedente/prestatore.'); ?>", "placeholder": "" ]} + {[ "type": "checkbox", "label": "", "name": "is_fattura_conto_terzi", "value": "$is_fattura_conto_terzi$", "help": "fetchOne('SELECT ragione_sociale FROM an_anagrafiche WHERE idanagrafica = '.prepare(setting('Azienda predefinita')))['ragione_sociale']).') come cessionario e il cliente come cedente/prestatore.'); ?>", "placeholder": "" ]}
- + - - + +
+ {[ "type": "select", "label": "", "name": "id_ritenuta_contributi", "value": "$id_ritenuta_contributi$", "values": "query=SELECT * FROM co_ritenuta_contributi" ]} +
+
- {[ "type": "textarea", "label": "", "name": "note", "help": "", "value": "$note$" ]} + {[ "type": "textarea", "label": "", "name": "note", "help": "", "value": "$note$" ]}
@@ -432,7 +441,7 @@ if ($record['stato'] != 'Pagato' && $record['stato'] != 'Emessa') {
'; // Lettura preventivi accettati, in attesa di conferma o in lavorazione - $prev_query = 'SELECT COUNT(*) AS tot FROM co_preventivi WHERE idanagrafica='.prepare($record['idanagrafica'])." AND id NOT IN (SELECT idpreventivo FROM co_righe_documenti WHERE idpreventivo IS NOT NULL) AND id NOT IN (SELECT idpreventivo FROM or_righe_ordini WHERE NOT idpreventivo IS NOT NULL) AND idstato IN(SELECT id FROM co_statipreventivi WHERE descrizione='Accettato' OR descrizione='In lavorazione' OR descrizione='In attesa di conferma') AND default_revision=1"; + $prev_query = 'SELECT COUNT(*) AS tot FROM co_preventivi WHERE idanagrafica='.prepare($record['idanagrafica'])." AND idstato IN(SELECT id FROM co_statipreventivi WHERE descrizione='Accettato' OR descrizione='In lavorazione' OR descrizione='In attesa di conferma') AND default_revision=1 AND co_preventivi.id IN (SELECT idpreventivo FROM co_righe_preventivi WHERE co_righe_preventivi.idpreventivo = co_preventivi.id AND (qta - qta_evasa) > 0)"; $preventivi = $dbo->fetchArray($prev_query)[0]['tot']; echo '
@@ -442,7 +451,7 @@ if ($record['stato'] != 'Pagato' && $record['stato'] != 'Emessa') {
'; // Lettura contratti accettati, in attesa di conferma o in lavorazione - $contr_query = 'SELECT COUNT(*) AS tot FROM co_contratti WHERE idanagrafica='.prepare($record['idanagrafica']).' AND id NOT IN (SELECT idcontratto FROM co_righe_documenti WHERE idcontratto IS NOT NULL) AND idstato IN( SELECT id FROM co_staticontratti WHERE fatturabile = 1) AND NOT EXISTS (SELECT id FROM co_righe_documenti WHERE co_righe_documenti.idcontratto = co_contratti.id)'; + $contr_query = 'SELECT COUNT(*) AS tot FROM co_contratti WHERE idanagrafica='.prepare($record['idanagrafica']).' AND idstato IN( SELECT id FROM co_staticontratti WHERE fatturabile = 1) AND co_contratti.id IN (SELECT idcontratto FROM co_righe_contratti WHERE co_righe_contratti.idcontratto = co_contratti.id AND (qta - qta_evasa) > 0)'; $contratti = $dbo->fetchArray($contr_query)[0]['tot']; echo '
@@ -525,21 +534,35 @@ include $docroot.'/modules/fatture/row-list.php'; {( "name": "filelist_and_upload", "id_module": "$id_module$", "id_record": "$id_record$" )} '.tr('Per allegare un documento alla fattura elettronica caricare il file specificando come categoria "Fattura Elettronica"').'.
'; - } -?> +if ($dir == 'entrata') { + echo ' +
'.tr('Per allegare un documento alla fattura elettronica caricare il file PDF specificando come categoria "Fattura Elettronica"').'.
'; +} +echo ' -'; if (!empty($note_accredito)) { echo ' @@ -572,10 +595,6 @@ if (!empty($note_accredito)) { $(".btn-sm[data-toggle=\"tooltip\"]").each(function() { $(this).on("click", function() { - /*if(!content_was_modified) { - return; - }*/ - form = $("#edit-form"); btn = $(this); diff --git a/modules/fatture/modutil.php b/modules/fatture/modutil.php index d6e316f84..bae9cbda7 100755 --- a/modules/fatture/modutil.php +++ b/modules/fatture/modutil.php @@ -93,10 +93,9 @@ function get_ivaindetraibile_fattura($iddocumento) */ function elimina_scadenza($iddocumento) { - $dbo = database(); + $fattura = Fattura::find($iddocumento); - $query2 = 'DELETE FROM co_scadenziario WHERE iddocumento='.prepare($iddocumento); - $dbo->query($query2); + $fattura->rimuoviScadenze(); } /** @@ -105,126 +104,19 @@ function elimina_scadenza($iddocumento) * $pagamento string Nome del tipo di pagamento. Se è vuoto lo leggo da co_pagamenti_documenti, perché significa che devo solo aggiornare gli importi. * $pagato boolean Indica se devo segnare l'importo come pagato. */ -function aggiungi_scadenza($iddocumento, $pagamento = '', $pagato = 0) +function aggiungi_scadenza($iddocumento, $pagamento = '', $pagato = false) { - $dbo = database(); - $fattura = Fattura::find($iddocumento); - if ($fattura->isFE()) { - $scadenze_fe = $fattura->registraScadenzeFE($pagato); - } - - // Lettura data di emissione fattura - $query3 = 'SELECT ritenutaacconto, data FROM co_documenti WHERE id='.prepare($iddocumento); - $rs = $dbo->fetchArray($query3); - $data = $rs[0]['data']; - $ritenutaacconto = $rs[0]['ritenutaacconto']; - - if (empty($scadenze_fe)) { - $totale_da_pagare = 0.00; - - $totale_fattura = get_totale_fattura($iddocumento); - $netto_fattura = get_netto_fattura($iddocumento); - $imponibile_fattura = get_imponibile_fattura($iddocumento); - $totale_iva = sum(abs($totale_fattura), -abs($imponibile_fattura)); - - // Verifico se la fattura è di acquisto o di vendita per scegliere che segno mettere nel totale - $query2 = 'SELECT dir FROM co_documenti INNER JOIN co_tipidocumento ON co_documenti.idtipodocumento=co_tipidocumento.id WHERE co_documenti.id='.prepare($iddocumento); - $rs2 = $dbo->fetchArray($query2); - $dir = $rs2[0]['dir']; - - /* - Inserisco la nuova scadenza (anche più di una riga per pagamenti multipli - */ - // Se il pagamento non è specificato lo leggo dal documento - if ($pagamento == '') { - $query = 'SELECT descrizione FROM co_pagamenti WHERE id=(SELECT idpagamento FROM co_documenti WHERE id='.prepare($iddocumento).')'; - $rs = $dbo->fetchArray($query); - $pagamento = $rs[0]['descrizione']; - } - - $query4 = 'SELECT * FROM co_pagamenti WHERE descrizione='.prepare($pagamento); - $rs = $dbo->fetchArray($query4); - for ($i = 0; $i < sizeof($rs); ++$i) { - // X giorni esatti - if ($rs[$i]['giorno'] == 0) { - $scadenza = date('Y-m-d', strtotime($data.' +'.$rs[$i]['num_giorni'].' day')); - } - - // Ultimo del mese - elseif ($rs[$i]['giorno'] < 0) { - $date = new DateTime($data); - - $add = floor($rs[$i]['num_giorni'] / 30); - for ($c = 0; $c < $add; ++$c) { - $date->modify('last day of next month'); - } - - // Ultimo del mese più X giorni - $giorni = -$rs[$i]['giorno'] - 1; - if ($giorni > 0) { - $date->modify('+'.($giorni).' day'); - } else { - $date->modify('last day of this month'); - } - - $scadenza = $date->format('Y-m-d'); - } - - // Giorno preciso del mese - else { - $scadenza = date('Y-m-'.$rs[$i]['giorno'], strtotime($data.' +'.$rs[$i]['num_giorni'].' day')); - } - - // All'ultimo ciclo imposto come cifra da pagare il totale della fattura meno gli importi già inseriti in scadenziario per evitare di inserire cifre arrotondate "male" - if ($i == (sizeof($rs) - 1)) { - $da_pagare = sum($netto_fattura, -$totale_da_pagare, 2); - } - - // Totale da pagare (totale x percentuale di pagamento nei casi pagamenti multipli) - else { - $da_pagare = sum($netto_fattura / 100 * $rs[$i]['prc'], 0, 2); - } - $totale_da_pagare = sum($da_pagare, $totale_da_pagare, 2); - - if ($dir == 'uscita') { - $da_pagare = -$da_pagare; - } - - $dbo->query('INSERT INTO co_scadenziario(iddocumento, data_emissione, scadenza, da_pagare, pagato, tipo) VALUES('.prepare($iddocumento).', '.prepare($data).', '.prepare($scadenza).', '.prepare($da_pagare).", 0, 'fattura')"); - - if ($pagato) { - $id_scadenza = $dbo->lastInsertedID(); - $dbo->update('co_scadenziario', [ - 'pagato' => $da_pagare, - 'data_pagamento' => $data, - ], ['id' => $id_scadenza]); - } - } - } - - // Se c'è una ritenuta d'acconto, la aggiungo allo scadenzario - if ($dir == 'uscita' && $ritenutaacconto > 0) { - $dbo->query('INSERT INTO co_scadenziario(iddocumento, data_emissione, scadenza, da_pagare, pagato, tipo) VALUES('.prepare($iddocumento).', '.prepare($data).', '.prepare(date('Y-m', strtotime($data.' +1 month')).'-15').', '.prepare(-$ritenutaacconto).", 0, 'ritenutaacconto')"); - - if ($pagato) { - $id_scadenza = $dbo->lastInsertedID(); - $dbo->update('co_scadenziario', [ - 'pagato' => -$ritenutaacconto, - 'data_pagamento' => $data, - ], ['id' => $id_scadenza]); - } - } - - return true; + $fattura->registraScadenze($pagato); } /** - * Funzione per aggiornare lo stato dei pagamenti nello scadenziario - * $iddocumento int ID della fattura - * $totale_pagato float Totale importo pagato - * $data_pagamento datetime Data in cui avviene il pagamento (yyyy-mm-dd). + * Funzione per aggiornare lo stato dei pagamenti nello scadenziario. + * + * @param $iddocumento int ID della fattura + * @param $totale_pagato float Totale importo pagato + * @param $data_pagamento datetime Data in cui avviene il pagamento (yyyy-mm-dd) */ function aggiorna_scadenziario($iddocumento, $totale_pagato, $data_pagamento) { @@ -393,7 +285,17 @@ function aggiungi_movimento($iddocumento, $dir, $primanota = 0) $numero = $rs[0]['numero']; } - $descrizione = $rs[0]['descrizione_tipodoc']." numero $numero"; + // Abbreviazioni contabili dei movimenti + $tipodoc = ''; + if ($rs[0]['descrizione_tipodoc'] == 'Nota di credito') { + $tipodoc = 'Nota di credito'; + } elseif ($rs[0]['descrizione_tipodoc'] == 'Nota di debito') { + $tipodoc = 'Nota di debito'; + } else { + $tipodoc = 'Fattura'; + } + + $descrizione = $tipodoc.' num. '.$numero; /* Il mastrino si apre con almeno 3 righe di solito (esempio fattura di vendita): diff --git a/modules/fatture/row-add.php b/modules/fatture/row-add.php index 1157cf24e..f1505d59e 100644 --- a/modules/fatture/row-add.php +++ b/modules/fatture/row-add.php @@ -3,7 +3,7 @@ include_once __DIR__.'/../../core.php'; // Info documento -$rs = $dbo->fetchArray('SELECT idanagrafica FROM co_documenti WHERE id='.prepare($id_record)); +$rs = $dbo->fetchArray('SELECT * FROM co_documenti WHERE id='.prepare($id_record)); $idanagrafica = $rs[0]['idanagrafica']; if ($module['name'] == 'Fatture di vendita') { @@ -26,6 +26,7 @@ $options = [ 'dir' => $dir, 'conti' => $conti, 'idanagrafica' => $idanagrafica, + 'show-ritenuta-contributi' => !empty($rs[0]['id_ritenuta_contributi']), ]; // Dati di default @@ -38,6 +39,7 @@ $result = [ 'tipo_sconto' => '', 'idiva' => '', 'idconto' => $idconto, + 'ritenuta_contributi' => true, ]; // Leggo l'iva predefinita per l'anagrafica e se non c'è leggo quella predefinita generica @@ -53,8 +55,13 @@ if ($listino[0]['prc_guadagno'] > 0) { } // Leggo la ritenuta d'acconto predefinita per l'anagrafica e se non c'è leggo quella predefinita generica +// id_ritenuta_acconto_vendite oppure id_ritenuta_acconto_acquisti $ritenuta_acconto = $dbo->fetchOne('SELECT id_ritenuta_acconto_'.($dir == 'uscita' ? 'acquisti' : 'vendite').' AS id_ritenuta_acconto FROM an_anagrafiche WHERE idanagrafica='.prepare($idanagrafica)); -$options['id_ritenuta_acconto_predefined'] = $ritenuta_acconto['id_ritenuta_acconto']; +$id_ritenuta_acconto = $ritenuta_acconto['id_ritenuta_acconto']; +if ($dir == 'entrata' && empty($id_ritenuta_acconto)) { + $id_ritenuta_acconto = setting("Percentuale ritenuta d'acconto"); +} +$options['id_ritenuta_acconto_predefined'] = $id_ritenuta_acconto; // Importazione della gestione dedicata $file = 'riga'; diff --git a/modules/fatture/row-edit.php b/modules/fatture/row-edit.php index c0ab1c78c..85798ff2d 100644 --- a/modules/fatture/row-edit.php +++ b/modules/fatture/row-edit.php @@ -22,6 +22,7 @@ $options = [ 'conti' => $conti, 'idanagrafica' => $idanagrafica, 'edit_articolo' => false, + 'show-ritenuta-contributi' => !empty($rs[0]['id_ritenuta_contributi']), ]; // Dati della riga diff --git a/modules/fatture/row-list.php b/modules/fatture/row-list.php index feba8b31a..8956e6849 100644 --- a/modules/fatture/row-list.php +++ b/modules/fatture/row-list.php @@ -39,14 +39,8 @@ foreach ($righe as $row) { $extra = ''; - $ref_modulo = null; - $ref_id = null; - // Articoli if ($row->isArticolo()) { - $ref_modulo = Modules::get('Articoli')['id']; - $ref_id = $riga['idarticolo']; - $riga['descrizione'] = (!empty($row->articolo) ? $row->articolo->codice.' - ' : '').$riga['descrizione']; $delete = 'unlink_articolo'; @@ -56,10 +50,8 @@ foreach ($righe as $row) { } // Intervento elseif (!empty($riga['idintervento'])) { - //$ref_modulo = Modules::get('Interventi')['id']; - //$ref_id = $riga['idintervento']; - - $intervento = $dbo->fetchOne('SELECT codice_cig,codice_cup,id_documento_fe FROM in_interventi WHERE id = '.prepare($riga['idintervento'])); + $intervento = $dbo->fetchOne('SELECT num_item,codice_cig,codice_cup,id_documento_fe FROM in_interventi WHERE id = '.prepare($riga['idintervento'])); + $riga['num_item'] = $intervento['num_item']; $riga['codice_cig'] = $intervento['codice_cig']; $riga['codice_cup'] = $intervento['codice_cup']; $riga['id_documento_fe'] = $intervento['id_documento_fe']; @@ -68,10 +60,8 @@ foreach ($righe as $row) { } // Preventivi elseif (!empty($riga['idpreventivo'])) { - //$ref_modulo = Modules::get('Preventivi')['id']; - //$ref_id = $riga['idpreventivo']; - - $preventivo = $dbo->fetchOne('SELECT codice_cig,codice_cup,id_documento_fe FROM co_preventivi WHERE id = '.prepare($riga['idpreventivo'])); + $preventivo = $dbo->fetchOne('SELECT num_item,codice_cig,codice_cup,id_documento_fe FROM co_preventivi WHERE id = '.prepare($riga['idpreventivo'])); + $riga['num_item'] = $preventivo['num_item']; $riga['codice_cig'] = $preventivo['codice_cig']; $riga['codice_cup'] = $preventivo['codice_cup']; $riga['id_documento_fe'] = $preventivo['id_documento_fe']; @@ -80,15 +70,23 @@ foreach ($righe as $row) { } // Contratti elseif (!empty($riga['idcontratto'])) { - //$ref_modulo = Modules::get('Contratti')['id']; - //$ref_id = $riga['idcontratto']; - - $contratto = $dbo->fetchOne('SELECT codice_cig,codice_cup,id_documento_fe FROM co_contratti WHERE id = '.prepare($riga['idcontratto'])); + $contratto = $dbo->fetchOne('SELECT num_item,codice_cig,codice_cup,id_documento_fe FROM co_contratti WHERE id = '.prepare($riga['idcontratto'])); + $riga['num_item'] = $contratto['num_item']; $riga['codice_cig'] = $contratto['codice_cig']; $riga['codice_cup'] = $contratto['codice_cup']; $riga['id_documento_fe'] = $contratto['id_documento_fe']; $delete = 'unlink_contratto'; + } + // Ordini (IDDOCUMENTO,CIG,CUP) + elseif (!empty($riga['idordine'])) { + $ordine = $dbo->fetchOne('SELECT num_item,codice_cig,codice_cup,id_documento_fe FROM or_ordini WHERE id = '.prepare($riga['idordine'])); + $riga['num_item'] = $ordine['num_item']; + $riga['codice_cig'] = $ordine['codice_cig']; + $riga['codice_cup'] = $ordine['codice_cup']; + $riga['id_documento_fe'] = $ordine['id_documento_fe']; + + $delete = 'unlink_riga'; } // Righe generiche else { @@ -109,18 +107,19 @@ foreach ($righe as $row) { $extra_riga = ''; if (!$riga['is_descrizione']) { - $extra_riga = tr('_DESCRIZIONE_CONTO_ _ID_DOCUMENTO_ _CODICE_CIG_ _CODICE_CUP_ ', [ + $extra_riga = tr('_DESCRIZIONE_CONTO__ID_DOCUMENTO__NUMERO_RIGA__CODICE_CIG__CODICE_CUP_', [ '_DESCRIZIONE_CONTO_' => $riga['descrizione_conto'] ?: null, - '_CODICE_CIG_' => $riga['codice_cig'] ? ',CIG: '.$riga['codice_cig'] : null, - '_CODICE_CUP_' => $riga['codice_cup'] ? ',CUP: '.$riga['codice_cup'] : null, '_ID_DOCUMENTO_' => $riga['id_documento_fe'] ? ' - DOC: '.$riga['id_documento_fe'] : null, + '_NUMERO_RIGA_' => $riga['num_item'] ? ', NRI: '.$riga['num_item'] : null, + '_CODICE_CIG_' => $riga['codice_cig'] ? ', CIG: '.$riga['codice_cig'] : null, + '_CODICE_CUP_' => $riga['codice_cup'] ? ', CUP: '.$riga['codice_cup'] : null, ]); } echo ' - '.Modules::link($ref_modulo, $ref_id, $riga['descrizione']).' + '.Modules::link($row->isArticolo() ? Modules::get('Articoli')['id'] : null, $row->isArticolo() ? $riga['idarticolo'] : null, $riga['descrizione']).' '.$extra_riga.''; if (!empty($riga['abilita_serial'])) { @@ -422,6 +421,20 @@ if (!empty($fattura->ritenuta_acconto)) { '; } +// RITENUTA CONTRIBUTI +if (!empty($fattura->totale_ritenuta_contributi)) { + echo ' + + + '.tr('Ritenuta contributi', [], ['upper' => true]).': + + + '.Translator::numberToLocale($fattura->totale_ritenuta_contributi).' € + + + '; +} + // NETTO A PAGARE if ($totale != $netto_a_pagare) { echo ' diff --git a/modules/fatture/src/Components/Articolo.php b/modules/fatture/src/Components/Articolo.php index d03256ee8..861294704 100644 --- a/modules/fatture/src/Components/Articolo.php +++ b/modules/fatture/src/Components/Articolo.php @@ -11,6 +11,7 @@ class Articolo extends Article use RelationTrait; protected $table = 'co_righe_documenti'; + protected $serialRowID = 'documento'; /** * Crea un nuovo articolo collegato ad una fattura. diff --git a/modules/fatture/src/Components/RelationTrait.php b/modules/fatture/src/Components/RelationTrait.php index e3c70193c..49adabdef 100644 --- a/modules/fatture/src/Components/RelationTrait.php +++ b/modules/fatture/src/Components/RelationTrait.php @@ -3,6 +3,8 @@ namespace Modules\Fatture\Components; use Modules\Fatture\Fattura; +use Modules\Ritenute\RitenutaAcconto; +use Modules\Rivalse\RivalsaINPS; trait RelationTrait { @@ -23,7 +25,7 @@ trait RelationTrait public function getNettoAttribute() { - $result = $this->totale - $this->ritenuta_acconto; + $result = $this->totale - $this->ritenuta_acconto - $this->ritenuta_contributi; if ($this->parent->split_payment) { $result = $result - $this->iva; @@ -31,4 +33,122 @@ trait RelationTrait return $result; } + + /** + * Restituisce il totale (imponibile + iva + rivalsa_inps + iva_rivalsainps) dell'elemento. + * + * @return float + */ + public function getTotaleAttribute() + { + return $this->imponibile_scontato + $this->iva + $this->rivalsa_inps + $this->iva_rivalsa_inps; + } + + public function getRivalsaINPSAttribute() + { + return $this->imponibile_scontato / 100 * $this->rivalsa->percentuale; + } + + public function getIvaRivalsaINPSAttribute() + { + return $this->rivalsa_inps / 100 * $this->aliquota->percentuale; + } + + public function getRitenutaAccontoAttribute() + { + $result = $this->imponibile_scontato; + + if ($this->calcolo_ritenuta_acconto == 'IMP+RIV') { + $result += $this->rivalsainps; + } + + return $result / 100 * $this->ritenuta->percentuale; + } + + public function getRitenutaContributiAttribute() + { + if ($this->attributes['ritenuta_contributi']) { + $result = $this->imponibile_scontato; + $ritenuta = $this->parent->ritenutaContributi; + + $result = $result * $ritenuta->percentuale_imponibile / 100; + + return $result / 100 * $ritenuta->percentuale; + } + + return 0; + } + + /** + * Imposta l'identificatore della Rivalsa INPS. + * + * @param int $value + */ + public function setIdRivalsaINPSAttribute($value) + { + $this->attributes['idrivalsainps'] = $value; + $this->load('rivalsa'); + } + + /** + * Imposta l'identificatore della Ritenuta d'Acconto. + * + * @param int $value + */ + public function setIdRitenutaAccontoAttribute($value) + { + $this->attributes['idritenutaacconto'] = $value; + $this->load('ritenuta'); + } + + public function getIdContoAttribute() + { + return $this->idconto; + } + + public function setIdContoAttribute($value) + { + $this->attributes['idconto'] = $value; + } + + public function rivalsa() + { + return $this->belongsTo(RivalsaINPS::class, 'idrivalsainps'); + } + + public function ritenuta() + { + return $this->belongsTo(RitenutaAcconto::class, 'idritenutaacconto'); + } + + /** + * Salva la riga, impostando i campi dipendenti dai parametri singoli. + * + * @param array $options + * + * @return bool + */ + public function save(array $options = []) + { + $this->fixRitenutaAcconto(); + $this->fixRivalsaINPS(); + + return parent::save($options); + } + + /** + * Effettua i conti per la Rivalsa INPS. + */ + protected function fixRivalsaINPS() + { + $this->attributes['rivalsainps'] = $this->rivalsa_inps; + } + + /** + * Effettua i conti per la Ritenuta d'Acconto, basandosi sul valore del campo calcolo_ritenuta_acconto. + */ + protected function fixRitenutaAcconto() + { + $this->attributes['ritenutaacconto'] = $this->ritenuta_acconto; + } } diff --git a/modules/fatture/src/Fattura.php b/modules/fatture/src/Fattura.php index 777793069..4f28b91a5 100644 --- a/modules/fatture/src/Fattura.php +++ b/modules/fatture/src/Fattura.php @@ -4,6 +4,8 @@ namespace Modules\Fatture; use Common\Document; use Modules\Anagrafiche\Anagrafica; +use Modules\Pagamenti\Pagamento; +use Modules\RitenuteContributi\RitenutaContributi; use Plugins\ExportFE\FatturaElettronica; use Traits\RecordTrait; use Util\Generator; @@ -14,11 +16,6 @@ class Fattura extends Document protected $table = 'co_documenti'; - /** - * The attributes that should be casted to native types. - * - * @var array - */ protected $casts = [ 'bollo' => 'float', ]; @@ -87,6 +84,9 @@ class Fattura extends Document $model->idconto = $id_conto; $model->idsede = $id_sede; + $id_ritenuta_contributi = ($tipo_documento->dir == 'entrata') ? setting('Ritenuta contributi') : null; + $model->id_ritenuta_contributi = $id_ritenuta_contributi ?: null; + if (!empty($id_pagamento)) { $model->idpagamento = $id_pagamento; } @@ -135,6 +135,8 @@ class Fattura extends Document return $this->tipo->dir == 'entrata' ? 'Fatture di vendita' : 'Fatture di acquisto'; } + // Calcoli + /** * Calcola il netto a pagare della fattura. * @@ -142,7 +144,228 @@ class Fattura extends Document */ public function getNettoAttribute() { - return parent::getNettoAttribute() + $this->bollo; + return $this->calcola('netto') + $this->bollo; + } + + /** + * Calcola la rivalsa INPS totale della fattura. + * + * @return float + */ + public function getRivalsaINPSAttribute() + { + return $this->calcola('rivalsa_inps'); + } + + /** + * Calcola l'IVA totale della fattura. + * + * @return float + */ + public function getIvaAttribute() + { + return $this->calcola('iva', 'iva_rivalsa_inps'); + } + + /** + * Calcola l'iva della rivalsa INPS totale della fattura. + * + * @return float + */ + public function getIvaRivalsaINPSAttribute() + { + return $this->calcola('iva_rivalsa_inps'); + } + + /** + * Calcola la ritenuta d'acconto totale della fattura. + * + * @return float + */ + public function getRitenutaAccontoAttribute() + { + return $this->calcola('ritenuta_acconto'); + } + + public function getTotaleRitenutaContributiAttribute() + { + return $this->calcola('ritenuta_contributi'); + } + + // Relazioni Eloquent + + public function anagrafica() + { + return $this->belongsTo(Anagrafica::class, 'idanagrafica'); + } + + public function tipo() + { + return $this->belongsTo(Tipo::class, 'idtipodocumento'); + } + + public function pagamento() + { + return $this->belongsTo(Pagamento::class, 'idpagamento'); + } + + public function stato() + { + return $this->belongsTo(Stato::class, 'idstatodocumento'); + } + + public function statoFE() + { + return $this->belongsTo(StatoFE::class, 'codice_stato_fe'); + } + + public function articoli() + { + return $this->hasMany(Components\Articolo::class, 'iddocumento'); + } + + public function righe() + { + return $this->hasMany(Components\Riga::class, 'iddocumento'); + } + + public function descrizioni() + { + return $this->hasMany(Components\Descrizione::class, 'iddocumento'); + } + + public function scontoGlobale() + { + return $this->hasOne(Components\Sconto::class, 'iddocumento'); + } + + public function ritenutaContributi() + { + return $this->belongsTo(RitenutaContributi::class, 'id_ritenuta_contributi'); + } + + // Metodi generali + + public function getXML() + { + if (empty($this->progressivo_invio)) { + $fe = new FatturaElettronica($this->id); + + return $fe->toXML(); + } + + $file = $this->uploads()->where('name', 'Fattura Elettronica')->first(); + + return file_get_contents($file->filepath); + } + + public function isFE() + { + return !empty($this->progressivo_invio) && $this->module == 'Fatture di acquisto'; + } + + /** + * Registra le scadenze della fattura elettronica collegata al documento. + * + * @param bool $is_pagato + * + * @return bool + */ + public function registraScadenzeFE($is_pagato = false) + { + $xml = \Util\XML::read($this->getXML()); + + $pagamenti = $xml['FatturaElettronicaBody']['DatiPagamento']['DettaglioPagamento']; + if (!empty($pagamenti)) { + $rate = isset($pagamenti[0]) ? $pagamenti : [$pagamenti]; + + foreach ($rate as $rata) { + $scadenza = $rata['DataScadenzaPagamento'] ?: $this->data; + $importo = -$rata['ImportoPagamento']; + + self::registraScadenza($this, $importo, $scadenza, $is_pagato); + } + } + + return !empty($pagamenti); + } + + /** + * Registra le scadenze tradizionali del gestionale. + * + * @param bool $is_pagato + */ + public function registraScadenzeTradizionali($is_pagato = false) + { + $rate = $this->pagamento->calcola($this->netto, $this->data); + $direzione = $this->tipo->dir; + + foreach ($rate as $rata) { + $importo = $direzione == 'uscita' ? -$rata['importo'] : $rata['importo']; + $scadenza = $rata['scadenza']; + + self::registraScadenza($this, $importo, $scadenza, $is_pagato); + } + } + + /** + * Registra una specifica scadenza nel database. + * + * @param Fattura $fattura + * @param float $importo + * @param string $scadenza + * @param bool $is_pagato + * @param string $type + */ + public static function registraScadenza(Fattura $fattura, $importo, $scadenza, $is_pagato, $type = 'fattura') + { + database()->insert('co_scadenziario', [ + 'iddocumento' => $fattura->id, + 'data_emissione' => $fattura->data, + 'scadenza' => $scadenza, + 'da_pagare' => $importo, + 'tipo' => $type, + 'pagato' => $is_pagato ? $importo : 0, + 'data_pagamento' => $is_pagato ? $scadenza : null, + ]); + } + + /** + * Registra le scadenze della fattura. + * + * @param bool $is_pagato + * @param bool $ignora_fe + */ + public function registraScadenze($is_pagato = false, $ignora_fe = false) + { + $this->rimuoviScadenze(); + + if (!$ignora_fe && $this->isFE()) { + $scadenze_fe = $this->registraScadenzeFE($is_pagato); + } + + if (empty($scadenze_fe)) { + $this->registraScadenzeTradizionali($is_pagato); + } + + $direzione = $this->tipo->dir; + $ritenuta_acconto = $this->ritenuta_acconto; + + // Se c'è una ritenuta d'acconto, la aggiungo allo scadenzario + if ($direzione == 'uscita' && $ritenuta_acconto > 0) { + $scadenza = date('Y-m', strtotime($data.' +1 month')).'-15'; + $importo = -$ritenuta_acconto; + + self::registraScadenza($this, $importo, $scadenza, $is_pagato, 'ritenutaacconto'); + } + } + + /** + * Elimina le scadenze della fattura. + */ + public function rimuoviScadenze() + { + database()->delete('co_scadenziario', ['iddocumento' => $this->id]); } /** @@ -187,93 +410,6 @@ class Fattura extends Document ], $this->id); } - public function anagrafica() - { - return $this->belongsTo(Anagrafica::class, 'idanagrafica'); - } - - public function tipo() - { - return $this->belongsTo(Tipo::class, 'idtipodocumento'); - } - - public function stato() - { - return $this->belongsTo(Stato::class, 'idstatodocumento'); - } - - public function statoFE() - { - return $this->belongsTo(StatoFE::class, 'codice_stato_fe'); - } - - public function articoli() - { - return $this->hasMany(Components\Articolo::class, 'iddocumento'); - } - - public function righe() - { - return $this->hasMany(Components\Riga::class, 'iddocumento'); - } - - public function descrizioni() - { - return $this->hasMany(Components\Descrizione::class, 'iddocumento'); - } - - public function scontoGlobale() - { - return $this->hasOne(Components\Sconto::class, 'iddocumento'); - } - - public function getXML() - { - if (empty($this->progressivo_invio)) { - $fe = new FatturaElettronica($this->id); - - return $fe->toXML(); - } - - $file = $this->uploads()->where('name', 'Fattura Elettronica')->first(); - - return file_get_contents($file->filepath); - } - - public function isFE() - { - return !empty($this->progressivo_invio) && $this->module == 'Fatture di acquisto'; - } - - public function registraScadenzeFE($is_pagato = false) - { - $database = $dbo = database(); - - $xml = \Util\XML::read($this->getXML()); - - $pagamenti = $xml['FatturaElettronicaBody']['DatiPagamento']['DettaglioPagamento']; - if (!empty($pagamenti)) { - $scadenze = isset($pagamenti[0]) ? $pagamenti : [$pagamenti]; - - foreach ($scadenze as $scadenza) { - $data = $scadenza['DataScadenzaPagamento']; - $importo = $scadenza['ImportoPagamento']; - - $dbo->insert('co_scadenziario', [ - 'iddocumento' => $this->id, - 'data_emissione' => $this->data, - 'scadenza' => $data, - 'da_pagare' => -$importo, - 'tipo' => 'fattura', - 'pagato' => $is_pagato ? $importo : 0, - 'data_pagamento' => $is_pagato ? $data : '', - ], ['id' => $id_scadenza]); - } - } - - return !empty($pagamenti); - } - // Metodi statici /** diff --git a/modules/fatture/variables.php b/modules/fatture/variables.php index 119afce29..0b2376517 100644 --- a/modules/fatture/variables.php +++ b/modules/fatture/variables.php @@ -17,5 +17,5 @@ return [ 'numero' => empty($r['numero_esterno']) ? $r['numero'] : $r['numero_esterno'], 'note' => $r['note'], 'data' => Translator::dateToLocale($r['data']), - 'logo_azienda' => !empty($logo_azienda) ? '': '', + 'logo_azienda' => !empty($logo_azienda) ? '' : '', ]; diff --git a/modules/gestione_componenti/ajax/select.php b/modules/gestione_componenti/ajax/select.php index 0a1833c20..483805bd8 100644 --- a/modules/gestione_componenti/ajax/select.php +++ b/modules/gestione_componenti/ajax/select.php @@ -24,7 +24,7 @@ switch ($resource) { $custom['contenuto'] = 'contenuto'; - $results = AJAX::completeResults($query, $where, $filter, $search, $custom); + $results = AJAX::selectResults($query, $where, $filter, $search, $limit, $custom); foreach ($results as $key => $value) { $matricola = \Util\Ini::getValue($r['contenuto'], 'Matricola'); diff --git a/modules/import/actions.php b/modules/import/actions.php index 405dc3d45..01057fec0 100644 --- a/modules/import/actions.php +++ b/modules/import/actions.php @@ -4,8 +4,11 @@ include_once __DIR__.'/../../core.php'; switch (post('op')) { case 'import': - $first_row = !post('first_row'); - $selected = post('fields'); + $include_first_row = post('include_first_row'); + $selected_fields = post('fields'); + $page = post('page'); + + $limit = 500; // Pulizia dei campi inutilizzati foreach ($selected as $key => $value) { @@ -16,46 +19,71 @@ switch (post('op')) { $fields = Import::getFields($id_record); - $csv = Import::getFile($id_record, $record['id'], [ - 'headers' => $first_row, - ]); + $csv = Import::getCSV($id_record, $record['id']); - // Gestione automatica dei valori convertiti - $csv = Filter::parse($csv); + $offset = isset($page) ? $page * $limit : 0; - // Interpretazione dei dati - $data = []; - foreach ($csv as $row) { - $data_row = []; + // Ignora la prima riga se composta da header + if ($offset == 0 && empty($include_first_row)) { + ++$offset; + } + $csv = $csv->setOffset($offset) + ->setLimit($limit); + + // Chiavi per la lettura CSV + $keys = []; + foreach ($selected_fields as $id => $field_id) { + if (is_numeric($field_id)) { + $value = $fields[$field_id]['field']; + } else { + $value = -($id + 1); + } + + $keys[] = $value; + } + + // Query dei campi selezionati + $queries = []; + foreach ($fields as $key => $field) { + if (!empty($field['query'])) { + $queries[$field['field']] = $field['query']; + } + } + + // Lettura dei record + $rows = $csv->fetchAssoc($keys, function ($row) use ($queries, $dbo) { foreach ($row as $key => $value) { - $field = $fields[$selected[$key]]; + if (is_int($key)) { + unset($row[$key]); + } elseif (isset($queries[$key])) { + $query = str_replace('|value|', prepare($value), $queries[$key]); - if (isset($selected[$key])) { - $name = $field['field']; + $value = $dbo->fetchOne($query)['result']; - $query = $field['query']; - if (!empty($query)) { - $query = str_replace('|value|', prepare($value), $query); - - $value = $dbo->fetchArray($query)[0]['result']; - } - - $data_row[$name] = $value; + $row[$key] = $value; } } - $data[] = $data_row; - } + return $row; + }); + + // Gestione automatica dei valori convertiti + $rows = iterator_to_array($rows); + $data = Filter::parse($rows); $primary_key = post('primary_key'); // Richiamo delle operazioni specifiche include $imports[$id_record]['import']; - flash()->info(tr('Importazione completata: _COUNT_ righe processate', [ - '_COUNT_' => count($csv), - ])); + $count = count($rows); + $more = $count == $limit; + + echo json_encode([ + 'more' => $more, + 'count' => $count, + ]); break; } diff --git a/modules/import/add.php b/modules/import/add.php index 9a17931ac..a14048541 100644 --- a/modules/import/add.php +++ b/modules/import/add.php @@ -18,7 +18,7 @@ foreach ($imports as $key => $value) {
- {[ "type": "file", "label": "", "name": "blob", "required": 1 ]} + {[ "type": "file", "label": "", "name": "blob", "required": 1, "extra": "accept=\".csv\"" ]}
diff --git a/modules/import/edit.php b/modules/import/edit.php index 8b4d85a44..9d7bd8720 100644 --- a/modules/import/edit.php +++ b/modules/import/edit.php @@ -35,16 +35,15 @@ if (empty($id_record)) {
- {[ "type": "checkbox", "label": "'.tr('Importa prima riga').'", "name": "first_row", "extra":"", "value": "1" ]} + {[ "type": "checkbox", "label": "'.tr('Importa prima riga').'", "name": "include_first_row", "extra":"", "value": "1" ]}
{[ "type": "select", "label": "'.tr('Chiave primaria').'", "name": "primary_key", "values": '.json_encode($select2).', "value": "'.$primary_key.'" ]}
'; - $rows = Import::getFile($id_record, $record['id'], [ - 'limit' => 10, - ]); + $csv = Import::getCSV($id_record, $record['id']); + $rows = $csv->setLimit(10)->fetchAll(); $count = count($rows[0]); @@ -67,7 +66,7 @@ if (empty($id_record)) { $selected = null; foreach ($fields as $key => $value) { if (in_array(str_to_lower($rows[0][$column]), $value['names'])) { - $first_row = 1; + $exclude_first_row = 1; $selected = $key; break; } @@ -111,13 +110,59 @@ if (empty($id_record)) { '; } diff --git a/modules/interventi/actions.php b/modules/interventi/actions.php index b7cf39bc9..3fe2dc5e8 100644 --- a/modules/interventi/actions.php +++ b/modules/interventi/actions.php @@ -11,46 +11,11 @@ use Modules\Interventi\TipoSessione; switch (post('op')) { case 'update': - $idpreventivo = post('idpreventivo'); $idcontratto = post('idcontratto'); $idcontratto_riga = post('idcontratto_riga'); - $idtipointervento = post('idtipointervento'); - - $data_richiesta = post('data_richiesta'); - $richiesta = post('richiesta'); - $idsede = post('idsede'); - - // Collegamento intervento a contratto (se impostato) - // Oltre al collegamento al contratto, l'intervento è collegato ad una riga di pianificazione, perciò è importante considerarla se è impostata - $array = [ - 'idintervento' => $id_record, - 'idtipointervento' => $idtipointervento, - 'data_richiesta' => $data_richiesta, - 'richiesta' => $richiesta, - 'idsede' => $idsede ?: 0, - ]; - // Creazione nuova pianificazione se non era impostata - if (!empty($idcontratto) && empty($idcontratto_riga)) { - // Se questo intervento era collegato ad un altro contratto aggiorno le informazioni... - $rs = $dbo->fetchArray('SELECT id FROM co_promemoria WHERE idintervento='.prepare($id_record)); - if (empty($rs)) { - $dbo->insert('co_promemoria', array_merge(['idcontratto' => $idcontratto], $array)); - } - - // ...altrimenti se sto cambiando contratto aggiorno solo l'id del nuovo contratto - else { - $dbo->update('co_promemoria', ['idcontratto' => $idcontratto], ['idintervento' => $id_record]); - } - } - - // Pianificazione già impostata, aggiorno solo il codice intervento - elseif (!empty($idcontratto) && !empty($idcontratto_riga)) { - $dbo->update('co_promemoria', $array, ['idcontratto' => $idriga, 'id' => $idcontratto_riga]); - } - - // Se non è impostato nessun contratto o riga, tolgo il collegamento dell'intervento al contratto - elseif (empty($idcontratto)) { + // Rimozione del collegamento al promemoria + if (!empty($idcontratto_riga) && $intervento->id_contratto != $idcontratto) { $dbo->update('co_promemoria', ['idintervento' => null], ['idintervento' => $id_record]); } @@ -58,32 +23,34 @@ switch (post('op')) { $sconto = post('sconto_globale'); // Salvataggio modifiche intervento - $dbo->update('in_interventi', [ - 'data_richiesta' => $data_richiesta, - 'richiesta' => $richiesta, - 'descrizione' => post('descrizione'), - 'informazioniaggiuntive' => post('informazioniaggiuntive'), + $intervento->data_richiesta = post('data_richiesta'); + $intervento->data_scadenza = post('data_scadenza'); + $intervento->richiesta = post('richiesta'); + $intervento->descrizione = post('descrizione'); + $intervento->informazioniaggiuntive = post('informazioniaggiuntive'); - 'idanagrafica' => post('idanagrafica'), - 'idclientefinale' => post('idclientefinale'), - 'idreferente' => post('idreferente'), - 'idtipointervento' => $idtipointervento, + $intervento->idanagrafica = post('idanagrafica'); + $intervento->idclientefinale = post('idclientefinale'); + $intervento->idreferente = post('idreferente'); + $intervento->idtipointervento = post('idtipointervento'); - 'idstatointervento' => post('idstatointervento'), - 'idsede' => $idsede, - 'idautomezzo' => post('idautomezzo'), - 'id_preventivo' => $idpreventivo, + $intervento->idstatointervento = post('idstatointervento'); + $intervento->idsede = post('idsede'); + $intervento->idautomezzo = post('idautomezzo'); + $intervento->id_preventivo = post('idpreventivo'); + $intervento->id_contratto = $idcontratto; - 'sconto_globale' => $sconto, - 'tipo_sconto_globale' => $tipo_sconto, + $intervento->sconto_globale = $sconto; + $intervento->tipo_sconto_globale = $tipo_sconto; - 'id_documento_fe' => post('id_documento_fe'), - 'codice_cup' => post('codice_cup'), - 'codice_cig' => post('codice_cig'), - ], ['id' => $id_record]); + $intervento->id_documento_fe = post('id_documento_fe'); + $intervento->num_item = post('num_item'); + $intervento->codice_cup = post('codice_cup'); + $intervento->codice_cig = post('codice_cig'); + $intervento->save(); - $stato = $dbo->selectOne('in_statiintervento', '*', ['idstatointervento' => post('idstatointervento')]); // Notifica chiusura intervento + $stato = $dbo->selectOne('in_statiintervento', '*', ['idstatointervento' => post('idstatointervento')]); if (!empty($stato['notifica']) && !empty($stato['destinatari']) && $stato['idstatointervento'] != $record['idstatointervento']) { $n = new Notifications\EmailNotification(); @@ -107,6 +74,7 @@ switch (post('op')) { $idtipointervento = post('idtipointervento'); $idstatointervento = post('idstatointervento'); $data_richiesta = post('data_richiesta'); + $data_scadenza = post('data_scadenza'); $anagrafica = Anagrafica::find($idanagrafica); $tipo = TipoSessione::find($idtipointervento); @@ -134,59 +102,47 @@ switch (post('op')) { $intervento->idsede = post('idsede'); } - $intervento->id_preventivo = post('$idpreventivo'); + $intervento->id_preventivo = post('idpreventivo'); + $intervento->id_contratto = post('idcontratto'); $intervento->richiesta = $richiesta; + $intervento->data_scadenza = $data_scadenza; $intervento->save(); - // Collego l'intervento al contratto - if (!empty($idcontratto)) { - $array = [ + // Se è specificato che l'intervento fa parte di una pianificazione aggiorno il codice dell'intervento sulla riga della pianificazione + if (!empty($idcontratto_riga)) { + $dbo->update('co_promemoria', [ 'idintervento' => $id_record, 'idtipointervento' => $idtipointervento, 'data_richiesta' => $data_richiesta, 'richiesta' => $richiesta, 'idsede' => $idsede ?: 0, - ]; + ], ['idcontratto' => $idcontratto, 'id' => $idcontratto_riga]); - // Se è specificato che l'intervento fa parte di una pianificazione aggiorno il codice dell'intervento sulla riga della pianificazione - if (!empty($idcontratto_riga)) { - $dbo->update('co_promemoria', $array, ['idcontratto' => $idcontratto, 'id' => $idcontratto_riga]); + //copio le righe dal promemoria all'intervento + $dbo->query('INSERT INTO in_righe_interventi (descrizione, qta,um,prezzo_vendita,prezzo_acquisto,idiva,desc_iva,iva,idintervento,sconto,sconto_unitario,tipo_sconto) SELECT descrizione, qta,um,prezzo_vendita,prezzo_acquisto,idiva,desc_iva,iva,'.$id_record.',sconto,sconto_unitario,tipo_sconto FROM co_promemoria_righe WHERE id_promemoria = '.$idcontratto_riga); - //copio le righe dal promemoria all'intervento - $dbo->query('INSERT INTO in_righe_interventi (descrizione, qta,um,prezzo_vendita,prezzo_acquisto,idiva,desc_iva,iva,idintervento,sconto,sconto_unitario,tipo_sconto) SELECT descrizione, qta,um,prezzo_vendita,prezzo_acquisto,idiva,desc_iva,iva,'.$id_record.',sconto,sconto_unitario,tipo_sconto FROM co_promemoria_righe WHERE id_promemoria = '.$idcontratto_riga.' '); + //copio gli articoli dal promemoria all'intervento + $dbo->query('INSERT INTO mg_articoli_interventi (idarticolo, idintervento,descrizione,prezzo_acquisto,prezzo_vendita,sconto, sconto_unitario, tipo_sconto,idiva,desc_iva,iva,idautomezzo, qta, um, abilita_serial, idimpianto) SELECT idarticolo, '.$id_record.',descrizione,prezzo_acquisto,prezzo_vendita,sconto,sconto_unitario,tipo_sconto,idiva,desc_iva,iva,idautomezzo, qta, um, abilita_serial, idimpianto FROM co_promemoria_articoli WHERE id_promemoria = '.$idcontratto_riga); - //copio gli articoli dal promemoria all'intervento - $dbo->query('INSERT INTO mg_articoli_interventi (idarticolo, idintervento,descrizione,prezzo_acquisto,prezzo_vendita,sconto, sconto_unitario, tipo_sconto,idiva,desc_iva,iva,idautomezzo, qta, um, abilita_serial, idimpianto) SELECT idarticolo, '.$id_record.',descrizione,prezzo_acquisto,prezzo_vendita,sconto,sconto_unitario,tipo_sconto,idiva,desc_iva,iva,idautomezzo, qta, um, abilita_serial, idimpianto FROM co_promemoria_articoli WHERE id_promemoria = '.$idcontratto_riga.' '); + // Copia degli allegati + $alleagti = Uploads::copy([ + 'id_plugin' => Plugins::get('Pianificazione interventi')['id'], + 'id_record' => $idcontratto_riga, + ], [ + 'id_module' => $id_module, + 'id_record' => $id_record, + ]); - // Copia degli allegati - $alleagti = Uploads::copy([ - 'id_plugin' => Plugins::get('Pianificazione interventi')['id'], - 'id_record' => $idcontratto_riga, - ], [ - 'id_module' => $id_module, - 'id_record' => $id_record, - ]); + if (!$alleagti) { + $errors = error_get_last(); + flash()->warning(tr('Errore durante la copia degli allegati')); + } - if (!$alleagti) { - $errors = error_get_last(); - flash()->warning(tr('Errore durante la copia degli allegati')); - } - - // Decremento la quantità per ogni articolo copiato - $rs_articoli = $dbo->fetchArray('SELECT * FROM mg_articoli_interventi WHERE idintervento = '.$id_record.' '); - foreach ($rs_articoli as $rs_articolo) { - add_movimento_magazzino($rs_articolo['idarticolo'], -$rs_articolo['qta'], ['idautomezzo' => $rs_articolo['idautomezzo'], 'idintervento' => $id_record]); - } - } else { - $dbo->insert('co_promemoria', [ - 'idcontratto' => $idcontratto, - 'idintervento' => $id_record, - 'idtipointervento' => $idtipointervento, - 'data_richiesta' => $data_richiesta, - 'richiesta' => $richiesta, - 'idsede' => $idsede ?: 0, - ]); + // Decremento la quantità per ogni articolo copiato + $rs_articoli = $dbo->fetchArray('SELECT * FROM mg_articoli_interventi WHERE idintervento = '.$id_record.' '); + foreach ($rs_articoli as $rs_articolo) { + add_movimento_magazzino($rs_articolo['idarticolo'], -$rs_articolo['qta'], ['idautomezzo' => $rs_articolo['idautomezzo'], 'idintervento' => $id_record]); } } @@ -535,7 +491,7 @@ switch (post('op')) { $id_tecnico = post('id_tecnico'); // Verifico se l'intervento è collegato ad un contratto - // TODO: utilizzare campo id_contratto in in_interventi come avviene già per i preventivi (id_preventivo) dalla 2.4.2 + // TODO: utilizzare campo id_contratto in in_interventi come avviene già per i preventivi (id_preventivo) dalla 2.4.2 $rs = $dbo->fetchArray('SELECT idcontratto FROM co_promemoria WHERE idintervento='.prepare($id_record)); $idcontratto = $rs[0]['idcontratto']; diff --git a/modules/interventi/add.php b/modules/interventi/add.php index ac3fe410d..be9cc3985 100644 --- a/modules/interventi/add.php +++ b/modules/interventi/add.php @@ -5,7 +5,6 @@ include_once __DIR__.'/../../core.php'; // Rimuovo session usate sui select combinati (sedi, preventivi, contratti, impianti) unset($_SESSION['superselect']['idanagrafica']); unset($_SESSION['superselect']['idsede']); -unset($_SESSION['superselect']['non_fatturato']); // Calcolo del nuovo codice $new_codice = \Modules\Interventi\Intervento::getNextCodice(); @@ -41,8 +40,8 @@ if (null !== filter('orario_inizio') && '00:00:00' != filter('orario_inizio')) { $orario_inizio = filter('orario_inizio'); $orario_fine = filter('orario_fine'); } else { - $orario_inizio = date('H').':00'; - $orario_fine = date('H', time() + 60 * 60).':00'; + $orario_inizio = date('H').':00:00'; + $orario_fine = date('H', time() + 60 * 60).':00:00'; } // Se sto pianificando un contratto, leggo tutti i dati del contratto per predisporre l'aggiunta intervento @@ -224,15 +223,19 @@ if (!empty($id_intervento)) {
-
- {[ "type": "timestamp", "label": "", "name": "data_richiesta", "required": 1, "value": "" ]} +
+ {[ "type": "timestamp", "label": "", "name": "data_richiesta", "required": 1, "value": "" ]} +
+ +
+ {[ "type": "timestamp", "label": "", "name": "data_scadenza", "required": 0, "value": "" ]}
-
+
{[ "type": "select", "label": "", "name": "idtipointervento", "required": 1, "values": "query=SELECT idtipointervento AS id, descrizione FROM in_tipiintervento ORDER BY descrizione ASC", "value": "", "ajax-source": "tipiintervento" ]}
-
+
{[ "type": "select", "label": "", "name": "idstatointervento", "required": 1, "values": "query=SELECT idstatointervento AS id, descrizione, colore AS _bgcolor_ FROM in_statiintervento WHERE deleted_at IS NULL", "value": "" ]}
diff --git a/modules/interventi/api/create.php b/modules/interventi/api/create.php index 9bc4df180..aeac93898 100644 --- a/modules/interventi/api/create.php +++ b/modules/interventi/api/create.php @@ -1,7 +1,7 @@ lastInsertedID(); $response['codice'] = $codice; + /* $start = date('Y-m-d H:i:s'); $end = date('Y-m-d H:i:s', strtotime('+1 hour', strtotime($start))); add_tecnico($response['id'], $user['idanagrafica'], $start, $end); + */ } break; diff --git a/modules/interventi/api/retrieve.php b/modules/interventi/api/retrieve.php index 3c6ea21de..e6144d9c1 100644 --- a/modules/interventi/api/retrieve.php +++ b/modules/interventi/api/retrieve.php @@ -48,6 +48,7 @@ switch ($resource) { // Periodo per selezionare interventi $today = date('Y-m-d'); $period_end = date('Y-m-d', strtotime($today.' +7 days')); + $period_start = date('Y-m-d', strtotime($today.' -2 months')); $query = "SELECT `in_interventi`.`id`, `in_interventi`.`codice`, @@ -64,7 +65,7 @@ switch ($resource) { `in_interventi`.`firma_file`, IF(firma_data = '0000-00-00 00:00:00', '', firma_data) AS `firma_data`, `in_interventi`.firma_nome, - (SELECT GROUP_CONCAT( CONCAT(my_impianti.matricola, ' - ', my_impianti.nome) SEPARATOR ', ') FROM (my_impianti_interventi INNER JOIN my_impianti ON my_impianti_interventi.idimpianto=my_impianti.id) WHERE my_impianti_interventi.idintervento = `in_interventi`.`id`) AS `impianti`, + (SELECT GROUP_CONCAT(CONCAT(my_impianti.matricola, ' - ', my_impianti.nome) SEPARATOR ', ') FROM (my_impianti_interventi INNER JOIN my_impianti ON my_impianti_interventi.idimpianto=my_impianti.id) WHERE my_impianti_interventi.idintervento = `in_interventi`.`id`) AS `impianti`, (SELECT MAX(`orario_fine`) FROM `in_interventi_tecnici` WHERE `in_interventi_tecnici`.`idintervento` = `in_interventi`.`id`) AS `data`, (SELECT GROUP_CONCAT(DISTINCT ragione_sociale SEPARATOR ', ') FROM `in_interventi_tecnici` INNER JOIN `an_anagrafiche` ON `in_interventi_tecnici`.`idtecnico` = `an_anagrafiche`.`idanagrafica` WHERE `in_interventi_tecnici`.`idintervento` = `in_interventi`.`id`) AS `tecnici`, `in_statiintervento`.`colore` AS `bgcolor`, @@ -74,9 +75,9 @@ switch ($resource) { INNER JOIN `in_statiintervento` ON `in_interventi`.`idstatointervento` = `in_statiintervento`.`idstatointervento` INNER JOIN `an_anagrafiche` ON `in_interventi`.`idanagrafica` = `an_anagrafiche`.`idanagrafica` LEFT JOIN `an_sedi` ON `in_interventi`.`idsede` = `an_sedi`.`id` - WHERE (SELECT MAX(`orario_fine`) FROM `in_interventi_tecnici` WHERE `in_interventi_tecnici`.`idintervento` = `in_interventi`.`id`) <= :period_end"; + WHERE EXISTS(SELECT `orario_fine` FROM `in_interventi_tecnici` WHERE `in_interventi_tecnici`.`idintervento` = `in_interventi`.`id` AND `orario_fine` BETWEEN :period_start AND :period_end)"; - // TODO: rimosse seguenti clausole: + // TODO: rimosse le seguenti clausole // WHERE `in_interventi`.idstatointervento IN(SELECT idstatointervento FROM in_statiintervento WHERE app_download=1) // nel database ufficiale manca in_statiintervento.app_download @@ -86,6 +87,7 @@ switch ($resource) { $parameters = [ ':period_end' => $period_end, + ':period_start' => $period_start, ]; break; diff --git a/modules/interventi/edit.php b/modules/interventi/edit.php index 9038b65e1..e20043970 100644 --- a/modules/interventi/edit.php +++ b/modules/interventi/edit.php @@ -42,13 +42,11 @@ $_SESSION['superselect']['idanagrafica'] = $record['idanagrafica'];
- -
fetchArray('SELECT id, idcontratto FROM co_promemoria WHERE idintervento='.prepare($id_record)); - if (count($rs) == 1) { - $idcontratto = $rs[0]['idcontratto']; - $idcontratto_riga = $rs[0]['id']; - } else { - $idcontratto = ''; - $idcontratto_riga = ''; - }*/ + $idcontratto_riga = $dbo->fetchOne('SELECT id FROM co_promemoria WHERE idintervento='.prepare($id_record))['id']; - if (($record['idcontratto'] != '')) { + if (!empty($record['idcontratto'])) { echo ' '.Modules::link('Contratti', $record['idcontratto'], null, null, 'class="pull-right"'); } ?> - {[ "type": "select", "label": "", "name": "idcontratto", "value": "", "ajax-source": "contratti", "readonly": "" ]} + {[ "type": "select", "label": "", "name": "idcontratto", "value": "", "ajax-source": "contratti", "readonly": "" ]} +
@@ -95,7 +87,11 @@ $_SESSION['superselect']['idanagrafica'] = $record['idanagrafica'];
- {[ "type": "timestamp", "label": "", "name": "data_richiesta", "required": 1, "value": "$data_richiesta$", "readonly": "" ]} + {[ "type": "timestamp", "label": "", "name": "data_richiesta", "required": 1, "value": "$data_richiesta$", "readonly": "" ]} +
+ +
+ {[ "type": "timestamp", "label": "", "name": "data_scadenza", "required": 0, "value": "$data_scadenza$", "readonly": "" ]}
@@ -143,15 +139,16 @@ $_SESSION['superselect']['idanagrafica'] = $record['idanagrafica']; fetchOne('SELECT codice_cig,codice_cup,id_documento_fe FROM co_contratti WHERE id = '.prepare($record['idcontratto'])); + $contratto = $dbo->fetchOne('SELECT num_item,codice_cig,codice_cup,id_documento_fe FROM co_contratti WHERE id = '.prepare($record['idcontratto'])); $record['id_documento_fe'] = $contratto['id_documento_fe']; $record['codice_cup'] = $contratto['codice_cup']; $record['codice_cig'] = $contratto['codice_cig']; + $record['num_item'] = $contratto['num_item']; } ?> -
+

-
- {[ "type": "", "label": "", "name": "id_documento_fe", "required": 0, "value": "", "maxlength": 20, "readonly": "", "extra": "" ]} +
+ {[ "type": "", "label": "", "name": "id_documento_fe", "required": 0, "help": "Obbligatorio per valorizzare CIG/CUP. È possible inserire:
  • N. determina
  • RDO
  • Ordine MEPA
'); ?>", "value": "", "maxlength": 20, "readonly": "", "extra": "" ]}
-
+
+ {[ "type": "", "label": "", "name": "num_item", "required": 0, "value": "", "maxlength": 15, "readonly": "", "extra": "" ]} +
+
+
+
{[ "type": "", "label": "", "name": "codice_cig", "required": 0, "value": "", "maxlength": 15, "readonly": "", "extra": "" ]}
-
+
{[ "type": "", "label": "", "name": "codice_cup", "required": 0, "value": "", "maxlength": 15, "readonly": "", "extra": "" ]}
@@ -358,6 +360,16 @@ $_SESSION['superselect']['idanagrafica'] = $record['idanagrafica']; //session_set('superselect,idzona', $(this).selectData().idzona, 0); } }); + + $('#codice_cig, #codice_cup').bind("keyup change", function(e) { + + if ($('#codice_cig').val() == '' && $('#codice_cup').val() == '' ){ + $('#id_documento_fe').prop('required', false); + }else{ + $('#id_documento_fe').prop('required', true); + } + + }); diff --git a/modules/interventi/init.php b/modules/interventi/init.php index 9426150c6..6b9292ee2 100644 --- a/modules/interventi/init.php +++ b/modules/interventi/init.php @@ -2,6 +2,17 @@ include_once __DIR__.'/../../core.php'; +use Modules\Interventi\Intervento; + if (isset($id_record)) { - $record = $dbo->fetchOne('SELECT *, (SELECT tipo FROM an_anagrafiche WHERE idanagrafica = in_interventi.idanagrafica) AS tipo_anagrafica, (SELECT completato FROM in_statiintervento WHERE idstatointervento=in_interventi.idstatointervento) AS flag_completato, IF((in_interventi.idsede = 0), (SELECT idzona FROM an_anagrafiche WHERE idanagrafica = in_interventi.idanagrafica), (SELECT idzona FROM an_sedi WHERE id = in_interventi.idsede)) AS idzona, (SELECT colore FROM in_statiintervento WHERE idstatointervento=in_interventi.idstatointervento) AS colore, (SELECT idcontratto FROM co_promemoria WHERE idintervento=in_interventi.id LIMIT 0,1) AS idcontratto, in_interventi.id_preventivo as idpreventivo FROM in_interventi WHERE id='.prepare($id_record)); + $intervento = Intervento::find($id_record); + + $record = $dbo->fetchOne('SELECT *, + (SELECT tipo FROM an_anagrafiche WHERE idanagrafica = in_interventi.idanagrafica) AS tipo_anagrafica, + (SELECT completato FROM in_statiintervento WHERE idstatointervento=in_interventi.idstatointervento) AS flag_completato, + IF((in_interventi.idsede = 0), (SELECT idzona FROM an_anagrafiche WHERE idanagrafica = in_interventi.idanagrafica), (SELECT idzona FROM an_sedi WHERE id = in_interventi.idsede)) AS idzona, + (SELECT colore FROM in_statiintervento WHERE idstatointervento=in_interventi.idstatointervento) AS colore, + in_interventi.id_preventivo as idpreventivo, + in_interventi.id_contratto as idcontratto + FROM in_interventi WHERE id='.prepare($id_record)); } diff --git a/modules/interventi/src/Components/RelationTrait.php b/modules/interventi/src/Components/RelationTrait.php index 3c5694b44..aed9c0490 100644 --- a/modules/interventi/src/Components/RelationTrait.php +++ b/modules/interventi/src/Components/RelationTrait.php @@ -25,14 +25,6 @@ trait RelationTrait { } - public function fixRivalsaINPS() - { - } - - public function fixRitenutaAcconto() - { - } - public function getSubtotaleAttribute() { return $this->prezzo_vendita * $this->qta; diff --git a/modules/interventi/src/Intervento.php b/modules/interventi/src/Intervento.php index 5f90f09ce..09bafee2a 100644 --- a/modules/interventi/src/Intervento.php +++ b/modules/interventi/src/Intervento.php @@ -4,6 +4,7 @@ namespace Modules\Interventi; use Common\Document; use Modules\Anagrafiche\Anagrafica; +use Modules\Contratti\Contratto; use Modules\Interventi\Components\Articolo; use Modules\Interventi\Components\Riga; use Modules\Preventivi\Preventivo; @@ -46,7 +47,12 @@ class Intervento extends Document public function preventivo() { - return $this->hasOne(Preventivo::class, 'id_preventivo'); + return $this->belongsTo(Preventivo::class, 'id_preventivo'); + } + + public function contratto() + { + return $this->belongsTo(Contratto::class, 'id_contratto'); } public function stato() diff --git a/modules/iva/ajax/select.php b/modules/iva/ajax/select.php index 112172e33..e01d6f641 100644 --- a/modules/iva/ajax/select.php +++ b/modules/iva/ajax/select.php @@ -4,7 +4,7 @@ include_once __DIR__.'/../../../core.php'; switch ($resource) { case 'iva': - $query = 'SELECT id, IF(codice IS NULL, descrizione, CONCAT(codice, " - ", descrizione)) AS descrizione FROM co_iva |where| ORDER BY descrizione ASC'; + $query = 'SELECT id, IF(codice IS NULL, descrizione, CONCAT(codice, " - ", descrizione)) AS descrizione, percentuale FROM co_iva |where| ORDER BY descrizione ASC'; foreach ($elements as $element) { $filter[] = 'id='.prepare($element); @@ -23,5 +23,7 @@ switch ($resource) { } } + $custom['percentuale'] = 'percentuale'; + break; } diff --git a/modules/ordini/actions.php b/modules/ordini/actions.php index 73c7bc340..807e05f25 100644 --- a/modules/ordini/actions.php +++ b/modules/ordini/actions.php @@ -22,11 +22,8 @@ switch (post('op')) { $idanagrafica = post('idanagrafica'); $data = post('data'); - // Leggo se l'ordine è cliente o fornitore - $tipo = $dbo->fetchOne('SELECT id FROM or_tipiordine WHERE dir='.prepare($dir)); - $anagrafica = Anagrafica::find($idanagrafica); - $tipo = Tipo::find($tipo['id']); + $tipo = Tipo::where('dir', $dir)->first(); $ordine = Ordine::build($anagrafica, $tipo, $data); $id_record = $ordine->id; @@ -90,6 +87,7 @@ switch (post('op')) { 'id_documento_fe' => post('id_documento_fe'), 'codice_cup' => post('codice_cup'), 'codice_cig' => post('codice_cig'), + 'num_item' => post('num_item'), ], ['id' => $id_record]); if ($dbo->query($query)) { @@ -347,88 +345,57 @@ switch (post('op')) { break; - case 'ordine_da_preventivo': + // Aggiunta di un preventivo in ordine + case 'add_preventivo': + $preventivo = \Modules\Preventivi\Preventivo::find(post('id_preventivo')); - $idanagrafica = post('idanagrafica'); - $idpreventivo = post('idpreventivo'); + // Creazione della fattura al volo + if (post('create_document') == 'on') { + $tipo = Tipo::where('dir', $dir)->first(); - $data = post('data'); + $ordine = Ordine::build($preventivo->anagrafica, $tipo, post('data')); + $ordine->idpagamento = $preventivo->idpagamento; + $ordine->save(); - // Leggo se l'ordine è cliente o fornitore - $rs = $dbo->fetchArray('SELECT id FROM or_tipiordine WHERE dir='.prepare($dir)); - $idtipoordine = $rs[0]['id']; + $id_record = $ordine->id; + } - if (post('idanagrafica') !== null) { - $numero = get_new_numeroordine($data); - if ($dir == 'entrata') { - $numero_esterno = get_new_numerosecondarioordine($data); - } else { - $numero_esterno = ''; - } + $parziale = false; + $righe = $preventivo->getRighe(); + foreach ($righe as $riga) { + if (post('evadere')[$riga->id] == 'on') { + $qta = post('qta_da_evadere')[$riga->id]; - $campo = ($dir == 'entrata') ? 'idpagamento_vendite' : 'idpagamento_acquisti'; + $copia = $riga->copiaIn($ordine, $qta); - // Tipo di pagamento predefinito dall'anagrafica - $query = 'SELECT id FROM co_pagamenti WHERE id=(SELECT '.$campo.' AS pagamento FROM an_anagrafiche WHERE idanagrafica='.prepare($idanagrafica).')'; - $rs = $dbo->fetchArray($query); - $idpagamento = isset($rs[0]) ? $rs[0]['id'] : null; - - // Se l'ordine è un ordine cliente e non è stato associato un pagamento predefinito al cliente leggo il pagamento dalle impostazioni - if ($dir == 'entrata' && empty($idpagamento)) { - $idpagamento = setting('Tipo di pagamento predefinito'); - } - - $query = 'INSERT INTO or_ordini( numero, numero_esterno, idanagrafica, idtipoordine, idpagamento, data, idstatoordine ) VALUES ( '.prepare($numero).', '.prepare($numero_esterno).', '.prepare($idanagrafica).', '.prepare($idtipoordine).', '.prepare($idpagamento).', '.prepare($data).", (SELECT `id` FROM `or_statiordine` WHERE `descrizione`='Bozza') )"; - $dbo->query($query); - - $id_record = $dbo->lastInsertedID(); - - flash()->info(tr('Aggiunto ordine numero _NUM_!', [ - '_NUM_' => $numero, - ])); - - // Lettura di tutte le righe della tabella in arrivo - // Inserisco anche le righe descrittive - foreach (post('evadere') as $i => $value) { - // Processo solo le righe da evadere - if (post('evadere')[$i] == 'on') { - $descrizione = post('descrizione')[$i]; - $prezzo = post('subtot')[$i]; - $qta = post('qta_da_evadere')[$i]; - $idiva = post('idiva')[$i]; - $um = post('um')[$i]; - $subtot = $prezzo * $qta; - $idarticolo = post('idarticolo')[$i]; - $sconto = post('sconto')[$i]; - - // Ottengo le informazioni sullo sconto - $qprc = 'SELECT tipo_sconto, sconto_unitario FROM co_righe_preventivi WHERE id='.prepare($i); - $rsprc = $dbo->fetchArray($qprc); - - $sconto_unitario = $rsprc[0]['sconto_unitario']; - $tipo_sconto = $rsprc[0]['tipo_sconto']; - - $sconto = $sconto * $qta; - - // Calcolo iva - $query = 'SELECT descrizione, percentuale, indetraibile FROM co_iva WHERE id='.prepare($idiva); - $rs = $dbo->fetchArray($query); - $iva = ($subtot - $sconto) / 100 * $rs[0]['percentuale']; - $iva_indetraibile = $iva / 100 * $rs[0]['indetraibile']; - - $query = 'INSERT INTO or_righe_ordini(idordine, idarticolo, idpreventivo, idiva, desc_iva, iva, iva_indetraibile, descrizione, subtotale, sconto, sconto_unitario, tipo_sconto, um, qta, is_descrizione, `order`) VALUES('.prepare($id_record).', '.prepare($idarticolo).', '.prepare($idpreventivo).', '.prepare($idiva).', '.prepare($rs[0]['descrizione']).', '.prepare($iva).', '.prepare($iva_indetraibile).', '.prepare($descrizione).', '.prepare($subtot).', '.prepare($sconto).', '.prepare($sconto_unitario).', '.prepare($tipo_sconto).', '.prepare($um).', '.prepare($qta).', '.prepare(empty($qta)).', (SELECT IFNULL(MAX(`order`) + 1, 0) FROM or_righe_ordini AS t WHERE idordine='.prepare($id_record).'))'; - $dbo->query($query); + // Aggiornamento seriali dalla riga dell'ordine + if ($copia->isArticolo()) { + $copia->movimenta($copia->qta); } + + $copia->save(); } - // Ricalcolo inps, ritenuta e bollo - if ($dir == 'entrata') { - ricalcola_costiagg_ordine($id_record); - } else { - ricalcola_costiagg_ordine($id_record); + if ($riga->qta != $riga->qta_evasa) { + $parziale = true; } } + // Aggiornamento sconto + if (post('evadere')[$preventivo->scontoGlobale->id] == 'on') { + $ordine->tipo_sconto_globale = $preventivo->tipo_sconto_globale; + $ordine->sconto_globale = $preventivo->tipo_sconto_globale == 'PRC' ? $preventivo->sconto_globale : $preventivo->sconto_globale; + $ordine->save(); + + $ordine->updateSconto(); + } + + ricalcola_costiagg_ordine($id_record); + + flash()->info(tr('Preventivo _NUM_ aggiunto!', [ + '_NUM_' => $preventivo->numero, + ])); + break; } diff --git a/modules/ordini/buttons.php b/modules/ordini/buttons.php index 9681ab6fd..955a6c975 100644 --- a/modules/ordini/buttons.php +++ b/modules/ordini/buttons.php @@ -2,32 +2,26 @@ include_once __DIR__.'/../../core.php'; -if (!in_array($record['stato'], ['Fatturato'])) { - echo ' - '; -} +
  • +  '.tr('fattura').' + +
  • '; + + echo ' + +
    '; diff --git a/modules/ordini/crea_documento.php b/modules/ordini/crea_documento.php index dfce55d91..098096f88 100644 --- a/modules/ordini/crea_documento.php +++ b/modules/ordini/crea_documento.php @@ -4,268 +4,36 @@ include_once __DIR__.'/../../core.php'; $module = Modules::get($id_module); -$data = [ - 'preventivo' => [ - 'table' => 'co_preventivi', - 'rows' => 'co_righe_preventivi', - 'id' => 'idpreventivo', - 'condition' => '', - ], -]; - -$documento = get('documento'); - -$pos = 'preventivo'; -$op = 'ordine_da_preventivo'; - -$head = tr('Preventivo numero _NUM_'); - -$table = $data[$pos]['table']; -$rows = $data[$pos]['rows']; -$id = $data[$pos]['id']; -$row = str_replace('id', 'id_riga_', $id); - -$module_name = 'Ordini cliente'; - -$op = !empty(get('op')) ? get('op') : $op; - -$button = tr('Crea ordine'); -$button = !empty(get('op')) ? tr('Aggiungi') : $button; - -// Info documento -$rs = $dbo->fetchArray('SELECT * FROM '.$table.' WHERE id='.prepare($id_record)); -$numero = !empty($rs[0]['numero_esterno']) ? $rs[0]['numero_esterno'] : $rs[0]['numero']; -$idanagrafica = $rs[0]['idanagrafica']; -$idsede = $rs[0]['idsede']; -$idpagamento = $rs[0]['idpagamento']; -$idconto = $rs[0]['idconto']; - -/* - Form di inserimento riga documento -*/ -echo ' -

    '.str_replace('_NUM_', $numero, $head).'.

    '; - -// Selezione articoli del preventivo da copiare nell'ordine, usando l'ordinamento scelto dall'utente -$rs = $dbo->fetchArray('SELECT * FROM '.$table.' INNER JOIN '.$rows.' ON '.$table.'.id='.$rows.'.'.$id.' WHERE '.$table.'.id='.prepare($id_record).' ORDER BY `order`'); - -if (!empty($rs)) { - echo ' -

    '.tr('Seleziona le righe e le relative quantità da inserire nell\'ordine.').'.

    - -
    - - - - - - - - - - -
    - -
    - {[ "type": "date", "label": "'.tr('Data del documento').'", "name": "data", "required": 1, "value": "-now-" ]} -
    -
    - -
    -
    - - - - - - - - - '; - - $totale = 0.00; - - foreach ($rs as $i => $r) { - // Descrizione - echo ' - - '; - - if ($r['is_descrizione']) { - continue; - } - - // Q.tà rimanente - echo ' - '; - - // Q.tà da evadere - echo ' - '; - - // Subtotale - $subtotale = $r['subtotale'] / $r['qta'] * ($r['qta']); - $sconto = $r['sconto'] / $r['qta'] * ($r['qta']); - $iva = $r['iva'] / $r['qta'] * ($r['qta']); - - echo ' - '; - - // Seriali - echo ' - - '; - - $totale += $subtotale - $sconto + $iva; - } - - // Totale - echo ' - - - - -
    '.tr('Descrizione').''.tr('Q.tà').''.tr('Q.tà da evadere').''.tr('Subtot.').''.tr('Seriali').'
    - - - - '; - - // Checkbox - da evadere? - echo ' - '; - - echo nl2br($r['descrizione']); - - echo ' - - - -

    '.Translator::numberToLocale($r['qta'], 'qta').'

    -
    - {[ "type": "number", "name": "qta_da_evadere['.$r['id'].']", "id": "qta_'.$i.'", "required": 1, "value": "'.$r['qta'].'", "extra" : "onkeyup=\"ricalcola_subtotale_riga('.$i.');\"", "decimals": "qta", "min-value": "0" ]} - - - - - - - '.Translator::numberToLocale($subtotale - $sconto + $iva).' €
    - - '.Translator::numberToLocale($subtotale - $sconto).' + '.Translator::numberToLocale($iva).' -
    '; - if (!empty($r['abilita_serial'])) { - $values = $dbo->fetchArray('SELECT DISTINCT serial FROM mg_prodotti WHERE dir=\''.$dir.'\' AND '.$row.' = \''.$r['id'].'\' AND serial IS NOT NULL AND serial NOT IN (SELECT serial FROM mg_prodotti WHERE serial IS NOT NULL AND dir=\''.$dir.'\' AND '.$data[$pos]['condition'].')'); - - echo ' - {[ "type": "select", "name": "serial['.$i.']['.$r['id'].']", "id": "serial_'.$i.'", "multiple": 1, "values": "query=SELECT DISTINCT serial AS id, serial AS descrizione FROM mg_prodotti WHERE dir=\''.$dir.'\' AND '.$row.' = \''.$r['id'].'\' AND serial IS NOT NULL AND serial NOT IN (SELECT serial FROM mg_prodotti WHERE serial IS NOT NULL AND dir=\''.$dir.'\' AND '.$data[$pos]['condition'].')", "value": "'.implode(',', array_column($values, 'serial')).'", "extra": "data-maximum=\"'.intval($r['qta_rimanente']).'\"" ]} - '; - } else { - echo '-'; - } - echo ' -
    - '.tr('Totale').': - - '.Translator::numberToLocale($totale).' € -
    '; - - echo ' - - -
    -
    - -
    -
    -
    '; +if (get('documento') == 'fattura') { + $final_module = $module['name'] == 'Ordini cliente' ? 'Fatture di vendita' : 'Fatture di acquisto'; } else { - echo ' -

    '.tr('Non ci sono articoli da evadere').'...

    '; + $final_module = $module['name'] == 'Ordini cliente' ? 'Ddt di vendita' : 'Ddt di acquisto'; } -echo ' - '; +$dir = $module['name'] == 'Ordini cliente' ? 'entrata' : 'uscita'; -?> +$options = [ + 'op' => 'add_ordine', + 'id_importazione' => 'id_ordine', + 'final_module' => $final_module, + 'original_module' => $module['name'], + 'sql' => [ + 'table' => 'or_ordini', + 'rows' => 'or_righe_ordini', + 'id_rows' => 'idordine', + ], + 'serials' => [ + 'id_riga' => 'id_riga_ordine', + 'condition' => '(id_riga_ddt IS NOT NULL OR id_riga_documento IS NOT NULL)', + ], + 'button' => tr('Aggiungi'), + 'dir' => $dir, + 'create_document' => true, +]; - +echo App::load('importa.php', $result, $options, true); diff --git a/modules/ordini/edit.php b/modules/ordini/edit.php index 476aeb06d..2811b661b 100644 --- a/modules/ordini/edit.php +++ b/modules/ordini/edit.php @@ -9,6 +9,8 @@ if ($module['name'] == 'Ordini cliente') { $dir = 'uscita'; } +$_SESSION['superselect']['idanagrafica'] = $record['idanagrafica']; + ?>
    @@ -104,22 +106,27 @@ if ($module['name'] == 'Ordini cliente') {
    -
    +

    -
    - {[ "type": "text", "label": "", "name": "id_documento_fe", "required": 0, "value": "$id_documento_fe$", "maxlength": 20, "readonly": "" ]} +
    + {[ "type": "text", "label": "", "name": "id_documento_fe", "required": 0, "help": "Obbligatorio per valorizzare CIG/CUP. È possible inserire:
    • N. determina
    • RDO
    • Ordine MEPA
    '); ?>", "value": "$id_documento_fe$", "maxlength": 20, "readonly": "" ]}
    -
    +
    + {[ "type": "text", "label": "", "name": "num_item", "required": 0, "value": "$num_item$", "maxlength": 15, "readonly": "" ]} +
    +
    +
    +
    {[ "type": "text", "label": "", "name": "codice_cig", "required": 0, "value": "$codice_cig$", "maxlength": 15, "readonly": "" ]}
    -
    +
    {[ "type": "text", "label": "", "name": "codice_cup", "required": 0, "value": "$codice_cup$", "maxlength": 15, "readonly": "" ]}
    @@ -238,4 +245,18 @@ $('#idanagrafica').change( function(){ $("#idsede").selectReset(); }); + +$(document).ready( function(){ + + $('#codice_cig, #codice_cup').bind("keyup change", function(e) { + + if ($('#codice_cig').val() == '' && $('#codice_cup').val() == '' ){ + $('#id_documento_fe').prop('required', false); + }else{ + $('#id_documento_fe').prop('required', true); + } + + }); + +}); diff --git a/modules/ordini/src/Components/Articolo.php b/modules/ordini/src/Components/Articolo.php index 8f02973d8..bb0dcbc89 100644 --- a/modules/ordini/src/Components/Articolo.php +++ b/modules/ordini/src/Components/Articolo.php @@ -11,6 +11,7 @@ class Articolo extends Article use RelationTrait; protected $table = 'or_righe_ordini'; + protected $serialRowID = 'ordine'; /** * Crea un nuovo articolo collegato ad una ordine. @@ -47,7 +48,7 @@ class Articolo extends Article ]); $this->articolo->movimenta(-$qta, $movimento, $data, false, [ - 'iddocumento' => $ordine->id, + 'idordine' => $ordine->id, ]); } diff --git a/modules/pagamenti/src/Pagamento.php b/modules/pagamenti/src/Pagamento.php new file mode 100644 index 000000000..194cb49d0 --- /dev/null +++ b/modules/pagamenti/src/Pagamento.php @@ -0,0 +1,82 @@ +hasMany(Fattura::class, 'idpagamento'); + } + + public function rate() + { + return $this->hasMany(Pagamento::class, 'descrizione', 'descrizione'); + } + + public function calcola($importo, $data) + { + $rate = $this->rate->sortBy('num_giorni'); + $number = count($rate); + + //dd($rate, $this); + $totale = 0.0; + + $results = []; + foreach ($rate as $key => $rata) { + // X giorni esatti + if ($rata['giorno'] == 0) { + $scadenza = date('Y-m-d', strtotime($data.' +'.$rata['num_giorni'].' day')); + } + + // Ultimo del mese + elseif ($rata['giorno'] < 0) { + $date = new DateTime($data); + + $add = floor($rata['num_giorni'] / 30); + for ($c = 0; $c < $add; ++$c) { + $date->modify('last day of next month'); + } + + // Ultimo del mese più X giorni + $giorni = -$rata['giorno'] - 1; + if ($giorni > 0) { + $date->modify('+'.($giorni).' day'); + } else { + $date->modify('last day of this month'); + } + + $scadenza = $date->format('Y-m-d'); + } + + // Giorno preciso del mese + else { + $scadenza = date('Y-m-'.$rata['giorno'], strtotime($data.' +'.$rata['num_giorni'].' day')); + } + + // All'ultimo ciclo imposto come cifra da pagare il totale della fattura meno gli importi già inseriti in scadenziario per evitare di inserire cifre arrotondate "male" + if ($key + 1 == $number) { + $da_pagare = sum($importo, -$totale, 2); + } + + // Totale da pagare (totale x percentuale di pagamento nei casi pagamenti multipli) + else { + $da_pagare = sum($importo / 100 * $rata['prc'], 0, 2); + } + + $totale = sum($da_pagare, $totale, 2); + + $results[] = [ + 'scadenza' => $scadenza, + 'importo' => $da_pagare, + ]; + } + + return $results; + } +} diff --git a/modules/partitario/actions.php b/modules/partitario/actions.php index b7907b5e5..8a1e4df49 100644 --- a/modules/partitario/actions.php +++ b/modules/partitario/actions.php @@ -24,6 +24,7 @@ switch (post('op')) { flash()->error(tr('Il numero scelto è già esistente!')); } } + break; // Modifica conto nel partitario diff --git a/modules/preventivi/actions.php b/modules/preventivi/actions.php index eeb9aceb8..816cd3396 100644 --- a/modules/preventivi/actions.php +++ b/modules/preventivi/actions.php @@ -3,8 +3,6 @@ include_once __DIR__.'/../../core.php'; use Modules\Anagrafiche\Anagrafica; -use Modules\Fatture\Fattura; -use Modules\Fatture\Tipo as TipoFattura; use Modules\Interventi\TipoSessione; use Modules\Preventivi\Components\Articolo; use Modules\Preventivi\Components\Riga; @@ -63,6 +61,7 @@ switch (post('op')) { $idiva = post('idiva'); $id_documento_fe = post('id_documento_fe'); + $num_item = post('num_item'); $codice_cig = post('codice_cig'); $codice_cup = post('codice_cup'); @@ -84,6 +83,7 @@ switch (post('op')) { ' tipo_sconto_globale='.prepare($tipo_sconto).','. ' sconto_globale='.prepare($sconto).','. ' id_documento_fe='.prepare($id_documento_fe).','. + ' num_item='.prepare($num_item).','. ' codice_cig='.prepare($codice_cig).','. ' codice_cup='.prepare($codice_cup).','. ' validita='.prepare($validita).','. @@ -368,36 +368,6 @@ switch (post('op')) { flash()->info(tr('Aggiunta nuova revisione!')); break; - - // Creazione fattura da preventivo - case 'fattura_da_preventivo': - $preventivo = Preventivo::find($id_record); - - $tipo = TipoFattura::where('descrizione', 'Fattura immediata di vendita')->first(); - $id_segment = $dbo->fetchOne('SELECT * FROM zz_segments WHERE id_module='.prepare($id_module)." AND predefined='1'")['id']; - $data = date('Y-m-d'); - - $fattura = Fattura::build($preventivo->anagrafica, $tipo, $data, $id_segment); - $fattura->idpagamento = $preventivo->idpagamento; - - $id_conto = setting('Conto predefinito fatture di vendita'); - - $righe = $preventivo->getRighe(); - foreach ($righe as $riga) { - $copia = $riga->copiaIn($fattura); - $copia->idconto = $id_conto; - - if ($riga->isArticolo()) { - $copia->movimenta($copia->qta); - } - } - - flash()->info(tr('Creata una nuova fattura!')); - - $id_record = $fattura->id; - $id_module = Modules::get('Fatture di vendita')['id']; - - break; } if (post('op') !== null && post('op') != 'update') { diff --git a/modules/preventivi/ajax/select.php b/modules/preventivi/ajax/select.php index 75edcd740..4538125c2 100644 --- a/modules/preventivi/ajax/select.php +++ b/modules/preventivi/ajax/select.php @@ -11,24 +11,12 @@ switch ($resource) { $filter[] = 'id='.prepare($element); } - $where[] = 'an_anagrafiche.idanagrafica='.prepare($superselect['idanagrafica']); - $where[] = 'co_preventivi.default_revision=1'; + if (empty($elements)) { + $where[] = 'an_anagrafiche.idanagrafica='.prepare($superselect['idanagrafica']); + $where[] = 'co_preventivi.default_revision=1'; - $stati = !empty($superselect['stati']) ? $superselect['stati'] : [ - 'In attesa di conferma', - 'Accettato', - 'In lavorazione', - 'Concluso', - 'In attesa di pagamento', - ]; - $desc = []; - foreach ($stati as $value) { - $desc[] = prepare($value); - } - $where[] = 'idstato IN (SELECT `id` FROM co_statipreventivi WHERE descrizione IN ('.implode(',', $desc).'))'; - - if (!empty($superselect['non_fatturato'])) { - $where[] = 'id NOT IN (SELECT idpreventivo FROM co_righe_documenti WHERE idpreventivo IS NOT NULL)'; + $stato = !empty($superselect['stato']) ? $superselect['stato'] : 'fatturabile'; + $where[] = 'idstato IN (SELECT `id` FROM co_staticontratti WHERE '.$stato.' = 1)'; } if (!empty($search)) { diff --git a/modules/preventivi/buttons.php b/modules/preventivi/buttons.php index 0a568a642..37931a601 100644 --- a/modules/preventivi/buttons.php +++ b/modules/preventivi/buttons.php @@ -5,33 +5,31 @@ include_once __DIR__.'/../../core.php'; echo' '; -if (!in_array($record['stato'], ['Bozza', 'Rifiutato', 'In attesa di conferma'])) { - $disabled = ''; -} else { +$disabled = $record['fatturabile'] || $record['annullato']; +if (!$disabled) { echo ' '; - $disabled = 'disabled'; } // Creazione altri documenti echo ' - -
    +

    -
    +
    {[ "type": "text", "label": "", "help": "Obbligatorio per valorizzare CIG/CUP. È possible inserire:
    • N. determina
    • RDO
    • Ordine MEPA
    '); ?>","name": "id_documento_fe", "required": 0, "value": "$id_documento_fe$", "maxlength": 20 ]}
    -
    +
    + {[ "type": "text", "label": "", "name": "num_item", "required": 0, "value": "$num_item$", "maxlength": 15 ]} +
    +
    +
    +
    {[ "type": "text", "label": "", "name": "codice_cig", "required": 0, "value": "$codice_cig$", "maxlength": 15 ]}
    -
    +
    {[ "type": "text", "label": "", "name": "codice_cup", "required": 0, "value": "$codice_cup$", "maxlength": 15 ]}
    @@ -203,6 +208,17 @@ include $docroot.'/modules/preventivi/row-list.php'; $("#data_accettazione").trigger("dp.change"); $("#data_rifiuto").trigger("dp.change"); + + $('#codice_cig, #codice_cup').bind("keyup change", function(e) { + + if ($('#codice_cig').val() == '' && $('#codice_cup').val() == '' ){ + $('#id_documento_fe').prop('required', false); + }else{ + $('#id_documento_fe').prop('required', true); + } + + }); + }); diff --git a/modules/preventivi/init.php b/modules/preventivi/init.php index 98bcff451..f57c9603d 100644 --- a/modules/preventivi/init.php +++ b/modules/preventivi/init.php @@ -5,5 +5,11 @@ include_once __DIR__.'/../../core.php'; if (isset($id_record)) { $preventivo = Modules\Preventivi\Preventivo::with('stato')->find($id_record); - $record = $dbo->fetchOne('SELECT *, (SELECT tipo FROM an_anagrafiche WHERE idanagrafica = co_preventivi.idanagrafica) AS tipo_anagrafica, (SELECT descrizione FROM co_statipreventivi WHERE id=idstato) AS stato FROM co_preventivi WHERE id='.prepare($id_record)); + $record = $dbo->fetchOne('SELECT *, + (SELECT tipo FROM an_anagrafiche WHERE idanagrafica = co_preventivi.idanagrafica) AS tipo_anagrafica, + (SELECT fatturabile FROM co_statipreventivi WHERE id=idstato) AS fatturabile, + (SELECT annullato FROM co_statipreventivi WHERE id=idstato) AS annullato, + (SELECT descrizione FROM co_statipreventivi WHERE id=idstato) AS stato + FROM co_preventivi + WHERE id='.prepare($id_record)); } diff --git a/modules/preventivi/row-list.php b/modules/preventivi/row-list.php index 232b95e9c..ce026c25d 100644 --- a/modules/preventivi/row-list.php +++ b/modules/preventivi/row-list.php @@ -40,10 +40,11 @@ foreach ($rs as $r) { // q.tà echo ' - '; + '; if (empty($r['is_descrizione'])) { echo ' - '.Translator::numberToLocale($r['qta'], 'qta'); + '.Translator::numberToLocale($r['qta'] - $r['qta_evasa'], 'qta').' +
    ('.tr('Q.tà iniziale').': '.Translator::numberToLocale($r['qta'], 'qta').')'; } echo ' '; diff --git a/modules/preventivi/src/Components/Articolo.php b/modules/preventivi/src/Components/Articolo.php index 518c9852d..273c06cc1 100644 --- a/modules/preventivi/src/Components/Articolo.php +++ b/modules/preventivi/src/Components/Articolo.php @@ -29,26 +29,7 @@ class Articolo extends Article public function movimenta($qta) { - $preventivo = $this->preventivo; - $tipo = $preventivo->tipo; - - $numero = $preventivo->numero_esterno ?: $preventivo->numero; - $data = $preventivo->data; - - $carico = ($tipo->dir == 'entrata') ? tr('Ripristino articolo da _TYPE_ _NUM_') : tr('Carico magazzino da _TYPE_ numero _NUM_'); - $scarico = ($tipo->dir == 'entrata') ? tr('Scarico magazzino per _TYPE_ numero _NUM_') : tr('Rimozione articolo da _TYPE_ _NUM_'); - - $qta = ($tipo->dir == 'uscita') ? -$qta : $qta; - $movimento = ($qta < 0) ? $carico : $scarico; - - $movimento = replace($movimento, [ - '_TYPE_' => $tipo->descrizione, - '_NUM_' => $numero, - ]); - - $this->articolo->movimenta(-$qta, $movimento, $data, false, [ - 'iddocumento' => $preventivo->id, - ]); + return; } public function getDirection() diff --git a/modules/preventivi/src/Preventivo.php b/modules/preventivi/src/Preventivo.php index 922c9cc5b..2fa0d2594 100644 --- a/modules/preventivi/src/Preventivo.php +++ b/modules/preventivi/src/Preventivo.php @@ -5,6 +5,7 @@ namespace Modules\Preventivi; use Carbon\Carbon; use Common\Document; use Modules\Anagrafiche\Anagrafica; +use Modules\Interventi\Intervento; use Modules\Interventi\TipoSessione; use Traits\RecordTrait; use Util\Generator; @@ -132,6 +133,11 @@ class Preventivo extends Document return $this->hasOne(Components\Sconto::class, 'idpreventivo'); } + public function interventi() + { + return $this->hasMany(Intervento::class, 'id_preventivo'); + } + // Metodi statici /** diff --git a/modules/primanota/add.php b/modules/primanota/add.php index 0511232e9..e9810794a 100644 --- a/modules/primanota/add.php +++ b/modules/primanota/add.php @@ -2,7 +2,7 @@ include_once __DIR__.'/../../core.php'; -?>
    +?> @@ -26,9 +26,14 @@ include_once __DIR__.'/../../core.php'; if ($tipo_doc == 'Nota di credito') { $nota_credito = true; + $tipo_doc = 'nota di credito'; + } elseif ($tipo_doc == 'Nota di debito') { + $tipo_doc = 'nota di debito'; + } else { + $tipo_doc = 'fattura'; } - $descrizione = tr('_DOC_ numero _NUM_ del _DATE_ (_NAME_)', [ + $descrizione = tr('Pag. _DOC_ num. _NUM_ del _DATE_ (_NAME_)', [ '_DOC_' => $tipo_doc, '_NUM_' => $numero_doc, '_DATE_' => Translator::dateToLocale($rs[0]['data']), @@ -242,7 +247,7 @@ include_once __DIR__.'/../../core.php';
    - +
    @@ -336,7 +341,7 @@ include_once __DIR__.'/../../core.php'; $('#bs-popup #modello_primanota').change(function(){ - + if ($(this).val()!=''){ $('#btn_crea_modello').html(' '+''); $('#bs-popup #idmastrino').val($(this).val()); @@ -344,19 +349,19 @@ include_once __DIR__.'/../../core.php'; $('#btn_crea_modello').html(' '+''); $('#bs-popup #idmastrino').val(0); } - + var idmastrino = $(this).val(); if(idmastrino!=''){ var causale = $(this).find('option:selected').text(); - + //aggiornava erroneamente anche la causale ed eventuale numero di fattura e data $('#bs-popup #desc').val(causale); - + $.get('/ajax_complete.php?op=get_conti&idmastrino='+idmastrino, function(data){ var conti = data.split(','); for(i=0;i - diff --git a/modules/ritenute/actions.php b/modules/ritenute/actions.php index d05aeb010..8254c9333 100644 --- a/modules/ritenute/actions.php +++ b/modules/ritenute/actions.php @@ -6,9 +6,8 @@ switch (filter('op')) { case 'update': $descrizione = filter('descrizione'); $percentuale = filter('percentuale'); - $percentuale_imponibile = filter('percentuale_imponibile'); + $percentuale_imponibile = filter('percentuale_imponibile'); - if (isset($descrizione) && isset($percentuale) && isset($percentuale_imponibile)) { if ($dbo->fetchNum('SELECT * FROM `co_ritenutaacconto` WHERE `descrizione`='.prepare($descrizione).' AND `id`!='.prepare($id_record)) == 0) { $dbo->query('UPDATE `co_ritenutaacconto` SET `descrizione`='.prepare($descrizione).', `percentuale`='.prepare($percentuale).', `percentuale_imponibile`='.prepare($percentuale_imponibile).' WHERE `id`='.prepare($id_record)); diff --git a/modules/ritenute/edit.php b/modules/ritenute/edit.php index b1522b703..5c885f232 100644 --- a/modules/ritenute/edit.php +++ b/modules/ritenute/edit.php @@ -51,4 +51,4 @@ if ($record['doc_associati'] == 0) { '.tr('Elimina').' '; -} \ No newline at end of file +} diff --git a/modules/ritenute_contributi/actions.php b/modules/ritenute_contributi/actions.php index 4ca850232..391e66416 100644 --- a/modules/ritenute_contributi/actions.php +++ b/modules/ritenute_contributi/actions.php @@ -6,9 +6,8 @@ switch (filter('op')) { case 'update': $descrizione = filter('descrizione'); $percentuale = filter('percentuale'); - $percentuale_imponibile = filter('percentuale_imponibile'); + $percentuale_imponibile = filter('percentuale_imponibile'); - if (isset($descrizione) && isset($percentuale) && isset($percentuale_imponibile)) { if ($dbo->fetchNum('SELECT * FROM `co_ritenuta_contributi` WHERE `descrizione`='.prepare($descrizione).' AND `id`!='.prepare($id_record)) == 0) { $dbo->query('UPDATE `co_ritenuta_contributi` SET `descrizione`='.prepare($descrizione).', `percentuale`='.prepare($percentuale).', `percentuale_imponibile`='.prepare($percentuale_imponibile).' WHERE `id`='.prepare($id_record)); diff --git a/modules/ritenute_contributi/edit.php b/modules/ritenute_contributi/edit.php index b1522b703..5c885f232 100644 --- a/modules/ritenute_contributi/edit.php +++ b/modules/ritenute_contributi/edit.php @@ -51,4 +51,4 @@ if ($record['doc_associati'] == 0) { '.tr('Elimina').' '; -} \ No newline at end of file +} diff --git a/modules/ritenute_contributi/src/RitenutaContributi.php b/modules/ritenute_contributi/src/RitenutaContributi.php index c6db0e8f6..82e9cf7fb 100644 --- a/modules/ritenute_contributi/src/RitenutaContributi.php +++ b/modules/ritenute_contributi/src/RitenutaContributi.php @@ -3,8 +3,14 @@ namespace Modules\RitenuteContributi; use Common\Model; +use Modules\Fatture\Fattura; class RitenutaContributi extends Model { protected $table = 'co_ritenuta_contributi'; + + public function fatture() + { + return $this->hasMany(Fattura::class, 'id_ritenuta_contributi'); + } } diff --git a/modules/scadenzario/edit.php b/modules/scadenzario/edit.php index b95cc2fb5..bce440c54 100644 --- a/modules/scadenzario/edit.php +++ b/modules/scadenzario/edit.php @@ -108,6 +108,15 @@ for ($i = 0; $i < count($rs); ++$i) { $totale_da_pagare = sum(array_column($rs, 'da_pagare')); $totale_pagato = sum(array_column($rs, 'pagato')); +if ($totale_da_pagare == $totale_pagato) { + echo ' +'; +} + echo ' '.tr('Totale').' @@ -137,6 +146,7 @@ echo '
    +{( "name": "log_email", "id_module": "$id_module$", "id_record": "$id_record$" )} '; diff --git a/plugins/importFE/rows.php b/plugins/importFE/rows.php index 6c59ecf34..3b9e06e31 100644 --- a/plugins/importFE/rows.php +++ b/plugins/importFE/rows.php @@ -87,6 +87,8 @@ if (!empty($pagamenti)) { $metodi = $pagamenti['DettaglioPagamento']; $metodi = isset($metodi[0]) ? $metodi : [$metodi]; + $codice_modalita_pagamento = $metodi[0]['ModalitaPagamento']; + echo '

    '.tr('Pagamento').'

    @@ -124,8 +126,19 @@ if (!empty($codice_modalita_pagamento)) { } $query .= ' GROUP BY descrizione ORDER BY descrizione ASC'; +// Pagamento echo ' - {[ "type": "select", "label": "'.tr('Pagamento').'", "name": "pagamento", "required": 1, "values": "query='.$query.'" ]}'; +
    +
    + {[ "type": "select", "label": "'.tr('Pagamento').'", "name": "pagamento", "required": 1, "values": "query='.$query.'" ]} +
    '; + +// Movimentazioni +echo ' +
    + {[ "type": "checkbox", "label": "'.tr('Movimenta gli articoli').'", "name": "movimentazione", "value": 1 ]} +
    +
    '; // Righe $righe = $fattura_pa->getRighe(); @@ -142,9 +155,7 @@ if (!empty($righe)) { - - - + '; @@ -159,9 +170,19 @@ if (!empty($righe)) { echo ' - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    '.tr('Descrizione').''.tr('Q.tà').''.tr('Prezzo unitario').''.tr('Dati contabili').'*'.tr('Dati contabili').'* '.tr('Articolo').'
    '.$riga['Descrizione'].''.Translator::numberToLocale($riga['Quantita']).' '.$riga['UnitaMisura'].''.Translator::numberToLocale($riga['PrezzoUnitario']).' €Aliquota iva: '.$riga['AliquotaIVA'].'% + '.$riga['Descrizione'].'
    + + '.tr('Q.tà: _QTA_ _UM_', [ + '_QTA_' => Translator::numberToLocale($riga['Quantita']), + '_UM_' => $riga['UnitaMisura'], + ]).'
    + + '.tr('Aliquota iva _PRC_% _DESC_', [ + '_PRC_' => Translator::numberToLocale($riga['AliquotaIVA']), + '_DESC_' => $riga['RiferimentoNormativo'] ? ' - '.$riga['RiferimentoNormativo'] : '', + ]).' +
    {[ "type": "select", "name": "iva['.$key.']", "values": "query='.str_replace('"', '\"', $query).'", "required": 1, "placeholder": "Aliquota iva" ]}
    diff --git a/plugins/importFE/src/FatturaElettronica.php b/plugins/importFE/src/FatturaElettronica.php index b03aeeec2..083bada1c 100644 --- a/plugins/importFE/src/FatturaElettronica.php +++ b/plugins/importFE/src/FatturaElettronica.php @@ -34,9 +34,9 @@ class FatturaElettronica /** @var Fattura Fattura collegata */ protected $fattura = null; - public function __construct($file) + public function __construct($name) { - $this->file = static::getImportDirectory().'/'.$file; + $this->file = static::getImportDirectory().'/'.$name; if (ends_with($file, '.p7m')) { $file = XML::decodeP7M($this->file); @@ -95,10 +95,10 @@ class FatturaElettronica return $filename; } - public static function isValid($file) + public static function isValid($name) { try { - new static($file); + new static($name); return true; } catch (UnexpectedValueException $e) { @@ -208,17 +208,23 @@ class FatturaElettronica return $result; } - public function saveRighe($articoli, $iva, $conto) + public function saveRighe($articoli, $iva, $conto, $movimentazione = true) { $righe = $this->getRighe(); + $fattura = $this->getFattura(); foreach ($righe as $key => $riga) { $articolo = ArticoloOriginale::find($articoli[$key]); + $riga['PrezzoUnitario'] = floatval($riga['PrezzoUnitario']); + $riga['Quantita'] = floatval($riga['Quantita']); + if (!empty($articolo)) { - $obj = Articolo::build($this->getFattura(), $articolo); + $obj = Articolo::build($fattura, $articolo); + + $obj->movimentazione($movimentazione); } else { - $obj = Riga::build($this->getFattura()); + $obj = Riga::build($fattura); } $obj->descrizione = $riga['Descrizione']; @@ -232,69 +238,57 @@ class FatturaElettronica } $sconti = $riga['ScontoMaggiorazione']; - if (!empty($sconti)) { - if ($sconti['Percentuale'] || $sconti['Importo']) { - $tipo = !empty($sconti['Percentuale']) ? 'PRC' : 'EUR'; - $unitario = $sconti['Percentuale'] ?: $sconti['Importo']; + $sconti = $sconti[0] ? $sconti : [$sconti]; + $tipo = !empty($sconti[0]['Percentuale']) ? 'PRC' : 'UNT'; - //SConto o MaGgiorazione - $unitario = ($sconti['Tipo'] == 'SC') ? $unitario : -$unitario; + $lista = []; + foreach ($sconti as $sconto) { + $unitario = $sconto['Percentuale'] ?: $sconto['Importo']; - if (!empty($unitario)) { - $obj->sconto_unitario = $unitario; - $obj->tipo_sconto = $tipo; - } + // Sconto o Maggiorazione + $lista[] = ($sconto['Tipo'] == 'SC') ? $unitario : -$unitario; } - // Sconti multipli - else { - $sconto = $sconti[0]['Percentuale'] ? $sconti[0]['Percentuale'] : $sconti['Percentuale']; - $tipo = !empty($sconto) ? 'PRC' : 'EUR'; + if ($tipo == 'PRC') { + $elenco = implode('+', $lista); + $sconto = calcola_sconto([ + 'sconto' => $elenco, + 'prezzo' => $obj->prezzo_unitario_vendita, + 'tipo' => 'PRC', + 'qta' => $obj->qta, + ]); - $sconto_totale = 0; - if ($tipo == 'PRC') { - /** - * Trasformo un eventuale sconto percentuale combinato in più - * sconti: - * Esempio: - * 40% + 30% è uno sconto del 42%. - */ - $prezzo_intero = $riga['PrezzoUnitario'] * $riga['Quantita']; - $prezzo_scontato = $prezzo_intero; - - foreach ($sconti as $scontor) { - $prezzo_scontato -= $prezzo_scontato / 100 * $scontor['Percentuale']; - } - - // Ricavo la percentuale finale di sconto con una proporzione - $percentuale_totale = (1 - ($prezzo_scontato / $prezzo_intero)) * 100; - - if (!empty($percentuale_totale)) { - $obj->sconto_unitario = $percentuale_totale; - $obj->tipo_sconto = $tipo; - } - } else { - // Combino gli sconti tra loro - foreach ($sconti as $sconto) { - $unitario = $sconto['Percentuale'] ?: $sconto['Importo']; - - //Sconto o Maggiorazione - $unitario = ($sconto['Tipo'] == 'SC') ? $unitario : -$unitario; - - $sconto_totale += $unitario; - } - - if (!empty($unitario)) { - $obj->sconto_unitario = $sconto_totale; - $obj->tipo_sconto = $tipo; - } - } + /* + * Trasformazione di sconti multipli in sconto percentuale combinato. + * Esempio: 40% + 30% è uno sconto del 42%. + */ + $sconto_unitario = $sconto * 100 / $obj->imponibile; + } else { + $sconto_unitario = sum($lista); } + + $obj->sconto_unitario = $sconto_unitario; + $obj->tipo_sconto = $tipo; } $obj->save(); } + + // Arrotondamenti differenti nella fattura XML + $totali = array_column($righe, 'PrezzoTotale'); + $diff = sum($totali) - $fattura->imponibile_scontato; + if (!empty($diff)) { + $obj = Riga::build($fattura); + + $obj->descrizione = tr('Arrotondamento calcolato in automatico'); + $obj->id_iva = $iva[0]; + $obj->idconto = $conto[0]; + $obj->prezzo_unitario_vendita = $diff; + $obj->qta = 1; + + $obj->save(); + } } public function getAllegati() @@ -381,7 +375,7 @@ class FatturaElettronica // Sconto globale $sconto = $dati_generali['ScontoMaggiorazione']; if (!empty($sconto)) { - $tipo = !empty($sconto['Percentuale']) ? 'PRC' : 'EUR'; + $tipo = !empty($sconto['Percentuale']) ? 'PRC' : 'UNT'; $unitario = $sconto['Percentuale'] ?: $sconto['Importo']; $unitario = ($sconto['Tipo'] == 'SC') ? $unitario : -$unitario; diff --git a/plugins/importFE/src/Interaction.php b/plugins/importFE/src/Interaction.php index 2aa216bc1..03b87cbe6 100644 --- a/plugins/importFE/src/Interaction.php +++ b/plugins/importFE/src/Interaction.php @@ -24,28 +24,14 @@ class Interaction extends Connection // Ricerca da remoto if (self::isEnabled()) { - $response = static::request('POST', 'get_fatture_da_importare'); + $response = static::request('POST', 'fatture_da_importare'); $body = static::responseBody($response); - $code = $body['code']; - - if ($code == '200') { + if ($body['status'] == '200') { $files = $body['results']; foreach ($files as $file) { - /* - * Verifico che l'XML (fattura di acquisto) non sia già stato importato nel db, controllo p.iva del fornitore e progressivo invio - * TODO: caricare contenuto xml e verificare anche la data (e magari numero) della fattura. Potrebbe essere che il fornitore l'anno successivo mi genera FE con stesso progressivo invio. - */ - if (preg_match("/^([A-Z]{2})(.+?)_([^\.]+)\.xml/i", $file, $m)) { - $partita_iva = $m[2]; - $progressivo_invio = $m[3]; - $fattura = database()->fetchOne('SELECT co_documenti.id FROM (co_documenti INNER JOIN co_tipidocumento ON co_documenti.idtipodocumento=co_tipidocumento.id) INNER JOIN an_anagrafiche ON co_documenti.idanagrafica=an_anagrafiche.idanagrafica WHERE co_tipidocumento.dir="uscita" AND an_anagrafiche.piva='.prepare($partita_iva).' AND co_documenti.progressivo_invio='.prepare($progressivo_invio)); - - if (!$fattura) { - $list[] = basename($file); - } - } + $list[] = basename($file); } } } @@ -59,7 +45,7 @@ class Interaction extends Connection $file = $directory.'/'.$name; if (!file_exists($file)) { - $response = static::request('POST', 'get_fattura_da_importare', [ + $response = static::request('POST', 'fattura_da_importare', [ 'name' => $name, ]); $body = static::responseBody($response); @@ -72,16 +58,15 @@ class Interaction extends Connection public static function processXML($filename) { - $response = static::request('POST', 'process_xml', [ + $response = static::request('POST', 'fattura_xml_salvata', [ 'filename' => $filename, ]); $body = static::responseBody($response); - if ($body['processed'] == '0') { - $message = $body['code'].' - '.$body['message']; - } else { - $message = ''; + $message = ''; + if ($body['status'] != '200') { + $message = $body['status'].' - '.$body['message']; } return $message; diff --git a/plugins/importFE/view.php b/plugins/importFE/view.php index 7f760dde4..643a44263 100644 --- a/plugins/importFE/view.php +++ b/plugins/importFE/view.php @@ -13,7 +13,7 @@ $xml->loadXML($content); // XSL $xsl = new DOMDocument(); -$xsl->load(DOCROOT.'/assets/src/xml/fe-stylesheet-1.2.1.xsl'); +$xsl->load(DOCROOT.'/plugins/xml/asso-invoice.xsl'); // XSLT $xslt = new XSLTProcessor(); diff --git a/plugins/receiptFE/actions.php b/plugins/receiptFE/actions.php index eb4dee9ce..ea342532c 100644 --- a/plugins/receiptFE/actions.php +++ b/plugins/receiptFE/actions.php @@ -27,23 +27,25 @@ switch (filter('op')) { $results = []; foreach ($list as $name) { - $file = Interaction::getReceipt($name); + Interaction::getReceipt($name); - $result = []; - if (!empty($file)) { - try { - $receipt = new Ricevuta($name, $file['content']); + $fattura = null; + try { + $receipt = new Ricevuta($name, $content); + $receipt->save(); - $result = [ - 'fattura' => $receipt->getFattura()->numero_esterno, - ]; - } catch (UnexpectedValueException $e) { - } + $fattura = $receipt->getFattura()->numero_esterno; + + $receipt->delete(); + + Interaction::processReceipt($name); + } catch (UnexpectedValueException $e) { } - $results[] = array_merge([ + $results[] = [ 'file' => $name, - ], $result); + 'fattura' => $fattura, + ]; } echo json_encode($results); diff --git a/plugins/receiptFE/edit.php b/plugins/receiptFE/edit.php index b37a4c684..b6fee87ef 100644 --- a/plugins/receiptFE/edit.php +++ b/plugins/receiptFE/edit.php @@ -12,7 +12,7 @@ if (!Interaction::isEnabled()) { } echo ' -

    '.tr("Le ricevute delle Fatture Elettroniche permettono di individuare se una determinata fattura rilasciata è $requesta accettata dal Sistema Di Interscambio e dal cliente relativo").'.

    +

    '.tr("Le ricevute delle Fatture Elettroniche permettono di individuare se una determinata fattura rilasciata è stata accettata dal Sistema Di Interscambio e dal cliente relativo").'.

    '.tr("Tramite il pulsante _BTN_ è possibile procedere all controllo automatico di queste ricevute, che aggiorneranno di conseguenza lo $requesto dei documenti relativi e verranno allegate ad essi", [ '_BTN_' => 'Ricerca', @@ -45,8 +45,8 @@ echo ' count = data.length; buttonRestore(btn, restore); - - if( count == 0 ){ + + if(count == 0){ swal({ title: "'.tr('Non ci sono ricevute da importare').'", showCancelButton: false, @@ -91,7 +91,6 @@ echo ' var html = "'.tr('Sono state elaborate le seguenti ricevute:').'"; - console.log(data); data.forEach(function(element) { var text = ""; if(element.fattura) { diff --git a/plugins/receiptFE/src/Interaction.php b/plugins/receiptFE/src/Interaction.php index 12c100b4d..ce5982280 100644 --- a/plugins/receiptFE/src/Interaction.php +++ b/plugins/receiptFE/src/Interaction.php @@ -13,19 +13,41 @@ class Interaction extends Connection { public static function getReceiptList() { - $response = static::request('POST', 'get_receipt_list'); - $body = static::responseBody($response)['results']; + $response = static::request('POST', 'notifiche_da_importare'); + $body = static::responseBody($response); - return $body; + return $body['results']; } public static function getReceipt($name) { - $response = static::request('POST', 'get_receipt', [ - 'name' => $name, + $directory = Ricevuta::getImportDirectory(); + $file = $directory.'/'.$name; + + if (!file_exists($file)) { + $response = static::request('POST', 'notifica_da_importare', [ + 'name' => $name, + ]); + $body = static::responseBody($response); + + Ricevuta::store($name, $body['content']); + } + + return $name; + } + + public static function processReceipt($filename) + { + $response = static::request('POST', 'notifica_xml_salvata', [ + 'filename' => $filename, ]); $body = static::responseBody($response); - return $body; + $result = true; + if ($body['status'] != '200') { + $result = $body['status'].' - '.$body['message']; + } + + return $result; } } diff --git a/plugins/receiptFE/src/Ricevuta.php b/plugins/receiptFE/src/Ricevuta.php index 3db884479..ce501e655 100644 --- a/plugins/receiptFE/src/Ricevuta.php +++ b/plugins/receiptFE/src/Ricevuta.php @@ -2,8 +2,11 @@ namespace Plugins\ReceiptFE; +use Modules; use Modules\Fatture\Fattura; +use Plugins; use UnexpectedValueException; +use Uploads; use Util\XML; /** @@ -13,18 +16,22 @@ use Util\XML; */ class Ricevuta { - /** @var array XML della fattura */ + protected static $directory = null; + + /** @var array Percorso del file XML */ + protected $file = null; + /** @var array XML della ricevuta */ protected $xml = null; - /** @var array XML della fattura */ + /** @var array XML della ricevuta */ protected $fattura = null; - public function __construct($name, $content) + public function __construct($name) { - $this->xml = XML::read($content); + $this->file = static::getImportDirectory().'/'.$name; + $this->xml = XML::readFile($this->file); - $nome = $this->xml['NomeFile']; - $filename = explode('.', $nome)[0]; + $filename = explode('.', $name)[0]; $pieces = explode('_', $filename); $progressivo_invio = $pieces[1]; @@ -35,25 +42,89 @@ class Ricevuta if (empty($this->fattura)) { throw new UnexpectedValueException(); - } else { - // Processo la ricevuta e salvo il codice e messaggio di errore - $filename = explode('.', $name)[0]; - $pieces = explode('_', $filename); - $codice = $pieces[2]; - $descrizione = $this->xml['Destinatario']['Descrizione']; - $data = $this->xml['DataOraRicezione']; - - $this->fattura->codice_stato_fe = $codice; - $this->fattura->descrizione_ricevuta_fe = $descrizione; - $this->fattura->data_stato_fe = date('Y-m-d H:i:s', strtotime($data)); - $this->fattura->save(); - - return true; } } + public static function store($filename, $content) + { + $directory = static::getImportDirectory(); + $file = $directory.'/'.$filename; + + directory($directory); + file_put_contents($file, $content); + + return $filename; + } + + public static function getImportDirectory() + { + if (!isset(self::$directory)) { + $plugin = Plugins::get('Ricevute FE'); + + self::$directory = DOCROOT.'/'.$plugin->upload_directory; + } + + return self::$directory; + } + + public function saveAllegato($codice) + { + $module = Modules::get('Fatture di vendita'); + + $info = [ + 'category' => tr('Fattura Elettronica'), + 'id_module' => $module->id, + 'id_record' => $this->fattura->id, + ]; + + // Registrazione XML come allegato + $filename = Uploads::upload($this->file, array_merge($info, [ + 'name' => tr('Ricevuta _TYPE_', [ + '_TYPE_' => $codice, + ]), + 'original' => basename($this->file), + ])); + } + + public function saveStato($codice) + { + $fattura = $this->getFattura(); + + // Modifica lo stato solo se la fattura non è già stata consegnata (per evitare problemi da doppi invii) + // In realtà per le PA potrebbe esserci lo stato NE (che può essere positiva o negativa) successivo alla RC + //if ($fattura->codice_stato_fe == 'RC') { + //return; + //} + + // Processo la ricevuta e salvo data ricezione, codice e messaggio + $descrizione = $this->xml['Destinatario']['Descrizione']; + $data = $this->xml['DataOraRicezione']; + + $fattura->data_stato_fe = date('Y-m-d H:i:s', strtotime($data)); + $fattura->codice_stato_fe = $codice; + $fattura->descrizione_ricevuta_fe = $descrizione; + + $fattura->save(); + } + + public function save() + { + $name = basename($this->file); + $filename = explode('.', $name)[0]; + $pieces = explode('_', $filename); + $codice = $pieces[2]; + + $this->saveAllegato($codice); + $this->saveStato($codice); + } + public function getFattura() { return $this->fattura; } + + public function delete() + { + delete($this->file); + } } diff --git a/plugins/revisioni/edit.php b/plugins/revisioni/edit.php index f8f90378c..4eea9bc12 100644 --- a/plugins/revisioni/edit.php +++ b/plugins/revisioni/edit.php @@ -1,4 +1,4 @@ -"; diff --git a/plugins/xml/AT_v1.0.xsl b/plugins/xml/AT_v1.0.xsl new file mode 100644 index 000000000..ef56f4468 --- /dev/null +++ b/plugins/xml/AT_v1.0.xsl @@ -0,0 +1,137 @@ + + + + + + + + + + + + + + + + +

    +
    +
    + +
    + + File con firma elettronica - + + Versione +
    +

    Attestazione di avvenuta trasmissione della fattura con impossibilità di recapito

    + +
      +
    • + Identificativo SdI: + +
    • + +
    • + Nome File: + +
    • + +
    • + Data Ora Ricezione: + +
    • + + +
    • +

      Riferimento Archivio:

      +
        +
      • + Identificativo SdI: + +
      • +
      • + Nome File: + +
      • +
      +
    • +
      + +
    • + Destinatario: + +
    • + +
    • + Message Id: + +
    • + +
    • + Pec Message-ID: + +
    • +
      + + +
    • + Note: + +
    • +
      + +
    • + Hash del File Originale: + +
    • +
    +
    +
    +
    + + + + + + diff --git a/plugins/xml/DT_v1.0.xsl b/plugins/xml/DT_v1.0.xsl new file mode 100644 index 000000000..8a827a7fe --- /dev/null +++ b/plugins/xml/DT_v1.0.xsl @@ -0,0 +1,145 @@ + + + + + + + + + + + + + + + + +
    +
    +
    + +
    + + File con firma elettronica - + + Versione +
    + + + + + Flusso semplificato + +
    +

    Notifica Decorrenza Termini

    + +
      +
    • + Identificativo SdI: + +
    • + + +
    • +

      Riferimento Fattura

      +
        +
      • + Numero Fattura: + +
      • +
      • + Anno Fattura: + +
      • + +
      • + Posizione Fattura: + +
      • +
        +
      +
    • +
      + +
    • + Nome File: + +
    • + + +
    • + Descrizione: + +
    • +
      + +
    • + Message Id: + +
    • + + +
    • + Pec Message Id: + +
    • +
      + + +
    • + Note: + +
    • +
      + +
    + +
    +
    +
    + +
    + + +
    +
    diff --git a/plugins/xml/EC_v1.0.xsl b/plugins/xml/EC_v1.0.xsl new file mode 100644 index 000000000..36f16f837 --- /dev/null +++ b/plugins/xml/EC_v1.0.xsl @@ -0,0 +1,132 @@ + + + + + + + + + + + + + + + + +
    +
    +
    + +
    + + File con firma elettronica - + + Versione +
    +

    Notifica Esito Committente

    + +
      +
    • + Identificativo SdI: + +
    • + + +
    • +

      Riferimento Fattura

      +
        +
      • + Numero Fattura: + +
      • +
      • + Anno Fattura: + +
      • + +
      • + Posizione Fattura: + +
      • +
        +
      +
    • +
      + +
    • + Esito: + + + + + + (Accettazione) + (Rifiuto) + +
    • + + +
    • + Descrizione: + +
    • +
      + + +
    • + Message Id Committente: + +
    • +
      +
    +
    +
    +
    + +
    + + +
    +
    diff --git a/plugins/xml/MC_v1.0.xsl b/plugins/xml/MC_v1.0.xsl new file mode 100644 index 000000000..2e5bb6ca4 --- /dev/null +++ b/plugins/xml/MC_v1.0.xsl @@ -0,0 +1,136 @@ + + + + + + + + + + + + + + + + +
    +
    +
    + +
    + + File con firma elettronica - + + Versione +
    +

    Notifica Mancata Consegna

    + +
      +
    • + Identificativo SdI: + +
    • + +
    • + Nome File: + +
    • + +
    • + Data Ora Ricezione: + +
    • + + +
    • +

      Riferimento Archivio

      +
        +
      • + Identificativo SdI: + +
      • +
      • + Nome File: + +
      • +
      +
    • +
      + + +
    • + Descrizione: + +
    • +
      + +
    • + Message Id: + +
    • + + +
    • + Pec Message Id: + +
    • +
      + + +
    • + Note: + +
    • +
      +
    +
    +
    +
    + +
    + + +
    +
    diff --git a/plugins/xml/NE_v1.0.xsl b/plugins/xml/NE_v1.0.xsl new file mode 100644 index 000000000..4287cf944 --- /dev/null +++ b/plugins/xml/NE_v1.0.xsl @@ -0,0 +1,175 @@ + + + + + + + + + + + + + + + + +
    +
    +
    + +
    + + File con firma elettronica - + + Versione +
    + + + + + Flusso semplificato + +
    +

    Notifica Esito

    + +
      +
    • + Identificativo SdI: + +
    • + +
    • + Nome File: + +
    • + + + +
    • + Message Id: + +
    • +
      + + +
    • + PEC Message Id: + +
    • +
      + + +
    • + Note: + +
    • +
      + +

      Esito Committente

      + + +
    • +
    • + Identificativo SdI: + +
    • + +
    • +

      Riferimento Fattura

      +
        +
      • + Numero Fattura: + +
      • +
      • + Anno Fattura: + +
      • + +
      • + Posizione Fattura: + +
      • +
        +
      +
    • + +
      + +
    • + Esito: + + + + + + (Accettazione) + (Rifiuto) + +
    • + + +
    • + Descrizione: + +
    • +
      + + +
    • + Message Id Committente: + +
    • +
      +
    +
    +
    +
    + +
    + + +
    +
    diff --git a/plugins/xml/NS_v1.0.xsl b/plugins/xml/NS_v1.0.xsl new file mode 100644 index 000000000..09caacd5d --- /dev/null +++ b/plugins/xml/NS_v1.0.xsl @@ -0,0 +1,148 @@ + + + + + + + + + + + + + + + + +
    +
    +
    + +
    + + File con firma elettronica - + + Versione +
    +

    Notifica Scarto

    + +
      +
    • + Identificativo SdI: + +
    • + +
    • + Nome File: + +
    • + +
    • + Data Ora Ricezione: + +
    • + + + +
    • +

      Riferimento Archivio

      +
        +
      • + Identificativo SdI: + +
      • +
      • + Nome File: + +
      • +
      +
    • +
      + + + +
    • + Message Id: + +
    • +
      + + +
    • + Pec Message Id: + +
    • +
      + + +
    • + Note: + +
    • +
      + +
    • + + + + + + + + + + + + +
      Lista errori
      CodiceDescrizione
      +
    • +
    +
    +
    +
    + +
    + + +
    +
    diff --git a/plugins/xml/RC_v1.0.xsl b/plugins/xml/RC_v1.0.xsl new file mode 100644 index 000000000..ea8831df7 --- /dev/null +++ b/plugins/xml/RC_v1.0.xsl @@ -0,0 +1,144 @@ + + + + + + + + + + + + + + + + +
    +
    +
    + +
    + + File con firma elettronica - + + Versione +
    + + + + + Flusso semplificato + +
    +

    Ricevuta Consegna

    + +
      +
    • + Identificativo SdI: + +
    • + +
    • + Nome File: + +
    • + +
    • + Data Ora Ricezione: + +
    • + +
    • + Data Ora Consegna: + +
    • + +
    • + Destinatario: + +
    • + + +
    • +

      Riferimento Archivio:

      +
        +
      • + Identificativo SdI: + +
      • +
      • + Nome File: + +
      • +
      +
    • +
      + +
    • + Message Id: + +
    • + +
    • + Pec Message-ID: + +
    • +
      + + +
    • + Note: + +
    • +
      +
    +
    +
    +
    + +
    + + +
    +
    diff --git a/plugins/xml/SE_v1.0.xsl b/plugins/xml/SE_v1.0.xsl new file mode 100644 index 000000000..a1a627253 --- /dev/null +++ b/plugins/xml/SE_v1.0.xsl @@ -0,0 +1,144 @@ + + + + + + + + + + + + + + + +
    +
    +
    + +
    + + File con firma elettronica - + + Versione +
    + +

    Scarto Esito committente

    + +
      +
    • + Identificativo SdI: + +
    • + + +
    • +

      Riferimento Fattura

      +
        +
      • + Numero Fattura: + +
      • +
      • + Anno Fattura: + +
      • + +
      • + Posizione Fattura: + +
      • +
        +
      +
    • +
      + +
    • + Scarto: + + + + + + (NOTIFICA NON CONFORME AL FORMATO) + (NOTIFICA NON AMMISSIBILE) + +
    • + +
    • + Message Id: + +
    • + + +
    • + Message-ID committente: + +
    • +
      + + +
    • + Pec Message-ID: + +
    • +
      + + +
    • + Note: + +
    • +
      +
    + +
    +
    +
    + +
    + + +
    +
    diff --git a/plugins/xml/asso-invoice.xsl b/plugins/xml/asso-invoice.xsl new file mode 100644 index 000000000..e396e3e60 --- /dev/null +++ b/plugins/xml/asso-invoice.xsl @@ -0,0 +1,2858 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - + + + + + + + + + + + + + + + + % + + + + + + + + + + + + + + + + + + + - + + + + + + + + + + + + + + + + % + + + + + + + + + + + + + + + + + + + + + + + + + + del + + + + + + CUP: + + + + CIG: + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + DDT + + + del + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    + +
    + + + + + + () + +
    +
    +
    + + + + + + + () + + + +
    + Periodo + + da + + + + + + a + + + + +
    + +
    + + + + + + + +
    + Tipo dato: + + + (dati relativi a lotti e scadenze) + + +
    + + +
    + + + + Lotto: + + + Rif. testo: + + + +
    +
    + + + + +
    + + + + Scadenza: + + + Rif. data: + + + + + + + +
    +
    + + +
    + + + + Quantità del suddetto lotto: + + + Rif. numero: + + + +
    +
    + + + +
    + +
    + + +
    + RIF.AMM. +
    +
    + +
    + + + + + + + + + + + + + + + + + + + + + +
    + + + + + + + + +
    +
    + +
    + + + + + + + + + + + + + +
    + +
    +
    + + + +
    + +
    +
    +
    +
    + + ------------------------ + + + + +
    + + + +
    + +
    + +
    +
    + + + + + +
    + +
    + +
    +
    + + + + + +
    + + + + + + + + + + + + + + + + + + + + + +
    Dati ritenuta d'accontoAliquota ritenutaCausale Importo
    + + + + + + + + + + + + (ritenuta persone fisiche) + + + (ritenuta persone giuridiche) + + + + + (!!! codice non previsto !!!) + + + + + + + + + + + + + + + + + + + + (decodifica come da modello 770S) + + + + + + + + + +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    + + + + + + + + + + + + + + + +
    + + + + + + + +
    + + +
    + + + + + + + + + + +
    + + + Identificativo fiscale ai fini IVA: + + + + + + +
    + +
    + + + + Codice fiscale: + + + + + + +
    + +
    + + + + Denominazione: + + + + + + +
    + +
    + + + + Cognome nome: + + + + + + + + + + + + + + + +
    + + +
    + + + + Regime fiscale: + + + + + + + + + + (ordinario) + + + (contribuenti minimi) + + + (nuove iniziative produttive) + + + (agricoltura e attività connesse e pesca) + + + (vendita sali e tabacchi) + + + (commercio fiammiferi) + + + (editoria) + + + (gestione servizi telefonia pubblica) + + + (rivendita documenti di trasporto pubblico e di sosta) + + + (intrattenimenti, giochi e altre attività di cui alla tariffa allegata al DPR 640/72) + + + (agenzie viaggi e turismo) + + + (agriturismo) + + + (vendite a domicilio) + + + (rivendita beni usati, oggetti d’arte, + d’antiquariato o da collezione) + + + (agenzie di vendite all’asta di oggetti d’arte, + antiquariato o da collezione) + + + (IVA per cassa P.A.) + + + (IVA per cassa - art. 32-bis, D.L. 83/2012) + + + (Regime forfettario) + + + (altro) + + + + + (!!! codice non previsto !!!) + + + + + +
    + +
    + + + +
    + + + + Indirizzo: + + + + + + + + +
    + +
    + + + + Comune: + + + + + + + + + Provincia: + + + + + + + + + +
    +
    + + + + Cap: + + + + + + + + + Nazione: + + + + + + + + +
    +
    +
    + + + + Telefono: + + + + + + + + +
    + +
    + + + + Email: + + + + + + + + + +
    + +
    + + + + Riferimento Amministrazione: + + + + + + + + + +
    + +
    + + +
    + + + Identificativo fiscale ai fini IVA: + + + + + + +
    + +
    + + + + Codice fiscale: + + + + + + +
    + + +
    + + Denominazione: + + + +
    +
    + + +
    + + Cognome nome: + + + + + + + + + + + + +
    +
    + +
    + + + + Regime fiscale: + + + + + + + + + + (ordinario) + + + (contribuenti minimi) + + + (nuove iniziative produttive) + + + (agricoltura e attività connesse e pesca) + + + (vendita sali e tabacchi) + + + (commercio fiammiferi) + + + (editoria) + + + (gestione servizi telefonia pubblica) + + + (rivendita documenti di trasporto pubblico e di sosta) + + + (intrattenimenti, giochi e altre attività di cui alla tariffa allegata al DPR 640/72) + + + (agenzie viaggi e turismo) + + + (agriturismo) + + + (vendite a domicilio) + + + (rivendita beni usati, oggetti d’arte, + d’antiquariato o da collezione) + + + (agenzie di vendite all’asta di oggetti d’arte, + antiquariato o da collezione) + + + (IVA per cassa P.A.) + + + (IVA per cassa - art. 32-bis, D.L. 83/2012) + + + (Regime forfettario) + + + (altro) + + + + + (!!! codice non previsto !!!) + + + + + +
    + + + +
    + + + + Indirizzo: + + + + + + + + +
    + +
    + + + + Comune: + + + + + + + + + Provincia: + + + + + + + + + +
    +
    + + + + Cap: + + + + + + + + + Nazione: + + + + + + + + +
    +
    +
    +
    + +
    +
    + + + +
    + + + +
    + + + + + + +
    + + +
    + + + + + + + +
    + + + Identificativo fiscale ai fini IVA: + + + + + + +
    + +
    + + + + Codice fiscale: + + + + + + +
    + +
    + + + + Denominazione: + + + + + + +
    + +
    + + + + Cognome nome: + + + + + + + + + + + + + + + +
    + + +
    + + + +
    + + + + Indirizzo: + + + + + + + + +
    + + + +
    + + + + Comune: + + + + + + + + + Provincia: + + + + + + + + + +
    +
    + + + + Cap: + + + + + + + + + Nazione: + + + + + + + + +
    +
    + + + + Pec: + + + + + +
    + + +
    +
    + + + +
    + + + Identificativo fiscale ai fini IVA: + + + + + + +
    + +
    + + + + Codice fiscale: + + + + + + +
    +
    + +
    + + + + Denominazione: + + + + + + +
    + +
    + + + + Cognome nome: + + + + + + + + + + + + + + + +
    + + + +
    + + + + Indirizzo: + + + + + + + + +
    + + + +
    + + + + Comune: + + + + + + + + + Provincia: + + + + + + + + + +
    +
    + + + + Cap: + + + + + + + + + Nazione: + + + + + + + + +
    +
    + + + + Pec: + + + + + +
    + + +
    + +
    +
    +
    +
    + +
    + + + + + +
    + + + + +
    + + +
    +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    Tipologia documentoArt. 73Numero documentoData documentoCodice destinatario
    + + + + + + + + + + + (fattura) + + + (acconto/anticipo su fattura) + + + (acconto/anticipo su parcella) + + + (nota di credito) + + + (nota di debito) + + + (parcella) + + + (autofattura) + + + + (fattura semplificata) + + + (nota di credito semplificata) + + + (nota di debito semplificata) + + + + + (!!! codice non previsto !!!) + + + + + + + + + + + + + + + + + + + + + + + + + Indicata PEC + + + + + + + + +
    + + +
    + + + + + + + + + + + + + + + + + +
    Causale
    + + + + + + + +
    +
    + +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    DescrizioneImposta%IVAPrezzo totale
    + + + + + + +
    + RIF.NORM. +
    +
    + +
    + + + + + + + + + + + + + + + +
    + +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + DDT + + + del + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    Cod. articoloDescrizioneQuantitàPrezzo unitarioUMSconto o magg.%IVAPrezzo totale
    + + + +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    Dati Cassa PrevidenzialeImponibile%Contr.Ritenuta%IVAImporto
    + + + + + + + + + + + (Cassa Nazionale Previdenza e Assistenza Avvocati + e Procuratori legali) + + + (Cassa Previdenza Dottori Commercialisti) + + + (Cassa Previdenza e Assistenza Geometri) + + + (Cassa Nazionale Previdenza e Assistenza + Ingegneri e Architetti liberi profess.) + + + (Cassa Nazionale del Notariato) + + + (Cassa Nazionale Previdenza e Assistenza + Ragionieri e Periti commerciali) + + + (Ente Nazionale Assistenza Agenti e Rappresentanti + di Commercio-ENASARCO) + + + (Ente Nazionale Previdenza e Assistenza Consulenti + del Lavoro-ENPACL) + + + (Ente Nazionale Previdenza e Assistenza + Medici-ENPAM) + + + (Ente Nazionale Previdenza e Assistenza + Farmacisti-ENPAF) + + + (Ente Nazionale Previdenza e Assistenza + Veterinari-ENPAV) + + + (Ente Nazionale Previdenza e Assistenza Impiegati + dell'Agricoltura-ENPAIA) + + + (Fondo Previdenza Impiegati Imprese di Spedizione + e Agenzie Marittime) + + + (Istituto Nazionale Previdenza Giornalisti + Italiani-INPGI) + + + (Opera Nazionale Assistenza Orfani Sanitari + Italiani-ONAOSI) + + + (Cassa Autonoma Assistenza Integrativa + Giornalisti Italiani-CASAGIT) + + + (Ente Previdenza Periti Industriali e Periti + Industriali Laureati-EPPI) + + + (Ente Previdenza e Assistenza + Pluricategoriale-EPAP) + + + (Ente Nazionale Previdenza e Assistenza + Biologi-ENPAB) + + + (Ente Nazionale Previdenza e Assistenza + Professione Infermieristica-ENPAPI) + + + (Ente Nazionale Previdenza e Assistenza + Psicologi-ENPAP) + + + (INPS) + + + + + (!!! codice non previsto !!!) + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    + + +
    + + + +
    + + + + + + + + +
    RIEPILOGHI IVA E TOTALI
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    esigibilità iva / riferimenti normativi%IVASpese accessorieTotale imponibileTotale imposta
    + + + + + + + + + + + + (esigibilità immediata) + + + (esigibilità differita) + + + (scissione dei pagamenti) + + + (!!! codice non previsto !!!) + + + + + + + Esigib. non dich. (si presume immediata) + + + + + +
    + +
    +
    +
    + + + + + + + + + + + + + + + + + + + + + + + + 0 + + + + + + + + + +
    + Importo bollo + + Sconto/Maggiorazione + + Valuta + + Totale documento +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    + + + + + +
    + +
    + + + +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    Modalità pagamentoIBANIstitutoData scadenzaImporto
    + + + + + + + + + + + Contanti + + + Assegno + + + Assegno circolare + + + Contanti presso Tesoreria + + + Bonifico + + + Vaglia cambiario + + + Bollettino bancario + + + Carta di pagamento + + + RID + + + RID utenze + + + RID veloce + + + RIBA + + + MAV + + + Quietanza erario + + + Giroconto su conti di contabilità speciale + + + Domiciliazione bancaria + + + Domiciliazione postale + + + Bollettino di c/c postale + + + SEPA Direct Debit + + + SEPA Direct Debit CORE + + + SEPA Direct Debit B2B + + + Trattenuta su somme già riscosse + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    + + +
    + + +
    + * +
    + +
    + +
    +
    + +
    + +
    + + + + +
    Allegati:
    + +
      + +
    • +
      + + + + +
      +
    • + + +
      + +
    + +
    + + + + +
    + + + +
    + +
    + + + + + +
    + + +
    + + + +
    +
    + + + + + + + + +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    + + +
    + diff --git a/src/AJAX.php b/src/AJAX.php index 657383673..7a0684da5 100644 --- a/src/AJAX.php +++ b/src/AJAX.php @@ -23,10 +23,12 @@ class AJAX * @param string $resource * @param array $elements * @param mixed $search + * @param int $page + * @param int $length * * @return array */ - public static function select($resource, $elements = [], $search = null) + public static function select($resource, $elements = [], $search = null, $page = 0, $length = 100) { if (!isset($elements)) { $elements = []; @@ -39,13 +41,23 @@ class AJAX array_unshift($files, DOCROOT.'/ajax_select.php'); foreach ($files as $file) { - $results = self::getSelectResults($file, $resource, $elements, $search); + $results = self::getSelectResults($file, $resource, $elements, [ + 'offset' => $page * $length, + 'length' => $length, + ], $search); + if (isset($results)) { break; } } - return $results; + $total = $results['recordsFiltered'] ?: count($results); + $list = $results['results'] ? $results['results'] : $results; + + return [ + 'results' => $list, + 'recordsFiltered' => $total, + ]; } /** @@ -55,11 +67,12 @@ class AJAX * @param array $where * @param array $filter * @param array $search + * @param array $limit * @param array $custom * * @return array */ - public static function completeResults($query, $where, $filter = [], $search = [], $custom = []) + public static function selectResults($query, $where, $filter = [], $search = [], $limit = [], $custom = []) { if (str_contains($query, '|filter|')) { $query = str_replace('|filter|', !empty($filter) ? 'WHERE '.implode(' OR ', $filter) : '', $query); @@ -72,21 +85,25 @@ class AJAX } $query = str_replace('|where|', !empty($where) ? 'WHERE '.implode(' AND ', $where) : '', $query); + $query .= ' LIMIT '.$limit['offset'].', '.$limit['length']; - $database = database(); - $rs = $database->fetchArray($query); + $data = \Util\Query::executeAndCount($query); + $rows = $data['results']; $results = []; - foreach ($rs as $r) { + foreach ($rows as $row) { $result = []; foreach ($custom as $key => $value) { - $result[$key] = $r[$value]; + $result[$key] = $row[$value]; } $results[] = $result; } - return $results; + return [ + 'results' => $results, + 'recordsFiltered' => $data['count'], + ]; } /** @@ -149,7 +166,7 @@ class AJAX * * @return array */ - protected static function find($file, $permissions = true) + public static function find($file, $permissions = true) { $dirname = substr($file, 0, strrpos($file, '/') + 1); @@ -196,11 +213,12 @@ class AJAX * @param string $file * @param string $resource * @param array $elements + * @param array $limit * @param mixed $search * * @return array|null */ - protected static function getSelectResults($file, $resource, $elements = [], $search = null) + protected static function getSelectResults($file, $resource, $elements = [], $limit = [], $search = null) { $superselect = self::getSelectInfo(); @@ -219,7 +237,7 @@ class AJAX require $file; if (!isset($results) && !empty($query)) { - $results = self::completeResults($query, $where, $filter, $search_fields, $custom); + $results = self::selectResults($query, $where, $filter, $search_fields, $limit, $custom); } return isset($results) ? $results : null; diff --git a/src/API.php b/src/API.php index 677810402..791b95984 100644 --- a/src/API.php +++ b/src/API.php @@ -28,6 +28,10 @@ class API extends \Util\Singleton 'code' => 404, 'message' => 'Non trovato', ], + 'externalError' => [ + 'code' => 409, + 'message' => 'Errore in un servizio esterno', + ], 'serverError' => [ 'code' => 500, 'message' => 'Errore del server', @@ -226,25 +230,7 @@ class API extends \Util\Singleton if (!is_array(self::$resources)) { $resources = []; - // Ignore dei warning - $resource = ''; - - // File nativi - $files = glob(DOCROOT.'/modules/*/api/{retrieve,create,update,delete}.php', GLOB_BRACE); - - // File personalizzati - $custom_files = glob(DOCROOT.'/modules/*/custom/api/{retrieve,create,update,delete}.php', GLOB_BRACE); - - // Pulizia dei file nativi che sono stati personalizzati - foreach ($custom_files as $key => $value) { - $index = array_search(str_replace('custom/api/', 'api/', $value), $files); - if ($index !== false) { - unset($files[$index]); - } - } - - $operations = array_merge($files, $custom_files); - asort($operations); + $operations = AJAX::find('api/{retrieve,create,update,delete}.php', false); foreach ($operations as $operation) { // Individua la tipologia e il modulo delle operazioni diff --git a/src/App.php b/src/App.php index d46726576..f8e43ab08 100644 --- a/src/App.php +++ b/src/App.php @@ -201,15 +201,16 @@ class App /** * Restituisce il codice HTML per il form contenente il file indicato. * - * @param string $path + * @param string $file * @param array $result * @param array $options + * @param bool $disableForm * * @return string */ - public static function load($file, $result, $options) + public static function load($file, $result, $options, $disableForm = false) { - $form = self::internalLoad('form.php', $result, $options); + $form = $disableForm ? '|response|' : self::internalLoad('form.php', $result, $options); $response = self::internalLoad($file, $result, $options); @@ -221,7 +222,7 @@ class App /** * Restituisce il codice HTML generato del file indicato. * - * @param string $path + * @param string $file * @param array $result * @param array $options * @param string $directory @@ -232,6 +233,8 @@ class App { $module = Modules::getCurrent(); + $database = $dbo = database(); + $id_module = $module['id']; $id_record = filter('id_record'); diff --git a/src/Backup.php b/src/Backup.php index 2e2dc8346..f9d2f4f6f 100644 --- a/src/Backup.php +++ b/src/Backup.php @@ -80,7 +80,7 @@ class Backup /** * Effettua il backup giornaliero. * - * @return null|bool + * @return bool|null */ public static function daily() { @@ -173,6 +173,7 @@ class Backup $dump = new Mysqldump('mysql:host='.$config['db_host'].';dbname='.$config['db_name'], $config['db_username'], $config['db_password'], [ 'add-drop-table' => true, + 'add-locks' => false, ]); $dump->start($file); diff --git a/src/Database.php b/src/Database.php index 655d45173..66e912733 100644 --- a/src/Database.php +++ b/src/Database.php @@ -442,7 +442,7 @@ class Database extends Util\Singleton // Valori da ottenere $select = []; foreach ((array) $array as $key => $value) { - $select[] = $value.(is_numeric($key) ? '' : ' AS '.$this->quote($key)); + $select[] = $value.(is_numeric($key) ? '' : ' AS '.$key); } $select = !empty($select) ? $select : ['*']; @@ -651,20 +651,4 @@ class Database extends Util\Singleton return true; } - - /** - * Prepara il campo per l'inserimento in uno statement SQL. - * - * @since 2.3 - * - * @param string $value - * - * @return string - */ - protected function quote($string) - { - $char = '`'; - - return $char.str_replace([$char, '#'], '', $string).$char; - } } diff --git a/src/Extensions/MessageHandler.php b/src/Extensions/MessageHandler.php index 0ca6ccebd..19df93336 100644 --- a/src/Extensions/MessageHandler.php +++ b/src/Extensions/MessageHandler.php @@ -29,8 +29,13 @@ class MessageHandler extends AbstractProcessingHandler } } - flash()->error($message); + // Messaggio nella sessione + try { + flash()->error($message); + } catch (\Exception $e) { + } + // Messaggio visivo immediato echo '
    '.$message.' diff --git a/src/HTMLBuilder/Handler/SelectHandler.php b/src/HTMLBuilder/Handler/SelectHandler.php index feafa081b..66aba5d09 100644 --- a/src/HTMLBuilder/Handler/SelectHandler.php +++ b/src/HTMLBuilder/Handler/SelectHandler.php @@ -98,8 +98,8 @@ class SelectHandler implements HandlerInterface * Gestione dell'input di tipo "select" con richieste AJAX (nome della richiesta indicato tramite attributo "ajax-source"). * Esempio: {[ "type": "select", "label": "Select di test", "name": "test", "ajax-source": "test" ]}. * - * @param array $values - * @param array $extras + * @param string $op + * @param array $elements * * @return string */ @@ -111,10 +111,11 @@ class SelectHandler implements HandlerInterface include DOCROOT.'/ajax_select.php'; $text = ob_get_clean(); - $result = ''; + $html = ''; - $array = (array) json_decode($text, true); - foreach ($array as $element) { + $response = (array) json_decode($text, true); + $results = $response['results']; + foreach ($results as $element) { $element = (array) $element; if (isset($element['children'][0])) { $element = (array) $element['children'][0]; @@ -137,11 +138,11 @@ class SelectHandler implements HandlerInterface } } - $result .= ' + $html .= ' '; } - return $result; + return $html; } /** diff --git a/src/HTMLBuilder/Manager/FileManager.php b/src/HTMLBuilder/Manager/FileManager.php index 179897476..3cd4e7e08 100644 --- a/src/HTMLBuilder/Manager/FileManager.php +++ b/src/HTMLBuilder/Manager/FileManager.php @@ -30,9 +30,6 @@ class FileManager implements ManagerInterface // ID del form $attachment_id = 'attachments_'.$options['id_module'].'_'.$options['id_plugin']; - // Cartella delle anteprime - $directory = \Uploads::getDirectory($options['id_module'], $options['id_plugin']); - $dbo = database(); // Codice HTML @@ -84,7 +81,7 @@ class FileManager implements ManagerInterface $result .= ' - + '.$r['name'].' ('.$file->extension.')'.' diff --git a/src/HTMLBuilder/Manager/WidgetManager.php b/src/HTMLBuilder/Manager/WidgetManager.php index add04c418..97fe31e27 100644 --- a/src/HTMLBuilder/Manager/WidgetManager.php +++ b/src/HTMLBuilder/Manager/WidgetManager.php @@ -153,29 +153,45 @@ class WidgetManager implements ManagerInterface protected function custom($widget) { $result = ' - -
  • - -
    -
    '; - - // Codice specifico - include_once $widget['php_include']; + '; $result .= ' -
    '; - // Icona +
    + '; + if (!empty($widget['icon'])) { $result .= ' -
    - -
    '; + '; } $result .= ' -
    -
  • '; + + +
    + '; + + if (!empty($widget['php_include'])) { + $result_ob = ''; + + ob_start(); + + include DOCROOT.'/'.$widget['php_include']; + $result_ob = ob_get_contents(); + + ob_end_clean(); + + $result .= $result_ob; + } + + $result .= ' + +
    '; + + $result .= ' +
    '; return $result; } diff --git a/src/HTMLBuilder/Wrapper/HTMLWrapper.php b/src/HTMLBuilder/Wrapper/HTMLWrapper.php index 78759f7e0..8ad2227b6 100644 --- a/src/HTMLBuilder/Wrapper/HTMLWrapper.php +++ b/src/HTMLBuilder/Wrapper/HTMLWrapper.php @@ -132,14 +132,14 @@ class HTMLWrapper implements WrapperInterface if ($type == 'untprc') { $choices = [ - [ - 'id' => 'UNT', - 'descrizione' => tr('€'), - ], [ 'id' => 'PRC', 'descrizione' => '%', ], + [ + 'id' => 'UNT', + 'descrizione' => tr('€'), + ], ]; } elseif ($type == 'email') { $choices = [ diff --git a/src/Import.php b/src/Import.php index 760070cbd..857bc7ca1 100644 --- a/src/Import.php +++ b/src/Import.php @@ -104,11 +104,10 @@ class Import * * @param string|int $module * @param int $file_id - * @param array $options * * @return array */ - public static function getFile($module, $file_id, $options = []) + public static function getCSV($module, $file_id) { $import = self::get($module); @@ -119,7 +118,7 @@ class Import return []; } - $file = DOCROOT.'/files/'.Modules::get('Import')['directory'].'/'.$import['files'][$find]['filename']; + $file = Modules::get('Import')->upload_directory.'/'.$import['files'][$find]['filename']; // Impostazione automatica per i caratteri di fine riga if (!ini_get('auto_detect_line_endings')) { @@ -130,21 +129,6 @@ class Import $csv = League\Csv\Reader::createFromPath($file, 'r'); $csv->setDelimiter(';'); - // Ignora la prima riga - $offset = 0; - if (!empty($options['headers'])) { - ++$offset; - } - $rows = $csv->setOffset($offset); - - // Limite di righe - if (!empty($options['limit'])) { - $rows = $rows->setLimit($options['limit']); - } - - // Lettura - $rows = $rows->fetchAll(); - - return $rows; + return $csv; } } diff --git a/src/Traits/PathTrait.php b/src/Traits/PathTrait.php index cc09753b1..bf01244f7 100644 --- a/src/Traits/PathTrait.php +++ b/src/Traits/PathTrait.php @@ -11,7 +11,7 @@ trait PathTrait * * @return string */ - public function getPath() + public function getPathAttribute() { return $this->main_folder.'/'.$this->directory; } @@ -19,21 +19,25 @@ trait PathTrait /** * Restituisce il percorso completo per il file indicato della struttura. * - * @return string + * @param $file + * + * @return string|null */ public function filepath($file) { - return App::filepath($this->getPath().'|custom|', $file); + return App::filepath($this->path.'|custom|', $file); } /** * Restituisce l'URL completa per il file indicato della struttura. * - * @return string + * @param $file + * + * @return string|null */ public function fileurl($file) { - $filepath = App::filepath($this->getPath().'|custom|', $file); + $filepath = App::filepath($this->path.'|custom|', $file); $result = str_replace(DOCROOT, ROOTDIR, $filepath); $result = str_replace('\\', '/', $result); diff --git a/src/Util/Query.php b/src/Util/Query.php index 8d91148aa..3d1e1e2bc 100644 --- a/src/Util/Query.php +++ b/src/Util/Query.php @@ -147,7 +147,24 @@ class Query $search_query = '`color_title_'.$m[1].'`'; } - $search_filters[] = $search_query.' LIKE '.prepare('%'.$value.'%'); + // Gestione confronti + $real_value = trim(str_replace(['<', '>'], ['<', '>'], $value)); + $more = starts_with($real_value, '>=') || starts_with($real_value, '> =') || starts_with($real_value, '>'); + $minus = starts_with($real_value, '<=') || starts_with($real_value, '< =') || starts_with($real_value, '<'); + + if ($minus || $more) { + $sign = str_contains($real_value, '=') ? '=' : ''; + if ($more) { + $sign = '>'.$sign; + } else { + $sign = '<'.$sign; + } + + $value = trim(str_replace(['<', '=', '>'], '', $value)); + $search_filters[] = 'CAST('.$search_query.' AS UNSIGNED) '.$sign.' '.prepare($value); + } else { + $search_filters[] = $search_query.' LIKE '.prepare('%'.$value.'%'); + } } } @@ -174,13 +191,30 @@ class Query } // Paginazione - if (!empty($limit)) { + if (!empty($limit) && intval($limit['length']) > 0) { $query .= ' LIMIT '.$limit['start'].', '.$limit['length']; } return $query; } + public static function executeAndCount($query) + { + $database = database(); + + // Esecuzione della query + $query = self::str_replace_once('SELECT', 'SELECT SQL_CALC_FOUND_ROWS', $query); + $results = $database->fetchArray($query); + + // Conteggio dei record filtrati + $count = $database->fetchOne('SELECT FOUND_ROWS() AS count'); + + return [ + 'results' => $results, + 'count' => $count['count'], + ]; + } + /** * Restituisce le somme richieste dalla query prevista dalla struttura. * @@ -202,7 +236,7 @@ class Query $result_query = self::getQuery($structure, $search); - $query = str_replace_once('SELECT', 'SELECT '.implode(', ', $total['summable']).' FROM(SELECT ', $result_query).') AS `z`'; + $query = self::str_replace_once('SELECT', 'SELECT '.implode(', ', $total['summable']).' FROM(SELECT ', $result_query).') AS `z`'; $sums = database()->fetchOne($query); $results = []; @@ -217,6 +251,28 @@ class Query return $results; } + /** + * Sostituisce la prima occorenza di una determinata stringa. + * + * @param string $str_pattern + * @param string $str_replacement + * @param string $string + * + * @since 2.3 + * + * @return string + */ + protected static function str_replace_once($str_pattern, $str_replacement, $string) + { + if (strpos($string, $str_pattern) !== false) { + $occurrence = strpos($string, $str_pattern); + + return substr_replace($string, $str_replacement, strpos($string, $str_pattern), strlen($str_pattern)); + } + + return $string; + } + /** * Interpreta lo standard modulare per l'individuazione delle query di un modulo/plugin del progetto. * diff --git a/src/Validate.php b/src/Validate.php index 86584f7ad..8bb6163d6 100644 --- a/src/Validate.php +++ b/src/Validate.php @@ -11,7 +11,7 @@ use Respect\Validation\Validator as v; */ class Validate { - public static function vatCheck($partita_iva) + public static function vatCheckIT($partita_iva) { if ($partita_iva === '') { return true; @@ -58,7 +58,7 @@ class Validate } // Controllo sulla sintassi - if (!static::vatCheck($vat_number)) { + if (starts_with($vat_number, 'IT') && !static::vatCheckIT($vat_number)) { return false; } diff --git a/templates/base/settings.php b/templates/base/settings.php index 86ffeaba0..83117a135 100644 --- a/templates/base/settings.php +++ b/templates/base/settings.php @@ -12,7 +12,7 @@ $settings = [ ], 'header-height' => 35, 'footer-height' => 5, - 'header-font-size' => 11, + 'header-font-size' => 10, ]; return $settings; diff --git a/templates/contratti_cons/body.php b/templates/contratti_cons/body.php index 1243f2c64..a8214b841 100644 --- a/templates/contratti_cons/body.php +++ b/templates/contratti_cons/body.php @@ -59,7 +59,23 @@ $totale_ore_impiegate = 0; $sconto = []; $imponibile = []; -$interventi = $dbo->fetchArray('SELECT *, in_interventi.id, in_interventi.codice, (SELECT GROUP_CONCAT(DISTINCT ragione_sociale) FROM in_interventi_tecnici JOIN an_anagrafiche ON an_anagrafiche.idanagrafica = in_interventi_tecnici.idtecnico WHERE idintervento=in_interventi.id) AS tecnici, (SELECT MIN(orario_inizio) FROM in_interventi_tecnici WHERE idintervento=in_interventi.id) AS inizio, (SELECT SUM(ore) FROM in_interventi_tecnici WHERE idintervento=in_interventi.id) AS ore, (SELECT SUM(km) FROM in_interventi_tecnici WHERE idintervento=in_interventi.id) AS km FROM co_promemoria JOIN in_interventi ON co_promemoria.idintervento=in_interventi.id WHERE co_promemoria.idcontratto='.prepare($id_record).' ORDER BY inizio DESC'); +$interventi = $dbo->fetchArray('SELECT in_interventi.id, in_interventi.codice, + (SELECT GROUP_CONCAT(DISTINCT ragione_sociale) FROM in_interventi_tecnici JOIN an_anagrafiche ON an_anagrafiche.idanagrafica = in_interventi_tecnici.idtecnico WHERE idintervento=in_interventi.id) AS tecnici, + (SELECT MIN(orario_inizio) FROM in_interventi_tecnici WHERE idintervento=in_interventi.id) AS inizio, + (SELECT SUM(ore) FROM in_interventi_tecnici WHERE idintervento=in_interventi.id) AS ore, + (SELECT MIN(km) FROM in_interventi_tecnici WHERE idintervento=in_interventi.id) AS km + FROM co_promemoria + INNER JOIN in_interventi ON co_promemoria.idintervento=in_interventi.id + WHERE co_promemoria.idcontratto='.prepare($id_record).' +UNION + SELECT in_interventi.id, in_interventi.codice, + (SELECT GROUP_CONCAT(DISTINCT ragione_sociale) FROM in_interventi_tecnici JOIN an_anagrafiche ON an_anagrafiche.idanagrafica = in_interventi_tecnici.idtecnico WHERE idintervento=in_interventi.id) AS tecnici, + (SELECT MIN(orario_inizio) FROM in_interventi_tecnici WHERE idintervento=in_interventi.id) AS inizio, + (SELECT SUM(ore) FROM in_interventi_tecnici WHERE idintervento=in_interventi.id) AS ore, + (SELECT MIN(km) FROM in_interventi_tecnici WHERE idintervento=in_interventi.id) AS km + FROM in_interventi + WHERE id_contratto = '.prepare($id_record).' +ORDER BY id DESC'); if (!empty($interventi)) { // Interventi diff --git a/templates/fatture/footer.php b/templates/fatture/footer.php index 453aec9a1..74855d666 100644 --- a/templates/fatture/footer.php +++ b/templates/fatture/footer.php @@ -218,8 +218,10 @@ if (!empty($record['rivalsainps'])) { '; } +$fattura = \Modules\Fatture\Fattura::find($id_record); + // Ritenuta d'acconto ( + bollo, se no rivalsa inps) -if (!empty($record['ritenutaacconto']) or (!empty($record['spit_payment']))) { +if (!empty($record['ritenutaacconto']) || !empty($fattura->totale_ritenuta_contributi) || !empty($record['spit_payment'])) { $rs2 = $dbo->fetchArray('SELECT percentuale FROM co_ritenutaacconto WHERE id=(SELECT idritenutaacconto FROM co_righe_documenti WHERE iddocumento='.prepare($id_record).' AND idritenutaacconto!=0 LIMIT 0,1)'); $first_colspan = 3; @@ -232,11 +234,19 @@ if (!empty($record['ritenutaacconto']) or (!empty($record['spit_payment']))) { --$second_colspan; } + $contributi = (!empty($record['ritenutaacconto']) ? ' - ' : '').tr('contributi: _PRC_%', [ + '_PRC_' => Translator::numberToLocale($fattura->ritenutaContributi->percentuale, 0), + ]); + $acconto = tr('acconto: _PRC_%', [ + '_PRC_' => Translator::numberToLocale($rs2[0]['percentuale'], 0), + ]); + echo ' - '.tr("Ritenuta d'acconto _PRC_%", [ - '_PRC_' => Translator::numberToLocale($rs2[0]['percentuale'], 0), + '.tr('Ritenuta (_ACCONTO__CONTRIBUTI_)', [ + '_ACCONTO_' => $acconto, + '_CONTRIBUTI_' => empty($fattura->ritenutaContributi) ? null : $contributi, ], ['upper' => true]).' '; @@ -263,7 +273,7 @@ if (!empty($record['ritenutaacconto']) or (!empty($record['spit_payment']))) { - '.Translator::numberToLocale($record['ritenutaacconto']).' € + '.Translator::numberToLocale($record['ritenutaacconto'] + $fattura->totale_ritenuta_contributi).' € '; if (empty($record['rivalsainps']) && abs($record['bollo']) > 0) { @@ -277,7 +287,7 @@ if (!empty($record['ritenutaacconto']) or (!empty($record['spit_payment']))) { echo ' - '.Translator::numberToLocale($totale - $record['ritenutaacconto']).' € + '.Translator::numberToLocale($totale - $record['ritenutaacconto'] - $fattura->totale_ritenuta_contributi).' € '; } @@ -305,7 +315,7 @@ if (!empty($record['split_payment'])) { - '.Translator::numberToLocale($totale - $totale_iva - $record['ritenutaacconto']).' € + '.Translator::numberToLocale($totale - $totale_iva - $record['ritenutaacconto'] - $fattura->totale_ritenuta_contributi).' € '; } diff --git a/templates/preventivi/body.php b/templates/preventivi/body.php index 0936bf38b..b9af68a73 100644 --- a/templates/preventivi/body.php +++ b/templates/preventivi/body.php @@ -195,7 +195,7 @@ echo ' '; // TOTALE COSTI FINALI -if ($options['pricing']) { +if ($options['pricing'] and !isset($options['hide_total']) ) { // Totale imponibile echo ' diff --git a/templates/registro_iva/body.php b/templates/registro_iva/body.php new file mode 100644 index 000000000..966fed840 --- /dev/null +++ b/templates/registro_iva/body.php @@ -0,0 +1,133 @@ += '.prepare($date_start).' AND co_documenti.data <= '.prepare($date_end).' GROUP BY co_documenti.id, co_righe_documenti.idiva ORDER BY co_documenti.'.(($dir == 'entrata') ? 'data' : 'numero'); +$rs = $dbo->fetchArray($query); + +if ('entrata' == $dir) { + echo "".tr('Registro iva vendita dal _START_ al _END_ _ESERCIZIO_', [ + '_START_' => Translator::dateToLocale($date_start), + '_END_' => Translator::dateToLocale($date_end), + '_ESERCIZIO_' => (date('Y', strtotime($date_start)) == date('Y', strtotime($date_end)) ? '- Esercizio '.date('Y', strtotime($date_end)) : ''), + ], ['upper' => true]).'

    '; +} elseif ('uscita' == $dir) { + echo "".tr('Registro iva acquisto dal _START_ al _END_ _ESERCIZIO_', [ + '_START_' => Translator::dateToLocale($date_start), + '_END_' => Translator::dateToLocale($date_end), + '_ESERCIZIO_' => (date('Y', strtotime($date_start)) == date('Y', strtotime($date_end)) ? '- Esercizio '.date('Y', strtotime($date_end)) : ''), + ], ['upper' => true]).'

    '; +} + +echo " + + + + + + + + + + + + + + + + + "; + +for ($i = 0; $i < sizeof($rs); ++$i) { + echo ' '; + + if ($rs[$i]['numero'] == $rs[$i - 1]['numero']) { + echo ' '; + echo ' '; + echo ' '; + echo ' '; + echo ' '; + echo ' '; + } else { + echo ' '; + echo ' '; + echo ' '; + echo ' '; + echo ' '; + echo " '; + } + + echo " '; + echo " '; + echo " '; + echo " '; + echo ' '; + + $v_iva[$rs[$i]['desc_iva']] += $rs[$i]['iva']; + $v_totale[$rs[$i]['desc_iva']] += $rs[$i]['subtotale']; + + $totale_iva += $rs[$i]['iva']; + $totale_subtotale += $rs[$i]['subtotale']; +} + +echo ' +
    No prot.No doc.DataTipo".(($dir == 'entrata') ? 'Cliente' : 'Fornitore')."Tot doc.Imponibile%IvaImposta
    '.$rs[$i]['numero'].''.$rs[$i]['numero_esterno'].''.date('d/m/Y', strtotime($rs[$i]['data'])).''.$rs[$i]['codice_tipo_documento_fe'].''.$rs[$i]['codice_anagrafica'].' / '.tr($rs[$i]['ragione_sociale'], [], ['upper' => true]).'".Translator::numberToLocale(get_totale_fattura($rs[$i]['iddocumento'])).' €".Translator::numberToLocale($rs[$i]['subtotale']).' €".Translator::numberToLocale($rs[$i]['percentuale'], 0).'".$rs[$i]['desc_iva'].'".Translator::numberToLocale($rs[$i]['iva']).' €
    '; + +echo "

    RIEPILOGO IVA

    "; + +echo " + + + + + + + "; + +foreach ($v_iva as $desc_iva => $tot_iva) { + if ('' != $desc_iva) { + echo " + + \n"; + + echo " \n"; + + echo " + \n"; + } +} + +echo " + + + + '; + +echo ' +
    IvaImponibileImposta
    \n"; + echo $desc_iva."\n"; + echo " \n"; + echo Translator::numberToLocale($v_totale[$desc_iva])." €\n"; + echo " \n"; + echo Translator::numberToLocale($v_iva[$desc_iva])." €\n"; + echo "
    TOTALE".Translator::numberToLocale($totale_subtotale)." €".Translator::numberToLocale($totale_iva).' €
    '; diff --git a/templates/registro_iva/footer.php b/templates/registro_iva/footer.php new file mode 100644 index 000000000..730f47596 --- /dev/null +++ b/templates/registro_iva/footer.php @@ -0,0 +1,17 @@ + + + + '.tr('Stampato con OpenSTAManager il _DATA_', ['_DATA_' => date('d/m/Y')]).' + + + + '.tr('Pagina _PAGE_ di _TOTAL_', [ + '_PAGE_' => '{PAGENO}', + '_TOTAL_' => '{nb}', + ]).' + + +'; diff --git a/templates/registro_iva/header.php b/templates/registro_iva/header.php new file mode 100644 index 000000000..2a7ce287a --- /dev/null +++ b/templates/registro_iva/header.php @@ -0,0 +1,17 @@ + +
    +
    +

    $f_ragionesociale$

    +

    $f_indirizzo$ $f_citta_full$

    +

    '.(!empty($f_piva) ? tr('P.Iva').': ' : '').'$f_piva$

    +

    '.(!empty($f_codicefiscale) ? tr('C.F.').': ' : '').'$f_codicefiscale$

    +

    '.(!empty($f_capsoc) ? tr('Cap.Soc.').': ' : '').'$f_capsoc$

    +

    '.(!empty($f_telefono) ? tr('Tel').': ' : '').'$f_telefono$

    +
    +
    + Logo +
    +
    '; diff --git a/templates/registro_iva/logo_azienda.jpg b/templates/registro_iva/logo_azienda.jpg deleted file mode 100644 index 3fd391452..000000000 Binary files a/templates/registro_iva/logo_azienda.jpg and /dev/null differ diff --git a/templates/registro_iva/pdfgen.registro_iva.php b/templates/registro_iva/pdfgen.registro_iva.php deleted file mode 100644 index b6a681aa4..000000000 --- a/templates/registro_iva/pdfgen.registro_iva.php +++ /dev/null @@ -1,151 +0,0 @@ -= '.prepare($date_start).' AND co_documenti.data <= '.prepare($date_end).' GROUP BY co_documenti.id, co_righe_documenti.idiva ORDER BY co_documenti.data'; -$rs = $dbo->fetchArray($query); - -if ('entrata' == $dir) { - $body .= "".tr('Registro iva vendita dal _START_ al _END_', [ - '_START_' => Translator::dateToLocale($date_start), - '_END_' => Translator::dateToLocale($date_end), - ], ['upper' => true]).'

    '; -} elseif ('uscita' == $dir) { - $body .= "".tr('Registro iva acquisto dal _START_ al _END_', [ - '_START_' => Translator::dateToLocale($date_start), - '_END_' => Translator::dateToLocale($date_end), - ], ['upper' => true]).'

    '; -} - -$body .= " - - - - - - - - - - - - - - - "; - -for ($i = 0; $i < sizeof($rs); ++$i) { - $body .= ''; - - if ($rs[$i]['numero'] == $rs[$i - 1]['numero']) { - $body .= " "; - $body .= " "; - $body .= " "; - } else { - $body .= " '; - $body .= " '; - $body .= " '; - } - - $body .= "'; - - $body .= " '; - $body .= " '; - $body .= " '; - $body .= " '; - $body .= ''; - - $v_iva[$rs[$i]['desc_iva']] += $rs[$i]['iva']; - $v_totale[$rs[$i]['desc_iva']] += $rs[$i]['subtotale']; - - $totale_iva += $rs[$i]['iva']; - $totale_subtotale += $rs[$i]['subtotale']; -} - -$body .= ' -
    No prot.No doc.Data".(($dir == 'entrata') ? 'Cliente' : 'Fornitore')."CausaleAliquotaImponibileImposta
    ".$rs[$i]['numero'].'".$rs[$i]['numero_esterno'].'".date('d/m/Y', strtotime($rs[$i]['data'])).'".$rs[$i]['ragione_sociale'].'".(($dir == 'entrata') ? 'Fattura di vendita' : 'Fattura di acquisto').'".$rs[$i]['desc_iva'].'".Translator::numberToLocale($rs[$i]['subtotale']).' €".Translator::numberToLocale($rs[$i]['iva']).' €
    - '; - -$body .= "

    RIEPILOGO IVA

    "; - -$body .= " - - - - - - - - - "; - -foreach ($v_iva as $desc_iva => $tot_iva) { - if ('' != $desc_iva) { - $body .= "\n"; - - $body .= "\n"; - - $body .= "\n"; - } -} - -$body .= " - - - - '; - -$body .= ' -
    Cod. IVAImponibileImposta
    \n"; - $body .= $desc_iva."\n"; - $body .= "\n"; - $body .= Translator::numberToLocale($v_totale[$desc_iva])." €\n"; - $body .= "\n"; - $body .= Translator::numberToLocale($v_iva[$desc_iva])." €\n"; - $body .= "
    TOTALE".Translator::numberToLocale($totale_subtotale)." €".Translator::numberToLocale($totale_iva).' €
    - '; - -$orientation = 'L'; -$report_name = 'registro_iva.pdf'; diff --git a/templates/registro_iva/registroiva.html b/templates/registro_iva/registroiva.html deleted file mode 100644 index c311fc99a..000000000 --- a/templates/registro_iva/registroiva.html +++ /dev/null @@ -1,59 +0,0 @@ - - - - $body$ - diff --git a/templates/registro_iva/registroiva_body.html b/templates/registro_iva/registroiva_body.html deleted file mode 100644 index 3fb65d993..000000000 --- a/templates/registro_iva/registroiva_body.html +++ /dev/null @@ -1,25 +0,0 @@ - - -
    - - - - - -
    - - $f_ragionesociale$ -

    - $f_indirizzo$ - $f_citta$ - $f_piva$ - $f_codicefiscale$ - $f_capsoc$ - $f_telefono$ -

    -
    -
    - Logo -
    -
    -
    diff --git a/templates/registro_iva/settings.php b/templates/registro_iva/settings.php new file mode 100644 index 000000000..793edc9bf --- /dev/null +++ b/templates/registro_iva/settings.php @@ -0,0 +1,6 @@ + 'L', + 'font-size' => '11pt', +]; diff --git a/tests/_support/AcceptanceTester.php b/tests/_support/AcceptanceTester.php index 6394f98f7..5f4b5d122 100644 --- a/tests/_support/AcceptanceTester.php +++ b/tests/_support/AcceptanceTester.php @@ -1,6 +1,5 @@ loadSessionSnapshot('login')) { - return; - } - // Operazioni di login $t->amOnPage('/'); @@ -126,8 +121,6 @@ class AcceptanceTester extends \Codeception\Actor // Controlla il completamento del login $t->see($username, '.user-panel'); - $t->saveSessionSnapshot('login'); - // Rimozione barra di debug $t->executeJS('$(".phpdebugbar-close-btn").click()'); } diff --git a/tests/_support/FunctionalTester.php b/tests/_support/FunctionalTester.php index 4f8e39312..e3a9dd03c 100644 --- a/tests/_support/FunctionalTester.php +++ b/tests/_support/FunctionalTester.php @@ -1,6 +1,5 @@ getModule('\Helper\Select2Ajax'); + $t = $this->getAcceptanceModule(); - $select2->selectOptionForSelect2($selector, $option, $timeout); + $select2->openSelect2($selector); + $t->wait(1); + $select2->selectByPosition($selector, $option, $timeout); + $select2->closeSelect2($selector); } public function seePageHasElement($element) diff --git a/tests/_support/Helper/Common/RowHelper.php b/tests/_support/Helper/Common/RowHelper.php index 61557ca25..8aebb81c1 100644 --- a/tests/_support/Helper/Common/RowHelper.php +++ b/tests/_support/Helper/Common/RowHelper.php @@ -97,7 +97,7 @@ class RowHelper extends \Codeception\Module $t->see('588,45', $this->getFinalValue('Totale')); // Sconto globale in euro - $t->fillField('Sconto incondizionato', 100); + $t->fillField('#sconto_generico', 100); $t->select2ajax('#tipo_sconto_generico', 'UNT'); $t->clickAndWait('Salva'); @@ -108,7 +108,7 @@ class RowHelper extends \Codeception\Module $t->see('466,45', $this->getFinalValue('Totale')); // Sconto globale in percentuale - $t->fillField('Sconto incondizionato', 10); + $t->fillField('#sconto_generico', 10); $t->select2ajax('#tipo_sconto_generico', 'PRC'); $t->clickAndWait('Salva'); @@ -135,13 +135,12 @@ class RowHelper extends \Codeception\Module protected function fill(AcceptanceTester $t, $descrizione, $qta, $prezzo, $sconto = 0, $tipo_sconto = 'UNT', $id_iva = null, $id_rivalsa_inps = null, $id_ritenuta_acconto = null) { $t->fillField('#descrizione_riga', $descrizione); - $t->fillField('Q.tà', $qta); + $t->fillField('#qta', $qta); - $label = ($this->dir == 'uscita') ? 'Prezzo unitario' : 'Prezzo unitario di vendita'; - $t->fillField($label, $prezzo); + $t->fillField('#prezzo', $prezzo); if (!empty($sconto)) { - $t->fillField('Sconto unitario', $sconto); + $t->fillField('#sconto', $sconto); if (in_array($tipo_sconto, ['PRC', 'UNT'])) { $t->select2ajax('#tipo_sconto', $tipo_sconto); diff --git a/tests/_support/Helper/Select2Ajax.php b/tests/_support/Helper/Select2Ajax.php index 702ccf419..7d169fbb1 100644 --- a/tests/_support/Helper/Select2Ajax.php +++ b/tests/_support/Helper/Select2Ajax.php @@ -4,21 +4,56 @@ namespace Helper; +/** + * Select2 version 4.0 or greater helpers for the jQuery based replacement for select boxes (Ajax version). + * + * Installation: + * - Put this file in your 'tests/_support/Helper' directory + * - Add it in your 'tests/acceptance.suite.yml' file, like this: + * class_name: AcceptanceTester + * modules: + * enabled: + * - WebDriver: + * # ... + * - \Helper\Select2Ajax + * - Run ./vendor/bin/codecept build + * + * @see http://select2.github.io/select2 + * + * @author Thomas Zilio + * @license MIT + */ class Select2Ajax extends Select2 { /** * Selects an option in a select2 component. * - * $t->selectOptionForSelect2('#my_select2', 'Option value'); - * $t->selectOptionForSelect2('#my_select2', ['Option value 1', 'Option value 2']); - * $t->selectOptionForSelect2('#my_select2', ['text' => 'Option text']); - * $t->selectOptionForSelect2('#my_select2', ['id' => 'Option value', 'text' => 'Option text']); - * * @param $selector * @param $option * @param int $timeout seconds. Default to 1 */ - public function selectOptionForSelect2($selector, $option, $timeout = 5) + public function selectByTextOrId($selector, $option, $timeout = 5) + { + $code = ' + $(options).each(function () { + if($(this).text == "'.$option.'" || $(this).id == "'.$option.'") { + $("'.$selector.'").selectSetNew(this.id, this.text); + } + });'; + + $this->execute($selector, $timeout, $code); + } + + public function selectByPosition($selector, $position, $timeout = 5) + { + $code = ' + var result = options['.$position.']; + $("'.$selector.'").selectSetNew(result.id, result.text);'; + + $this->execute($selector, $timeout, $code); + } + + protected function execute($selector, $timeout, $code) { $t = $this->getAcceptanceModule(); $selector = $this->getSelect2Selector($selector); @@ -28,39 +63,26 @@ class Select2Ajax extends Select2 $option = (string) $option; } - if (is_string($option) || (is_array($option) && array_values($option) === $option)) { - $t->executeJS('jQuery("'.$selector.'").selectSetNew('.json_encode($option).', "ID: " + '.json_encode($option).');', [$timeout]); - } elseif (is_array($option)) { - $optionId = 'null'; - if (isset($option['text']) && empty($option['id'])) { - $optionText = $option['text']; - $optionId = <<executeJS($script, [$timeout]); - } else { - $t->fail(); + $results_selector = str_replace('#', '', $selector); + + $script = << ({key,value})); + + if(output[0]) { + options.push(output[0].value.data); } + }) + + $code +}); +EOT; + + $t->executeJS($script, [$timeout]); } } diff --git a/tests/_support/UnitTester.php b/tests/_support/UnitTester.php index cf33c1cc4..5d79d95e5 100644 --- a/tests/_support/UnitTester.php +++ b/tests/_support/UnitTester.php @@ -1,6 +1,5 @@ $value) { + $files[$key] = realpath(DOCROOT.'/'.$value); +} + +delete($files); diff --git a/update/2_4_7.sql b/update/2_4_7.sql new file mode 100644 index 000000000..f926da880 --- /dev/null +++ b/update/2_4_7.sql @@ -0,0 +1,35 @@ +UPDATE `in_interventi` SET `id_contratto` = (SELECT `idcontratto` FROM `co_promemoria` WHERE `idintervento` = `in_interventi`.`id`); + +ALTER TABLE `co_righe_contratti` ADD `qta_evasa` DECIMAL(12, 4) NOT NULL; +ALTER TABLE `co_righe_preventivi` ADD `qta_evasa` DECIMAL(12, 4) NOT NULL; + +-- Inserisco due nuovi stati preventivi +UPDATE `co_statipreventivi` SET `descrizione` = 'Fatturato', `completato` = 1, `annullato` = 0, `icona` = 'fa fa-file-text-o text-success' WHERE `descrizione` = 'In attesa di pagamento'; +INSERT INTO `co_statipreventivi` (`id`, `descrizione`, `completato`, `annullato`, `icona`) VALUES +(NULL, 'Parzialmente fatturato', 0, 0, 'fa fa-file-text-o text-warning'); + +ALTER TABLE `co_statipreventivi` ADD `fatturabile` BOOLEAN NOT NULL DEFAULT FALSE; +UPDATE `co_statipreventivi` SET `fatturabile` = 1 WHERE `descrizione` IN('Parzialmente fatturato', 'Concluso', 'Pagato', 'In lavorazione', 'Accettato', 'In attesa di conferma'); + +-- Inserisco due nuovi stati contratti +UPDATE `co_staticontratti` SET `descrizione` = 'Fatturato', `pianificabile` = 0, `fatturabile` = 0, `icona` = 'fa fa-file-text-o text-success' WHERE `descrizione` = 'In attesa di pagamento'; +INSERT INTO `co_staticontratti` (`id`, `descrizione`, `pianificabile`, `fatturabile`, `icona`) VALUES +(NULL, 'Parzialmente fatturato', 0, 1, 'fa fa-file-text-o text-warning'); + +UPDATE `zz_widgets` SET `query` = REPLACE(`query`, 'In attesa di pagamento', 'Fatturato'); + +-- Fix ritenuta contributi +ALTER TABLE `co_documenti` CHANGE `id_ritenuta_contributi` `id_ritenuta_contributi` INT(11); +UPDATE `co_documenti` SET `id_ritenuta_contributi` = NULL WHERE `id_ritenuta_contributi` = 0; +ALTER TABLE `co_documenti` ADD FOREIGN KEY (`id_ritenuta_contributi`) REFERENCES `co_ritenuta_contributi`(`id`) ON DELETE SET NULL; +ALTER TABLE `co_righe_documenti` ADD `ritenuta_contributi` BOOLEAN NOT NULL DEFAULT FALSE; + +INSERT INTO `zz_settings` (`id`, `nome`, `valore`, `tipo`, `editable`, `sezione`, `order`) VALUES (NULL, 'Ritenuta contributi', '', 'query=SELECT * FROM co_ritenuta_contributi', 1, 'Fatturazione', 12); + +-- Fix ricerca documentali +UPDATE `zz_modules` SET `options` = '{ "main_query": [ { "type": "table", "fields": "Descrizione", "query": "SELECT zz_documenti_categorie.`descrizione`as Descrizione, zz_documenti_categorie.`id`as id FROM zz_documenti_categorie WHERE deleted_at IS NULL AND 1=1 HAVING 2=2"} ]}' WHERE `name` = 'Categorie documenti'; +UPDATE `zz_modules` SET `options` = '{ "main_query": [ { "type": "table", "fields": "Categoria, Nome, Data", "query": "SELECT id,(SELECT descrizione FROM zz_documenti_categorie WHERE zz_documenti_categorie.id = idcategoria) AS Categoria, zz_documenti.nome AS Nome, DATE_FORMAT( zz_documenti.`data`, ''%d/%m/%Y'' ) AS `Data` FROM zz_documenti WHERE `data` >= ''|period_start|'' AND `data` <= ''|period_end|'' AND 1=1 HAVING 2=2"} ]}' WHERE `name` = 'Gestione documentale'; + +-- Sollecito di pagamento +INSERT INTO `zz_emails` (`id`, `id_module`, `id_smtp`, `name`, `icon`, `subject`, `reply_to`, `cc`, `bcc`, `body`, `read_notify`, `predefined`) VALUES +(NULL, (SELECT `id` FROM `zz_modules` WHERE `name` = 'Scadenzario'), 1, 'Sollecito di pagamento', 'fa fa-envelope', 'Sollecito di pagamento fattura {numero}', '', '', '', '

    Spett.le {ragione_sociale},

    \r\n\r\n

    da un riscontro contabile, ci risulta che la fattura numero {numero} a Voi intestata, equivalente ad un ammontare di Euro {totale}, è scaduta in data {data_scadenza}.

    \r\n\r\n

    La sollecitiamo pertanto di provvedere quanto prima a regolarizzare la sua situazione contabile. A tal proposito, il pagamento potrà essere effettuato tramite {pagamento}.

    \r\n\r\n

    Se ha già provveduto al pagamento, ritenga nulla la presente.

    \r\n\r\n

     

    \r\n\r\n

    La ringraziamo e le porgiamo i nostri saluti.

    \r\n', '0', '1'); diff --git a/update/2_4_8.sql b/update/2_4_8.sql new file mode 100644 index 000000000..5d80990a2 --- /dev/null +++ b/update/2_4_8.sql @@ -0,0 +1,15 @@ +-- Fix problema username vuoti in zz_logs +ALTER TABLE `zz_logs` CHANGE `username` `username` varchar(255); + +-- Aggiunta tipologia di documento Parcella +INSERT INTO `co_tipidocumento` (`id`, `descrizione`, `dir`, `reversed`, `codice_tipo_documento_fe`) VALUES (NULL, 'Parcella', 'entrata', '0', 'TD06'); +INSERT INTO `co_tipidocumento` (`id`, `descrizione`, `dir`, `reversed`, `codice_tipo_documento_fe`) VALUES (NULL, 'Parcella', 'uscita', '0', 'TD06'); + +-- Aggiunto codice cig e codice cup per contratti e interventi +ALTER TABLE `co_contratti` ADD `num_item` VARCHAR(15) AFTER `id_documento_fe`; +ALTER TABLE `in_interventi` ADD `num_item` VARCHAR(15) AFTER `id_documento_fe`; +ALTER TABLE `or_ordini` ADD `num_item` VARCHAR(15) AFTER `id_documento_fe`; +ALTER TABLE `co_preventivi` ADD `num_item` VARCHAR(15) AFTER `id_documento_fe`; + +-- Aggiunta data scadenza attività +ALTER TABLE `in_interventi` ADD `data_scadenza` DATETIME AFTER `data_invio`; diff --git a/update/2_4_9.sql b/update/2_4_9.sql new file mode 100644 index 000000000..af014a0fc --- /dev/null +++ b/update/2_4_9.sql @@ -0,0 +1,20 @@ +-- Escluso Art.74 ter D.P.R. 633/72 +INSERT INTO `co_iva` (`descrizione`, `percentuale`, `indetraibile`, `esente`, `codice_natura_fe`, `codice`, `default`) VALUES +("Escluso Art.74 ter D.P.R. 633/72", 0, 0, 1, "N4", NULL, 1); + +-- Aggiungo vista "Conto" per Fatture di acquisto (opzionale) +INSERT INTO `zz_views` (`id`, `id_module`, `name`, `query`, `order`, `search`, `slow`, `format`, `search_inside`, `order_by`, `visible`, `summable`, `default`) VALUES +(NULL, (SELECT id FROM zz_modules WHERE `name` = 'Fatture di acquisto') , 'Conto', '(SELECT GROUP_CONCAT(DISTINCT(co_pianodeiconti3.descrizione)) FROM co_righe_documenti INNER JOIN co_pianodeiconti3 ON co_pianodeiconti3.id = co_righe_documenti.idconto WHERE co_righe_documenti.iddocumento = co_documenti.id)', 10, 1, 0, 0, '', '', 0, 0, 1); + +-- Stato FE (Notifica esito) +INSERT INTO `fe_stati_documento` (`codice`, `descrizione`, `icon`) VALUES ('NE', 'Notifica esito', 'fa fa-check text-success'); + +-- Aggiunta data ricezione, utile per le fatture di acquisto +ALTER TABLE `co_documenti` ADD `data_ricezione` DATE NULL AFTER `data`; + +-- Importo marca da bollo a 2 (https://www.fiscoetasse.com/approfondimenti/12090-applicazione-della-marca-da-bollo-sulle-fatture.html) +UPDATE `zz_settings` SET `valore` = '2' WHERE `zz_settings`.`nome` = 'Importo marca da bollo'; + +-- Stampa preventivo (senza totali) +INSERT INTO `zz_prints` (`id`, `id_module`, `is_record`, `name`, `title`, `directory`, `previous`, `options`, `icon`, `version`, `compatibility`, `order`, `predefined`, `default`, `enabled`) VALUES +(NULL, (SELECT id FROM zz_modules WHERE name='Preventivi'), 1, 'Preventivo (senza totali)', 'Preventivo (senza totali)', 'preventivi', 'idpreventivo', '{"pricing":true, "hide_total":true}', 'fa fa-print', '', '', 0, 0, 1, 1); diff --git a/update/tables.php b/update/tables.php index 4ecdc3731..a71618eca 100644 --- a/update/tables.php +++ b/update/tables.php @@ -32,7 +32,7 @@ return [ 'co_righe_documenti', 'co_righe_preventivi', 'co_ritenutaacconto', - 'co_ritenuta_contributi', + 'co_ritenuta_contributi', 'co_rivalse', 'co_scadenziario', 'co_staticontratti', diff --git a/view.php b/view.php index eff3f1cec..9c064cdbd 100644 --- a/view.php +++ b/view.php @@ -15,18 +15,42 @@ $link = ROOTDIR.'/'.$file->filepath; if ($file->isFatturaElettronica()) { $content = file_get_contents(DOCROOT.'/'.$file->filepath); + // Individuazione stylesheet + $default_stylesheet = 'asso-invoice'; + + $name = basename($file->original); + $filename = explode('.', $name)[0]; + $pieces = explode('_', $filename); + $codice = $pieces[2]; + if (!empty($codice)) { + $stylesheet = $codice.'_v1.0'; + } + + $stylesheet = DOCROOT.'/plugins/xml/'.$stylesheet.'.xsl'; + $stylesheet = file_exists($stylesheet) ? $stylesheet : DOCROOT.'/plugins/xml/'.$default_stylesheet.'.xsl'; + + // Fix per ricevute con namespace errato + $content = str_replace('http://ivaservizi.agenziaentrate.gov.it/docs/xsd/fattura/messaggi/v1.0', 'http://www.fatturapa.gov.it/sdi/messaggi/v1.0', $content); + // XML $xml = new DOMDocument(); $xml->loadXML($content); // XSL $xsl = new DOMDocument(); - $xsl->load(DOCROOT.'/assets/src/xml/fe-stylesheet-1.2.1.xsl'); + $xsl->load($stylesheet); // XSLT $xslt = new XSLTProcessor(); $xslt->importStylesheet($xsl); + echo ' +'; + echo $xslt->transformToXML($xml); } else { echo '