Skip to content

Distributori di Carburante

In questo calcolo verranno affrontati due importi: uno per il calcolo del canone dovuto e l'altro per il calcolo dell'eventuale eccedenza COSAP da versare ( dato dalla differenza positiva tra il costo dell'eventuale occupazione con passo carrabile per l'accesso al distributore ed il canone) I dati necessari ai fini del calcolo vengono richiesti tramite una scheda dinamicha nel Front-End e sono i seguenti:

Parametro Descrizione
Tipo di impianto Tipologia dell'impianto per cui si stà presentando la domanda( es. Stazione di servizio, Stazione senza gasolio, Distributori isolati, ... )
Localizzazione Localizzazione dell'intervento composta da Via, Km e Metro
Quote aggiuntive Eventuali quote aggiuntive a seconda che si tratti di colonnine a singola pompa, colonnine con erogazione su entrambi i lati, colonnine di erogazione multiprodotto
Servizi accessori Nell'area di servizio potrebbero essere presenti servizi accessori quali Bar, Ristoranti, Albergo, etc. che potrebbero avere dei coefficienti moltiplicativi aggiuntivi
MQ Passi carrabili MQ di passi carrabili di accesso al distributore. Utilizzati per il calcolo dell'eventuale eccedenza COSAP

In base a questi parametri vengono create delle mappature che portano a degli importi e/o a dei coefficienti moltiplicativi. Fare riferimento alla configurazione fatta per il CSI e riportata più avanti per degli esempi concreti

Algoritmi di calcolo

Il Canone dei distributori è stato calcolato secondo questo algoritmo ( [Tariffa derivante dalla tipologia di impianto e categoria di strada] + (Numero distributori singoli * relativa tariffa ) + (Numero distributori doppi * relativa tariffa ) + ( Numero distributori doppi * relativa tariffa ) ) * Coefficiente servizi accessori

Il Canone COSAP per i passi carrabili viene calcolato semplicemente per poi verificare se c'è un eccedenza COSAP tra questo e il canone dei distributori. Non viene registrato come pendenza ma viene comunque calcolato secondo questo algoritmo [somma Mq passi carrabili * tariffa corrispondente]

L'Eccedenza COSAP viene calcolata con questo algoritmo [Canone COSAP per i passi carrabili - Canone dei distributori] e diventa onere solamente se maggiore di 0

Calcolo della scadenza

Gli importi sopra calcolati, hanno scadenze diverse e sono 31/03 per quanto riguarda l'eccedenza COSAP e 30/06 per il canone dei distributori. Anche queste scadenze vengono impostate e gestite tramite le formule in una scheda dinamica di Backoffice che effettua il calcolo

Scheda dinamica per il calcolo

Di seguito verranno illustrate le formule utilizzate. Tali formule potrebbero subire variazioni nel corso del tempo che non verranno riportate in questo documento per cui trattarle semplicemente come spunto

Formule condivise

Sono state definite una serie di costanti che identificano le causali oneri da utilizzare, le tipologie di aree che contengono le categorie delle strade e altri messaggi. In generale contengono tutti i valori fissi che potrebbero variare nel tempo

private static class Constants
{
    public const int IdCausaleCanone = 2;
    public const int IdCausaleEccedenzaCOSAP = 3;
    public const int CodiceTipoAreaCanone = 3;
    public const int CodiceTipoAreaCosap = 4;
    public const string ErogazioneSingoloUnLato = "Distributori erogazione singolo prodotto su un lato";
    public const string ErogazioneSingoloDueLati = "Distributori erogazione singolo prodotto su due lati";
    public const string ErogazioneMultiplaUnLato = "Distributori erogazione multiprodotto su un lato";
    public const string ErogazioneMultiplaDueLati = "Distributori erogazione multiprodotto su due lati";
}

viene definito un'array composto dalle causali oneri previste per verificare se c'è stato qualche pagamento che non permetterebbe più di rifare il calcolo

public IEnumerable<int> getCausali()
{
    return new[] { Constants.IdCausaleCanone, Constants.IdCausaleEccedenzaCOSAP };

}

viene identificata la struttura che identifica il numero di colonnine singole, doppie e multiprodotto

public class TipologiaColonnine {
    public int Singolo { get; set; }
    public int Doppio { get; set; }
    public int Multiprodotto { get; set; }

    public TipologiaColonnine(){
        this.Singolo = 0;
        this.Doppio = 0;
        this.Multiprodotto = 0;
    }
}

Di seguito viene mostrata la funzione richiamata al caricamento della scheda per impostare i valori iniziali

public void InizializzaScheda()
{
    TrovaCampo("COSAP-CATEGORIA-STRADA").ListaValori[0].Valore = this.getCategoriaStrada(Constants.CodiceTipoAreaCanone).Denominazione;
    TrovaCampo("COSAP-CATEGORIA-STRADA-COSAP").ListaValori[0].Valore = this.getCategoriaStrada(Constants.CodiceTipoAreaCosap).Denominazione;

    if( TrovaCampo("COSAP-SERVIZI-ACCESSORI-ID").ListaValori[0].GetValoreODefault("") == "" ) {
        var campoId = TrovaCampo("COSAP-SERVIZI-ACCESSORI-ID");


        var campoDescrizione = TrovaCampo("COSAP-SERVIZI-ACCESSORI-DESCRIZIONE");
        var i = 0;
        var serviziAccessori = GetDecodificheAttive("SERACC");

        foreach( var servizio in serviziAccessori ){
            campoId.ListaValori[i].Valore = servizio.Chiave;
            campoDescrizione.ListaValori[i].Valore = servizio.Valore;
            i++;        
        }
    }

}

Il metodo che effettua le chiamate pe il calcolo vero e proprio

public void CalcolaOneri(){

    var idCategoriaStradaDistr = getCategoriaStrada(Constants.CodiceTipoAreaCanone).CodiceArea.ToString();
    var idCategoriaStradaCosap = getCategoriaStrada(Constants.CodiceTipoAreaCosap).CodiceArea.ToString();
    var idTipoImpianto = TrovaCampo("COSAP-TIPO-IMPIANTO").GetValoreODefault("");
    var idServiziAccessori = serviziAccessoriPresenti();

    var colonnine = GetTipologiaColonnine();

    var mqPassiCarrabili = GetMQPassiCarrabili();

    var service = new Init.SIGePro.Manager.Logic.Cosap.CSIPiemonte.DistributoriCarburante.CalcoloCosapDistributoriCarburanteService();
    var request = getRequest(idTipoImpianto,idCategoriaStradaDistr, idCategoriaStradaCosap, colonnine, mqPassiCarrabili, idServiziAccessori);
    var authInfo = CheckToken();

    var importi = service.CalcolaImporti(request, authInfo);

    //IMPORTI
    TrovaCampo("COSAP-IMPORTO-CANONE-DISTRIBUTORI").Valore = importi.Canone.Importo.ToString();
    TrovaCampo("COSAP-IMPORTO-PASSI-CARRABILI").Valore = importi.PassiCarrabili.Importo.ToString();
    TrovaCampo("COSAP-IMPORTO-ECCEDENZA").Valore = importi.Eccedenza.Importo.ToString();

    //DESCRIZIONI
    TrovaCampo("COSAP-CALCOLO-CANONE-DISTRIBUTORI").Valore = importi.Canone.SpiegazioneFormula;
    TrovaCampo("COSAP-CALCOLO-PASSI-CARRABILI").Valore = importi.PassiCarrabili.SpiegazioneFormula + " ( IMPORTO NON DOVUTO )";
    TrovaCampo("COSAP-CALCOLO-ECCEDENZA").Valore = importi.Eccedenza.SpiegazioneFormula + ( (importi.Eccedenza.Importo.Valore <= 0) ? " ( IMPORTO NON DOVUTO )" : "");
}

il metodo sopra, ad un certo punto deve raccogliere i parametri per il calcolo e passarli alla libreria .NET che effettua il calcolo. La raccolta dei parametri avviene con una chiamata al metodo seguente

private Init.SIGePro.Manager.Logic.Cosap.CSIPiemonte.DistributoriCarburante.CalcolaImportiRequest getRequest(string tipologiaDistributore,string categoriaStradaDistributore, string categoriaStradaCosap,TipologiaColonnine colonnine, double mqPassiCarrabili,IEnumerable<string> serviziAccessori )
{

    var distributoriSingoli = colonnine.Singolo;
    var distributoriDoppi = colonnine.Doppio;
    var distributoriMultiprodotto = colonnine.Multiprodotto;

    var request = new Init.SIGePro.Manager.Logic.Cosap.CSIPiemonte.DistributoriCarburante.CalcolaImportiRequest(tipologiaDistributore, categoriaStradaDistributore, categoriaStradaCosap, distributoriSingoli, distributoriDoppi, distributoriMultiprodotto, mqPassiCarrabili, serviziAccessori);

    return request;
}

il metodo seguente invece inserisce gli oneri nella pratica

public void InserisciOnere( )
{
    var scadenzaCanone = this.getDataScadenzaCanone();
    var scadenzaEccedenzaCOSAP = this.getDataScadenzaEccedenzaCOSAP();
    var codiceIstanza = Convert.ToInt32( IstanzaCorrente.CODICEISTANZA );

    var oneri = new List<Init.SIGePro.Manager.Logic.GestioneOneri.OnereDaRegistrare>();

    //importo canone
    var importoCanone = TrovaCampo("COSAP-IMPORTO-CANONE-DISTRIBUTORI").GetValoreODefault(0.0d);
    if( importoCanone > 0 )
    {   
        oneri.Add(new Init.SIGePro.Manager.Logic.GestioneOneri.OnereDaRegistrare( codiceIstanza, Constants.IdCausaleCanone, importoCanone, scadenzaCanone ));
    }

    //eccedenza COSAP
    var eccedenzaCOSAP = TrovaCampo("COSAP-IMPORTO-ECCEDENZA").GetValoreODefault(0.0d);
    if( eccedenzaCOSAP > 0 )
    {   
        oneri.Add(new Init.SIGePro.Manager.Logic.GestioneOneri.OnereDaRegistrare( codiceIstanza, Constants.IdCausaleEccedenzaCOSAP, eccedenzaCOSAP, scadenzaEccedenzaCOSAP ));
    }

    var authInfo = CheckToken();
    new Init.SIGePro.Manager.Logic.GestioneOneri.OneriService(authInfo).AggiornaOInserisciByIdCausale(oneri);


    //richiamare la registrazione degli oneri
    TrovaCampo("COSAP-ONERI-INVIATI").Valore = "Oneri registrati correttamente in data " + DateTime.Now.ToString("dd/MM/yyyy");

    ModelloCorrente.Salva();
    ModelloCorrente.RichiediReloadInterfaccia();
}

per verificare se c'è almeno un onere pagato tra quelli utilizzati dal calcolo viene utilizzato il seguente metodo

public bool OnerePagato()
{

    var authInfo = CheckToken();
    var codiceIstanza = Convert.ToInt32( IstanzaCorrente.CODICEISTANZA );
    var idCausali = getCausali();

    return new Init.SIGePro.Manager.Logic.GestioneOneri.OneriService(authInfo).AlmenoUnOnerePagato(codiceIstanza, idCausali);

}

e infine tutta la lista di metodi accessori creati per semplificare la lettura delle formule in un ambito complesso come questo

private IEnumerable<String> serviziAccessoriPresenti(){

    var lista = new List<String>();
    var serviziAccessoriId = TrovaCampo("COSAP-SERVIZI-ACCESSORI-ID");
    var serviziAccessoriPresenti = TrovaCampo("COSAP-SERVIZI-ACCESSORI-PRESENTE");

    for( var i = 0; i<serviziAccessoriPresenti.ListaValori.Count; i++ ){
        if( serviziAccessoriPresenti.ListaValori[i].GetValoreODefault(0) == 1 ){
            lista.Add( serviziAccessoriId.ListaValori[i].Valore );
        }
    }

    return lista;
}

private DateTime getDataScadenzaCanone(){
    string data = "30/06/" + DateTime.Now.Year.ToString();
    var dataScadenza = DateTime.ParseExact(data, "dd/MM/yyyy",null);

    if( DateTime.Compare( dataScadenza, DateTime.Now ) < 0 )
    {
        return dataScadenza.AddYears(1);
    }

    return dataScadenza;
}

private DateTime getDataScadenzaEccedenzaCOSAP(){
    string data = "31/03/" + DateTime.Now.Year.ToString();
    var dataScadenza = DateTime.ParseExact(data, "dd/MM/yyyy",null);

    if( DateTime.Compare( dataScadenza, DateTime.Now ) < 0 )
    {
        return dataScadenza.AddYears(1);
    }

    return dataScadenza;
}

public TipologiaColonnine GetTipologiaColonnine(){

    var colonnine = new TipologiaColonnine();
    var ColonnineNumero = TrovaCampo("DISTRIBUTORE_SERBATOI_NUMERO").ListaValori;
    var ColonnineTipo = TrovaCampo("DISTRIBUTORE_COLONNINE_EROGAZIONE_TIPOLOGIA").ListaValori;

    for(var i = 0; i < ColonnineNumero.Count; i++) {

        var qt = ColonnineNumero[i].GetValoreODefault(0);

        switch( ColonnineTipo[i].GetValoreODefault("")  ) 
        {
            case Constants.ErogazioneSingoloUnLato:
                colonnine.Singolo += qt;
                break;
            case Constants.ErogazioneSingoloDueLati:
                colonnine.Doppio += qt;
                break;
            case Constants.ErogazioneMultiplaUnLato:
            case Constants.ErogazioneMultiplaDueLati:
                colonnine.Multiprodotto += qt;
                break;
            default:
                break;
        }
    } 

    return colonnine;
}

public bool OnereCalcolato()
{
    return !String.IsNullOrEmpty(TrovaCampo("COSAP-IMPORTO-CANONE-DISTRIBUTORI").ListaValori[0].GetValoreODefault(""));
}

private double GetMQPassiCarrabili()
{
    var areaMq = TrovaCampo("AREA_MQ").ListaValori[0].GetValoreODefault(0.0d);
    var corsiaMq = TrovaCampo("CORSIA_SUPERFICIE_TOT").ListaValori[0].GetValoreODefault(0.0d);

    return areaMq + corsiaMq;
}

private Init.SIGePro.Manager.Logic.GestioneStradario.DettaglioArea getCategoriaStrada(int codiceTipoArea)
{
    return this.getCategoriaStrada(0,codiceTipoArea);
}

private Init.SIGePro.Manager.Logic.GestioneStradario.DettaglioArea getCategoriaStrada(int indice, int codiceTipoArea)
{
    var codiceStradario = Convert.ToInt32( IstanzaCorrente.IstanzeDyn2Dati.Where( x => x.CampoDinamico.Nomecampo == "LOCALIZZAZIONE_STRADA"  && x.IndiceMolteplicita == indice )
                    .Select( y => y.Valore)
                    .FirstOrDefault() );

    var kmDa = Convert.ToDouble( IstanzaCorrente.IstanzeDyn2Dati.Where( x => x.CampoDinamico.Nomecampo == "LOCALIZZAZIONE_KM_INIZIALE" && x.IndiceMolteplicita == indice )
                    .Select( y => y.Valore)
                    .FirstOrDefault() );

    var metroDa = Convert.ToInt32( IstanzaCorrente.IstanzeDyn2Dati.Where( x => x.CampoDinamico.Nomecampo == "LOCALIZZAZIONE_METRO_INIZIALE" && x.IndiceMolteplicita == indice )
                    .Select( y => y.Valore)
                    .FirstOrDefault());

    var kmA = Convert.ToDouble( IstanzaCorrente.IstanzeDyn2Dati.Where( x => x.CampoDinamico.Nomecampo == "LOCALIZZAZIONE_KM_FINALE" && x.IndiceMolteplicita == indice )
                    .Select( y => y.Valore)
                    .FirstOrDefault() );

    var metroA = Convert.ToInt32( IstanzaCorrente.IstanzeDyn2Dati.Where( x => x.CampoDinamico.Nomecampo == "LOCALIZZAZIONE_METRO_FINALE" && x.IndiceMolteplicita == indice )
                    .Select( y => y.Valore)
                    .FirstOrDefault());


    var request = new Init.SIGePro.Manager.Logic.GestioneStradario.TrovaAreaDaKmAKmRequest( codiceTipoArea, codiceStradario, kmDa, metroDa, kmA, metroA );

    var authInfo = CheckToken();
    var response = new Init.SIGePro.Manager.Logic.GestioneStradario.GestioneAreeService(authInfo).TrovaArea(request);

    if( response == null || response.Count() == 0 )
        return new Init.SIGePro.Manager.Logic.GestioneStradario.DettaglioArea();

    if( response.Count() > 1 )
        throw new Exception( String.Format("Impossibile identificare in maniera univoca la categoria stradale. Trovati {0} risultati", response.Count()));

    return response.FirstOrDefault();
}

Formule al caricamento

Al caricamento della scheda vengono inizializzati i vaolori necessari e mostrati/nascosti i bottoni di calcolo e di pagamento a seconda che l'onere sia già stato pagato oppure sia già stato calcolato

TrovaCampo("COSAP-AREA-SEDIMI-PROP-STRADALE").Valore = "area coperta su sedimi di proprietà stradale";
TrovaCampo("COSAP-DIMENSIONI-CORSIE").Valore = "dimensioni delle corsie di accelerazione/decelerazione";

InizializzaScheda();

if( !OnereCalcolato() ) 
{
    NascondiCampiDinamici(new []{"COSAP-REGISTRA-ONERI"}, 0);
    return 0;
}

if( OnerePagato() )
{
    NascondiCampiDinamici(new []{"COSAP-CALCOLA-ONERI","COSAP-REGISTRA-ONERI"}, 0);
    return 0;
}

Formule alla modifica di un campo

Anche in questo caso vengono mostrati/nascosti campi oppure avviato il calcolo o la registrazione degli oneri

switch( CampoModificato.NomeCampo ){
    case "COSAP-CALCOLA-ONERI": 
        CalcolaOneri();
        MostraCampiDinamici(new []{"COSAP-REGISTRA-ONERI"}, 0);
    break;

    case "COSAP-REGISTRA-ONERI":
        InserisciOnere();
        break;

    default:
        break;
}