diff --git a/CHANGELOG.md b/CHANGELOG.md index fc8556528..d9dd3a5af 100755 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,7 @@ Tutti i maggiori cambiamenti di questo progetto saranno documentati in questo fi Il formato utilizzato è basato sulle linee guida di [Keep a Changelog](http://keepachangelog.com/), e il progetto segue il [Semantic Versioning](http://semver.org/) per definire le versioni delle release. +- [2.4.26 (2021-09-24)](#2426-2021-09-24) - [2.4.25 (2021-08-25)](#2425-2021-08-25) - [2.4.24 (2021-07-28)](#2424-2021-07-28) - [2.4.23 (2021-05-18)](#2423-2021-05-18) @@ -36,15 +37,21 @@ Il formato utilizzato è basato sulle linee guida di [Keep a Changelog](http://k - [2.2 (2016-11-10)](#22-2016-11-10) - [2.1 (2015-04-02)](#21-2015-04-02) -## 2.4.26 (2021-00-00) +## 2.4.26 (2021-09-24) ### Aggiunto (Added) - Aggiunto modal in fase di **Stampa Bilancio** per visualizzare o meno l'elenco analitico dei clienti e fornitori - Aggiunta scelta del tipo documento in fase di creazione fattura da un altro documento + - Aggiunta possibilità di creare delle ricorrenze per gli **Interventi** in fase di aggiunta + - Aggiunta scelta del tipo documento in fase di creazione fattura da un azione di gruppo di un altro documento + - Aggiunta sistema di gestione Combinazioni Articoli ### Modificato (Changed) - + - Modificata query per generare liste in **Newsletter** ### Fixed - Fix orario della modifica del listino di riferimento dell'articolo + - Fix movimentazione articoli tra due sedi tramite **DDT** + - Fix duplicazione **Pagamenti** + ## 2.4.25 (2021-08-25) ### Aggiunto (Added) diff --git a/assets/src/js/functions/input.js b/assets/src/js/functions/input.js index a45a555f4..201b886bd 100644 --- a/assets/src/js/functions/input.js +++ b/assets/src/js/functions/input.js @@ -293,6 +293,14 @@ Input.prototype.set = function (value) { CKEDITOR.instances[name].setData(value); } else { this.element.val(value).trigger("change"); + + // Impostazione valore per checkbox + let group = this.element.closest(".form-group"); + if (group.find("input[type=checkbox]").length) { + value = value === true || parseInt(value) !== 1; + group.find("[type=hidden]").val(+value).trigger('change') + group.find("[type=checkbox]").prop("checked", value); + } } return this; diff --git a/gulpfile.js b/gulpfile.js index e13758c78..57ea3f20c 100755 --- a/gulpfile.js +++ b/gulpfile.js @@ -399,6 +399,7 @@ function release(done) { '!include/custom/**', '!backup/**', '!files/**', + 'files/temp/.gitkeep', '!logs/**', '!config.inc.php', '!update/structure.php', diff --git a/include/init/update.php b/include/init/update.php index f0debc345..5e1ef168c 100755 --- a/include/init/update.php +++ b/include/init/update.php @@ -202,7 +202,7 @@ if (filter('action') == 'do_update') { foreach ($updates as $update) { if ($update['sql'] && (!empty($update['done']) || is_null($update['done']))) { - $queries = readSQLFile(base_dir().$update['directory'].$update['filename'].'.sql', ';'); + $queries = readSQLFile(base_dir().'/'.$update['directory'].$update['filename'].'.sql', ';'); $total += count($queries); if (intval($update['done']) > 1) { @@ -214,7 +214,7 @@ if (filter('action') == 'do_update') { $total += $scriptValue; } } - + echo ' '; diff --git a/modules/interventi/bulk.php b/modules/interventi/bulk.php index fc5d1cf41..e08bd06f1 100755 --- a/modules/interventi/bulk.php +++ b/modules/interventi/bulk.php @@ -33,7 +33,6 @@ if (!isset($_SESSION['module_'.$id_fatture]['id_segment'])) { $_SESSION['module_'.$id_fatture]['id_segment'] = isset($segments[0]['id']) ? $segments[0]['id'] : null; } $id_segment = $_SESSION['module_'.$id_fatture]['id_segment']; - $idtipodocumento = $dbo->selectOne('co_tipidocumento', ['id'], [ 'predefined' => 1, 'dir' => 'entrata', @@ -85,7 +84,6 @@ switch (post('op')) { $dir = 'entrata'; $tipo_documento = Tipo::where('id', post('idtipodocumento'))->first(); - $id_iva = setting('Iva predefinita'); $id_conto = setting('Conto predefinito fatture di vendita'); $accodare = post('accodare'); @@ -96,9 +94,11 @@ switch (post('op')) { // Lettura righe selezionate foreach ($interventi as $intervento) { $id_anagrafica = $intervento['idanagrafica']; - $id_documento = $id_documento_cliente[$id_anagrafica]; + $anagrafica = Anagrafica::find($id_anagrafica); + $id_iva = $anagrafica->idiva_vendite ?: setting('Iva predefinita'); + // Se non c'è già una fattura appena creata per questo cliente, creo una fattura nuova if (empty($id_documento)) { if (!empty($accodare)) { @@ -109,7 +109,6 @@ switch (post('op')) { } if (empty($id_documento)) { - $anagrafica = Anagrafica::find($id_anagrafica); $fattura = Fattura::build($anagrafica, $tipo_documento, $data, $id_segment); $id_documento = $fattura->id; diff --git a/modules/interventi/modutil.php b/modules/interventi/modutil.php index aa31df742..50d1759ac 100755 --- a/modules/interventi/modutil.php +++ b/modules/interventi/modutil.php @@ -143,10 +143,6 @@ function aggiungi_intervento_in_fattura($id_intervento, $id_fattura, $descrizion $fattura = Fattura::find($id_fattura); $intervento = Intervento::find($id_intervento); - if (!empty($fattura->anagrafica->idiva_vendite)) { - $id_iva = $fattura->anagrafica->idiva_vendite; - } - $data = $intervento->fine; $codice = $intervento->codice; diff --git a/modules/newsletter/actions.php b/modules/newsletter/actions.php index 5c085652e..f0d4ba719 100755 --- a/modules/newsletter/actions.php +++ b/modules/newsletter/actions.php @@ -24,7 +24,8 @@ use Modules\Emails\Mail; use Modules\Emails\Template; use Modules\ListeNewsletter\Lista; use Modules\Newsletter\Newsletter; -use Respect\Validation\Validator as v; +use Notifications\EmailNotification; +use PHPMailer\PHPMailer\Exception; include_once __DIR__.'/../../core.php'; @@ -61,42 +62,19 @@ switch (filter('op')) { break; case 'send': - $template = $newsletter->template; - $uploads = $newsletter->uploads()->pluck('id'); + $newsletter = Newsletter::find($id_record); $destinatari = $newsletter->destinatari(); $count = $destinatari->count(); for ($i = 0; $i < $count; ++$i) { $destinatario = $destinatari->skip($i)->first(); - $origine = $destinatario->getOrigine(); - - $anagrafica = $origine instanceof Anagrafica ? $origine : $origine->anagrafica; - - $abilita_newsletter = $anagrafica->enable_newsletter; - $email = $destinatario->email; - if (empty($email) || empty($abilita_newsletter) || !v::email()->validate($email)) { - continue; - } - - // Inizializzazione email - $mail = Mail::build($user, $template, $anagrafica->id); - - // Completamento informazioni - $mail->addReceiver($email); - $mail->subject = $newsletter->subject; - $mail->content = $newsletter->content; - $mail->id_newsletter = $newsletter->id; - - // Registrazione allegati - foreach ($uploads as $upload) { - $mail->addUpload($upload); - } - - $mail->save(); + $mail = $newsletter->inviaDestinatario($destinatario); // Aggiornamento riferimento per la newsletter - $destinatario->id_email = $mail->id; - $destinatario->save(); + if (!empty($mail)) { + $destinatario->id_email = $mail->id; + $destinatario->save(); + } } // Aggiornamento stato newsletter @@ -107,6 +85,38 @@ switch (filter('op')) { break; + case 'test': + $receiver_id = post('id'); + $receiver_type = post('type'); + + // Individuazione destinatario interessato + $newsletter = Newsletter::find($id_record); + $destinatario = $newsletter->destinatari() + ->where('record_type', '=', $receiver_type) + ->where('record_id', '=', $receiver_id) + ->first(); + + // Generazione email e tentativo di invio + $inviata = false; + if (!empty($destinatario)) { + $mail = $newsletter->inviaDestinatario($destinatario, true); + + try { + $email = EmailNotification::build($mail, true); + $email->send(); + + $inviata = true; + } catch (Exception $e) { + // $mail->delete(); + } + } + + echo json_encode([ + 'result' => $inviata, + ]); + + break; + case 'block': $mails = $newsletter->emails; diff --git a/modules/newsletter/ajax/table.php b/modules/newsletter/ajax/table.php index 34099113f..c4979b8eb 100644 --- a/modules/newsletter/ajax/table.php +++ b/modules/newsletter/ajax/table.php @@ -114,12 +114,15 @@ foreach ($destinatari_filtrati as $destinatario) { $riga = array_merge($riga, [ '
'. - (!empty($anagrafica->enable_newsletter) ? + (!empty($origine->enable_newsletter) ? ' '.tr('Abilitato').'' : ' '.tr('Disabilitato').'' ).'
', - '
+ '
'.(empty($lista) && !empty($origine->email) && !empty($origine->enable_newsletter) ? ' + + + ' : '').' diff --git a/modules/newsletter/edit.php b/modules/newsletter/edit.php index 9b1c63d7c..4c1e65b56 100755 --- a/modules/newsletter/edit.php +++ b/modules/newsletter/edit.php @@ -240,4 +240,47 @@ $(document).ready(function() { } }); }); + +function testInvio(button) { + const destinatario_id = $(button).data("id"); + const destinatario_type = $(button).data("type"); + const email = $(button).data("email"); + + swal({ + title: "'.tr('Invio di test?').'", + html: `'.tr("Vuoi effettuare un invio di test all'indirizzo _EMAIL_?", ['_EMAIL_' => '${email}']).' '.tr("L'email non sarà registrata come inviata, e l'invio della newsletter non escluderà questo indirizzo").'.`, + type: "warning", + showCancelButton: true, + confirmButtonText: "'.tr('Invia').'", + confirmButtonClass: "btn btn-lg btn-success", + }).then(function() { + const restore = buttonLoading(button); + $.ajax({ + url: globals.rootdir + "/actions.php", + type: "POST", + dataType: "JSON", + data: { + id_module: globals.id_module, + id_record: globals.id_record, + op: "test", + id: destinatario_id, + type: destinatario_type, + }, + success: function (response) { + buttonRestore(button, restore); + + if (response.result) { + swal("'.tr('Invio completato').'", "", "success"); + } else { + swal("'.tr('Invio fallito').'", "", "error"); + } + }, + error: function() { + buttonRestore(button, restore); + + swal("'.tr('Errore').'", "'.tr("Errore durante l'invio dell'email").'", "error"); + } + }); + }); +} '; diff --git a/modules/newsletter/src/Newsletter.php b/modules/newsletter/src/Newsletter.php index 335ffa4fa..74fe13040 100755 --- a/modules/newsletter/src/Newsletter.php +++ b/modules/newsletter/src/Newsletter.php @@ -29,6 +29,7 @@ use Modules\Anagrafiche\Sede; use Modules\Emails\Account; use Modules\Emails\Mail; use Modules\Emails\Template; +use Respect\Validation\Validator as v; use Traits\RecordTrait; class Newsletter extends Model @@ -132,6 +133,45 @@ class Newsletter extends Model ->where('record_type', '=', $tipo); } + /** + * Metodo per inviare l'email della newsletter a uno specifico destinatario. + * + * @return Mail|null + */ + public function inviaDestinatario(Destinatario $destinatario, $test = false) + { + $template = $this->template; + $uploads = $this->uploads()->pluck('id'); + + $origine = $destinatario->getOrigine(); + + $anagrafica = $origine instanceof Anagrafica ? $origine : $origine->anagrafica; + + $abilita_newsletter = $origine->enable_newsletter; + $email = $destinatario->email; + if (empty($email) || empty($abilita_newsletter) || !v::email()->validate($email)) { + return null; + } + + // Inizializzazione email + $mail = Mail::build(auth()->getUser(), $template, $anagrafica->id); + + // Completamento informazioni + $mail->addReceiver($email); + $mail->subject = ($test ? '[Test] ' : '').$this->subject; + $mail->content = $this->content; + $mail->id_newsletter = $this->id; + + // Registrazione allegati + foreach ($uploads as $upload) { + $mail->addUpload($upload); + } + + $mail->save(); + + return $mail; + } + // Relazione Eloquent public function destinatari() diff --git a/modules/ordini/bulk.php b/modules/ordini/bulk.php index be1b04583..45897cc5c 100644 --- a/modules/ordini/bulk.php +++ b/modules/ordini/bulk.php @@ -35,14 +35,17 @@ if (!isset($_SESSION['module_'.$id_fatture]['id_segment'])) { } $id_segment = $_SESSION['module_'.$id_fatture]['id_segment']; $idconto = setting('Conto predefinito fatture di vendita'); +$idtipodocumento = $dbo->selectOne('co_tipidocumento', ['id'], [ + 'predefined' => 1, + 'dir' => 'entrata', +])['id']; switch (post('op')) { case 'crea_fattura': $documenti = collect(); $numero_totale = 0; - $descrizione_tipo = 'Fattura immediata di vendita'; - $tipo_documento = Tipo::where('descrizione', $descrizione_tipo)->first(); + $tipo_documento = Tipo::where('id', post('idtipodocumento'))->first(); $stato_documenti_accodabili = Stato::where('descrizione', 'Bozza')->first(); $accodare = post('accodare'); @@ -145,7 +148,8 @@ if ($module['name'] == 'Ordini cliente') { 'data' => [ 'title' => tr('Fatturare i _TYPE_ selezionati?', ['_TYPE_' => strtolower($module['name'])]), 'msg' => '{[ "type": "checkbox", "label": "'.tr('Aggiungere alle _TYPE_ non ancora emesse?', ['_TYPE_' => strtolower($module_fatture)]).'", "placeholder": "'.tr('Aggiungere alle _TYPE_ nello stato bozza?', ['_TYPE_' => strtolower($module_fatture)]).'", "name": "accodare" ]} -
{[ "type": "select", "label": "'.tr('Sezionale').'", "name": "id_segment", "required": 1, "values": "query=SELECT id, name AS descrizione FROM zz_segments WHERE id_module=\''.$id_fatture.'\' AND is_fiscale = 1 ORDER BY name", "value": "'.$id_segment.'" ]}', +
{[ "type": "select", "label": "'.tr('Sezionale').'", "name": "id_segment", "required": 1, "values": "query=SELECT id, name AS descrizione FROM zz_segments WHERE id_module=\''.$id_fatture.'\' AND is_fiscale = 1 ORDER BY name", "value": "'.$id_segment.'" ]}
+ {[ "type": "select", "label": "'.tr('Tipo documento').'", "name": "idtipodocumento", "required": 1, "values": "query=SELECT id, CONCAT(codice_tipo_documento_fe, \' - \', descrizione) AS descrizione FROM co_tipidocumento WHERE enabled = 1 AND dir =\'entrata\' ORDER BY codice_tipo_documento_fe", "value": "'.$idtipodocumento.'" ]}', 'button' => tr('Procedi'), 'class' => 'btn btn-lg btn-warning', 'blank' => false, diff --git a/modules/preventivi/bulk.php b/modules/preventivi/bulk.php index 686c0e76f..b9b8e4ee3 100755 --- a/modules/preventivi/bulk.php +++ b/modules/preventivi/bulk.php @@ -34,6 +34,10 @@ if (!isset($_SESSION['module_'.$id_fatture]['id_segment'])) { $_SESSION['module_'.$id_fatture]['id_segment'] = isset($segments[0]['id']) ? $segments[0]['id'] : null; } $id_segment = $_SESSION['module_'.$id_fatture]['id_segment']; +$idtipodocumento = $dbo->selectOne('co_tipidocumento', ['id'], [ + 'predefined' => 1, + 'dir' => 'entrata', +])['id']; switch (post('op')) { case 'crea_fattura': @@ -41,8 +45,7 @@ switch (post('op')) { $numero_totale = 0; // Informazioni della fattura - $descrizione_tipo = 'Fattura immediata di vendita'; - $tipo_documento = Tipo::where('descrizione', $descrizione_tipo)->first(); + $tipo_documento = Tipo::where('id', post('idtipodocumento'))->first(); $stato_documenti_accodabili = Stato::where('descrizione', 'Bozza')->first(); $accodare = post('accodare'); @@ -123,7 +126,8 @@ $operations['crea_fattura'] = [ 'text' => ' '.tr('Fattura _TYPE_', ['_TYPE_' => strtolower($module['name'])]), 'data' => [ 'title' => tr('Fatturare i _TYPE_ selezionati?', ['_TYPE_' => strtolower($module['name'])]), - 'msg' => '{[ "type": "checkbox", "label": "'.tr('Aggiungere alle fatture di vendita non ancora emesse?').'", "placeholder": "'.tr('Aggiungere alle fatture di vendita nello stato bozza?').'", "name": "accodare" ]}
{[ "type": "select", "label": "'.tr('Sezionale').'", "name": "id_segment", "required": 1, "values": "query=SELECT id, name AS descrizione FROM zz_segments WHERE id_module=\''.$id_fatture.'\' AND is_fiscale = 1 ORDER BY name", "value": "'.$id_segment.'" ]}', + 'msg' => '{[ "type": "checkbox", "label": "'.tr('Aggiungere alle fatture di vendita non ancora emesse?').'", "placeholder": "'.tr('Aggiungere alle fatture di vendita nello stato bozza?').'", "name": "accodare" ]}
{[ "type": "select", "label": "'.tr('Sezionale').'", "name": "id_segment", "required": 1, "values": "query=SELECT id, name AS descrizione FROM zz_segments WHERE id_module=\''.$id_fatture.'\' AND is_fiscale = 1 ORDER BY name", "value": "'.$id_segment.'" ]}
+ {[ "type": "select", "label": "'.tr('Tipo documento').'", "name": "idtipodocumento", "required": 1, "values": "query=SELECT id, CONCAT(codice_tipo_documento_fe, \' - \', descrizione) AS descrizione FROM co_tipidocumento WHERE enabled = 1 AND dir =\'entrata\' ORDER BY codice_tipo_documento_fe", "value": "'.$idtipodocumento.'" ]}', 'button' => tr('Procedi'), 'class' => 'btn btn-lg btn-warning', 'blank' => false, diff --git a/modules/preventivi/src/Preventivo.php b/modules/preventivi/src/Preventivo.php index 2976cf77e..12f9b9a57 100755 --- a/modules/preventivi/src/Preventivo.php +++ b/modules/preventivi/src/Preventivo.php @@ -43,6 +43,18 @@ class Preventivo extends Document protected $table = 'co_preventivi'; + /** + * The attributes that should be mutated to dates. + * + * @var array + */ + protected $dates = [ + 'data_bozza', + 'data_conclusione', + 'data_accettazione', + 'data_rifiuto', + ]; + /** * Crea un nuovo preventivo. * diff --git a/modules/smtp/actions.php b/modules/smtp/actions.php index 49e6b7b4e..8fd8b05f1 100755 --- a/modules/smtp/actions.php +++ b/modules/smtp/actions.php @@ -17,6 +17,10 @@ * along with this program. If not, see . */ +use Models\Module; +use Models\OAuth2; +use Modules\Emails\Account; + include_once __DIR__.'/../../core.php'; switch (filter('op')) { @@ -34,6 +38,8 @@ switch (filter('op')) { break; case 'update': + $account = Account::find($id_record); + $predefined = post('predefined'); if (!empty($predefined)) { $dbo->query('UPDATE em_accounts SET predefined = 0'); @@ -55,26 +61,38 @@ switch (filter('op')) { 'timeout' => post('timeout'), 'ssl_no_verify' => post('ssl_no_verify'), 'predefined' => $predefined, - - // OAuth2 - 'provider' => post('provider'), - 'client_id' => post('client_id'), - 'client_secret' => post('client_secret'), - 'oauth2_config' => json_encode(post('config')), ], ['id' => $id_record]); flash()->info(tr('Informazioni salvate correttamente!')); // Rimozione informazioni OAuth2 in caso di disabilitazione if (!$abilita_oauth2) { - $dbo->update('em_accounts', [ - 'provider' => null, - 'client_id' => null, - 'client_secret' => null, - 'access_token' => null, - 'refresh_token' => null, - 'oauth2_config' => null, - ], ['id' => $id_record]); + $oauth2 = $account->oauth2; + if (!empty($oauth2)) { + $account->oauth2()->dissociate(); + $account->save(); + + $oauth2->delete(); + } + } + // Aggiornamento delle informazioni per OAuth2 + else { + $oauth2 = $account->oauth2 ?: OAuth2::build(); + + $oauth2->class = post('provider'); + $oauth2->client_id = post('client_id'); + $oauth2->client_secret = post('client_secret'); + $oauth2->config = post('config'); + + // Link di redirect dopo la configurazione + $modulo_account_email = Module::pool('Account email'); + $oauth2->after_configuration = base_path().'/editor.php?id_module='.$modulo_account_email->id.'&id_record='.$id_record; + + $oauth2->save(); + + // Associazione Account-OAuth2 + $account->oauth2()->associate($oauth2); + $account->save(); } // Validazione indirizzo email mittente @@ -119,7 +137,9 @@ switch (filter('op')) { break; case 'oauth2': - $redirect = base_path().'/oauth2.php?id_account='.$account->id; + $oauth2 = $account->oauth2; + + $redirect = base_path().'/oauth2.php?id='.$oauth2->id; redirect($redirect); break; diff --git a/modules/smtp/edit.php b/modules/smtp/edit.php index 1b4a032b8..7a17f7e1f 100755 --- a/modules/smtp/edit.php +++ b/modules/smtp/edit.php @@ -17,7 +17,7 @@ * along with this program. If not, see . */ -use Modules\Emails\OAuth2; +use Modules\Emails\Account; include_once __DIR__.'/../../core.php'; @@ -101,16 +101,18 @@ echo '
'; // Elenco provider disponibili -$providers = OAuth2::$providers; +$providers = Account::$providers; $elenco_provider = []; foreach ($providers as $key => $provider) { $elenco_provider[] = [ - 'id' => $key, + 'id' => $provider['class'], + 'short' => $key, 'text' => $provider['name'], 'help' => $provider['help'], ]; } +$oauth2 = $account->oauth2; echo '
@@ -122,32 +124,32 @@ echo '
- {[ "type": "select", "label": "'.tr('Provider account').'", "name": "provider", "value": "$provider$", "values": '.json_encode($elenco_provider).', "disabled": "'.intval(empty($account->provider)).'" ]} + {[ "type": "select", "label": "'.tr('Provider account').'", "name": "provider", "value": '.json_encode($oauth2->class).', "values": '.json_encode($elenco_provider).', "disabled": "'.intval(empty($oauth2)).'" ]}
- {[ "type": "checkbox", "label": "'.tr('Abilita OAuth2').'", "name": "abilita_oauth2", "value": "'.intval(!empty($account->provider)).'" ]} + {[ "type": "checkbox", "label": "'.tr('Abilita OAuth2').'", "name": "abilita_oauth2", "value": "'.intval(!empty($oauth2)).'" ]}
-
- - -
- {[ "type": "text", "label": "'.tr('Client ID').'", "name": "client_id", "value": "$client_id$", "disabled": "'.intval(empty($account->provider)).'" ]} -
- -
- {[ "type": "text", "label": "'.tr('Client Secret').'", "name": "client_secret", "value": "$client_secret$", "disabled": "'.intval(empty($account->provider)).'" ]} -
- -
+
+
+
+ {[ "type": "text", "label": "'.tr('Client ID').'", "name": "client_id", "value": "'.$oauth2->client_id.'", "disabled": "'.intval(empty($oauth2)).'" ]} +
+ +
+ {[ "type": "text", "label": "'.tr('Client Secret').'", "name": "client_secret", "value": "'.$oauth2->client_secret.'", "disabled": "'.intval(empty($oauth2)).'" ]} +
+ +
+
+
'.tr('Durante la procedura di configurazione verrà effettuato il logout dal gestionale').'.
@@ -163,7 +165,7 @@ foreach ($providers as $key => $provider) { $config = $provider['class']::getConfigInputs(); foreach ($config as $name => $field) { $field['name'] = 'config['.$name.']'; - $field['value'] = $account->oauth2_config[$name]; + $field['value'] = $oauth2 ? $oauth2->config[$name] : null; echo '
'.input($field).'
'; @@ -186,7 +188,7 @@ abilita_oauth2.change(function() { const disable = !abilita_oauth2.get(); provider.setDisabled(disable); - const inputs = $("#oauth2-config .openstamanager-input"); + const inputs = $(".oauth2-config .openstamanager-input"); for (i of inputs) { input(i).setDisabled(disable); } @@ -204,7 +206,7 @@ provider.change(function() { // Impostazione dei dati aggiuntivi da configurare config.html("") - aggiungiContenuto(config, "#provider-" + data.id); + aggiungiContenuto(config, "#provider-" + data.short); }) $(document).ready(function() { diff --git a/modules/stato_servizi/edit.php b/modules/stato_servizi/edit.php index 9b701ab21..63c59d60a 100755 --- a/modules/stato_servizi/edit.php +++ b/modules/stato_servizi/edit.php @@ -19,8 +19,6 @@ use API\Services; use Carbon\Carbon; -use Models\Cache; -use Modules\StatoServizi\ServicesHook; include_once __DIR__.'/../../core.php'; @@ -28,12 +26,6 @@ include_once __DIR__.'/../../core.php'; echo '
'; -/** - * Contenuto aggiornato e gestito dall'Hook ServicesHook. - * - * @var array - */ -$response = Cache::pool('Informazioni su Services')->content; $limite_scadenze = (new Carbon())->addDays(60); if (Services::isEnabled()) { echo ' @@ -48,7 +40,7 @@ if (Services::isEnabled()) {
'; - $servizi = collect($response['servizi'])->flatten(1); + $servizi = Services::getServiziAttivi()->flatten(1); if (!$servizi->isEmpty()) { echo ' @@ -99,8 +91,9 @@ if (Services::isEnabled()) {
'; // Elaborazione delle risorse API in scadenza - if (!empty($response['risorse-api'])) { - $risorse_in_scadenza = ServicesHook::getRisorseInScadenza($response['risorse-api'], $limite_scadenze); + $risorse_attive = Services::getRisorseAttive(); + if (!$risorse_attive->isEmpty()) { + $risorse_in_scadenza = Services::getRisorseInScadenza($limite_scadenze); if (!$risorse_in_scadenza->isEmpty()) { echo '

'.tr('Le seguenti risorse sono in scadenza:').'

@@ -115,11 +108,12 @@ if (Services::isEnabled()) {
'; foreach ($risorse_in_scadenza as $servizio) { - $scadenza = Carbon::parse($servizio['data_scadenza']); + $scadenza = Carbon::parse($servizio['expiration_at']); + echo ' - - + + '; } diff --git a/modules/stato_servizi/src/ServicesHook.php b/modules/stato_servizi/src/ServicesHook.php index fdfe85555..f90a4a63e 100644 --- a/modules/stato_servizi/src/ServicesHook.php +++ b/modules/stato_servizi/src/ServicesHook.php @@ -21,29 +21,15 @@ namespace Modules\StatoServizi; use API\Services; use Carbon\Carbon; -use Hooks\CachedManager; +use Hooks\Manager; -class ServicesHook extends CachedManager +class ServicesHook extends Manager { - public function getCacheName() - { - return 'Informazioni su Services'; - } - - public function cacheData() - { - $response = Services::request('GET', 'info'); - - return Services::responseBody($response); - } - public function response() { - $servizi = $this->getCache()->content; - $limite_scadenze = (new Carbon())->addDays(60); - // Elaborazione dei servizi in scadenza - $risorse_in_scadenza = self::getRisorseInScadenza($servizi['risorse-api'], $limite_scadenze); + $limite_scadenze = (new Carbon())->addDays(60); + $risorse_in_scadenza = Services::getRisorseInScadenza($limite_scadenze); $message = tr('I seguenti servizi sono in scadenza: _LIST_', [ '_LIST_' => implode(', ', $risorse_in_scadenza->pluck('nome')->all()), @@ -56,26 +42,13 @@ class ServicesHook extends CachedManager ]; } - /** - * Restituisce l'elenco delle risorse API in scadenza, causa data oppure crediti. - * - * @param $servizi - */ - public static function getRisorseInScadenza($risorse, $limite_scadenze) + public function execute() { - // Elaborazione dei servizi in scadenza - $risorse_in_scadenza = collect($risorse) - ->filter(function ($item) use ($limite_scadenze) { - return (isset($item['expiration_at']) && Carbon::parse($item['expiration_at'])->lessThan($limite_scadenze)) - || (isset($item['credits']) && $item['credits'] < 100); - }); + return false; + } - return $risorse_in_scadenza->transform(function ($item, $key) { - return [ - 'nome' => $item['name'], - 'data_scadenza' => $item['expiration_at'], - 'crediti' => $item['credits'], - ]; - }); + public function needsExecution() + { + return false; } } diff --git a/oauth2.php b/oauth2.php index 49c325c5a..0039bd1bd 100644 --- a/oauth2.php +++ b/oauth2.php @@ -1,8 +1,23 @@ . + */ -use Models\Module; -use Modules\Emails\Account; -use Modules\Emails\OAuth2; +use Models\OAuth2; $skip_permissions = true; include_once __DIR__.'/core.php'; @@ -12,12 +27,12 @@ session_write_close(); $state = $_GET['state']; $code = $_GET['code']; -// Account individuato via oauth2_state +// Account individuato via state if (!empty($state)) { - $account = Account::where('oauth2_state', '=', $state) + $account = OAuth2::where('state', '=', $state) ->first(); } else { - $account = Account::find(get('id_account')); + $account = OAuth2::find(get('id')); // Impostazione access token a null per reimpostare la configurazione $account->access_token = null; @@ -31,16 +46,12 @@ if (empty($account)) { return; } -// Inizializzazione -$oauth2 = new OAuth2($account); - // Redirect all'URL di autorizzazione del servizio esterno -$redirect = $oauth2->configure($code, $state); +$redirect = $account->configure($code, $state); // Redirect automatico al record if (empty($redirect)) { - $modulo_account_email = Module::pool('Account email'); - $redirect = base_path().'/editor.php?id_module='.$modulo_account_email->id.'&id_record='.$account->id; + $redirect = $account->after_configuration; } if (empty($_GET['error'])) { diff --git a/plugins/exportFE/src/Interaction.php b/plugins/exportFE/src/Interaction.php index 4adc6583f..84752c10b 100755 --- a/plugins/exportFE/src/Interaction.php +++ b/plugins/exportFE/src/Interaction.php @@ -30,6 +30,11 @@ use UnexpectedValueException; */ class Interaction extends Services { + public static function isEnabled() + { + return parent::isEnabled() && self::verificaRisorsaAttiva('Fatturazione Elettronica'); + } + public static function sendInvoice($id_record) { try { diff --git a/plugins/importFE/src/FatturaOrdinaria.php b/plugins/importFE/src/FatturaOrdinaria.php index 99e4dcd17..69fc51795 100755 --- a/plugins/importFE/src/FatturaOrdinaria.php +++ b/plugins/importFE/src/FatturaOrdinaria.php @@ -160,6 +160,9 @@ class FatturaOrdinaria extends FatturaElettronica } if (!empty($articolo)) { + $articolo->idconto_acquisto = $conto[$key]; + $articolo->save(); + $obj = Articolo::build($fattura, $articolo); $obj->movimentazione($movimentazione); diff --git a/plugins/importFE/src/Interaction.php b/plugins/importFE/src/Interaction.php index 90019cd28..6d6ee8109 100755 --- a/plugins/importFE/src/Interaction.php +++ b/plugins/importFE/src/Interaction.php @@ -29,6 +29,11 @@ use Models\Cache; */ class Interaction extends Services { + public static function isEnabled() + { + return parent::isEnabled() && self::verificaRisorsaAttiva('Fatturazione Elettronica'); + } + public static function getInvoiceList() { $list = self::getRemoteList(); diff --git a/plugins/receiptFE/src/Interaction.php b/plugins/receiptFE/src/Interaction.php index 35edd3a15..22a1a73af 100755 --- a/plugins/receiptFE/src/Interaction.php +++ b/plugins/receiptFE/src/Interaction.php @@ -29,6 +29,11 @@ use Models\Cache; */ class Interaction extends Services { + public static function isEnabled() + { + return parent::isEnabled() && self::verificaRisorsaAttiva('Fatturazione Elettronica'); + } + public static function getReceiptList() { $list = self::getRemoteList(); diff --git a/plugins/referenti/actions.php b/plugins/referenti/actions.php index dbeda2089..665a362f5 100755 --- a/plugins/referenti/actions.php +++ b/plugins/referenti/actions.php @@ -46,6 +46,8 @@ switch ($operazione) { break; case 'updatereferente': + $opt_out_newsletter = post('disable_newsletter'); + $dbo->update('an_referenti', [ 'idanagrafica' => $id_parent, 'nome' => post('nome'), @@ -53,6 +55,8 @@ switch ($operazione) { 'telefono' => post('telefono'), 'email' => post('email'), 'idsede' => post('idsede'), + + 'enable_newsletter' => empty($opt_out_newsletter), ], ['id' => $id_record]); flash()->info(tr('Salvataggio completato!')); diff --git a/plugins/referenti/add.php b/plugins/referenti/add.php index d2e9cf51f..15b7083f3 100755 --- a/plugins/referenti/add.php +++ b/plugins/referenti/add.php @@ -49,9 +49,13 @@ echo '
-
+
{[ "type": "select", "label": "'.tr('Sede').'", "name": "idsede", "values": "query=SELECT 0 AS id, \'Sede legale\' AS descrizione UNION SELECT id, CONCAT_WS(\' - \', nomesede, citta) AS descrizione FROM an_sedi WHERE idanagrafica='.$id_parent.'", "value": "0", "required": 1 ]}
+ +
+ {[ "type": "checkbox", "label": "'.tr('Opt-out per newsletter').'", "name": "disable_newsletter", "id": "disable_newsletter_m", "value": "0" ]} +
diff --git a/plugins/referenti/edit.php b/plugins/referenti/edit.php index 8b58fd5ae..ea04449a9 100755 --- a/plugins/referenti/edit.php +++ b/plugins/referenti/edit.php @@ -48,9 +48,13 @@ echo '
-
+
{[ "type": "select", "label": "'.tr('Sede').'", "name": "idsede", "values": "query=SELECT 0 AS id, \'Sede legale\' AS descrizione UNION SELECT id, CONCAT_WS(\' - \', nomesede, citta) AS descrizione FROM an_sedi WHERE idanagrafica='.$id_parent.'", "value" : "$idsede$", "required": 1 ]}
+ +
+ {[ "type": "checkbox", "label": "'.tr('Opt-out per newsletter').'", "name": "disable_newsletter", "id": "disable_newsletter_m", "value": "'.empty($record['enable_newsletter']).'" ]} +
diff --git a/plugins/sedi/actions.php b/plugins/sedi/actions.php index ff5f30723..08a8a7358 100755 --- a/plugins/sedi/actions.php +++ b/plugins/sedi/actions.php @@ -53,6 +53,8 @@ switch ($operazione) { break; case 'updatesede': + $opt_out_newsletter = post('disable_newsletter'); + $dbo->update('an_sedi', [ 'nomesede' => post('nomesede'), 'indirizzo' => post('indirizzo'), @@ -73,6 +75,8 @@ switch ($operazione) { 'gaddress' => post('gaddress'), 'lat' => post('lat'), 'lng' => post('lng'), + + 'enable_newsletter' => empty($opt_out_newsletter), ], ['id' => $id_record]); flash()->info(tr('Salvataggio completato!')); diff --git a/plugins/sedi/edit.php b/plugins/sedi/edit.php index 9c25607de..8b1e555f4 100755 --- a/plugins/sedi/edit.php +++ b/plugins/sedi/edit.php @@ -95,10 +95,15 @@ echo ' {[ "type": "text", "label": "'.tr('Indirizzo email').'", "name": "email", "value": "$email$" ]}
-
+
+ {[ "type": "checkbox", "label": "'.tr('Opt-out per newsletter').'", "name": "disable_newsletter", "id": "disable_newsletter_m", "value": "'.empty($record['enable_newsletter']).'" ]} +
+ +
{[ "type": "select", "label": "'.tr('Zona').'", "name": "idzona", "ajax-source": "zone", "value": "$idzona$", "placeholder": "'.tr('Nessuna zona').'", "icon-after": "add|'.Modules::get('Zone')['id'].'" ]}
+
{[ "type": "textarea", "label": "'.tr('Note').'", "name": "note", "value": "$note$" ]} diff --git a/src/API/App/v1/Interventi.php b/src/API/App/v1/Interventi.php index a6c6999ce..7204f5adb 100644 --- a/src/API/App/v1/Interventi.php +++ b/src/API/App/v1/Interventi.php @@ -216,6 +216,7 @@ class Interventi extends AppResource $record->richiesta = $data['richiesta']; $record->descrizione = $data['descrizione']; $record->informazioniaggiuntive = $data['informazioni_aggiuntive']; + $record->idsede_destinazione = $data['id_sede'] ?: 0; // Salvataggio firma eventuale if (empty($record->firma_nome) && !empty($data['firma_nome'])) { diff --git a/src/API/Services.php b/src/API/Services.php index b81cc3239..e5c7cdd01 100755 --- a/src/API/Services.php +++ b/src/API/Services.php @@ -19,7 +19,9 @@ namespace API; +use Carbon\Carbon; use GuzzleHttp\Client; +use Models\Cache; /** * Classe per l'interazione con API esterne. @@ -30,11 +32,98 @@ class Services { protected static $client = null; + /** + * Controlla se il gestionale ha accesso a Services. + * + * @return bool + */ public static function isEnabled() { return !empty(setting('OSMCloud Services API Token')); } + /** + * Restituisce le informazioni disponibili su Services. + * + * @return array + */ + public static function getInformazioni($force = false) + { + $cache = Cache::pool('Informazioni su Services'); + + // Aggiornamento dei contenuti della cache + if (!$cache->isValid() || $force) { + $response = self::request('GET', 'info'); + $content = self::responseBody($response); + + $cache->set($content); + + return $content; + } + + return $cache->content; + } + + /** + * Restituisce i servizi attivi attraverso Services. + * + * @return \Illuminate\Support\Collection + */ + public static function getServiziAttivi() + { + return collect(self::getInformazioni()['servizi']); + } + + /** + * Restituisce le risorse attive in Services. + * + * @return \Illuminate\Support\Collection + */ + public static function getRisorseAttive() + { + return collect(self::getInformazioni()['risorse-api']); + } + + /** + * Controlla se il gestionale ha accesso a una specifica risorsa di Services. + * + * @return bool + */ + public static function verificaRisorsaAttiva($servizio) + { + return self::isEnabled() && self::getRisorseAttive()->search(function ($item) use ($servizio) { + return $item['name'] == $servizio; + }) !== false; + } + + /** + * Restituisce le risorse in scadenza per assenza di crediti oppure per data di fine prossima. + * + * @param Carbon $limite_scadenze + * + * @return \Illuminate\Support\Collection + */ + public static function getRisorseInScadenza($limite_scadenze) + { + return self::getRisorseAttive() + ->filter(function ($item) use ($limite_scadenze) { + return (isset($item['expiration_at']) && Carbon::parse($item['expiration_at'])->lessThan($limite_scadenze)) + || (isset($item['credits']) && $item['credits'] < 100); + }); + } + + /** + * Effettua una richiesta a Services. + * + * @param $type + * @param $resource + * @param array $data + * @param array $options + * + * @throws \GuzzleHttp\Exception\GuzzleException + * + * @return \Psr\Http\Message\ResponseInterface + */ public static function request($type, $resource, $data = [], $options = []) { $client = static::getClient(); @@ -53,6 +142,13 @@ class Services return $client->request($type, '', $options); } + /** + * Restituisce il corpo JSON della risposta in array. + * + * @param $response + * + * @return array + */ public static function responseBody($response) { $body = $response->getBody(); diff --git a/src/Models/OAuth2.php b/src/Models/OAuth2.php new file mode 100644 index 000000000..f5affef56 --- /dev/null +++ b/src/Models/OAuth2.php @@ -0,0 +1,212 @@ +. + */ + +namespace Models; + +use Common\SimpleModelTrait; +use Illuminate\Database\Eloquent\Model; +use InvalidArgumentException; +use League\OAuth2\Client\Provider\AbstractProvider; +use League\OAuth2\Client\Provider\Exception\IdentityProviderException; +use League\OAuth2\Client\Token\AccessToken; + +class OAuth2 extends Model +{ + use SimpleModelTrait; + + protected $provider; + + protected $table = 'zz_oauth2'; + + protected $casts = [ + 'config' => 'array', + ]; + + /** + * @return AbstractProvider + */ + public function getProvider() + { + // Inizializza il provider per l'autenticazione OAuth2. + if (!isset($this->provider)) { + $config = $this->config ?? []; + $config = array_merge($config, [ + 'clientId' => $this->client_id, + 'clientSecret' => $this->client_secret, + 'redirectUri' => base_url().'/oauth2.php', + 'accessType' => 'offline', + ]); + + $class = $this->class; + if (!class_exists($class)) { + throw new InvalidArgumentException('Classe non esistente'); + } + + $this->provider = new $class($config); + } + + return $this->provider; + } + + public function needsConfiguration() + { + $access_token = $this->getAccessToken(); + + return empty($access_token); + } + + /** + * Gestisce le operazioni di configurazione per l'autenticazione OAuth2. + * Restituisce l'URL di redirect per le operazioni di aggiornamento dei dati, lancia un eccezione in caso di errori e restituisce null in caso di completamento della configurazione. + * + * Nota: l'autenticazione OAuth2 richiede una serie di richieste su una singola pagina + * - Richiesta di autenticazione al server remoto (code, state vuoti) + * - Conferma di autenticazione alla pagina di redirect (code, state impostati) + * - Richiesta del token di accesso dalla pagina di redirect al server remoto + * + * @param string|null $code + * @param string|null $state + * + * @throws IdentityProviderException + * @throws InvalidArgumentException + * + * @return string|null + */ + public function configure($code, $state) + { + if (!$this->needsConfiguration()) { + return null; + } + + $provider = $this->getProvider(); + $options = method_exists($provider, 'getOptions') ? $provider->getOptions() : []; + if (empty($code)) { + // Fetch the authorization URL from the provider; this returns the + // urlAuthorize option and generates and applies any necessary parameters + // (e.g. state). + $authorization_url = $provider->getAuthorizationUrl($options); + + // Get the state generated for you and store it to the session. + $this->state = $provider->getState(); + $this->save(); + + // Redirect the user to the authorization URL. + return $authorization_url; + } elseif (!empty($this->state) && $this->state !== $state) { + $this->state = null; + $this->save(); + + throw new InvalidArgumentException(); + } else { + $this->state = null; + $this->save(); + + // Try to get an access token using the authorization code grant + $access_token = $provider->getAccessToken('authorization_code', [ + 'code' => $code, + ]); + $refresh_token = $access_token->getRefreshToken(); + + $this->updateTokens($access_token, $refresh_token); + } + + return null; + } + + /** + * @return string|null + */ + public function getRefreshToken() + { + $this->checkTokens(); + + return $this->attributes['refresh_token']; + } + + /** + * Restituisce l'access token per l'autenticazione OAuth2. + * + * @return AccessToken|null + */ + public function getAccessToken() + { + $this->checkTokens(); + + return unserialize($this->attributes['access_token']); + } + + /** + * Effettua una richiesta utilizzando il token di accesso prestabilito. + * + * @param string $method + * @param string $url + * @param array $options + * + * @return array + */ + public function request($method, $url, $options = []) + { + $provider = $this->getProvider(); + $accessToken = $this->getAccessToken(); + + $request = $provider->getAuthenticatedRequest($method, $url, $accessToken, $options); + + return $provider->getParsedResponse($request); + } + + /** + * Imposta Access Token e Refresh Token per l'autenticazione OAuth2. + * + * @param AccessToken|null + */ + protected function updateTokens($access_token, $refresh_token) + { + $this->access_token = serialize($access_token); + + $previous_refresh_token = $this->refresh_token; + $this->refresh_token = $refresh_token ?: $previous_refresh_token; + + $this->save(); + } + + /** + * Controlla la validità dei token correnti e ne effettua il refresh se necessario. + */ + protected function checkTokens() + { + $access_token = unserialize($this->access_token); + + if (!empty($access_token) && $access_token->hasExpired()) { + // Tentativo di refresh del token di accesso + $refresh_token = $this->refresh_token; + if (!empty($refresh_token)) { + $access_token = $this->getProvider()->getAccessToken('refresh_token', [ + 'refresh_token' => $this->refresh_token, + ]); + + $refresh_token = $access_token->getRefreshToken(); + } else { + $access_token = null; + $refresh_token = null; + } + + $this->updateTokens($access_token, $refresh_token); + } + } +} diff --git a/src/Notifications/EmailNotification.php b/src/Notifications/EmailNotification.php index 831c7175b..bcfb07ff1 100755 --- a/src/Notifications/EmailNotification.php +++ b/src/Notifications/EmailNotification.php @@ -69,16 +69,15 @@ class EmailNotification extends PHPMailer implements NotificationInterface $this->Username = $account['username']; // Configurazione OAuth2 - if (!empty($account['access_token'])) { - $oauth2 = $account->getGestoreOAuth2(); - + $oauth2 = $account->oauth2; + if (!empty($oauth2)) { $this->AuthType = 'XOAUTH2'; $this->setOAuth( new OAuth([ 'provider' => $oauth2->getProvider(), 'refreshToken' => $oauth2->getRefreshToken(), - 'clientId' => $account->client_id, - 'clientSecret' => $account->client_secret, + 'clientId' => $oauth2->client_id, + 'clientSecret' => $oauth2->client_secret, 'userName' => $account->username, ]) ); diff --git a/src/Validate.php b/src/Validate.php index 8b0b718e6..f79a6ecf0 100755 --- a/src/Validate.php +++ b/src/Validate.php @@ -98,7 +98,7 @@ class Validate } */ // Controllo attraverso apilayer - if (Services::isEnabled()) { + if (Services::verificaRisorsaAttiva('Verifica Partita IVA')) { $response = Services::request('post', 'check_iva', [ 'partita_iva' => $vat_number, ]); @@ -151,7 +151,7 @@ class Validate } // Controllo attraverso apilayer - if (Services::isEnabled()) { + if (Services::verificaRisorsaAttiva('Verifica Email')) { $response = Services::request('post', 'check_email', [ 'email' => $email, ]); diff --git a/templates/bilancio/body.php b/templates/bilancio/body.php index 820ef8d74..f5aca9adb 100644 --- a/templates/bilancio/body.php +++ b/templates/bilancio/body.php @@ -134,7 +134,7 @@ echo '
- + '; } } diff --git a/templates/preventivi/body.php b/templates/preventivi/body.php index 45105f16d..8c9828726 100755 --- a/templates/preventivi/body.php +++ b/templates/preventivi/body.php @@ -18,19 +18,36 @@ */ use Carbon\CarbonInterval; +use Illuminate\Database\Eloquent\ModelNotFoundException; use Modules\Anagrafiche\Anagrafica; +use Modules\Banche\Banca; +use Modules\Pagamenti\Pagamento; include_once __DIR__.'/../../core.php'; $anagrafica = Anagrafica::find($documento['idanagrafica']); -$pagamento = $dbo->fetchOne('SELECT * FROM co_pagamenti WHERE id = '.prepare($documento['idpagamento'])); +$anagrafica_azienda = Anagrafica::find(setting('Azienda predefinita')); -// Verifico se c'è una banca predefinita per il mio cliente -if (!empty($anagrafica->idbanca_vendite)) { - $banca = $dbo->fetchOne('SELECT co_banche.nome, co_banche.iban, co_banche.bic FROM co_banche WHERE co_banche.id_pianodeiconti3 = '.prepare($pagamento['idconto_vendite']).' AND co_banche.id_anagrafica = '.prepare($anagrafica->id).' AND co_banche.id ='.prepare($anagrafica->idbanca_vendite)); -} elseif (!empty($pagamento['idconto_vendite'])) { - // Altrimenti prendo quella associata la metodo di pagamento selezionato - $banca = $dbo->fetchOne('SELECT co_banche.nome, co_banche.iban, co_banche.bic FROM co_banche WHERE co_banche.id_pianodeiconti3 = '.prepare($pagamento['idconto_vendite']).' AND co_banche.id_anagrafica = '.prepare($anagrafica->id).' AND co_banche.deleted_at IS NULL'); +$pagamento = Pagamento::find($documento['idpagamento']); + +// Banca dell'Azienda corrente impostata come predefinita per il Cliente +$banca_azienda = Banca::where('id_anagrafica', '=', $anagrafica_azienda->id) + ->where('id_pianodeiconti3', '=', $pagamento['idconto_vendite'] ?: 0); +try { + $banca = (clone $banca_azienda) + ->findOrFail($anagrafica->idbanca_vendite); +} catch (ModelNotFoundException $e) { + // Ricerca prima banca dell'Azienda con Conto corrispondente + $banca = (clone $banca_azienda) + ->orderBy('predefined', 'DESC') + ->first(); +} + +// Ri.Ba: Banca predefinita *del Cliente* piuttosto che dell'Azienda +if ($pagamento->isRiBa()) { + $banca = Banca::where('id_anagrafica', $anagrafica->id) + ->where('predefined', 1) + ->first(); } // Righe documento diff --git a/update/2_4_26.php b/update/2_4_26.php new file mode 100644 index 000000000..f5c08f0c7 --- /dev/null +++ b/update/2_4_26.php @@ -0,0 +1,12 @@ +id.'&id_record='; + +$database->query("INSERT INTO `zz_oauth2` (`id`, `class`, `client_id`, `client_secret`, `config`, `state`, `access_token`, `refresh_token`, `after_configuration`) SELECT `id`, 'Modules\\\\Emails\\\\OAuth2\\\\Microsoft', `client_id`, `client_secret`, `oauth2_config`, `oauth2_state`, `access_token`, `refresh_token`, CONCAT('".$redirect."', `id`) FROM `em_accounts` WHERE `provider` = 'microsoft' AND `client_id` IS NOT NULL"); + +$database->query("INSERT INTO `zz_oauth2` (`id`, `class`, `client_id`, `client_secret`, `config`, `state`, `access_token`, `refresh_token`, `after_configuration`) SELECT `id`, 'Modules\\\\Emails\\\\OAuth2\\\\Google', `client_id`, `client_secret`, `oauth2_config`, `oauth2_state`, `access_token`, `refresh_token`, CONCAT('".$redirect."', `id`) FROM `em_accounts` WHERE `provider` = 'google' AND `client_id` IS NOT NULL"); + +$database->query('UPDATE `em_accounts` SET `id_oauth2` = (SELECT `id` FROM `zz_oauth2` WHERE `zz_oauth2`.`id` = `em_accounts`.`id`)'); diff --git a/update/2_4_26.sql b/update/2_4_26.sql index fc4a4fa92..4c1945ccf 100644 --- a/update/2_4_26.sql +++ b/update/2_4_26.sql @@ -107,3 +107,27 @@ INSERT INTO `em_lists` (`id`, `name`, `description`, `query`, `deleted_at`) VALU -- Fix riferimento documento per righe create da Interventi UPDATE `co_righe_documenti` SET `original_document_id` = `idintervento`, `original_document_type` = 'Modules\\Interventi\\Intervento' WHERE `idintervento` IS NOT NULL; + +-- Generalizzazione della configurazione OAuth2 +CREATE TABLE IF NOT EXISTS `zz_oauth2` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + `class` varchar(255) DEFAULT NULL, + `client_id` text DEFAULT NULL, + `client_secret` text DEFAULT NULL, + `config` text DEFAULT NULL, + `state` text DEFAULT NULL, + `access_token` text DEFAULT NULL, + `refresh_token` text DEFAULT NULL, + `after_configuration` text DEFAULT NULL, + `created_at` timestamp NULL DEFAULT CURRENT_TIMESTAMP, + `updated_at` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, + PRIMARY KEY (`id`) +) ENGINE=InnoDB; + +ALTER TABLE `em_accounts` ADD `id_oauth2` INT(11) DEFAULT NULL, + ADD FOREIGN KEY (`id_oauth2`) REFERENCES `zz_oauth2`(`id`); + +-- Aggiunta opt-out Newsletter per Referenti e Sedi +ALTER TABLE `an_referenti` ADD `enable_newsletter` BOOLEAN DEFAULT TRUE; +ALTER TABLE `an_sedi` ADD `enable_newsletter` BOOLEAN DEFAULT TRUE; + diff --git a/update/tables.php b/update/tables.php index 76c355e97..c305d13de 100755 --- a/update/tables.php +++ b/update/tables.php @@ -99,6 +99,7 @@ return [ 'mg_valori_attributi', 'my_impianto_componenti', 'my_componenti', + 'zz_oauth2', 'or_ordini', 'or_righe_ordini', 'or_statiordine',
'.$servizio['nome'].''.$servizio['crediti'].''.$servizio['name'].''.$servizio['credits'].' '.dateFormat($scadenza).' ('.$scadenza->diffForHumans().')
'.$liv3_p['numero'].' '.$liv3_p['descrizione'].''.numberFormat(abs($liv3_p['totale'])).''.numberFormat(-$liv3_p['totale']).'