1
0
mirror of https://github.com/devcode-it/openstamanager.git synced 2025-06-05 22:09:38 +02:00

Supporto ai Dettagli Fornitori per gli Articoli (#810)

* Introduzione informazioni sui fornitori per articolo
* Supporto alla selezione del prezzo in base al fornitore
* Aggiunto supporto alla quantità minima

Co-authored-by: Fabio Lovato <fabiol@devcode.it>
This commit is contained in:
Thomas Zilio
2020-07-06 13:32:43 +02:00
committed by GitHub
parent 3baee2d60b
commit 02ba6e8398
33 changed files with 513 additions and 103 deletions

View File

@@ -39,4 +39,5 @@ return [
'plugins/pianificazione_interventi' => 'Plugins\PianificazioneInterventi', 'plugins/pianificazione_interventi' => 'Plugins\PianificazioneInterventi',
'plugins/pianificazione_fatturazione' => 'Plugins\PianificazioneFatturazione', 'plugins/pianificazione_fatturazione' => 'Plugins\PianificazioneFatturazione',
'plugins/statistiche_articoli' => 'Plugins\StatisticheArticoli', 'plugins/statistiche_articoli' => 'Plugins\StatisticheArticoli',
'plugins/fornitori_articolo' => 'Plugins\FornitoriArticolo',
]; ];

View File

@@ -6,6 +6,8 @@ $_SESSION['superselect']['dir'] = $options['dir'];
$_SESSION['superselect']['idanagrafica'] = $options['idanagrafica']; $_SESSION['superselect']['idanagrafica'] = $options['idanagrafica'];
$_SESSION['superselect']['idarticolo'] = $options['idarticolo']; $_SESSION['superselect']['idarticolo'] = $options['idarticolo'];
$qta_minima = 0;
// Articolo // Articolo
if (empty($result['idarticolo'])) { if (empty($result['idarticolo'])) {
echo ' echo '
@@ -13,16 +15,30 @@ if (empty($result['idarticolo'])) {
<div class="col-md-12"> <div class="col-md-12">
{[ "type": "select", "label": "'.tr('Articolo').'", "name": "idarticolo", "required": 1, "value": "'.$result['idarticolo'].'", "ajax-source": "articoli", "icon-after": "add|'.Modules::get('Articoli')['id'].'" ]} {[ "type": "select", "label": "'.tr('Articolo').'", "name": "idarticolo", "required": 1, "value": "'.$result['idarticolo'].'", "ajax-source": "articoli", "icon-after": "add|'.Modules::get('Articoli')['id'].'" ]}
</div> </div>
</div>'; </div>
<input type="hidden" name="id_dettaglio_fornitore" id="id_dettaglio_fornitore" value="">';
} else { } else {
$database = database(); $database = database();
$articolo = $database->fetchArray('SELECT id, codice, descrizione FROM mg_articoli WHERE id = '.prepare($result['idarticolo']))[0]; $articolo = $database->fetchOne('SELECT mg_articoli.id,
mg_fornitore_articolo.id AS id_dettaglio_fornitore,
IFNULL(mg_fornitore_articolo.codice_fornitore, mg_articoli.codice) AS codice,
IFNULL(mg_fornitore_articolo.descrizione, mg_articoli.descrizione) AS descrizione,
IFNULL(mg_fornitore_articolo.qta_minima, 0) AS qta_minima
FROM mg_articoli
LEFT JOIN mg_fornitore_articolo ON mg_fornitore_articolo.id_articolo = mg_articoli.id AND mg_fornitore_articolo.id = '.prepare($result['id_dettaglio_fornitore']).'
WHERE mg_articoli.id = '.prepare($result['idarticolo']));
$qta_minima = $articolo['qta_minima'];
echo ' echo '
<p><strong>'.tr('Articolo').':</strong> '.$articolo['codice'].' - '.$articolo['descrizione'].'.</p> <p><strong>'.tr('Articolo').':</strong> '.$articolo['codice'].' - '.$articolo['descrizione'].'.</p>
<input type="hidden" name="idarticolo" id="idarticolo" value="'.$articolo['id'].'">'; <input type="hidden" name="idarticolo" id="idarticolo" value="'.$articolo['id'].'">';
} }
echo '
<input type="hidden" name="qta_minima" id="qta_minima" value="'.$qta_minima.'">';
// Selezione impianto per gli Interventi // Selezione impianto per gli Interventi
if ($module['name'] == 'Interventi') { if ($module['name'] == 'Interventi') {
echo ' echo '
@@ -68,7 +84,7 @@ if ($module['name'] != 'Contratti' && $module['name'] != 'Preventivi') {
echo ' echo '
<script> <script>
$(document).ready(function () { $(document).ready(function () {
$("#idarticolo").on("change", function(){ $("#idarticolo").on("change", function() {
// Autoimpostazione dei valori relativi // Autoimpostazione dei valori relativi
if ($(this).val()) { if ($(this).val()) {
session_set("superselect,idarticolo", $(this).val(), 0); session_set("superselect,idarticolo", $(this).val(), 0);
@@ -77,25 +93,29 @@ $(document).ready(function () {
$data = $(this).selectData(); $data = $(this).selectData();
var id_conto = $data.idconto_'.($options['dir'] == 'entrata' ? 'vendita' : 'acquisto').';
$("#prezzo_unitario").val($data.prezzo_'.($options['dir'] == 'entrata' ? 'vendita' : 'acquisto').'); $("#prezzo_unitario").val($data.prezzo_'.($options['dir'] == 'entrata' ? 'vendita' : 'acquisto').');
$("#costo_unitario").val($data.prezzo_acquisto); $("#costo_unitario").val($data.prezzo_acquisto);
$("#descrizione_riga").val($data.descrizione);'; $("#descrizione_riga").val($data.descrizione);';
if ($options['dir'] == 'entrata') { if ($options['dir'] == 'entrata') {
echo ' echo '
if( $data.idiva_vendita ){ if($data.idiva_vendita) {
$("#idiva").selectSetNew($data.idiva_vendita, $data.iva_vendita); $("#idiva").selectSetNew($data.idiva_vendita, $data.iva_vendita);
}'; }';
} else {
echo '
$("#id_dettaglio_fornitore").val($data.id_dettaglio_fornitore);
$("#qta_minima").val($data.qta_minima);
aggiorna_qta_minima();';
} }
echo ' echo '
var id_conto = $data.idconto_'.($options['dir'] == 'entrata' ? 'vendita' : 'acquisto').';
if(id_conto) { if(id_conto) {
$("#idconto").selectSetNew(id_conto, $data.idconto_'.($options['dir'] == 'entrata' ? 'vendita' : 'acquisto').'_title); $("#idconto").selectSetNew(id_conto, $data.idconto_'.($options['dir'] == 'entrata' ? 'vendita' : 'acquisto').'_title);
} }
$("#um").selectSetNew($data.um, $data.um); $("#um").selectSetNew($data.um, $data.um);
}'; }';
@@ -117,6 +137,41 @@ if ($module['name'] != 'Contratti' && $module['name'] != 'Preventivi') {
} }
echo ' echo '
}); });';
});
if ($options['dir'] == 'uscita') {
echo '
aggiorna_qta_minima();
$("#qta").keyup(aggiorna_qta_minima);';
}
echo '
});';
if ($options['dir'] == 'uscita') {
echo '
// Funzione per l\'aggiornamento in tempo reale del guadagno
function aggiorna_qta_minima() {
var qta_minima = parseFloat($("#qta_minima").val());
var qta = $("#qta").val().toEnglish();
if (qta_minima == 0) {
return;
}
var parent = $("#qta").closest("div").parent();
var div = parent.find("div[id*=\"errors\"]");
div.html("<small>'.tr('Quantità minima').': " + qta_minima.toLocale() + "</small>");
if (qta < qta_minima) {
parent.addClass("has-error");
div.addClass("text-danger").removeClass("text-success");
} else {
parent.removeClass("has-error");
div.removeClass("text-danger").addClass("text-success");
}
}';
}
echo '
</script>'; </script>';

View File

@@ -6,6 +6,7 @@ use Common\Document;
use Illuminate\Database\Eloquent\Builder; use Illuminate\Database\Eloquent\Builder;
use Modules\Articoli\Articolo as Original; use Modules\Articoli\Articolo as Original;
use Modules\Articoli\Movimento; use Modules\Articoli\Movimento;
use Plugins\FornitoriArticolo\Dettaglio;
use UnexpectedValueException; use UnexpectedValueException;
abstract class Article extends Row abstract class Article extends Row
@@ -55,6 +56,14 @@ abstract class Article extends Row
return $this->parent->direzione; return $this->parent->direzione;
} }
/**
* Restituisce il codice impostato per l'articolo corrente.
*/
public function getCodiceAttribute()
{
return $this->dettaglioFornitore->codice_fornitore ?: $this->articolo->codice;
}
/** /**
* Imposta i seriali collegati all'articolo. * Imposta i seriali collegati all'articolo.
* *
@@ -161,6 +170,11 @@ abstract class Article extends Row
return $this->belongsTo(Original::class, 'idarticolo'); return $this->belongsTo(Original::class, 'idarticolo');
} }
public function dettaglioFornitore()
{
return $this->belongsTo(Dettaglio::class, 'id_dettaglio_fornitore')->withTrashed();
}
public function movimentazione($value = true) public function movimentazione($value = true)
{ {
$this->abilita_movimentazione = $value; $this->abilita_movimentazione = $value;
@@ -232,7 +246,7 @@ abstract class Article extends Row
{ {
// Precaricamento Articolo // Precaricamento Articolo
static::addGlobalScope('articolo', function (Builder $builder) { static::addGlobalScope('articolo', function (Builder $builder) {
$builder->with('articolo'); $builder->with('articolo', 'dettaglioFornitore');
}); });
parent::boot(true); parent::boot(true);

View File

@@ -4,82 +4,63 @@ include_once __DIR__.'/../../../core.php';
switch ($resource) { switch ($resource) {
case 'articoli': case 'articoli':
// Se non ci sono sedi settate, carico tutti gli articoli $sedi_non_impostate = !isset($superselect['idsede_partenza']) && !isset($superselect['idsede_destinazione']);
if (!isset($superselect['idsede_partenza']) && (!isset($superselect['idsede_destinazione']))) {
$query = 'SELECT $query = 'SELECT
mg_articoli.id, mg_articoli.id,
mg_articoli.codice, mg_articoli.barcode,
mg_articoli.barcode, IFNULL(mg_fornitore_articolo.codice_fornitore, mg_articoli.codice) AS codice,
mg_articoli.descrizione, IFNULL(mg_fornitore_articolo.descrizione, mg_articoli.descrizione) AS descrizione,
round(mg_articoli.qta,'.setting('Cifre decimali per quantità').') AS qta, IFNULL(mg_fornitore_articolo.prezzo_acquisto, mg_articoli.prezzo_acquisto) AS prezzo_acquisto,
mg_articoli.um, IFNULL(mg_fornitore_articolo.qta_minima, 0) AS qta_minima,
mg_articoli.idiva_vendita, mg_fornitore_articolo.id AS id_dettaglio_fornitore,
mg_articoli.idconto_vendita, round(mg_articoli.qta,'.setting('Cifre decimali per quantità').') AS qta,
mg_articoli.idconto_acquisto, mg_articoli.um,
mg_articoli.prezzo_vendita, mg_articoli.servizio,
mg_articoli.prezzo_acquisto, mg_articoli.idiva_vendita,
mg_articoli.servizio, mg_articoli.idconto_vendita,
categoria.`nome` AS categoria, mg_articoli.idconto_acquisto,
sottocategoria.`nome` AS sottocategoria, mg_articoli.prezzo_vendita,
co_iva.descrizione AS iva_vendita, categoria.`nome` AS categoria,
CONCAT(conto_vendita_categoria .numero, ".", conto_vendita_sottocategoria.numero, " ", conto_vendita_sottocategoria.descrizione) AS idconto_vendita_title, sottocategoria.`nome` AS sottocategoria,
CONCAT(conto_acquisto_categoria .numero, ".", conto_acquisto_sottocategoria.numero, " ", conto_acquisto_sottocategoria.descrizione) AS idconto_acquisto_title co_iva.descrizione AS iva_vendita,
FROM mg_articoli CONCAT(conto_vendita_categoria .numero, ".", conto_vendita_sottocategoria.numero, " ", conto_vendita_sottocategoria.descrizione) AS idconto_vendita_title,
LEFT JOIN co_iva ON mg_articoli.idiva_vendita = co_iva.id CONCAT(conto_acquisto_categoria .numero, ".", conto_acquisto_sottocategoria.numero, " ", conto_acquisto_sottocategoria.descrizione) AS idconto_acquisto_title
LEFT JOIN `mg_categorie` AS categoria ON `categoria`.`id` = `mg_articoli`.`id_categoria` FROM mg_articoli
LEFT JOIN `mg_categorie` AS sottocategoria ON `sottocategoria`.`id` = `mg_articoli`.`id_sottocategoria` LEFT JOIN co_iva ON mg_articoli.idiva_vendita = co_iva.id
LEFT JOIN co_pianodeiconti3 AS conto_vendita_sottocategoria ON conto_vendita_sottocategoria.id=mg_articoli.idconto_vendita LEFT JOIN `mg_categorie` AS categoria ON `categoria`.`id` = `mg_articoli`.`id_categoria`
LEFT JOIN co_pianodeiconti2 AS conto_vendita_categoria ON conto_vendita_sottocategoria.idpianodeiconti2=conto_vendita_categoria.id LEFT JOIN `mg_categorie` AS sottocategoria ON `sottocategoria`.`id` = `mg_articoli`.`id_sottocategoria`
LEFT JOIN co_pianodeiconti3 AS conto_acquisto_sottocategoria ON conto_acquisto_sottocategoria.id=mg_articoli.idconto_acquisto LEFT JOIN co_pianodeiconti3 AS conto_vendita_sottocategoria ON conto_vendita_sottocategoria.id=mg_articoli.idconto_vendita
LEFT JOIN co_pianodeiconti2 AS conto_acquisto_categoria ON conto_acquisto_sottocategoria.idpianodeiconti2=conto_acquisto_categoria.id LEFT JOIN co_pianodeiconti2 AS conto_vendita_categoria ON conto_vendita_sottocategoria.idpianodeiconti2=conto_vendita_categoria.id
|where| LEFT JOIN co_pianodeiconti3 AS conto_acquisto_sottocategoria ON conto_acquisto_sottocategoria.id=mg_articoli.idconto_acquisto
ORDER BY LEFT JOIN co_pianodeiconti2 AS conto_acquisto_categoria ON conto_acquisto_sottocategoria.idpianodeiconti2=conto_acquisto_categoria.id
mg_articoli.id_categoria ASC,
mg_articoli.id_sottocategoria ASC, LEFT JOIN mg_fornitore_articolo ON mg_fornitore_articolo.id_articolo = mg_articoli.id AND mg_fornitore_articolo.deleted_at IS NULL AND mg_fornitore_articolo.id_fornitore = '.prepare($superselect['idanagrafica']);
mg_articoli.codice ASC,
mg_articoli.descrizione ASC';
}
// Se c'è una sede settata, carico tutti gli articoli presenti in quella sede // Se c'è una sede settata, carico tutti gli articoli presenti in quella sede
else { if (!$sedi_non_impostate) {
$query = 'SELECT $query .= '
mg_articoli.id, LEFT JOIN (SELECT idarticolo, idsede_azienda, idsede_controparte FROM mg_movimenti GROUP BY idarticolo) movimenti ON movimenti.idarticolo=mg_articoli.id
mg_articoli.codice, LEFT JOIN an_sedi ON an_sedi.id = movimenti.idsede_azienda';
mg_articoli.barcode,
mg_articoli.descrizione,
round(mg_articoli.qta,'.setting('Cifre decimali per quantità').') AS qta,
mg_articoli.um,
mg_articoli.idiva_vendita,
mg_articoli.idconto_vendita,
mg_articoli.idconto_acquisto,
mg_articoli.prezzo_vendita,
mg_articoli.prezzo_acquisto,
categoria.`nome` AS categoria,
sottocategoria.`nome` AS sottocategoria,
co_iva.descrizione AS iva_vendita,
mg_articoli.servizio,
CONCAT(conto_vendita_categoria .numero, ".", conto_vendita_sottocategoria.numero, " ", conto_vendita_sottocategoria.descrizione) AS idconto_vendita_title,
CONCAT(conto_acquisto_categoria .numero, ".", conto_acquisto_sottocategoria.numero, " ", conto_acquisto_sottocategoria.descrizione) AS idconto_acquisto_title
FROM mg_articoli
LEFT JOIN co_iva ON mg_articoli.idiva_vendita = co_iva.id
LEFT JOIN `mg_categorie` AS categoria ON `categoria`.`id` = `mg_articoli`.`id_categoria`
LEFT JOIN `mg_categorie` AS sottocategoria ON `sottocategoria`.`id` = `mg_articoli`.`id_sottocategoria`
LEFT JOIN co_pianodeiconti3 AS conto_vendita_sottocategoria ON conto_vendita_sottocategoria.id=mg_articoli.idconto_vendita
LEFT JOIN co_pianodeiconti2 AS conto_vendita_categoria ON conto_vendita_sottocategoria.idpianodeiconti2=conto_vendita_categoria.id
LEFT JOIN co_pianodeiconti3 AS conto_acquisto_sottocategoria ON conto_acquisto_sottocategoria.id=mg_articoli.idconto_acquisto
LEFT JOIN co_pianodeiconti2 AS conto_acquisto_categoria ON conto_acquisto_sottocategoria.idpianodeiconti2=conto_acquisto_categoria.id
LEFT JOIN (SELECT idarticolo, idsede_azienda, idsede_controparte FROM mg_movimenti GROUP BY idarticolo) movimenti ON movimenti.idarticolo=mg_articoli.id
LEFT JOIN an_sedi ON an_sedi.id = movimenti.idsede_azienda
|where|
GROUP BY
mg_articoli.id
ORDER BY
mg_articoli.id_categoria ASC,
mg_articoli.id_sottocategoria ASC,
mg_articoli.codice ASC,
mg_articoli.descrizione ASC';
} }
$query .= '
|where|';
// Se c'è una sede settata, carico tutti gli articoli presenti in quella sede
if (!$sedi_non_impostate) {
$query .= '
GROUP BY
mg_articoli.id';
}
$query .= '
ORDER BY
mg_articoli.id_categoria ASC,
mg_articoli.id_sottocategoria ASC,
mg_articoli.codice ASC,
mg_articoli.descrizione ASC';
foreach ($elements as $element) { foreach ($elements as $element) {
$filter[] = 'mg_articoli.id='.prepare($element); $filter[] = 'mg_articoli.id='.prepare($element);
} }
@@ -102,6 +83,8 @@ switch ($resource) {
'id' => 'id', 'id' => 'id',
'codice' => 'codice', 'codice' => 'codice',
'descrizione' => 'descrizione', 'descrizione' => 'descrizione',
'qta_minima' => 'qta_minima',
'id_dettaglio_fornitore' => 'id_dettaglio_fornitore',
'servizio' => 'servizio', 'servizio' => 'servizio',
'qta' => 'qta', 'qta' => 'qta',
'um' => 'um', 'um' => 'um',
@@ -185,6 +168,8 @@ switch ($resource) {
'text' => $r['codice'].' - '.$r['descrizione'].' '.(!$r['servizio'] ? '('.Translator::numberToLocale($qta).(!empty($r['um']) ? ' '.$r['um'] : '').')' : ''), 'text' => $r['codice'].' - '.$r['descrizione'].' '.(!$r['servizio'] ? '('.Translator::numberToLocale($qta).(!empty($r['um']) ? ' '.$r['um'] : '').')' : ''),
'codice' => $r['codice'], 'codice' => $r['codice'],
'descrizione' => $r['descrizione'], 'descrizione' => $r['descrizione'],
'qta_minima' => $r['qta_minima'],
'id_dettaglio_fornitore' => $r['id_dettaglio_fornitore'],
'barcode' => $r['barcode'], 'barcode' => $r['barcode'],
'qta' => $r['qta'], 'qta' => $r['qta'],
'um' => $r['um'], 'um' => $r['um'],

View File

@@ -42,11 +42,13 @@ $_SESSION['superselect']['id_categoria'] = $record['id_categoria'];
</div> </div>
</div> </div>
</div> </div>
<div class="row"> <div class="row">
<div class="col-md-12"> <div class="col-md-12">
{[ "type": "textarea", "label": "<?php echo tr('Descrizione'); ?>", "name": "descrizione", "required": 1, "value": "$descrizione$" ]} {[ "type": "textarea", "label": "<?php echo tr('Descrizione'); ?>", "name": "descrizione", "required": 1, "value": "$descrizione$" ]}
</div> </div>
</div> </div>
<div class="row"> <div class="row">
<div class="col-md-4"> <div class="col-md-4">
{[ "type": "checkbox", "label": "<?php echo tr('Abilita serial number'); ?>", "name": "abilita_serial", "value": "$abilita_serial$", "help": "<?php echo tr('Abilita serial number in fase di aggiunta articolo in fattura o ddt'); ?>", "placeholder": "<?php echo tr('Serial number'); ?>", "extra": "<?php echo ($record['serial'] > 0) ? 'readonly' : ''; ?>" ]} {[ "type": "checkbox", "label": "<?php echo tr('Abilita serial number'); ?>", "name": "abilita_serial", "value": "$abilita_serial$", "help": "<?php echo tr('Abilita serial number in fase di aggiunta articolo in fattura o ddt'); ?>", "placeholder": "<?php echo tr('Serial number'); ?>", "extra": "<?php echo ($record['serial'] > 0) ? 'readonly' : ''; ?>" ]}
@@ -129,7 +131,7 @@ $_SESSION['superselect']['id_categoria'] = $record['id_categoria'];
<div class="panel-body"> <div class="panel-body">
<div class="row"> <div class="row">
<div class="col-md-6"> <div class="col-md-6">
{[ "type": "number", "label": "<?php echo tr('Prezzo di acquisto'); ?>", "name": "prezzo_acquisto", "value": "$prezzo_acquisto$", "icon-after": "<?php echo currency(); ?>" ]} {[ "type": "number", "label": "<?php echo tr('Prezzo di acquisto'); ?>", "name": "prezzo_acquisto", "value": "$prezzo_acquisto$", "icon-after": "<?php echo currency(); ?>", "help": "<?php echo tr('Prezzo di acquisto previsto per i fornitori i cui dati non sono stati inseriti nel plugin Fornitori'); ?>." ]}
</div> </div>
<div class="col-md-6"> <div class="col-md-6">
@@ -139,7 +141,7 @@ $_SESSION['superselect']['id_categoria'] = $record['id_categoria'];
<div class="row"> <div class="row">
<div class="col-md-12"> <div class="col-md-12">
{[ "type": "select", "label": "<?php echo tr('Fornitore predefinito'); ?>", "name": "id_fornitore", "value": "$id_fornitore$", "ajax-source": "fornitori", "icon-after": "add|<?php echo Modules::get('Anagrafiche')['id']; ?>|tipoanagrafica=Fornitore&readonly_tipo=1" ]} {[ "type": "select", "label": "<?php echo tr('Fornitore predefinito'); ?>", "name": "id_fornitore", "value": "$id_fornitore$", "ajax-source": "fornitori", "icon-after": "add|<?php echo Modules::get('Anagrafiche')['id']; ?>|tipoanagrafica=Fornitore&readonly_tipo=1", "help": "<?php echo tr('Fornitore predefinito, utilizzato dal gestionale per funzioni più avanzate della gestione magazzino'); ?>." ]}
</div> </div>
</div> </div>

View File

@@ -6,6 +6,7 @@ use Common\Model;
use Illuminate\Database\Eloquent\SoftDeletes; use Illuminate\Database\Eloquent\SoftDeletes;
use Modules; use Modules;
use Modules\Interventi\Components\Articolo as ArticoloIntervento; use Modules\Interventi\Components\Articolo as ArticoloIntervento;
use Plugins\FornitoriArticolo\Dettaglio;
use Traits\RecordTrait; use Traits\RecordTrait;
use Uploads; use Uploads;
@@ -170,4 +171,16 @@ class Articolo extends Model
{ {
return $this->belongsTo(Categoria::class, 'id_sottocategoria'); return $this->belongsTo(Categoria::class, 'id_sottocategoria');
} }
public function dettaglioFornitori()
{
return $this->hasMany(Dettaglio::class, 'id_articolo');
}
public function dettaglioFornitore($id_fornitore)
{
return $this->dettaglioFornitori()
->where('id_fornitore', $id_fornitore)
->first();
}
} }

View File

@@ -114,6 +114,7 @@ switch (post('op')) {
} else { } else {
$originale = ArticoloOriginale::find(post('idarticolo')); $originale = ArticoloOriginale::find(post('idarticolo'));
$articolo = Articolo::build($contratto, $originale); $articolo = Articolo::build($contratto, $originale);
$articolo->id_dettaglio_fornitore = post('id_dettaglio_fornitore') ?: null;
} }
$qta = post('qta'); $qta = post('qta');

View File

@@ -31,7 +31,7 @@ foreach ($righe as $riga) {
// Descrizione // Descrizione
$descrizione = nl2br($riga->descrizione); $descrizione = nl2br($riga->descrizione);
if ($riga->isArticolo()) { if ($riga->isArticolo()) {
$descrizione = Modules::link('Articoli', $riga->idarticolo, $riga->articolo->codice.' - '.$descrizione); $descrizione = Modules::link('Articoli', $riga->idarticolo, $riga->codice.' - '.$descrizione);
} }
echo ' echo '

View File

@@ -137,6 +137,7 @@ switch (post('op')) {
} else { } else {
$originale = ArticoloOriginale::find(post('idarticolo')); $originale = ArticoloOriginale::find(post('idarticolo'));
$articolo = Articolo::build($ddt, $originale); $articolo = Articolo::build($ddt, $originale);
$articolo->id_dettaglio_fornitore = post('id_dettaglio_fornitore') ?: null;
} }
$articolo->descrizione = post('descrizione'); $articolo->descrizione = post('descrizione');

View File

@@ -45,7 +45,8 @@ foreach ($righe as $riga) {
<td>'; <td>';
if ($riga->isArticolo()) { if ($riga->isArticolo()) {
echo Modules::link('Articoli', $riga->idarticolo, $riga->articolo->codice.' - '.$riga->descrizione); echo '
'.Modules::link('Articoli', $riga->idarticolo, $riga->codice.' - '.$riga->descrizione);
} else { } else {
echo nl2br($riga->descrizione); echo nl2br($riga->descrizione);
} }

View File

@@ -395,6 +395,7 @@ switch (post('op')) {
} else { } else {
$originale = ArticoloOriginale::find(post('idarticolo')); $originale = ArticoloOriginale::find(post('idarticolo'));
$articolo = Articolo::build($fattura, $originale); $articolo = Articolo::build($fattura, $originale);
$articolo->id_dettaglio_fornitore = post('id_dettaglio_fornitore') ?: null;
} }
$qta = post('qta'); $qta = post('qta');

View File

@@ -80,7 +80,7 @@ foreach ($righe as $riga) {
if ($riga->isArticolo()) { if ($riga->isArticolo()) {
echo ' echo '
'.Modules::link('Articoli', $riga->idarticolo, $riga->articolo->codice.' - '.$riga->descrizione); '.Modules::link('Articoli', $riga->idarticolo, $riga->codice.' - '.$riga->descrizione);
} else { } else {
echo nl2br($riga->descrizione); echo nl2br($riga->descrizione);
} }

View File

@@ -211,6 +211,7 @@ $riga = $intervento->getRiga($type, $id_riga);
} else { } else {
$originale = ArticoloOriginale::find(post('idarticolo')); $originale = ArticoloOriginale::find(post('idarticolo'));
$articolo = Articolo::build($intervento, $originale); $articolo = Articolo::build($intervento, $originale);
$articolo->id_dettaglio_fornitore = post('id_dettaglio_fornitore') ?: null;
} }
$qta = post('qta'); $qta = post('qta');

View File

@@ -43,7 +43,7 @@ if (!$righe->isEmpty()) {
if ($mancanti > 0) { if ($mancanti > 0) {
$extra = 'class="warning"'; $extra = 'class="warning"';
} }
$descrizione = (!empty($riga->articolo) ? $riga->articolo->codice.' - ' : '').$riga['descrizione']; $descrizione = (!empty($riga->articolo) ? $riga->codice.' - ' : '').$riga['descrizione'];
echo ' echo '
<tr '.$extra.'> <tr '.$extra.'>

View File

@@ -118,6 +118,7 @@ switch (post('op')) {
} else { } else {
$originale = ArticoloOriginale::find(post('idarticolo')); $originale = ArticoloOriginale::find(post('idarticolo'));
$articolo = Articolo::build($ordine, $originale); $articolo = Articolo::build($ordine, $originale);
$articolo->id_dettaglio_fornitore = post('id_dettaglio_fornitore') ?: null;
} }
$articolo->descrizione = post('descrizione'); $articolo->descrizione = post('descrizione');
@@ -357,11 +358,20 @@ switch (post('op')) {
$copia = $riga->replicate(); $copia = $riga->replicate();
$copia->setParent($ordine); $copia->setParent($ordine);
$riga->original_id = null; // Ripristino dei valori di default per campi potenzialmente impostati
$riga->original_type = null; $copia->original_id = null;
$riga->qta_evasa = 0; $copia->original_type = null;
$copia->qta = $qta;
$copia->qta_evasa = 0;
$copia->costo_unitario = 0;
$copia->setSconto(0, 'EUR');
$riga->qta = $qta; // Impostazione al prezzo di acquisto per Articoli
if ($copia->isArticolo()) {
$articolo = $copia->articolo;
$fornitore = $articolo->dettaglioFornitore($anagrafica->id); // Informazioni del fornitore
$copia->setPrezzoUnitario($fornitore ? $fornitore->prezzo_acquisto : $articolo->prezzo_acquisto, $copia->aliquota->id);
}
$copia->save(); $copia->save();
} }

View File

@@ -50,7 +50,7 @@ foreach ($righe as $riga) {
if ($riga->isArticolo()) { if ($riga->isArticolo()) {
echo ' echo '
'.Modules::link('Articoli', $riga->idarticolo, $riga->articolo->codice.' - '.$riga->descrizione); '.Modules::link('Articoli', $riga->idarticolo, $riga->codice.' - '.$riga->descrizione);
} else { } else {
echo nl2br($riga->descrizione); echo nl2br($riga->descrizione);
} }

View File

@@ -147,6 +147,7 @@ switch (post('op')) {
} else { } else {
$originale = ArticoloOriginale::find(post('idarticolo')); $originale = ArticoloOriginale::find(post('idarticolo'));
$articolo = Articolo::build($preventivo, $originale); $articolo = Articolo::build($preventivo, $originale);
$articolo->id_dettaglio_fornitore = post('id_dettaglio_fornitore') ?: null;
} }
$qta = post('qta'); $qta = post('qta');

View File

@@ -31,7 +31,7 @@ foreach ($righe as $riga) {
// Descrizione // Descrizione
$descrizione = nl2br($riga->descrizione); $descrizione = nl2br($riga->descrizione);
if ($riga->isArticolo()) { if ($riga->isArticolo()) {
$descrizione = Modules::link('Articoli', $riga->idarticolo, $riga->articolo->codice.' - '.$descrizione); $descrizione = Modules::link('Articoli', $riga->idarticolo, $riga->codice.' - '.$descrizione);
} }
echo ' echo '
<td> <td>

View File

@@ -1155,7 +1155,7 @@ class FatturaElettronica
$codice_articolo = [ $codice_articolo = [
'CodiceTipo' => 'COD', 'CodiceTipo' => 'COD',
'CodiceValore' => $riga->articolo->codice, 'CodiceValore' => $riga->codice,
]; ];
$dettaglio['CodiceArticolo'] = $codice_articolo; $dettaglio['CodiceArticolo'] = $codice_articolo;

View File

@@ -0,0 +1,47 @@
<?php
use Modules\Anagrafiche\Anagrafica;
use Modules\Articoli\Articolo;
use Plugins\FornitoriArticolo\Dettaglio;
include_once __DIR__.'/../../core.php';
switch (filter('op')) {
case 'update_fornitore':
$id_articolo = filter('id_articolo');
$articolo = Articolo::find($id_articolo);
$id_anagrafica = filter('id_anagrafica');
$precedente = Dettaglio::where('id_articolo', $id_record)
->where('id_fornitore', $id_anagrafica)
->first();
if (empty($precedente)) {
$anagrafica = Anagrafica::find($id_anagrafica);
$fornitore = Dettaglio::build($anagrafica, $articolo);
} else {
$fornitore = $precedente->replicate();
$precedente->delete();
}
$fornitore->codice_fornitore = post('codice_fornitore');
$fornitore->descrizione = post('descrizione');
$fornitore->prezzo_acquisto = post('prezzo_acquisto');
$fornitore->qta_minima = post('qta_minima');
$fornitore->giorni_consegna = post('giorni_consegna');
$fornitore->save();
flash()->info(tr('Informazioni salvate correttamente!'));
break;
case 'delete_fornitore':
$id_riga = post('id_riga');
$fornitore = Dettaglio::find($id_riga);
$fornitore->delete();
flash()->info(tr('Relazione articolo-fornitore rimossa correttamente!'));
break;
}

View File

@@ -0,0 +1,118 @@
<?php
use Plugins\FornitoriArticolo\Dettaglio;
include_once __DIR__.'/../../core.php';
echo '
<p>'.tr("In questa sezione è possibile definire le caratteristiche di base dell'articolo in relazione fornitore di origine, come codice e prezzo di acquisto predefinito").'. '.tr("Queste informazioni saranno utilizzate in automatico per la compilazione dell'articolo al momento dell'inserimento in un documento di acquisto relativo al fornitore indicato, sovrascrivendo le impostazioni predefinite della sezione Acquisto per l'articolo").'.</p>
<p>'.tr("Ogni fornitore, tra cui si evidenzia quello predefinito per l'articolo, può essere descritto una sola volta con le informazioni aggiuntive").'.</p>
<div class="box">
<div class="box-header">
<h3 class="box-title">'.tr('Nuovo fornitore').'</h3>
</div>
<div class="box-body">
<div class="row">
<div class="col-md-9">
{[ "type": "select", "label": "'.tr('Fornitore').'", "name": "id_fornitore_informazioni", "required": 1, "ajax-source": "fornitori", "value": "" ]}
</div>
<div class="col-md-3">
<button type="button" class="btn btn-primary btn-block" style="margin-top:25px;" onclick="add_fornitore()">
<i class="fa fa-plus"></i> '.tr('Aggiungi').'
</button>
</div>
</div>
</div>
</div>';
$fornitori = Dettaglio::where('id_articolo', $id_record)->get();
if (!$fornitori->isEmpty()) {
echo '
<h4>'.tr('Elenco fornitori').'</h4>
<table class="table table-striped table-condensed table-bordered">
<thead>
<tr>
<th>'.tr('Fornitore').'</th>
<th width="150">'.tr('Codice').'</th>
<th>'.tr('Descrizione').'</th>
<th class="text-center" width="210">'.tr('Q.tà minima ordinabile').'</th>
<th class="text-center" width="150">'.tr('Tempi di consegna').'</th>
<th class="text-center" width="150">'.tr('Prezzo acquisto').'</th>
<th class="text-center" width="70"></th>
</tr>
</thead>
<tbody>';
foreach ($fornitori as $fornitore) {
$anagrafica = $fornitore->anagrafica;
echo '
<tr '.( ($anagrafica->id == $articolo->id_fornitore) ? 'class="success"' : '' ).'>
<td>
'.Modules::link('Anagrafiche', $anagrafica->id, $anagrafica->ragione_sociale).'
</td>
<td class="text-center">
'.$fornitore['codice_fornitore'].'
</td>
<td>
'.$fornitore['descrizione'].'
</td>
<td class="text-right">
'.numberFormat($fornitore['qta_minima']).' '.$fornitore->articolo->um.'
</td>
<td class="text-right">
'.tr('_NUM_ gg', [
'_NUM_' => numberFormat($fornitore['giorni_consegna'], 0),
]).'
</td>
<td class="text-right">
<span>'.moneyFormat($fornitore['prezzo_acquisto']).'</span>
</td>
<td class="text-center">
<a class="btn btn-secondary btn-xs btn-warning" onclick="edit_fornitore('.$fornitore['id'].', '.$anagrafica->id.')">
<i class="fa fa-edit"></i>
</a>
<a class="btn btn-secondary btn-xs btn-danger ask" data-op="delete_fornitore" data-id_riga="'.$fornitore['id'].'" data-id_plugin="'.$id_plugin.'" data-backto="record-edit">
<i class="fa fa-trash-o"></i>
</a>
</td>
</tr>';
}
echo '
</tbody>
</table>';
} else {
echo '
<div class="alert alert-info">
<i class="fa fa-info-circle"></i> '.tr('Nessuna informazione disponibile').'...
</div>';
}
echo '
<script>
function edit_fornitore(id_riga, id_anagrafica) {
openModal("Modifica dati fornitore", "'.$structure->fileurl('edit_fornitore.php').'?id_plugin='.$id_plugin.'&id_module='.$id_module.'&id_parent='.$id_record.'&id_articolo='.$id_record.'&id_riga=" + id_riga + "&id_anagrafica=" + id_anagrafica);
}
function add_fornitore() {
var id_fornitore = $("#id_fornitore_informazioni").val();
if (id_fornitore){
edit_fornitore("", id_fornitore);
} else {
swal("'.tr('Errore').'", "'.tr('Nessun fornitore selezionato').'", "error");
}
}
</script>';

View File

@@ -0,0 +1,74 @@
<?php
use Modules\Anagrafiche\Anagrafica;
use Modules\Articoli\Articolo;
use Plugins\FornitoriArticolo\Dettaglio;
include_once __DIR__.'/../../core.php';
$id_articolo = get('id_articolo');
$articolo = Articolo::find($id_articolo);
$id_anagrafica = get('id_anagrafica');
$anagrafica = Anagrafica::find($id_anagrafica);
$id_riga = get('id_riga');
$fornitore = [];
if (!empty($id_riga)) {
$fornitore = Dettaglio::find($id_riga);
} else {
$fornitore = $articolo->dettaglioFornitore($id_anagrafica);
}
echo '
<p>'.tr('Informazioni relative al fornitore _NAME_', [
'_NAME_' => $anagrafica->ragione_sociale,
]).'.</p>
<form action="" method="post">
<input type="hidden" name="backto" value="record-edit">
<input type="hidden" name="op" value="update_fornitore">
<input type="hidden" name="id_plugin" value="'.$id_plugin.'">
<input type="hidden" name="id_riga" value="'.$id_riga.'">
<input type="hidden" name="id_anagrafica" value="'.$id_anagrafica.'">
<input type="hidden" name="id_articolo" value="'.$id_articolo.'">
<div class="row">
<div class="col-md-12">
{[ "type": "text", "label": "'.tr('Codice fornitore').'", "name": "codice_fornitore", "required": 1, "value": "'.$fornitore['codice_fornitore'].'" ]}
</div>
</div>
<div class="row">
<div class="col-md-12">
{[ "type": "textarea", "label": "'.tr('Descrizione').'", "name": "descrizione", "required": 1, "value": "'.$fornitore['descrizione'].'" ]}
</div>
</div>
<div class="row">
<div class="col-md-4">
{[ "type": "number", "label": "'.tr('Prezzo acquisto').'", "name": "prezzo_acquisto", "required": 1, "value": "'.$fornitore['prezzo_acquisto'].'", "icon-after": "&euro;" ]}
</div>
<div class="col-md-4">
{[ "type": "number", "label": "'.tr('Qta minima ordinabile').'", "name": "qta_minima", "required": 0, "value": "'.$fornitore['qta_minima'].'", "icon-after": "'.$articolo->um.'" ]}
</div>
<div class="col-md-4">
{[ "type": "text", "label": "'.tr('Tempi di consegna').'", "name": "giorni_consegna", "class": "text-right", "required": 0, "value": "'.$fornitore['giorni_consegna'].'", "icon-after": "'.tr('gg').'" ]}
</div>
</div>
<div class="clearfix"></div>
<div class="row">
<div class="col-md-12">
<button class="btn btn-primary pull-right">
<i class="fa fa-edit"></i> '.tr('Modifica').'
</button>
</div>
</div>
</form>
<script>$(document).ready(init);</script>';

View File

@@ -0,0 +1,49 @@
<?php
namespace Plugins\FornitoriArticolo;
use Common\Model;
use Illuminate\Database\Eloquent\SoftDeletes;
use Modules\Anagrafiche\Anagrafica;
use Modules\Articoli\Articolo;
/**
* Classe per la gestione delle relazioni tra articolo e fornitore.
*
* @since 2.4.15
*/
class Dettaglio extends Model
{
use SoftDeletes;
protected $table = 'mg_fornitore_articolo';
/**
* Crea una nuova relazione tra Articolo e Fornitore.
*
* @return self
*/
public static function build(Anagrafica $fornitore, Articolo $articolo)
{
$model = parent::build();
$model->anagrafica()->associate($fornitore);
$model->articolo()->associate($articolo);
$model->save();
return $model;
}
// Relazioni Eloquent
public function anagrafica()
{
return $this->belongsTo(Anagrafica::class, 'id_fornitore');
}
public function articolo()
{
return $this->belongsTo(Articolo::class, 'id_articolo');
}
}

View File

@@ -192,6 +192,7 @@ switch ($operazione) {
} else { } else {
$originale = ArticoloOriginale::find(post('idarticolo')); $originale = ArticoloOriginale::find(post('idarticolo'));
$articolo = Articolo::build($promemoria, $originale); $articolo = Articolo::build($promemoria, $originale);
$articolo->id_dettaglio_fornitore = post('id_dettaglio_fornitore') ?: null;
} }
$qta = post('qta'); $qta = post('qta');

View File

@@ -44,7 +44,7 @@ if (!$righe->isEmpty()) {
if ($mancanti > 0) { if ($mancanti > 0) {
$extra = 'class="warning"'; $extra = 'class="warning"';
} }
$descrizione = (!empty($riga->articolo) ? $riga->articolo->codice.' - ' : '').$riga['descrizione']; $descrizione = (!empty($riga->articolo) ? $riga->codice.' - ' : '').$riga['descrizione'];
echo ' echo '
<tr '.$extra.'> <tr '.$extra.'>

View File

@@ -106,7 +106,7 @@ foreach ($righe as $riga) {
if ($riga->isArticolo()) { if ($riga->isArticolo()) {
// Codice articolo // Codice articolo
$text = tr('COD. _COD_', [ $text = tr('COD. _COD_', [
'_COD_' => $riga->articolo->codice, '_COD_' => $riga->codice,
]); ]);
echo ' echo '
<br><small>'.$text.'</small>'; <br><small>'.$text.'</small>';

View File

@@ -53,7 +53,7 @@ foreach ($righe as $riga) {
if ($riga->isArticolo()) { if ($riga->isArticolo()) {
// Codice articolo // Codice articolo
$text = tr('COD. _COD_', [ $text = tr('COD. _COD_', [
'_COD_' => $riga->articolo->codice, '_COD_' => $riga->codice,
]); ]);
echo ' echo '
<br><small>'.$text.'</small>'; <br><small>'.$text.'</small>';

View File

@@ -53,7 +53,7 @@ foreach ($righe as $riga) {
if ($riga->isArticolo()) { if ($riga->isArticolo()) {
// Codice articolo // Codice articolo
$text = tr('COD. _COD_', [ $text = tr('COD. _COD_', [
'_COD_' => $riga->articolo->codice, '_COD_' => $riga->codice,
]); ]);
echo ' echo '
<br><small>'.$text.'</small>'; <br><small>'.$text.'</small>';

View File

@@ -162,7 +162,7 @@ if (!$righe->isEmpty()) {
if ($riga->isArticolo()) { if ($riga->isArticolo()) {
// Codice articolo // Codice articolo
$text = tr('COD. _COD_', [ $text = tr('COD. _COD_', [
'_COD_' => $riga->articolo->codice, '_COD_' => $riga->codice,
]); ]);
echo ' echo '
<br><small>'.$text.'</small>'; <br><small>'.$text.'</small>';

View File

@@ -79,7 +79,7 @@ foreach ($righe as $riga) {
if ($riga->isArticolo()) { if ($riga->isArticolo()) {
// Codice articolo // Codice articolo
$text = tr('COD. _COD_', [ $text = tr('COD. _COD_', [
'_COD_' => $riga->articolo->codice, '_COD_' => $riga->codice,
]); ]);
echo ' echo '
<br><small>'.$text.'</small>'; <br><small>'.$text.'</small>';

View File

@@ -153,7 +153,7 @@ foreach ($righe as $riga) {
if ($riga->isArticolo()) { if ($riga->isArticolo()) {
// Codice articolo // Codice articolo
$text = tr('COD. _COD_', [ $text = tr('COD. _COD_', [
'_COD_' => $riga->articolo->codice, '_COD_' => $riga->codice,
]); ]);
echo ' echo '
<br><small>'.$text.'</small>'; <br><small>'.$text.'</small>';

View File

@@ -63,3 +63,37 @@ CREATE TABLE IF NOT EXISTS `co_riferimenti_righe` (
`target_id` int(11) NOT NULL, `target_id` int(11) NOT NULL,
PRIMARY KEY (`id`) PRIMARY KEY (`id`)
) ENGINE=InnoDB; ) ENGINE=InnoDB;
-- Aggiunta relazione tra articoli e fornitori
CREATE TABLE IF NOT EXISTS `mg_fornitore_articolo` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`id_articolo` int(11) NOT NULL,
`id_fornitore` int(11) NOT NULL,
`codice_fornitore` varchar(255) NOT NULL,
`descrizione` varchar(255) NOT NULL,
`prezzo_acquisto` decimal(15, 6) NOT NULL,
`qta_minima` decimal(15, 6) NOT NULL,
`giorni_consegna` int(11) NOT NULL,
`deleted_at` TIMESTAMP NULL DEFAULT NULL,
PRIMARY KEY (`id`),
FOREIGN KEY (`id_articolo`) REFERENCES `mg_articoli`(`id`) ON DELETE CASCADE,
FOREIGN KEY (`id_fornitore`) REFERENCES `an_anagrafiche`(`idanagrafica`) ON DELETE CASCADE
);
INSERT INTO `zz_plugins` (`id`, `name`, `title`, `idmodule_from`, `idmodule_to`, `position`, `directory`, `options`) VALUES
(NULL, 'Fornitori Articolo', 'Fornitori', (SELECT `id` FROM `zz_modules` WHERE `name`='Articoli'), (SELECT `id` FROM `zz_modules` WHERE `name`='Articoli'), 'tab', 'fornitori_articolo', 'custom');
ALTER TABLE `or_righe_ordini` ADD `id_dettaglio_fornitore` int(11) NULL,
ADD FOREIGN KEY (`id_dettaglio_fornitore`) REFERENCES `mg_fornitore_articolo`(`id`) ON DELETE SET NULL;
ALTER TABLE `dt_righe_ddt` ADD `id_dettaglio_fornitore` int(11) NULL,
ADD FOREIGN KEY (`id_dettaglio_fornitore`) REFERENCES `mg_fornitore_articolo`(`id`) ON DELETE SET NULL;
ALTER TABLE `co_righe_preventivi` ADD `id_dettaglio_fornitore` int(11) NULL,
ADD FOREIGN KEY (`id_dettaglio_fornitore`) REFERENCES `mg_fornitore_articolo`(`id`) ON DELETE SET NULL;
ALTER TABLE `co_righe_contratti` ADD `id_dettaglio_fornitore` int(11) NULL,
ADD FOREIGN KEY (`id_dettaglio_fornitore`) REFERENCES `mg_fornitore_articolo`(`id`) ON DELETE SET NULL;
ALTER TABLE `co_righe_documenti` ADD `id_dettaglio_fornitore` int(11) NULL,
ADD FOREIGN KEY (`id_dettaglio_fornitore`) REFERENCES `mg_fornitore_articolo`(`id`) ON DELETE SET NULL;
ALTER TABLE `in_righe_interventi` ADD `id_dettaglio_fornitore` int(11) NULL,
ADD FOREIGN KEY (`id_dettaglio_fornitore`) REFERENCES `mg_fornitore_articolo`(`id`) ON DELETE SET NULL;
ALTER TABLE `co_righe_promemoria` ADD `id_dettaglio_fornitore` int(11) NULL,
ADD FOREIGN KEY (`id_dettaglio_fornitore`) REFERENCES `mg_fornitore_articolo`(`id`) ON DELETE SET NULL;

View File

@@ -76,6 +76,7 @@ return [
'in_tipiintervento', 'in_tipiintervento',
'in_vociservizio', 'in_vociservizio',
'mg_articoli', 'mg_articoli',
'mg_fornitore_articolo',
'mg_categorie', 'mg_categorie',
'mg_causali_movimenti', 'mg_causali_movimenti',
'mg_listini', 'mg_listini',