Aggiunto modulo Listini clienti e modifiche gestione prezzi

This commit is contained in:
MatteoPistorello 2022-11-15 17:38:42 +01:00
parent 56ae94374b
commit 6eea64f0ee
31 changed files with 1055 additions and 63 deletions

View File

@ -86,6 +86,7 @@
"Modules\\Iva\\": ["modules/iva/custom/src/", "modules/iva/src/"],
"Modules\\DDT\\": ["modules/ddt/custom/src/", "modules/ddt/src/"],
"Modules\\Fatture\\": ["modules/fatture/custom/src/", "modules/fatture/src/"],
"Modules\\ListiniCliente\\": ["modules/listini_cliente/custom/src/", "modules/listini_cliente/src/"],
"Modules\\Ordini\\": ["modules/ordini/custom/src/", "modules/ordini/src/"],
"Modules\\Preventivi\\": ["modules/preventivi/custom/src/", "modules/preventivi/src/"],
"Modules\\Contratti\\": ["modules/contratti/custom/src/", "modules/contratti/src/"],
@ -106,6 +107,7 @@
"Modules\\Importazione\\": ["modules/import/custom/src/", "modules/import/src/"],
"Modules\\Impostazioni\\": ["modules/impostazioni/custom/src/", "modules/impostazioni/src/"],
"Modules\\Partitario\\": ["modules/partitario/custom/src/", "modules/partitario/src/"],
"Modules\\StatoEmail\\": ["modules/stato_email/custom/src/", "modules/stato_email/src/"],
"Plugins\\ExportFE\\": ["plugins/exportFE/custom/src/", "plugins/exportFE/src/"],
"Plugins\\ImportFE\\": ["plugins/importFE/custom/src/", "plugins/importFE/src/"],
"Plugins\\ReceiptFE\\": ["plugins/receiptFE/custom/src/", "plugins/receiptFE/src/"],
@ -116,7 +118,6 @@
"Plugins\\ListinoClienti\\": ["plugins/listino_clienti/custom/src/", "plugins/listino_clienti/src/"],
"Plugins\\ListinoFornitori\\": ["plugins/listino_fornitori/custom/src/", "plugins/listino_fornitori/src/"],
"Plugins\\ComponentiImpianti\\": ["plugins/componenti/custom/src/", "plugins/componenti/src/"],
"Modules\\StatoEmail\\": ["modules/stato_email/custom/src/", "modules/stato_email/src/"],
"Plugins\\PresentazioniBancarie\\": ["plugins/presentazioni_bancarie/custom/src/", "plugins/presentazioni_bancarie/src/"]
},
"files": [

View File

@ -19,6 +19,7 @@
$result['idarticolo'] = isset($result['idarticolo']) ? $result['idarticolo'] : null;
$qta_minima = 0;
$id_listino = $dbo->selectOne('an_anagrafiche', 'id_listino', ['idanagrafica' => $options['idanagrafica']])['id_listino'];
// Articolo
if (empty($result['idarticolo'])) {
@ -60,6 +61,7 @@ if (empty($result['idarticolo'])) {
ottieniDettagliArticolo("'.$articolo['id'].'").then(function (){
verificaPrezzoArticolo();
verificaScontoArticolo();
verificaMinimoVendita();
});
});
</script>';
@ -124,7 +126,7 @@ $(document).ready(function () {
}
});
$("#tipo_sconto").on("change", function() {
input("tipo_sconto").on("change", function() {
verificaScontoArticolo();
});
@ -207,6 +209,7 @@ $("#idsede").on("change", function() {
$(document).on("change", "input[name^=qta], input[name^=prezzo_unitario], input[name^=sconto]", function() {
verificaPrezzoArticolo();
verificaScontoArticolo();
verificaMinimoVendita();
});
/**
@ -219,7 +222,7 @@ function getDettaglioPerQuantita(qta) {
let dettaglio_predefinito = null;
let dettaglio_selezionato = null;
for (const dettaglio of data) {
if (dettaglio.minimo == null && dettaglio.massimo == null) {
if (dettaglio.minimo == null && dettaglio.massimo == null && dettaglio.prezzo_unitario != null) {
dettaglio_predefinito = dettaglio;
continue;
}
@ -245,6 +248,78 @@ function getPrezzoPerQuantita(qta) {
return dettaglio ? parseFloat(dettaglio.prezzo_unitario) : 0;
}
/**
* Restituisce il prezzo del listino registrato per l\'articolo-anagrafica.
*/
function getPrezzoListino() {
const data = globals.aggiunta_articolo.dettagli;
if (!data) return null;
let dettaglio_listino = null;
for (const dettaglio of data) {
if (dettaglio.prezzo_unitario_listino != null) {
dettaglio_listino = dettaglio;
continue;
}
}
return dettaglio_listino ? parseFloat(dettaglio_listino.prezzo_unitario_listino) : 0;
}
/**
* Restituisce il prezzo della scheda articolo.
*/
function getPrezzoScheda() {
const data = globals.aggiunta_articolo.dettagli;
if (!data) return null;
let dettaglio_scheda = null;
for (const dettaglio of data) {
if (dettaglio.prezzo_scheda != null) {
dettaglio_scheda = dettaglio;
continue;
}
}
return dettaglio_scheda ? parseFloat(dettaglio_scheda.prezzo_scheda) : 0;
}
/**
* Restituisce l\'ultimo prezzo registrato dell\' articolo.
*/
function getPrezzoUltimo() {
const data = globals.aggiunta_articolo.dettagli;
if (!data) return null;
let dettaglio_ultimo = null;
for (const dettaglio of data) {
if (dettaglio.prezzo_ultimo != null) {
dettaglio_ultimo = dettaglio;
continue;
}
}
return dettaglio_ultimo ? parseFloat(dettaglio_ultimo.prezzo_ultimo) : 0;
}
/**
* Restituisce lo sconto registrato del listino registrato per l\'articolo-anagrafica.
*/
function getScontoListino() {
const data = globals.aggiunta_articolo.dettagli;
if (!data) return null;
let dettaglio_listino = null;
for (const dettaglio of data) {
if (dettaglio.sconto_percentuale_listino != null) {
dettaglio_listino = dettaglio;
continue;
}
}
return dettaglio_listino ? parseFloat(dettaglio_listino.sconto_percentuale_listino) : 0;
}
/**
* Restituisce lo sconto registrato per una specifica quantità dell\'articolo.
*/
@ -269,56 +344,130 @@ function ottieniDettagliArticolo(id_articolo) {
* Funzione per verificare se il prezzo unitario corrisponde a quello registrato per l\'articolo, e proporre in automatico una correzione.
*/
function verificaPrezzoArticolo() {
let qta = $("#qta").val().toEnglish();
let prezzo_previsto = getPrezzoPerQuantita(qta);
let prezzo_unitario_input = $("#prezzo_unitario");
let prezzo_unitario = prezzo_unitario_input.val().toEnglish();
let div = prezzo_unitario_input.closest("div").parent().find("div[id*=errors]");
let div = $(".prezzi");
if (prezzo_previsto === prezzo_unitario || prezzo_previsto === 0 ) {
div.css("padding-top", "0");
div.html("");
div.css("padding-top", "0");
div.html("");
return;
let qta = $("#qta").val().toEnglish();
let prezzo_anagrafica = getPrezzoPerQuantita(qta);
let prezzo_listino = getPrezzoListino();
let prezzo_std = getPrezzoScheda();
let prezzo_last = getPrezzoUltimo();
if (prezzo_anagrafica || prezzo_listino || prezzo_std || prezzo_last) {
div.html(`<table class="table table-extra-condensed table-prezzi" style="background:#eee; margin-top:-13px;"><tbody>`);
}
let table = $(".table-prezzi");
if (prezzo_anagrafica) {
table.append(`<tr><td class="pr_anagrafica"><small>'.($options['dir'] == 'uscita' ? tr('Prezzo listino') : tr('Netto cliente')).': '.Plugins::link(($options['dir'] == 'uscita' ? 'Listino Fornitori' : 'Netto Clienti'), $result['idarticolo'], tr('Visualizza'), null, '').'</small></td><td align="right" class="pr_anagrafica"><small>` + prezzo_anagrafica.toLocale() + ` ` + globals.currency + `</small></td>`);
let tr = $(".pr_anagrafica").parent();
if (prezzo_unitario == prezzo_anagrafica.toFixed(2)) {
tr.append(`<td><button type="button" class="btn btn-xs btn-info pull-right disabled" style="font-size:10px;"><i class="fa fa-check"></i> '.tr('Aggiorna').'</button></td>`);
} else{
tr.append(`<td><button type="button" class="btn btn-xs btn-info pull-right" onclick="aggiornaPrezzoArticolo(\'anagrafica\')" style="font-size:10px;"><i class="fa fa-refresh"></i> '.tr('Aggiorna').'</button></td>`);
}
table.append(`</tr>`);
}
div.css("padding-top", "5px");
div.html(`<small class="label label-info" id="listino" >'.tr('Prezzo').': ` + prezzo_previsto.toLocale() + " " + globals.currency + " " + `'.Plugins::link(($options['dir'] == 'uscita' ? 'Listino Fornitori' : 'Listino Clienti'), $options['idanagrafica'], null, null, '').'<button type="button" class="btn btn-xs btn-info pull-right" onclick="aggiornaPrezzoArticolo()"><i class="fa fa-refresh"></i> '.tr('Aggiorna').'</button></small>`);
edit_listino = $("#listino").find("a");
edit_listino.attr("href", edit_listino.attr("href").replace(/id_record=[0-9]*/, "id_record=" + $("#idarticolo").val()));
if (prezzo_listino) {
table.append(`<tr><td class="pr_listino"><small>'.tr('Prezzo listino').': '.Modules::link('Listini Cliente', $id_listino, tr('Visualizza'), null, '').'</small></td><td align="right" class="pr_listino"><small>` + prezzo_listino.toLocale() + ` ` + globals.currency + `</small></td>`);
let tr = $(".pr_listino").parent();
if (prezzo_unitario == prezzo_listino.toFixed(2)) {
tr.append(`<td><button type="button" class="btn btn-xs btn-info pull-right disabled" style="font-size:10px;"><i class="fa fa-check"></i> '.tr('Aggiorna').'</button></td>`);
} else{
tr.append(`<td><button type="button" class="btn btn-xs btn-info pull-right" onclick="aggiornaPrezzoArticolo(\'listino\')" style="font-size:10px;"><i class="fa fa-refresh"></i> '.tr('Aggiorna').'</button></td>`);
}
table.append(`</tr>`);
}
if (prezzo_std) {
table.append(`<tr><td class="pr_std"><small>'.tr('Prezzo articolo').': '.Modules::link('Articoli', $result['idarticolo'], tr('Visualizza'), null, '').'</small></td><td align="right" class="pr_std"><small>` + prezzo_std.toLocale() + ` ` + globals.currency + `</small></td></tr>`);
let tr = $(".pr_std").parent();
if (prezzo_unitario == prezzo_std.toFixed(2)) {
tr.append(`<td><button type="button" class="btn btn-xs btn-info pull-right disabled" style="font-size:10px;"><i class="fa fa-check"></i> '.tr('Aggiorna').'</button></td>`);
} else{
tr.append(`<td><button type="button" class="btn btn-xs btn-info pull-right" onclick="aggiornaPrezzoArticolo(\'std\')" style="font-size:10px;"><i class="fa fa-refresh"></i> '.tr('Aggiorna').'</button></td>`);
}
}
if (prezzo_last) {
table.append(`<tr><td class="pr_last"><small>'.tr('Ultimo prezzo').': '.Modules::link('Articoli', $result['idarticolo'], tr('Visualizza'), null, '').'</small></td><td align="right" class="pr_last"><small>` + prezzo_last.toLocale() + ` ` + globals.currency + `</small></td></tr>`);
let tr = $(".pr_last").parent();
if (prezzo_unitario == prezzo_last.toFixed(2)) {
tr.append(`<td><button type="button" class="btn btn-xs btn-info pull-right disabled" style="font-size:10px;"><i class="fa fa-check"></i> '.tr('Aggiorna').'</button></td>`);
} else{
tr.append(`<td><button type="button" class="btn btn-xs btn-info pull-right" onclick="aggiornaPrezzoArticolo(\'last\')" style="font-size:10px;"><i class="fa fa-refresh"></i> '.tr('Aggiorna').'</button></td>`);
}
}
if (prezzo_anagrafica || prezzo_listino || prezzo_std) {
table.append(`</tbody></table>`);
}
}
/**
* Funzione per verificare se lo sconto unitario corrisponde a quello registrato per l\'articolo, e proporre in automatico una correzione.
*/
function verificaScontoArticolo() {
let qta = $("#qta").val().toEnglish();
let sconto_previsto = getScontoPerQuantita(qta);
let prezzo_unitario_input = $("#prezzo_unitario");
let prezzo_unitario = prezzo_unitario_input.val().toEnglish();
let prezzo_anagrafica = getPrezzoPerQuantita(qta);
let prezzo_listino = getPrezzoListino();
let sconto_previsto = 0;
if (prezzo_unitario == prezzo_anagrafica.toFixed(2)) {
let qta = $("#qta").val().toEnglish();
sconto_previsto = getScontoPerQuantita(qta);
} else if (prezzo_unitario == prezzo_listino.toFixed(2)) {
sconto_previsto = getScontoListino();
}
let sconto_input = $("#sconto");
let sconto = sconto_input.val().toEnglish();
let div = sconto_input.parent().next();
if (sconto_previsto === 0 || sconto_previsto === sconto || $("#tipo_sconto").val() === "UNT") {
let div = $(".sconto");
if (sconto_previsto === 0 || sconto_previsto === sconto) {
div.css("padding-top", "0");
div.html("");
return;
}
div.css("padding-top", "5px");
div.html(`<small class="label label-info" >'.tr('Sconto suggerito').': ` + sconto_previsto.toLocale() + `%<button type="button" class="btn btn-xs btn-info pull-right" onclick="aggiornaScontoArticolo()"><i class="fa fa-refresh"></i> '.tr('Aggiorna').'</button></small>`);
div.css("margin-top", "-13px");
div.html(`<small class="label label-info">'.tr('Sconto suggerito').': ` + sconto_previsto.toLocale() + `%<button type="button" class="btn btn-xs btn-info pull-right" onclick="aggiornaScontoArticolo()"><i class="fa fa-refresh"></i> '.tr('Aggiorna').'</button></small>`);
}
/**
* Funzione per aggiornare il prezzo unitario sulla base dei valori automatici.
*/
function aggiornaPrezzoArticolo() {
let qta = $("#qta").val().toEnglish();
let prezzo_previsto = getPrezzoPerQuantita(qta);
function aggiornaPrezzoArticolo(aggiorna = "") {
let prezzo_previsto = 0;
if (aggiorna == "listino") {
prezzo_previsto = getPrezzoListino();
} else if (aggiorna == "anagrafica") {
let qta = $("#qta").val().toEnglish();
prezzo_previsto = getPrezzoPerQuantita(qta);
} else if (aggiorna == "std") {
prezzo_previsto = getPrezzoScheda();
} else if (aggiorna == "last") {
prezzo_previsto = getPrezzoUltimo();
} else {
let qta = $("#qta").val().toEnglish();
prezzo1 = getPrezzoPerQuantita(qta);
prezzo2 = getPrezzoListino();
prezzo_previsto = (!prezzo1 ? prezzo2 : (!prezzo2 ? prezzo1 : (prezzo1 > prezzo2 ? prezzo2 : prezzo1)));
}
$("#prezzo_unitario").val(prezzo_previsto).trigger("change");
@ -332,10 +481,22 @@ function aggiornaPrezzoArticolo() {
* Funzione per aggiornare lo sconto unitario sulla base dei valori automatici.
*/
function aggiornaScontoArticolo() {
let qta = $("#qta").val().toEnglish();
let sconto_previsto = getScontoPerQuantita(qta);
let prezzo_unitario_input = $("#prezzo_unitario");
let prezzo_unitario = prezzo_unitario_input.val().toEnglish();
let prezzo_anagrafica = getPrezzoPerQuantita(qta);
let prezzo_listino = getPrezzoListino();
let sconto_previsto = 0;
if (prezzo_unitario == prezzo_anagrafica.toFixed(2)) {
let qta = $("#qta").val().toEnglish();
sconto_previsto = getScontoPerQuantita(qta);
} else if (prezzo_unitario == prezzo_listino.toFixed(2)) {
sconto_previsto = getScontoListino();
}
$("#sconto").val(sconto_previsto).trigger("change");
input("tipo_sconto").set("PRC").trigger("change");
// Aggiornamento automatico di guadagno e margine
if (direzione === "entrata") {
@ -367,4 +528,17 @@ function aggiornaQtaMinima() {
}
}
function verificaMinimoVendita() {
let prezzo_unitario_input = $("#prezzo_unitario");
let prezzo_unitario = prezzo_unitario_input.val().toEnglish();
let minimo_vendita = parseFloat($("#idarticolo").selectData().minimo_vendita);
let div = $(".minimo_vendita");
div.css("margin-top", "-13px");
if (prezzo_unitario < minimo_vendita) {
div.html(`<p class="label-warning">'.tr('Attenzione:<br>valore inferiore al prezzo minimo di vendita ').'` + minimo_vendita.toLocale() + ` ` + globals.currency + `</p>`);
} else {
div.html("");
}
}
</script>';

View File

@ -180,14 +180,26 @@ echo '
if ($options['dir'] == 'entrata') {
echo '
<div class="row">
<div class="col-md-4 margine"></div>';
<div class="col-md-4 margine"></div>
<div class="col-md-4 prezzi"></div>';
// Provvigione
echo '
<div class="col-md-offset-4 col-md-4">
<div class="col-md-4">
<div class="sconto"></div>
{[ "type": "number", "label": "'.tr('Provvigione unitaria').'", "name": "provvigione", "value": "'.($result['provvigione_percentuale'] ?: ($result['provvigione_unitaria'] ?: $result['provvigione_default'])).'", "icon-after": "choice|untprc|'.($result['tipo_provvigione'] ?: $result['tipo_provvigione_default']).'", "help": "'.tr('Provvigione destinata all\'agente.').'", "min-value": "0" ]}
</div>
</div>
<div class="row">
<div class="col-md-offset-4 col-md-4 minimo_vendita text-center"></div>
</div>';
} else {
echo '
<div class="row">
<div class="col-md-6 prezzi"></div>
<div class="col-md-6 sconto"></div>
</div>
<br>';
}
// Data prevista evasione (per ordini)
@ -311,11 +323,21 @@ if (in_array($module['name'], ['Fatture di vendita', 'Fatture di acquisto'])) {
function controlla_sconto() {
let sconto = $("#sconto").val().toEnglish();
let div = $("#sconto").closest("div").next("div[id*=errors]");
let div_margine = $(".margine");
let div_prezzi = $(".prezzi");
div.css("margin-top", "-13px");
if (sconto > 0) {
div_margine.css("margin-top", "-20px");
div_prezzi.css("margin-top", "-20px");
div.html(`<small class="label label-default" >'.tr('Sconto').'</small>`);
} else if (sconto < 0) {
div_margine.css("margin-top", "-20px");
div_prezzi.css("margin-top", "-20px");
div.html(`<small class="label label-default" >'.tr('Maggiorazione').'</small>`);
} else {
div_margine.css("margin-top", "0px");
div_prezzi.css("margin-top", "0px");
div.html("");
}
}

View File

@ -74,8 +74,8 @@ switch (post('op')) {
$anagrafica->diciturafissafattura = post('diciturafissafattura');
$anagrafica->idpagamento_acquisti = post('idpagamento_acquisti');
$anagrafica->idpagamento_vendite = post('idpagamento_vendite');
$anagrafica->idlistino_acquisti = post('idlistino_acquisti');
$anagrafica->idlistino_vendite = post('idlistino_vendite');
$anagrafica->id_piano_sconto_acquisti = post('id_piano_sconto_acquisti');
$anagrafica->id_piano_sconto_vendite = post('id_piano_sconto_vendite');
$anagrafica->idiva_acquisti = post('idiva_acquisti');
$anagrafica->idiva_vendite = post('idiva_vendite');
$anagrafica->idbanca_acquisti = post('idbanca_acquisti');
@ -100,6 +100,7 @@ switch (post('op')) {
$anagrafica->id_ritenuta_acconto_acquisti = post('id_ritenuta_acconto_acquisti');
$anagrafica->id_ritenuta_acconto_vendite = post('id_ritenuta_acconto_vendite');
$anagrafica->split_payment = post('split_payment');
$anagrafica->id_listino = post('id_listino');
$anagrafica->tipologie = (array) post('idtipoanagrafica');
$anagrafica->codice_fiscale = strtoupper(post('codice_fiscale'));

View File

@ -519,7 +519,7 @@ if ($is_cliente or $is_fornitore or $is_tecnico) {
<div class="row">
<div class="col-md-6">
{[ "type": "select", "label": "'.tr('Piano di sconto/magg. su articoli').'", "name": "idlistino_vendite", "values": "query=SELECT id, nome AS descrizione FROM mg_listini ORDER BY nome ASC", "value": "$idlistino_vendite$" ]}
{[ "type": "select", "label": "'.tr('Piano di sconto/magg. su articoli').'", "name": "id_piano_sconto_vendite", "values": "query=SELECT id, nome AS descrizione FROM mg_piani_sconto ORDER BY nome ASC", "value": "$id_piano_sconto_vendite$" ]}
</div>
<div class="col-md-6">
@ -535,6 +535,16 @@ if ($is_cliente or $is_fornitore or $is_tecnico) {
<div class="col-md-6">
{[ "type": "select", "label": "'.tr('Agenti secondari').'", "multiple": "1", "name": "idagenti[]", "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 AND an_anagrafiche.idanagrafica NOT IN (SELECT idagente FROM an_anagrafiche WHERE idanagrafica = '.prepare($record['idanagrafica']).')) OR (an_anagrafiche.idanagrafica IN (SELECT idagente FROM an_anagrafiche_agenti WHERE idanagrafica = '.prepare($record['idanagrafica']).') ) ORDER BY ragione_sociale", "value": "$idagenti$" ]}
</div>
</div>
<div class="row">
<div class="col-md-6">
{[ "type": "select", "label": "'.tr('Listino').'", "name": "id_listino", "ajax-source": "listini", "value": "$id_listino$" ]}
</div>
<div class="col-md-6">
{[ "type": "select", "label": "'.tr('Tipo attività predefinita').'", "name": "idtipointervento_default", "values": "query=SELECT idtipointervento AS id, descrizione FROM in_tipiintervento ORDER BY descrizione ASC", "value": "$idtipointervento_default$" ]}
</div>
</div>';
// Collegamento con il conto
@ -554,11 +564,6 @@ if ($is_cliente or $is_fornitore or $is_tecnico) {
echo '
</div>
<div class="col-md-6">
{[ "type": "select", "label": "'.tr('Tipo attività predefinita').'", "name": "idtipointervento_default", "values": "query=SELECT idtipointervento AS id, descrizione FROM in_tipiintervento ORDER BY descrizione ASC", "value": "$idtipointervento_default$" ]}
</div>
</div>
</div>';
@ -586,7 +591,7 @@ if ($is_cliente or $is_fornitore or $is_tecnico) {
<div class="row">
<div class="col-md-6">
{[ "type": "select", "label": "'.tr('Piano di sconto/magg. su articoli').'", "name": "idlistino_acquisti", "values": "query=SELECT id, nome AS descrizione FROM mg_listini ORDER BY nome ASC", "value": "$idlistino_acquisti$" ]}
{[ "type": "select", "label": "'.tr('Piano di sconto/magg. su articoli').'", "name": "id_piano_sconto_acquisti", "values": "query=SELECT id, nome AS descrizione FROM mg_piani_sconto ORDER BY nome ASC", "value": "$id_piano_sconto_acquisti$" ]}
</div>';
// Collegamento con il conto

View File

@ -145,6 +145,7 @@ switch (post('op')) {
$articolo->um_secondaria = post('um_secondaria');
$articolo->fattore_um_secondaria = post('fattore_um_secondaria');
$articolo->qta_multipla = post('qta_multipla');
$articolo->setMinimoVendita(post('minimo_vendita'), post('idiva_vendita'));
if (empty(post('coefficiente'))) {
$articolo->setPrezzoVendita(post('prezzo_vendita'), post('idiva_vendita'));

View File

@ -142,22 +142,32 @@ switch ($resource) {
$query_anagrafica = replace($query, [
'|where|' => ' AND id_anagrafica = '.prepare($id_anagrafica),
]);
$results = $database->fetchArray($query_anagrafica);
$prezzi = $database->fetchArray($query_anagrafica);
$query = 'SELECT sconto_percentuale AS sconto_percentuale_listino,
'.($prezzi_ivati ? 'prezzo_unitario_ivato' : 'prezzo_unitario').' AS prezzo_unitario_listino
FROM mg_listini
LEFT JOIN mg_listini_articoli ON mg_listini.id=mg_listini_articoli.id_listino
LEFT JOIN an_anagrafiche ON mg_listini.id=an_anagrafiche.id_listino
WHERE (mg_listini.is_sempre_visibile=1 OR (mg_listini.data_attivazione<=NOW() AND mg_listini_articoli.data_scadenza>=NOW())) AND id_articolo = '.prepare($id_articolo).' AND dir = '.prepare($direzione).' |where|';
// Lettura dei prezzi relativi all'anagrafica
$query_anagrafica = replace($query, [
'|where|' => ' AND idanagrafica = '.prepare($id_anagrafica),
]);
$listino = $database->fetchArray($query_anagrafica);
// Lettura dei prezzi registrati direttamente sull'articolo, per compatibilità con il formato standard
if (empty($results)) {
$result = $database->fetchOne('SELECT prezzo_acquisto, '.($prezzi_ivati ? 'prezzo_vendita_ivato' : 'prezzo_vendita').' AS prezzo_vendita FROM mg_articoli WHERE id = '.prepare($id_articolo));
$results = [
[
'minimo' => null,
'massimo' => null,
'sconto_percentuale' => 0,
'prezzo_unitario' => $direzione == 'uscita' ? $result['prezzo_acquisto'] : $result['prezzo_vendita'],
],
];
if ($direzione == 'uscita') {
$prezzo_articolo = $database->fetchArray('SELECT prezzo_acquisto AS prezzo_scheda FROM mg_articoli WHERE id = '.prepare($id_articolo));
} else {
$prezzo_articolo = $database->fetchArray('SELECT '.($prezzi_ivati ? 'prezzo_vendita_ivato' : 'prezzo_vendita').' AS prezzo_scheda FROM mg_articoli WHERE id = '.prepare($id_articolo));
}
// Ultimo prezzo al cliente
$ultimo_prezzo = $dbo->fetchArray('SELECT '.($prezzi_ivati ? '(prezzo_unitario_ivato-sconto_unitario_ivato)' : '(prezzo_unitario-sconto_unitario)').' AS prezzo_ultimo FROM co_righe_documenti LEFT JOIN co_documenti ON co_documenti.id=co_righe_documenti.iddocumento WHERE idarticolo='.prepare($id_articolo).' AND idanagrafica='.prepare($id_anagrafica).' AND idtipodocumento IN(SELECT id FROM co_tipidocumento WHERE dir='.prepare($direzione).') ORDER BY data DESC LIMIT 0,1');
$results = array_merge($prezzi, $listino, $prezzo_articolo, $ultimo_prezzo);
echo json_encode($results);
break;

View File

@ -35,14 +35,16 @@ switch ($resource) {
$usare_iva_anagrafica = $superselect['dir'] == 'entrata' && !empty($superselect['idanagrafica']);
$solo_non_varianti = $superselect['solo_non_varianti'];
$idagente = $superselect['idagente'];
$id_listino = $superselect['id_listino'];
$query = "SELECT
DISTINCT mg_articoli.id,
IF(`categoria`.`nome` IS NOT NULL, CONCAT(`categoria`.`nome`, IF(`sottocategoria`.`nome` IS NOT NULL, CONCAT(' (', `sottocategoria`.`nome`, ')'), '-')), '<i>".tr('Nessuna categoria')."</i>') AS optgroup,
mg_articoli.barcode,
mg_articoli.".($prezzi_ivati ? 'prezzo_vendita_ivato' : 'prezzo_vendita').' AS prezzo_vendita,
mg_articoli.prezzo_vendita_ivato AS prezzo_vendita_ivato,';
mg_articoli.".($prezzi_ivati ? 'prezzo_vendita_ivato' : 'prezzo_vendita')." AS prezzo_vendita,
mg_articoli.prezzo_vendita_ivato AS prezzo_vendita_ivato,
mg_articoli.".($prezzi_ivati ? 'minimo_vendita_ivato' : 'minimo_vendita')." AS minimo_vendita,";
// Informazioni relative al fornitore specificato dal documenti di acquisto
if ($usare_dettaglio_fornitore) {
@ -159,6 +161,10 @@ switch ($resource) {
$where[] = 'mg_articoli.id_combinazione IS NULL';
}
if ($id_listino) {
$where[] = 'mg_articoli.id NOT IN (SELECT id_articolo FROM mg_listini_articoli WHERE id_listino='.prepare($id_listino).')';
}
if (!empty($search)) {
$search_fields[] = 'mg_articoli.descrizione LIKE '.prepare('%'.$search.'%');
$search_fields[] = 'mg_articoli.codice LIKE '.prepare('%'.$search.'%');

View File

@ -266,9 +266,13 @@ echo '
</div>
<div class="row">
<div class="col-md-12">
<div class="col-md-6">
{[ "type": "select", "label": "<?php echo tr('Conto predefinito di vendita'); ?>", "name": "idconto_vendita", "value": "$idconto_vendita$", "ajax-source": "conti-vendite" ]}
</div>
<div class="col-md-6">
{[ "type": "number", "label": "<?php echo tr('Minimo di vendita'); ?>", "name": "minimo_vendita", "value": "<?php echo ($prezzi_ivati ? $articolo->minimo_vendita_ivato : $articolo->minimo_vendita); ?>", "icon-after": "<?php echo currency(); ?>", "help": "<?php echo ($prezzi_ivati ? tr('Importo IVA inclusa') : ''); ?>" ]}
</div>
</div>
</div>
</div>

View File

@ -142,6 +142,27 @@ class Articolo extends Model
}
}
/**
* Imposta il prezzo di vendita sulla base dell'impstazione per l'utilizzo dei prezzi comprensivi di IVA.
*
* @param $prezzo_vendita
* @param $id_iva
*/
public function setMinimoVendita($prezzo_minimo, $id_iva)
{
// Calcolo prezzo minimo di vendita ivato e non ivato
$prezzi_ivati = setting('Utilizza prezzi di vendita comprensivi di IVA');
$id_iva = $id_iva ?: setting('Iva predefinita');
$percentuale_aliquota = floatval(Aliquota::find($id_iva)->percentuale);
if ($prezzi_ivati) {
$this->minimo_vendita_ivato = $prezzo_minimo;
$this->minimo_vendita = $prezzo_minimo / (1 + $percentuale_aliquota / 100);
} else {
$this->minimo_vendita = $prezzo_minimo;
$this->minimo_vendita_ivato = $prezzo_minimo * (1 + $percentuale_aliquota / 100);
}
}
/**
* Imposta il prezzo di acquisto e aggiorna il prezzo di vendita in base al coefficiente.
*

View File

@ -72,7 +72,7 @@ if (get('is_descrizione') !== null) {
$file = 'articolo';
// Aggiunta sconto di default da listino per le vendite
$listino = $dbo->fetchOne('SELECT prc_guadagno FROM an_anagrafiche INNER JOIN mg_listini ON an_anagrafiche.idlistino_vendite=mg_listini.id WHERE idanagrafica='.prepare($documento['idanagrafica']));
$listino = $dbo->fetchOne('SELECT prc_guadagno FROM an_anagrafiche INNER JOIN mg_piani_sconto ON an_anagrafiche.id_piano_sconto_vendite=mg_piani_sconto.id WHERE idanagrafica='.prepare($documento['idanagrafica']));
if (!empty($listino['prc_guadagno'])) {
$result['sconto_percentuale'] = $listino['prc_guadagno'];

View File

@ -75,7 +75,7 @@ if (get('is_descrizione') !== null) {
$file = 'articolo';
// Aggiunta sconto di default da listino per le vendite
$listino = $dbo->fetchOne('SELECT prc_guadagno FROM an_anagrafiche INNER JOIN mg_listini ON an_anagrafiche.idlistino_vendite=mg_listini.id WHERE idanagrafica='.prepare($documento['idanagrafica']));
$listino = $dbo->fetchOne('SELECT prc_guadagno FROM an_anagrafiche INNER JOIN mg_piani_sconto ON an_anagrafiche.id_piano_sconto_vendite=mg_piani_sconto.id WHERE idanagrafica='.prepare($documento['idanagrafica']));
if (!empty($listino['prc_guadagno'])) {
$result['sconto_percentuale'] = $listino['prc_guadagno'];

View File

@ -101,7 +101,7 @@ if (get('is_descrizione') !== null) {
$file = 'articolo';
// Aggiunta sconto di default da listino per le vendite
$listino = $dbo->fetchOne('SELECT prc_guadagno FROM an_anagrafiche INNER JOIN mg_listini ON an_anagrafiche.idlistino_vendite=mg_listini.id WHERE idanagrafica='.prepare($documento['idanagrafica']));
$listino = $dbo->fetchOne('SELECT prc_guadagno FROM an_anagrafiche INNER JOIN mg_piani_sconto ON an_anagrafiche.id_piano_sconto_vendite=mg_piani_sconto.id WHERE idanagrafica='.prepare($documento['idanagrafica']));
if (!empty($listino['prc_guadagno'])) {
$result['sconto_percentuale'] = $listino['prc_guadagno'];

View File

@ -81,7 +81,7 @@ if (get('is_descrizione') !== null) {
$file = 'articolo';
// Aggiunta sconto di default da listino per le vendite
$listino = $dbo->fetchOne('SELECT prc_guadagno FROM an_anagrafiche INNER JOIN mg_listini ON an_anagrafiche.idlistino_vendite=mg_listini.id WHERE idanagrafica='.prepare($documento['idanagrafica']));
$listino = $dbo->fetchOne('SELECT prc_guadagno FROM an_anagrafiche INNER JOIN mg_piani_sconto ON an_anagrafiche.id_piano_sconto_vendite=mg_piani_sconto.id WHERE idanagrafica='.prepare($documento['idanagrafica']));
if (!empty($listino['prc_guadagno'])) {
$result['sconto_percentuale'] = $listino['prc_guadagno'];

View File

@ -0,0 +1,91 @@
<?php
/*
* OpenSTAManager: il software gestionale open source per l'assistenza tecnica e la fatturazione
* Copyright (C) DevCode s.r.l.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
include_once __DIR__.'/../../core.php';
use Modules\Articoli\Articolo AS ArticoloOriginale;
use Modules\ListiniCliente\Articolo;
use Modules\ListiniCliente\Listino;
switch (filter('op')) {
case 'update':
$listino->nome = post('nome');
$listino->data_attivazione = post('data_attivazione') ?: null;
$listino->data_scadenza_predefinita = post('data_scadenza_predefinita') ?: null;
$listino->is_sempre_visibile = post('is_sempre_visibile');
$listino->note = post('note');
$listino->save();
flash()->info(tr('Listino modificato correttamente!'));
break;
case 'add':
$listino = Listino::build(post('nome'));
$listino->data_attivazione = post('data_attivazione') ?: null;
$listino->data_scadenza_predefinita = post('data_scadenza_predefinita') ?: null;
$listino->is_sempre_visibile = post('is_sempre_visibile');
$listino->note = post('note');
$listino->save();
$id_record = $listino->id;
flash()->info(tr('Nuovo listino aggiunto!'));
break;
case 'manage_articolo':
if (empty(post('id'))) {
$articolo_originale = ArticoloOriginale::find(post('id_articolo'));
$articolo_listino = Articolo::build($articolo_originale, $id_record);
$articolo_listino->data_scadenza = post('data_scadenza') ?: null;
$articolo_listino->setPrezzoUnitario(post('prezzo_unitario'));
$articolo_listino->sconto_percentuale = post('sconto_percentuale');
$articolo_listino->save();
} else {
$articolo_listino = Articolo::find(post('id'));
$articolo_listino->data_scadenza = post('data_scadenza') ?: null;
$articolo_listino->setPrezzoUnitario(post('prezzo_unitario'));
$articolo_listino->sconto_percentuale = post('sconto_percentuale');
$articolo_listino->save();
}
flash()->info(tr('Nuovo articolo al listino aggiunto!'));
break;
case 'delete_articolo':
$articolo_listino = Articolo::find(post('id'));
$articolo_listino->delete();
flash()->info(tr('Articolo del listino eliminato correttamente!'));
break;
case 'delete':
if (isset($id_record)) {
$listino->delete();
$dbo->query('UPDATE `an_anagrafiche` SET id_listino=0 WHERE id_listino='.prepare($id_record));
$dbo->query('DELETE FROM `mg_listini_articoli` WHERE id_listino='.prepare($id_record));
flash()->info(tr('Listino eliminato correttamente!'));
}
break;
}

View File

@ -0,0 +1,58 @@
<?php
/*
* OpenSTAManager: il software gestionale open source per l'assistenza tecnica e la fatturazione
* Copyright (C) DevCode s.r.l.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
include_once __DIR__.'/../../core.php';
echo '
<form action="" method="post" id="add-form">
<input type="hidden" name="op" value="add">
<input type="hidden" name="backto" value="record-edit">
<div class="row">
<div class="col-md-4">
{[ "type":"text", "label":"'.tr('Nome').'", "name":"nome", "required":"1" ]}
</div>
<div class="col-md-3">
{[ "type":"date", "label":"'.tr('Data attivazione').'", "name":"data_attivazione", "required":"1" ]}
</div>
<div class="col-md-3">
{[ "type":"date", "label":"'.tr('Data scadenza default').'", "name":"data_scadenza_predefinita" ]}
</div>
<div class="col-md-2">
{[ "type":"checkbox", "label":"'.tr('Sempre visibile').'", "name":"is_sempre_visibile", "help": "'.tr('Se attivo il valore sarà visibile sull\'articolo').'" ]}
</div>
</div>
<div class="row">
<div class="col-md-12">
{[ "type":"textarea", "label":"'.tr('Note').'", "name":"note" ]}
</div>
</div>
<!-- PULSANTI -->
<div class="row">
<div class="col-md-12 text-right">
<button type="submit" class="btn btn-primary"><i class="fa fa-plus"></i> '.tr('Aggiungi').'</button>
</div>
</div>
</form>';

View File

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

View File

@ -0,0 +1,198 @@
<?php
/*
* OpenSTAManager: il software gestionale open source per l'assistenza tecnica e la fatturazione
* Copyright (C) DevCode s.r.l.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
include_once __DIR__.'/../../core.php';
echo '
<form action="" method="post" id="edit-form">
<input type="hidden" name="backto" value="record-edit">
<input type="hidden" name="op" value="update">
<div class="panel panel-primary">
<div class="panel-heading">
<h3 class="panel-title">'.tr('Listino').'</h3>
</div>
<div class="panel-body">
<div class="row">
<div class="col-md-4">
{[ "type":"text", "label":"'.tr('Nome').'", "name":"nome", "value":"$nome$", "required":"1" ]}
</div>
<div class="col-md-3">
{[ "type":"date", "label":"'.tr('Data attivazione').'", "name":"data_attivazione", "value":"$data_attivazione$", "required":"1" ]}
</div>
<div class="col-md-3">
{[ "type":"date", "label":"'.tr('Data scadenza default').'", "name":"data_scadenza_predefinita", "value":"$data_scadenza_predefinita$" ]}
</div>
<div class="col-md-2">
{[ "type":"checkbox", "label":"'.tr('Sempre visibile').'", "name":"is_sempre_visibile", "value":"$is_sempre_visibile$", "help": "'.tr('Se attivo il valore sarà visibile sull\'articolo').'" ]}
</div>
</div>
<div class="row">
<div class="col-md-12">
{[ "type":"textarea", "label":"'.tr('Note').'", "name":"note", "value":"$note$" ]}
</div>
</div>
<hr>
<div class="row">
<div class="col-md-offset-7 col-md-3">
{[ "type":"select", "label":"'.tr('Articolo').'", "ajax-source": "articoli", "select-options": {"permetti_movimento_a_zero": 1, "id_listino": '.$id_record.'} ]}
</div>
<div class="col-md-2">
<div class="btn-group btn-group-flex">
<button type="button" class="btn btn-primary" style="margin-top:25px;" onclick="aggiungiArticolo(this, true)">
<i class="fa fa-plus"></i> '.tr('Aggiungi').'
</button>
</div>
</div>
</div>
<div style="max-height:400px; overflow:auto;">
<table class="table table-striped table-condensed table-bordered">
<tr>
<th class="text-center" width="14%">'.tr('Codice').'</th>
<th class="text-center">'.tr('Descrizione').'</th>
<th class="text-center" width="10%">'.tr('Data scadenza').'</th>
<th class="text-center" width="10%">'.tr('Minimo').'</th>
<th class="text-center" width="10%">'.tr('Prezzo di listino').'</th>
<th class="text-center" width="10%">'.tr('Prezzo ivato').'</th>
<th class="text-center" width="10%">'.tr('Sconto').'</th>
<th class="text-center" width="7%">#</th>
</tr>';
foreach ($articoli as $articolo) {
echo '
<tr data-id="'.$articolo['id'].'">
<td class="text-center">
'.Modules::link('Articoli', $articolo['id_articolo'], $articolo['codice'], null, '').'
</td>
<td>
'.$articolo['descrizione'].'
</td>
<td class="text-center">
'.dateFormat($articolo['data_scadenza']).'
</td>
<td class="text-center">
'.moneyFormat($articolo['minimo_vendita']).'
</td>
<td class="text-center">
'.moneyFormat($articolo['prezzo_unitario']).'
</td>
<td class="text-center">
'.moneyFormat($articolo['prezzo_unitario_ivato']).'
</td>
<td class="text-center">
'.numberFormat($articolo['sconto_percentuale']).' %
</td>
<td class="text-center">
<a class="btn btn-xs btn-warning" title="'.tr('Modifica articolo').'" onclick="modificaArticolo(this)">
<i class="fa fa-edit"></i>
</a>
<a class="btn btn-xs btn-danger" title="'.tr('Rimuovi articolo').'" onclick="rimuoviArticolo($(this).closest(\'tr\').data(\'id\'))">
<i class="fa fa-trash"></i>
</a>
</td>
</tr>';
}
if (empty($articoli)) {
echo '
<tr data-id="'.$articolo['id'].'">
<td colspan="7" class="text-center">
'.tr('Nessun articolo presente').'
</td>
</tr>';
}
echo '
</table>
</div>
</div>
</div>
</form>
<a class="btn btn-danger ask" data-backto="record-list">
<i class="fa fa-trash"></i>'.tr('Elimina').'
</a>
<script>
function aggiungiArticolo(button) {
let panel = $(button).closest(".panel");
let id_articolo = panel.find("select").val();
if (id_articolo) {
openModal("'.tr('Listino articolo').'", "'.$structure->fileurl('modals/manage_articolo.php').'?id_module='.$id_module.'&id_record='.$id_record.'&id_articolo=" + id_articolo);
} else {
swal("'.tr('Attenzione').'", "'.tr('Inserire un articolo').'", "warning");
}
}
async function modificaArticolo(button) {
let riga = $(button).closest("tr");
let id = riga.data("id");
// Chiusura tooltip
if ($(button).hasClass("tooltipstered"))
$(button).tooltipster("close");
// Apertura modal
openModal("'.tr('Listino articolo').'", "'.$structure->fileurl('modals/manage_articolo.php').'?id_module='.$id_module.'&id_record='.$id_record.'&id=" + id);
}
function rimuoviArticolo(id) {
swal({
title: "'.tr('Rimuovere questo articolo?').'",
html: "'.tr('Sei sicuro di volere rimuovere questo articolo dal listino?').' '.tr("L'operazione è irreversibile").'.",
type: "warning",
showCancelButton: true,
confirmButtonText: "'.tr('Sì').'"
}).then(function () {
$.ajax({
url: globals.rootdir + "/actions.php",
type: "POST",
dataType: "json",
data: {
id_module: globals.id_module,
id_record: globals.id_record,
op: "delete_articolo",
id: id,
},
success: function (response) {
location.reload();
},
error: function() {
location.reload();
}
});
}).catch(swal.noop);
}
</script>';

View File

@ -0,0 +1,30 @@
<?php
/*
* OpenSTAManager: il software gestionale open source per l'assistenza tecnica e la fatturazione
* Copyright (C) DevCode s.r.l.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
include_once __DIR__.'/../../core.php';
use Modules\ListiniCliente\Listino;
if (isset($id_record)) {
$listino = Listino::find($id_record);
$record = $dbo->fetchOne('SELECT * FROM `mg_listini` WHERE id='.prepare($id_record));
$prezzi_ivati = setting('Utilizza prezzi di vendita comprensivi di IVA');
$articoli = $dbo->fetchArray('SELECT mg_listini_articoli.*, mg_articoli.codice, mg_articoli.descrizione, mg_articoli.'.($prezzi_ivati ? 'minimo_vendita_ivato' : 'minimo_vendita').' AS minimo_vendita FROM mg_listini_articoli LEFT JOIN mg_articoli ON mg_listini_articoli.id_articolo=mg_articoli.id WHERE id_listino='.prepare($id_record));
}

View File

@ -0,0 +1,74 @@
<?php
/*
* OpenSTAManager: il software gestionale open source per l'assistenza tecnica e la fatturazione
* Copyright (C) DevCode s.r.l.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
include_once __DIR__.'/../../../core.php';
include_once __DIR__.'/../../../../core.php';
if (empty(get('id'))) {
$listino = $dbo->selectOne('mg_listini', '*', ['id' => get('id_record')]);
$data_scadenza = $listino['data_scadenza_predefinita'];
$id_articolo = get('id_articolo');
} else {
$articolo = $dbo->selectOne('mg_listini_articoli', '*', ['id' => get('id')]);
$data_scadenza = $articolo['data_scadenza'];
$id_articolo = $articolo['id_articolo'];
}
$prezzi_ivati = setting('Utilizza prezzi di vendita comprensivi di IVA');
$prezzo_unitario = $prezzi_ivati ? $articolo['prezzo_unitario_ivato'] : $articolo['prezzo_unitario'];
echo '
<form id="add_form" action="'.base_path().'/editor.php?id_module='.$id_module.'&id_record='.get('id_record').'" method="post">
<input type="hidden" name="op" value="manage_articolo">
<input type="hidden" name="backto" value="record-edit">
<input type="hidden" name="id_articolo" value="'.get('id_articolo').'">
<input type="hidden" name="id" value="'.get('id').'">
<div class="row">
<div class="col-md-12">
{[ "type":"select", "label":"'.tr('Articolo').'", "name":"id_articolo", "ajax-source": "articoli", "select-options": {"permetti_movimento_a_zero": 1}, "value": "'.$id_articolo.'", "disabled": "1" ]}
</div>
</div>
<div class="row">
<div class="col-md-4">
{[ "type":"date", "label":"'.tr('Data scadenza').'", "name":"data_scadenza", "value":"'.$data_scadenza.'", "required": "1" ]}
</div>
<div class="col-md-4">
{[ "type":"number", "label":"'.tr('Prezzo unitario').'", "name":"prezzo_unitario", "icon-after": "'.currency().'", "value":"'.$prezzo_unitario.'" ]}
</div>
<div class="col-md-4">
{[ "type":"number", "label":"'.tr('Sconto percentuale').'", "name":"sconto_percentuale", "icon-after": "%", "value":"'.$articolo['sconto_percentuale'].'" ]}
</div>
</div>
<!-- PULSANTI -->
<div class="row">
<div class="col-md-12 text-right">
<button type="submit" class="btn btn-success">
<i class="fa fa-check"></i> '.tr('Salva').'
</button>
</div>
</div>
</form>';
echo '
<script>$(document).ready(init)</script>';

View File

@ -0,0 +1,86 @@
<?php
/*
* OpenSTAManager: il software gestionale open source per l'assistenza tecnica e la fatturazione
* Copyright (C) DevCode s.r.l.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
namespace Modules\ListiniCliente;
use Common\SimpleModelTrait;
use Illuminate\Database\Eloquent\Model;
use Modules\Articoli\Articolo AS ArticoloOriginale;
use Modules\Iva\Aliquota;
/*
* Classe per la gestione delle relazioni articolo-prezzo sulla base di un range di quantità e di una specifica anagrafica.
*
* @since 2.4.18
*/
class Articolo extends Model
{
use SimpleModelTrait;
protected $table = 'mg_listini_articoli';
/**
* Crea una nuova relazione tra Articolo e Listino per la gestione dei prezzi.
*
* @return self
*/
public static function build(ArticoloOriginale $articolo, $id_listino, $direzione = 'entrata')
{
$model = new static();
$model->articolo()->associate($articolo);
$model->id_listino = $id_listino;
$model->dir = $direzione == 'uscita' ? 'uscita' : 'entrata';
$model->save();
return $model;
}
/**
* Imposta il prezzo di vendita sulla base dell'impstazione per l'utilizzo dei prezzi comprensivi di IVA.
*
* @param $prezzo_unitario
*/
public function setPrezzoUnitario($prezzo_unitario)
{
$id_iva = $this->articolo->idiva_vendita;
// Calcolo prezzo di vendita ivato e non ivato
$prezzi_ivati = ($this->dir == 'entrata' ? setting('Utilizza prezzi di vendita comprensivi di IVA') : 0);
$percentuale_aliquota = floatval(Aliquota::find($id_iva)->percentuale);
if ($prezzi_ivati) {
$this->prezzo_unitario_ivato = $prezzo_unitario;
$this->prezzo_unitario = $prezzo_unitario / (1 + $percentuale_aliquota / 100);
} else {
$this->prezzo_unitario = $prezzo_unitario;
$this->prezzo_unitario_ivato = $prezzo_unitario * (1 + $percentuale_aliquota / 100);
}
}
public function articolo()
{
return $this->belongsTo(ArticoloOriginale::class, 'id_articolo');
}
public function listino()
{
return $this->belongsTo(Listino::class, 'id_listino');
}
}

View File

@ -0,0 +1,50 @@
<?php
/*
* OpenSTAManager: il software gestionale open source per l'assistenza tecnica e la fatturazione
* Copyright (C) DevCode s.r.l.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
namespace Modules\ListiniCliente;
use Common\SimpleModelTrait;
use Illuminate\Database\Eloquent\Model;
/*
* Classe per la gestione delle relazioni articolo-prezzo sulla base di un range di quantità e di una specifica anagrafica.
*
* @since 2.4.18
*/
class Listino extends Model
{
use SimpleModelTrait;
protected $table = 'mg_listini';
/**
* Crea una nuova relazione tra Articolo e Anagrafica per la gestione dei prezzi.
*
* @return self
*/
public static function build($nome)
{
$model = new static();
$model->nome = $nome;
$model->save();
return $model;
}
}

View File

@ -73,7 +73,7 @@ if (get('is_descrizione') !== null) {
$file = 'articolo';
// Aggiunta sconto di default da listino per le vendite
$listino = $dbo->fetchOne('SELECT prc_guadagno FROM an_anagrafiche INNER JOIN mg_listini ON an_anagrafiche.idlistino_vendite=mg_listini.id WHERE idanagrafica='.prepare($documento['idanagrafica']));
$listino = $dbo->fetchOne('SELECT prc_guadagno FROM an_anagrafiche INNER JOIN mg_piani_sconto ON an_anagrafiche.id_piano_sconto_vendite=mg_piani_sconto.id WHERE idanagrafica='.prepare($documento['idanagrafica']));
if (!empty($listino['prc_guadagno'])) {
$result['sconto_percentuale'] = $listino['prc_guadagno'];

View File

@ -22,7 +22,7 @@ include_once __DIR__.'/../../core.php';
use Modules\PianiSconto\PianoSconto;
if (isset($id_record)) {
$record = $dbo->fetchOne('SELECT * FROM mg_listini WHERE id='.prepare($id_record));
$record = $dbo->fetchOne('SELECT * FROM mg_piani_sconto WHERE id='.prepare($id_record));
$listino = PianoSconto::find($id_record);
}

View File

@ -26,7 +26,7 @@ class PianoSconto extends Model
{
use SimpleModelTrait;
protected $table = 'mg_listini';
protected $table = 'mg_piani_sconto';
public static function build($nome, $percentuale)
{

View File

@ -72,7 +72,7 @@ if (get('is_descrizione') !== null) {
$file = 'articolo';
// Aggiunta sconto di default da listino per le vendite
$listino = $dbo->fetchOne('SELECT prc_guadagno FROM an_anagrafiche INNER JOIN mg_listini ON an_anagrafiche.idlistino_vendite=mg_listini.id WHERE idanagrafica='.prepare($documento['idanagrafica']));
$listino = $dbo->fetchOne('SELECT prc_guadagno FROM an_anagrafiche INNER JOIN mg_piani_sconto ON an_anagrafiche.id_piano_sconto_vendite=mg_piani_sconto.id WHERE idanagrafica='.prepare($documento['idanagrafica']));
if (!empty($listino['prc_guadagno'])) {
$result['sconto_percentuale'] = $listino['prc_guadagno'];

View File

@ -19,7 +19,10 @@
include_once __DIR__.'/../../core.php';
use Models\OperationLog;
use Modules\Anagrafiche\Anagrafica;
use Modules\Emails\Mail;
use Modules\Emails\Template;
use Modules\Fatture\Fattura;
use Modules\Scadenzario\Scadenza;
@ -66,6 +69,91 @@ switch (post('op')) {
]));
}
break;
case 'send-sollecito':
$list = [];
foreach ($id_records as $id) {
$scadenza = Scadenza::find($id);
$documento = $scadenza->documento;
// Controllo se è una fattura di vendita
if ($documento->direzione == 'entrata'){
$id_documento = $documento->id;
$id_anagrafica = $documento->idanagrafica;
$fattura_allegata = $dbo->selectOne('zz_files', 'id', ['id_module' => $id_module, 'id_record' => $id, 'original' => 'Fattura di vendita.pdf'])['id'];
// Allego stampa della fattura se non presente
if (empty($fattura_allegata)) {
$print_predefined = $dbo->selectOne('zz_prints', '*', ['predefined' => 1, 'id_module' => Modules::get('Fatture di vendita')['id']]);
$print = Prints::render($print_predefined['id'], $id_documento, null, true);
$name = 'Fattura di vendita';
$upload = Uploads::upload($print['pdf'], [
'name' => $name,
'original_name' => $name.'.pdf',
'category' => 'Generale',
'id_module' => $id_module,
'id_record' => $id,
]);
$fattura_allegata = $dbo->selectOne('zz_files', 'id', ['id_module' => $id_module, 'id_record' => $id, 'original' => 'Fattura di vendita.pdf'])['id'];
}
// Selezione destinatari e invio mail
$template = Template::pool('Sollecito di pagamento');
if (!empty($template)) {
$creata_mail = false;
$emails = [];
// Aggiungo email anagrafica
if (!empty($documento->anagrafica->email)) {
$emails[] = $documento->anagrafica->email;
$mail = Mail::build(auth()->getUser(), $template, $id);
$mail->addReceiver($documento->anagrafica->email);
$creata_mail = true;
}
// Aggiungo email referenti in base alla mansione impostata nel template
$mansioni = $dbo->select('em_mansioni_template', 'idmansione', ['id_template' => $template->id]);
foreach ($mansioni as $mansione) {
$referenti = $dbo->table('an_referenti')->where('idmansione', $mansione['idmansione'])->where('idanagrafica', $id_anagrafica)->where('email', '!=', '')->get();
if (!$referenti->isEmpty() && $creata_mail == false) {
$mail = Mail::build(auth()->getUser(), $template, $id);
$creata_mail = true;
}
foreach ($referenti as $referente) {
if (!in_array($referente->email, $emails)) {
$emails[] = $referente->email;
$mail->addReceiver($referente->email);
}
}
}
if ($creata_mail == true) {
if (!empty($fattura_allegata)) {
$mail->addUpload($fattura_allegata);
}
$mail->save();
OperationLog::setInfo('id_email', $mail->id);
OperationLog::setInfo('id_module', $id_module);
OperationLog::setInfo('id_record', $id_record);
OperationLog::build('send-email');
array_push($list, $documento->numero_esterno);
}
}
}
}
if ($list){
flash()->info(tr('Mail inviata per le Fatture _LIST_ !', [
'_LIST_' => implode(',', $list),
]));
}
break;
}
@ -102,4 +190,14 @@ $operations['change-bank'] = [
],
];
$operations['send-sollecito'] = [
'text' => '<span><i class="fa fa-envelope"></i> '.tr('Invia mail sollecito').'</span>',
'data' => [
'title' => tr('Inviare mail sollecito?'),
'msg' => tr('Per ciascuna scadenza selezionata collegata ad una fattura di vendita, verrà inviata una mail con allegata la fattura di vendita corrispondente.<br>(Template utilizzato: Sollecito di pagamento)'),
'button' => tr('Invia'),
'class' => 'btn btn-lg btn-warning',
],
];
return $operations;

View File

@ -27,7 +27,7 @@ echo '
<div class="panel-body">';
$listini = $dbo->fetchArray('SELECT * FROM mg_listini ORDER BY id ASC');
$listini = $dbo->fetchArray('SELECT * FROM mg_piani_sconto ORDER BY id ASC');
if (!empty($listini)) {
echo '

View File

@ -61,7 +61,7 @@ if (get('is_descrizione') !== null) {
$file = 'articolo';
// Aggiunta sconto di default da listino per le vendite
$listino = $dbo->fetchOne('SELECT prc_guadagno FROM an_anagrafiche INNER JOIN mg_listini ON an_anagrafiche.idlistino_vendite=mg_listini.id WHERE idanagrafica='.prepare($documento['idanagrafica']));
$listino = $dbo->fetchOne('SELECT prc_guadagno FROM an_anagrafiche INNER JOIN mg_piani_sconto ON an_anagrafiche.id_piano_sconto_vendite=mg_piani_sconto.id WHERE idanagrafica='.prepare($documento['idanagrafica']));
if (!empty($listino['prc_guadagno'])) {
$result['sconto_percentuale'] = $listino['prc_guadagno'];

25
update/2_4_38.sql Normal file
View File

@ -0,0 +1,25 @@
-- Aggiunto modulo Listini clienti
RENAME TABLE `mg_listini` TO `mg_piani_sconto`;
ALTER TABLE `an_anagrafiche` CHANGE `idlistino_acquisti` `id_piano_sconto_acquisti` INT(11) NULL DEFAULT NULL;
ALTER TABLE `an_anagrafiche` CHANGE `idlistino_vendite` `id_piano_sconto_vendite` INT(11) NULL DEFAULT NULL;
ALTER TABLE `an_anagrafiche` ADD `id_listino` INT NOT NULL AFTER `id_piano_sconto_acquisti`;
CREATE TABLE `mg_listini` ( `id` INT NOT NULL AUTO_INCREMENT , `nome` VARCHAR(255) NOT NULL , `data_attivazione` DATE NULL , `data_scadenza_predefinita` DATE NULL , `is_sempre_visibile` BOOLEAN NOT NULL , `note` TEXT NOT NULL , `created_at` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP , `updated_at` TIMESTAMP on update CURRENT_TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP , PRIMARY KEY (`id`));
CREATE TABLE `mg_listini_articoli` ( `id` INT NOT NULL AUTO_INCREMENT , `id_listino` INT NOT NULL, `id_articolo` INT NOT NULL , `data_scadenza` DATE NOT NULL , `prezzo_unitario` DECIMAL(15,6) NOT NULL , `prezzo_unitario_ivato` DECIMAL(15,6) NOT NULL , `sconto_percentuale` DECIMAL(15,6) NOT NULL , `dir` VARCHAR(20) NOT NULL , `created_at` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP , `updated_at` TIMESTAMP on update CURRENT_TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP , PRIMARY KEY (`id`));
INSERT INTO `zz_modules` (`id`, `name`, `title`, `directory`, `options`, `options2`, `icon`, `version`, `compatibility`, `order`, `parent`, `default`, `enabled`, `use_notes`, `use_checklists`) VALUES (NULL, 'Listini cliente', 'Listini cliente', 'listini_cliente', 'SELECT |select| FROM `mg_listini` WHERE 1=1 HAVING 2=2', '', 'fa fa-angle-right', '2.*', '2.*', '2', (SELECT `id` FROM `zz_modules` AS `t` WHERE `t`.`name`='Magazzino'), '1', '1', '0', '0');
INSERT INTO `zz_views` ( `id_module`, `name`, `query`, `order`, `search`, `slow`, `format`, `search_inside`, `order_by`, `visible`, `summable`, `default`) VALUES
((SELECT `id` FROM `zz_modules` WHERE name='Listini cliente'), 'id', 'id', 1, 1, 0, 0, '', '', 0, 0, 1),
((SELECT `id` FROM `zz_modules` WHERE name='Listini cliente'), 'Nome', 'nome', 2, 1, 0, 0, '', '', 1, 0, 1);
((SELECT `id` FROM `zz_modules` WHERE name='Listini cliente'), 'Data attivazione', 'data_attivazione', 3, 1, 0, 1, 0, '', '', 1, 0, 1),
((SELECT `id` FROM `zz_modules` WHERE name='Listini cliente'), 'Articoli', '(SELECT COUNT(id) FROM mg_listini_articoli WHERE id_listino=mg_listini.id)', 4, 1, 0, 0, 0, '', '', 1, 0, 1),
((SELECT `id` FROM `zz_modules` WHERE name='Listini cliente'), 'Anagrafiche', '(SELECT COUNT(idanagrafica) FROM an_anagrafiche WHERE id_listino=mg_listini.id)', 5, 1, 0, 0, 0, '', '', 1, 0, 1),
((SELECT `id` FROM `zz_modules` WHERE name='Listini cliente'), 'Ultima modifica', '(SELECT username FROM zz_users WHERE id=(SELECT id_utente FROM zz_operations WHERE id_module=(SELECT id FROM zz_modules WHERE name=\'Listini cliente\') AND id_record=mg_listini.id ORDER BY id DESC LIMIT 0,1))', 6, 1, 0, 0, 0, '', '', 1, 0, 1),
((SELECT `id` FROM `zz_modules` WHERE name='Listini cliente'), 'Sempre visibile', 'IF(is_sempre_visibile=0,\'NO\',\'\')', 7, 1, 0, 0, 0, '', '', 1, 0, 1);
UPDATE `zz_plugins` SET `title` = 'Netto clienti', `name` = 'Netto Clienti' WHERE `zz_plugins`.`name` = 'Listino Clienti';
ALTER TABLE `mg_articoli` ADD `minimo_vendita` DECIMAL(15,6) NOT NULL AFTER `prezzo_vendita_ivato`;
ALTER TABLE `mg_articoli` ADD `minimo_vendita_ivato` DECIMAL(15,6) NOT NULL AFTER `minimo_vendita`;

View File

@ -93,6 +93,8 @@ return [
'mg_categorie',
'mg_causali_movimenti',
'mg_listini',
'mg_listini_articoli',
'mg_piani_sconto',
'mg_prezzi_articoli',
'mg_movimenti',
'mg_prodotti',