using SteamWare;
using System;
using System.Data.SqlClient;
using System.Reflection;

namespace GMW_data
{
  /// <summary>
  /// classe gestione operazioni sul magazzino
  /// </summary>
  public class MagClass
  {
    /// <summary>
    /// Oggetto locale gestione classe datamatrix...
    /// </summary>
    protected DataMatrix DataMatrix_mgr = new DataMatrix();

    #region area table adapters

    // variabile di tipo table adapter
    public DS_magazzinoTableAdapters.AnagMagTableAdapter taAnagMag;
    public DS_magazzinoTableAdapters.BlocchiTableAdapter taBlocchi;
    public DS_magazzinoTableAdapters.CelleTableAdapter taCelle;
    public DS_magazzinoTableAdapters.TipoCellaTableAdapter taTipoCella;
    public DS_magazzinoTableAdapters.ElencoCartelliniTableAdapter taCartellini;
    public DS_magazzinoTableAdapters.PosizioneUdcCorrenteTableAdapter taPosUdcCorr;
    public DS_magazzinoTableAdapters.PosizioneUdcStoricoTableAdapter taPosUdcStorico;
    public DS_magazzinoTableAdapters.V_MagazziniOverviewTableAdapter taMagOverw;
    public DS_magazzinoTableAdapters.V_DettMagPartTableAdapter taDettMagPart;
    public DS_magazzinoTableAdapters.v_UdcDetailTableAdapter taDettUDC;
    public DS_magazzinoTableAdapters.ElencoListePrelievoTableAdapter taElencoListePrelievo;
    public DS_magazzinoTableAdapters.RigheListePrelievoTableAdapter taRigheListePrelievo;
    public DS_magazzinoTableAdapters.TipoListaPrelievoTableAdapter taTipoListaPrelievo;
    public DS_magazzinoTableAdapters.V_ParticolariOverviewTableAdapter taVParticolariOverwiew;
    public DS_magazzinoTableAdapters.v_particolariEsponenteFiguraTableAdapter taPartExpFig;
    public DS_magazzinoTableAdapters.V_statoCelleCapienzaAssegnatiTableAdapter taStatoCelle;
    public DS_magazzinoTableAdapters.RapQualTableAdapter taRapQual;
    public DS_magazzinoTableAdapters.v_RapQualSuntoTableAdapter taRQ_sunto;
    public DS_magazzinoTableAdapters.AnagLegheTableAdapter taAnagLeghe;
    public DS_magazzinoTableAdapters.v_posizioniDelibereTableAdapter taPosizDelib;
    public DS_magazzinoTableAdapters.AnagParticolariTableAdapter taAnagPart;
    public DS_magazzinoTableAdapters.AnagPosizioniTableAdapter taAnagPos;
    public DS_magazzinoTableAdapters.StoricoAzioniOperatoreTableAdapter taSAO;
    public DS_magazzinoTableAdapters.AnagLineeTableAdapter taAL;
    public DS_magazzinoTableAdapters.stp_ParticolareInOutOkTableAdapter taPartIO;
    public DS_magazzinoTableAdapters.Attr2UDCTableAdapter taAtt2UDC;
    public DS_magazzinoTableAdapters.ElencoAssiemiTableAdapter taEA;
    public DS_magazzinoTableAdapters.AL2UDCTableAdapter taAL2UDC;
    public DS_magazzinoTableAdapters.ElencoTrattamentiTableAdapter taET;
    public DS_magazzinoTableAdapters.v_A2U2DTableAdapter taA2U2D;
    public DS_magazzinoTableAdapters.UDC_check4deleteTableAdapter taUdcChk4Del;
    public DS_magazzinoTableAdapters.AnagKitTableAdapter taAK;
    public DS_magazzinoTableAdapters.RelKit2PartTableAdapter taRK2P;
    public DS_magazzinoTableAdapters.ConfLineaTableAdapter taConfLin;


    /// <summary>
    /// init dei table adapters
    /// </summary>
    protected void initTA()
    {
      // istanzio oggetto

      taAnagMag = new DS_magazzinoTableAdapters.AnagMagTableAdapter();
      taBlocchi = new DS_magazzinoTableAdapters.BlocchiTableAdapter();
      taCelle = new DS_magazzinoTableAdapters.CelleTableAdapter();
      taTipoCella = new DS_magazzinoTableAdapters.TipoCellaTableAdapter();
      taCartellini = new DS_magazzinoTableAdapters.ElencoCartelliniTableAdapter();
      taPosUdcCorr = new DS_magazzinoTableAdapters.PosizioneUdcCorrenteTableAdapter();
      taPosUdcStorico = new DS_magazzinoTableAdapters.PosizioneUdcStoricoTableAdapter();
      taMagOverw = new DS_magazzinoTableAdapters.V_MagazziniOverviewTableAdapter();
      taDettMagPart = new DS_magazzinoTableAdapters.V_DettMagPartTableAdapter();
      taDettUDC = new DS_magazzinoTableAdapters.v_UdcDetailTableAdapter();
      taElencoListePrelievo = new DS_magazzinoTableAdapters.ElencoListePrelievoTableAdapter();
      taRigheListePrelievo = new DS_magazzinoTableAdapters.RigheListePrelievoTableAdapter();
      taTipoListaPrelievo = new DS_magazzinoTableAdapters.TipoListaPrelievoTableAdapter();
      taVParticolariOverwiew = new DS_magazzinoTableAdapters.V_ParticolariOverviewTableAdapter();
      taPartExpFig = new DS_magazzinoTableAdapters.v_particolariEsponenteFiguraTableAdapter();
      taStatoCelle = new DS_magazzinoTableAdapters.V_statoCelleCapienzaAssegnatiTableAdapter();
      taRapQual = new DS_magazzinoTableAdapters.RapQualTableAdapter();
      taRQ_sunto = new DS_magazzinoTableAdapters.v_RapQualSuntoTableAdapter();
      taAnagLeghe = new DS_magazzinoTableAdapters.AnagLegheTableAdapter();
      taPosizDelib = new DS_magazzinoTableAdapters.v_posizioniDelibereTableAdapter();
      taAnagPart = new DS_magazzinoTableAdapters.AnagParticolariTableAdapter();
      taAnagPos = new DS_magazzinoTableAdapters.AnagPosizioniTableAdapter();
      taSAO = new DS_magazzinoTableAdapters.StoricoAzioniOperatoreTableAdapter();
      taAL = new DS_magazzinoTableAdapters.AnagLineeTableAdapter();
      taPartIO = new DS_magazzinoTableAdapters.stp_ParticolareInOutOkTableAdapter();
      taAtt2UDC = new DS_magazzinoTableAdapters.Attr2UDCTableAdapter();
      taEA = new DS_magazzinoTableAdapters.ElencoAssiemiTableAdapter();
      taAL2UDC = new DS_magazzinoTableAdapters.AL2UDCTableAdapter();
      taET = new DS_magazzinoTableAdapters.ElencoTrattamentiTableAdapter();
      taA2U2D = new DS_magazzinoTableAdapters.v_A2U2DTableAdapter();
      taUdcChk4Del = new DS_magazzinoTableAdapters.UDC_check4deleteTableAdapter();
      taAK = new DS_magazzinoTableAdapters.AnagKitTableAdapter();
      taRK2P = new DS_magazzinoTableAdapters.RelKit2PartTableAdapter();
      taConfLin = new DS_magazzinoTableAdapters.ConfLineaTableAdapter();
    }
    /// <summary>
    /// effettua setup dei connection strings da web.config delal singola applicazione
    /// </summary>
    protected virtual void setupConnectionStringBase()
    {
      string connString = memLayer.ML.confReadString("GMWConnectionString");
      // connections del db
      taAnagMag.Connection.ConnectionString = connString;
      taBlocchi.Connection.ConnectionString = connString;
      taCelle.Connection.ConnectionString = connString;
      taTipoCella.Connection.ConnectionString = connString;
      taCartellini.Connection.ConnectionString = connString;
      taPosUdcCorr.Connection.ConnectionString = connString;
      taPosUdcStorico.Connection.ConnectionString = connString;
      taMagOverw.Connection.ConnectionString = connString;
      taDettMagPart.Connection.ConnectionString = connString;
      taDettUDC.Connection.ConnectionString = connString;
      taElencoListePrelievo.Connection.ConnectionString = connString;
      taRigheListePrelievo.Connection.ConnectionString = connString;
      taTipoListaPrelievo.Connection.ConnectionString = connString;
      taVParticolariOverwiew.Connection.ConnectionString = connString;
      taPartExpFig.Connection.ConnectionString = connString;
      taStatoCelle.Connection.ConnectionString = connString;
      taRapQual.Connection.ConnectionString = connString;
      taRQ_sunto.Connection.ConnectionString = connString;
      taAnagLeghe.Connection.ConnectionString = connString;
      taPosizDelib.Connection.ConnectionString = connString;
      taAnagPart.Connection.ConnectionString = connString;
      taAnagPos.Connection.ConnectionString = connString;
      taSAO.Connection.ConnectionString = connString;
      taAL.Connection.ConnectionString = connString;
      taPartIO.Connection.ConnectionString = connString;
      taAtt2UDC.Connection.ConnectionString = connString;
      taEA.Connection.ConnectionString = connString;
      taAL2UDC.Connection.ConnectionString = connString;
      taET.Connection.ConnectionString = connString;
      taA2U2D.Connection.ConnectionString = connString;
      taUdcChk4Del.Connection.ConnectionString = connString;
      taAK.Connection.ConnectionString = connString;
      taRK2P.Connection.ConnectionString = connString;
      taConfLin.Connection.ConnectionString = connString;
    }

    #endregion

    #region Inizializzazione

    public MagClass()
    {
      initTA();
      setupConnectionStringBase();

      // aggiunta x gestione timeout esteso (ove necessario)!
      fixCommandTimeout();
    }

    /// <summary>
    /// sistemazione timeout comandi nei tableadapter
    /// </summary>
    private void fixCommandTimeout()
    {
      SetAllCommandTimeouts(taCartellini, memLayer.ML.confReadInt("sqlLongCommandTimeout"));
      SetAllCommandTimeouts(taPosUdcCorr, memLayer.ML.confReadInt("sqlLongCommandTimeout"));
      SetAllCommandTimeouts(taElencoListePrelievo, memLayer.ML.confReadInt("sqlLongCommandTimeout"));
    }
    void SetAllCommandTimeouts(object adapter, int timeout)
    {
      var commands = adapter.GetType().InvokeMember(
              "CommandCollection",
              BindingFlags.GetProperty | BindingFlags.Instance | BindingFlags.NonPublic,
              null, adapter, new object[0]);
      var sqlCommand = (SqlCommand[])commands;
      foreach (var cmd in sqlCommand)
      {
        cmd.CommandTimeout = timeout;
      }
    }

    /// <summary>
    /// oggetto static per fare chiamate sul magazzino
    /// </summary>
    public static MagClass magazzino = new MagClass();

    #endregion

    #region metodi protected

    /// <summary>
    /// aggiunge le righe liste di prelievo necessarie a soddisfare la richiesta in logica FIFO dato un elenco di cartellini, la qta totale da allocare e la lista attuale
    /// </summary>
    /// <param name="QtaTot"></param>
    /// <param name="codListaAttuale"></param>
    /// <param name="tabellaElencoCartellini"></param>
    private void allocaRigheListaPrelievo(decimal QtaTot, string codListaAttuale, DS_magazzino.ElencoCartelliniDataTable tabellaElencoCartellini)
    {
      //ricavo il valore UDC della riga del più vecchio
      string udcAttuale;
      bool qtaOk = false;
      bool dataFinished = false;
      int progrUdc = 0;
      int numUdcDisponibili = tabellaElencoCartellini.Rows.Count;
      // contiene la quantità della riga attuale
      decimal qtaRiga;
      // somma progressiva della qta allocata - calcolo da db!
      decimal qtaAllocata = taElencoListePrelievo.getByCodLista(codListaAttuale)[0].Prelevato;
      //ciclo WHILE per lo riempimento FIFO con UDC secondo richiesta a partire da elenco fornito
      while (!qtaOk && !dataFinished)
      {
        /*
         * crea una riga in righelistaprelievo passando come valori 
         * il codlista attuale ricavato da sopr
         * l'UDC dal primo della tabella getOlderUDC 
         * 
         * 
         * recupero quantità dalla riga corrente;
         * 
         * imposto proposto a 1;
         * imposto prelevato 0;
         * taRighelistePreliveo.Insert;
         * 
         * qtaAllocata = qtaAllocata + Qta di questa riga (riuso il valore della colonna QTA
         * tabella[contatore]; contatore++; 
         * qtaOk = (qtaAllocata >= qtaRichiesta)
         * dataFinished = (contatore >= numRighe);
         * 
         * */
        // ricavo la riga più vecchia
        qtaRiga = tabellaElencoCartellini[progrUdc].Qta;
        udcAttuale = tabellaElencoCartellini[progrUdc].UDC;
        // eseguo query di insert
        taRigheListePrelievo.Insert(codListaAttuale, udcAttuale, qtaRiga, true, false);

        //incremento qta allocata
        qtaAllocata = (qtaAllocata + qtaRiga);
        //incremento contatore
        progrUdc++;

        // verifico le condizioni, false se non cambia nulla true se cambia e si esce dal while
        qtaOk = (qtaAllocata >= QtaTot);
        dataFinished = (progrUdc >= numUdcDisponibili);
      }
    }

    #endregion

    #region Metodi esposti

    #region operazioni su AL

    /// <summary>
    /// Fornisce un nuovo codice AL tipo completo a partire dalla richiesta e salva i dati
    /// </summary>
    /// <param name="tipologia">tipologia dell'AL da generare</param>
    /// <param name="CodCella">codice della cella contentente gli UDC da associare</param>
    /// <param name="CodSoggetto">codice dell'operatore</param>
    /// <param name="anno">anno in cui intestare i cartellini, trimma a 2 cifre DX</param>
    /// <param name="Cesta">codice cesta</param>
    /// <param name="note">note da associare agli UDC</param>
    /// <returns>AL del nuovo Assieme Logico e lo associa agli UDC della postazione/cella</returns>
    public string creaAssociaAlRxNt(tipoAL tipologia, string CodCella, string CodSoggetto, int anno, string Cesta, string note)
    {
      // imposto valori default
      string CodCS = memLayer.ML.cdv("CodCS");
      string PostFlux = "";
      string CodFlusso = "";
      string TipoAL = "";
      string CodEvento = "";
      string CodDtxStart = "";
      string CodDtxEnd = "";
      switch (tipologia)
      {
        case tipoAL.AL_RxDt:
          PostFlux = "RxDt";
          CodFlusso = "AR";
          TipoAL = "R";
          CodEvento = "UDC_RX_DT";
          // calcolo primo/ultimo dtx OK
          try
          {
            DS_DataMatrix.stp_getFirstLastDtxRow rigaFirstLast = DataMatrix_mgr.taFirstLastUdc.GetData(CodCella)[0];
            if (!rigaFirstLast.IsNull(0))
            {
              CodDtxStart = rigaFirstLast.DtxStart;
              CodDtxEnd = rigaFirstLast.DtxEnd;
            }
            else
            {
              CodDtxStart = "";
              CodDtxEnd = "";
            }
          }
          catch
          {
            CodDtxStart = "";
            CodDtxEnd = "";
          }
          break;
        case tipoAL.AL_RxNt:
          PostFlux = "RxNt";
          CodFlusso = "AR";
          TipoAL = "R";
          CodEvento = "UDC_RX";
          break;
        default:
          break;
      }
      DateTime DataRif = DateTime.Now;
      // trim fix
      string CodSoggettoTrim = CodSoggetto.Trim();
      string annoTrim = anno.ToString();
      if (annoTrim.Length > 2)
      {
        annoTrim = annoTrim.Substring(2, 2);
      }
      // out: codice AL...
      string AL = "NA";
      // creo nuovo Assieme Logico ed associo UDC! 
      try
      {
        taEA.insertNewRX(CodCS, annoTrim, Cesta, PostFlux, CodFlusso, TipoAL, DataRif, CodSoggettoTrim, CodDtxStart, CodDtxEnd, CodCella, CodEvento, note, ref AL);
      }
      catch (Exception exc)
      {
        // loggo errore
        logger.lg.scriviLog(string.Format("ERRORE CREAZIONE AL: {0} procedura stp_UAL_insertNewRX, parametri: {1} | {2} | {3} | {4} | {5} | {6} | {7} | {8} | {9} | {10} | {11} | {12} | {13} {0} {14}", Environment.NewLine, CodCS, annoTrim, Cesta, PostFlux, CodFlusso, TipoAL, DataRif, CodSoggettoTrim, CodDtxStart, CodDtxEnd, CodCella, CodEvento, note, exc), tipoLog.EXCEPTION);
      }
      return AL;
    }

    /// <summary>
    /// Fornisce un nuovo codice AL tipo completo a partire dalla richiesta e salva i dati
    /// </summary>
    /// <param name="CodLinea">Codice Linea</param>
    /// <param name="FormatoDtmx">Formato DataMatrix</param>
    /// <param name="CodEventoUdc">CodEvento creazione UDC</param>
    /// <param name="CodStatoUdc">CodEvento creazione UDC</param>
    /// <param name="tipologia">tipologia dell'AL da generare</param>
    /// <param name="CodCella">codice della cella contentente gli UDC da associare</param>
    /// <param name="CodSoggetto">codice dell'operatore</param>
    /// <param name="anno">anno in cui intestare i cartellini, trimma a 2 cifre DX</param>
    /// <param name="Cesta">codice cesta</param>
    /// <param name="note">note da associare agli UDC</param>
    /// <returns>AL del nuovo Assieme Logico e lo associa agli UDC della postazione/cella</returns>
    public string creaAssociaAlUdcRxDt(string CodLinea, string FormatoDtmx, string CodEventoUdc, string CodStatoUdc, tipoAL tipologia, string CodCella, string CodSoggetto, int anno, string Cesta, string note)
    {
      // imposto valori default
      string CodCS = memLayer.ML.cdv("CodCS");
      string PostFlux = "";
      string CodFlusso = "";
      string CodFlussoUdc = "";
      string TipoAL = "";
      string CodDtxStart = "";
      string CodDtxEnd = "";
      switch (tipologia)
      {
        case tipoAL.AL_RxDt:
          PostFlux = "RxDt";
          CodFlusso = "AR";
          CodFlussoUdc = "RX";
          TipoAL = "R";
          // calcolo primo/ultimo dtx OK
          try
          {
            DS_DataMatrix.stp_getFirstLastDtxRow rigaFirstLast = DataMatrix_mgr.taFirstLastUdc.GetData(CodCella)[0];
            if (!rigaFirstLast.IsNull(0))
            {
              CodDtxStart = rigaFirstLast.DtxStart;
              CodDtxEnd = rigaFirstLast.DtxEnd;
            }
            else
            {
              CodDtxStart = "";
              CodDtxEnd = "";
            }
          }
          catch
          {
            CodDtxStart = "";
            CodDtxEnd = "";
          }
          break;
        default:
          break;
      }
      DateTime DataRif = DateTime.Now;
      // trim fix
      string CodSoggettoTrim = CodSoggetto.Trim();
      string annoTrim = anno.ToString();
      if (annoTrim.Length > 2)
      {
        annoTrim = annoTrim.Substring(2, 2);
      }
      // out: codice AL...
      string AL = "NA";
      // creo nuovo Assieme Logico ed associo UDC! 
      try
      {


        DataMatrix_mgr.taL2D.createUdcAl(CodLinea, FormatoDtmx, CodFlusso, TipoAL, Cesta, CodCS, CodFlussoUdc, annoTrim, "", "", "", "", "", DataRif, 0, memLayer.ML.cdv("CodImballoRX"), CodSoggettoTrim, 0, memLayer.ML.cdvi("IdxPosizioneRxTemp"), "U", CodEventoUdc, 0, 0, CodStatoUdc, "", false, note);
        // vado a leggere AL da riga corrente
        AL = DataMatrix_mgr.taL2D.getByLineFormato(Postazione.currCodLinea, FormatoDtmx)[0].AL;

      }
      catch (Exception exc)
      {
        // loggo errore
        logger.lg.scriviLog(string.Format("ERRORE CREAZIONE AL: {0} procedura dmtx.stp_L2D_createUdc, parametri: {1} | {2} | {3} | {4} | {5} | {6} | {7} | {8} | {9} | {10} | {11} | {12} | {13} {0} {14}", Environment.NewLine, CodCS, annoTrim, Cesta, PostFlux, CodFlusso, TipoAL, DataRif, CodSoggettoTrim, CodDtxStart, CodDtxEnd, CodCella, CodEventoUdc, note, exc), tipoLog.EXCEPTION);
      }
      return AL;
    }

    /// <summary>
    /// Crea un nuovo AL di tipo TT a partire da uno RX e sistema di conseguenza UDC ed eventuali Dtx
    /// </summary>
    /// <param name="AL_from">Codice AL RX sorgente</param>
    /// <param name="tipologia">tipologia (T)</param>
    /// <param name="CodSoggetto">Operatore</param>
    /// <param name="note">Note</param>
    /// <param name="NumTratt">Numero Trattamento</param>
    /// <param name="Durezza">Durezza rilevata</param>
    /// <param name="Punzone">Codice Punzone da utilizzare (se indicato)</param>
    /// <returns></returns>
    public string creaAssociaAlTT(string SourceAL, tipoAL tipologia, string CodSoggetto, string note, string NumTratt, int Durezza, string punzone)
    {
      // imposto valori default
      string TipoAL = "";
      string CodEvento = "";
      DateTime DataRif = DateTime.Now;
      // trim fix
      string CodSoggettoTrim = CodSoggetto.Trim();
      // out: codice AL...
      string AL = "NA";
      switch (tipologia)
      {
        case tipoAL.AL_TT:
          TipoAL = "T";
          CodEvento = "UDC_TRATT";
          break;
        default:
          break;
      }
      // creo nuovo Assieme Logico ed associo UDC! 
      try
      {
        taEA.insertNewTT(SourceAL, TipoAL, DataRif, CodSoggetto, note, NumTratt, Durezza, punzone, ref AL);
      }
      catch (Exception exc)
      {
        // loggo errore
        logger.lg.scriviLog(string.Format("ERRORE avanzamento AL TT: {0} procedura stp_UAL_insertNewTT, parametri: {1} | {2} | {3} | {4} | {5} | {6} | {0} {7}", Environment.NewLine, SourceAL, TipoAL, DataRif, CodSoggetto, CodEvento, note, exc), tipoLog.EXCEPTION);
      }
      return AL;
    }
    /// <summary>
    /// Crea un nuovo AL di tipo TL a partire da uno TT e sistema di conseguenza UDC ed eventuali Dtx
    /// </summary>
    /// <param name="AL_from">Codice AL TT sorgente</param>
    /// <param name="tipologia">tipologia (L)</param>
    /// <param name="CodCella">codice cella di destinazione</param>
    /// <param name="CodSoggetto">Operatore</param>
    /// <returns></returns>
    public string creaAssociaAlTL(string SourceAL, tipoAL tipologia, string CodSoggetto, string CodCella)
    {
      // imposto valori default
      string TipoAL = "";
      DateTime DataRif = DateTime.Now;
      // trim fix
      string CodSoggettoTrim = CodSoggetto.Trim();
      // out: codice AL...
      string AL = "NA";
      switch (tipologia)
      {
        case tipoAL.AL_LI:
          TipoAL = "L";
          break;
        default:
          break;
      }
      // creo nuovo Assieme Logico ed associo UDC! 
      try
      {
        taEA.insertNewTL(SourceAL, TipoAL, DataRif, CodSoggetto, CodCella, ref AL);
      }
      catch (Exception exc)
      {
        // loggo errore
        logger.lg.scriviLog(string.Format("ERRORE avanzamento AL TL: {0} procedura stp_UAL_insertNewTL, parametri: {1} | {2} | {3} | {4} | {0} {5}", Environment.NewLine, SourceAL, TipoAL, DataRif, CodSoggetto, exc), tipoLog.EXCEPTION);
      }
      return AL;
    }
    /// <summary>
    /// Crea un nuovo AL di tipo KitANime
    /// </summary>                                       
    /// <param name="tipologia">tipologia (AN)</param>
    /// <param name="anno">anno</param>
    /// <param name="CodSoggetto">Operatore</param>   
    /// <param name="note">note</param>
    /// <param name="CodKIT">Codice KIT</param>
    /// <param name="note">Qta KIT</param>
    /// <returns></returns>
    public string creaAlKitAnime(tipoAL tipologia, int anno, string CodSoggetto, string note, string CodKIT, int QtaKIT)
    {
      // imposto valori default
      string CodCS = memLayer.ML.cdv("CodCS");
      string CodFlusso = "";
      string TipoAL = "";
      string CodEvento = "";
      switch (tipologia)
      {
        case tipoAL.AL_KitAnime:
          CodFlusso = "AA";
          TipoAL = "A";
          CodEvento = "UDC_ANIMA";
          break;
        default:
          break;
      }
      DateTime DataRif = DateTime.Now;
      // trim fix
      string CodSoggettoTrim = CodSoggetto.Trim();
      string annoTrim = anno.ToString();
      if (annoTrim.Length > 2)
      {
        annoTrim = annoTrim.Substring(2, 2);
      }
      // out: codice AL...
      string AL = "NA";
      // creo nuovo Assieme Logico ed associo UDC! 
      try
      {
        taEA.insertNewKitAnime(CodCS, annoTrim, "0001", CodFlusso, TipoAL, DataRif, CodSoggettoTrim, CodEvento, note, CodKIT, QtaKIT, ref AL);

      }
      catch (Exception exc)
      {
        // loggo errore
        logger.lg.scriviLog(string.Format("ERRORE CREAZIONE AL KIT ANIME: {0} procedura insertNewKitAnime, parametri: {1} | {2} | {3} | {4} | {5} | {6} | {7} | {8} | {9} | {10} {0} {11}", Environment.NewLine, CodCS, annoTrim, CodFlusso, TipoAL, DataRif, CodSoggettoTrim, CodEvento, note, CodKIT, QtaKIT, exc), tipoLog.EXCEPTION);
      }
      return AL;
    }
    /// <summary>
    /// elimina un AL che sia vuoto (da datamatrix)
    /// </summary>
    /// <param name="AL"></param>
    /// <param name="CodSoggetto"></param>
    /// <returns></returns>
    public bool eliminaEmptyAL(string AL, string CodSoggetto)
    {
      bool answ = false;
      try
      {
        taEA.eliminaEmpty(AL, DateTime.Now, CodSoggetto);
      }
      catch (Exception exc)
      {
        logger.lg.scriviLog(string.Format("Errore in eliminazione AL non vuoto: {0}{1}", Environment.NewLine, exc), tipoLog.EXCEPTION);
      }
      return answ;
    }

    /// <summary>
    /// verifica se l'AL indicato sia valido, ovvero esistente
    /// </summary>
    /// <param name="AL"></param>
    /// <returns></returns>
    public bool checkAL(string AL)
    {
      bool answ = false;
      try
      {
        answ = (taEA.getByAL(AL).Rows.Count > 0);
      }
      catch
      { }
      return answ;
    }
    /// <summary>
    /// travasa gli UDC / datamatrix tra 2 AL
    /// </summary>
    /// <param name="ALFrom">Codice AL sorgente</param>
    /// <param name="ALDest">Codice AL destinazione</param>
    /// <param name="clientIp">IP del chiamante</param>
    /// <returns>esito comando</returns>
    public bool travasoAL(string ALFrom, string ALDest, string clientIp)
    {
      bool answ = false;
      try
      {
        taAL2UDC.moveUdcDtx(ALFrom, ALDest, CodSoggCurrUser);
        logger.lg.scriviLog(string.Format(" | {0} | travaso UDC: da {1} a {2} | soggetto {3}", clientIp, ALFrom, ALDest, CodSoggCurrUser), tipoLog.INFO);
        answ = true;
      }
      catch
      { }
      return answ;
    }
    /// <summary>
    /// effettua la stampa di un dato AL
    /// </summary>
    /// <param name="AL">Codice AL</param>
    /// <param name="printer">stampante specifica (da postazione o std da webconfig, a cura dell'utente)</param>
    /// <param name="clientIp">IP del chiamante</param>
    /// <returns></returns>
    public bool stampaAL(string AL, string printer, string clientIp)
    {
      bool answ = false;
      tipoCartellino tipoCart = tipoCartellino.cartAL;
      // controllo se esista UDC
      if (checkAL(AL))
      {
        // in base al codice AL scelgo il tipo di cartellino...
        switch (verificaTipoAl(AL))
        {
          case tipoAL.AL_KitAnime:
            tipoCart = tipoCartellino.cartALANkit;
            break;
          case tipoAL.AL_RX:
          case tipoAL.AL_RxDt:
          case tipoAL.AL_RxNt:
            tipoCart = tipoCartellino.cartALRX;
            break;
          case tipoAL.AL_TT:
            tipoCart = tipoCartellino.cartALTT;
            break;
          case tipoAL.AL_LI:
          case tipoAL.ND:
          default:
            tipoCart = tipoCartellino.cartAL;
            break;
        }
        answ = reportPrinter.obj.stampaCartellino(tipoCart, AL, printer);
        logger.lg.scriviLog(string.Format(" | {0} | stampato AL {1} | stampante {2} | tipo {3}", clientIp, AL, printer, tipoCart), tipoLog.INFO);
      }
      else
      {
        logger.lg.scriviLog(string.Format("ERRORE: non e' stato possibile stampare AL richiesto poiche' non trovato: | IP: {0} | AL {1} | stampante {2} | tipo {3}", clientIp, AL, printer, tipoCart), tipoLog.INFO);
      }
      return answ;
    }
    /// <summary>
    /// verifica il tipo di AL dato il codice
    /// </summary>
    /// <param name="AL"></param>
    /// <returns></returns>
    public tipoAL verificaTipoAl(string AL)
    {
      tipoAL answ = tipoAL.ND;
      if (AL.StartsWith("ALR"))
      {
        answ = tipoAL.AL_RX;
      }
      else if (AL.StartsWith("ALT"))
      {
        answ = tipoAL.AL_TT;
      }
      else if (AL.StartsWith("ALL"))
      {
        answ = tipoAL.AL_LI;
      }
      else if (AL.StartsWith("ALA"))
      {
        answ = tipoAL.AL_KitAnime;
      }
      else
      {
        answ = tipoAL.ND;
      }
      return answ;
    }

    #endregion

    #region operazioni su UDC

    /// <summary>
    /// effettua lo spostamento di un UDC tra 2 posizioni indicate
    /// </summary>
    /// <param name="CodCS">Codice company/sito</param>
    /// <param name="UDC">Codice UDC</param>
    /// <param name="IdxCellaTo">Cella di destinazione</param>
    /// <param name="resetRLP">indica se sia richiesto resettare le Righe Liste Prelievo con lo spostsamento</param>
    /// <param name="clientIp">IP del chiamante</param>
    /// <returns>esito comando</returns>
    public bool spostaUDC(string CodCS, string UDC, int IdxCellaTo, bool resetRLP, string clientIp)
    {
      bool answ = false;
      // procedo SOLO se la cella di dest è VUOTA...
      if (!MagClass.magazzino.cellaPiena(CodCS, IdxCellaTo))
      {
        try
        {
          taPosUdcCorr.stp_spostaUdc(CodCS, UDC, IdxCellaTo, resetRLP, CodSoggCurrUser);
          // cerco nuova posizione...
          if (taPosUdcCorr.getByCellaUdc(UDC, IdxCellaTo).Rows.Count > 0)
          {
            answ = true;
          }
        }
        catch (Exception e)
        {
          logger.lg.scriviLog(string.Format(" | {1} | Errore durante spostamento cella: {0}", e, clientIp), tipoLog.EXCEPTION);
        }
        // solo se ha fatto spostamento posizione corrente verifico se fare spostamento in posizione LOGICA magazzino
        if (answ)
        {
          try
          {
            // verifico tipo cella e se ci sia da fare spostamento in mag logico/contabile
            int idxTipoCella = taCelle.getByIdxCella(IdxCellaTo)[0].IdxTipoCella;
            bool needSetMag = taTipoCella.getByIdx(idxTipoCella)[0].SetMag;
            if (needSetMag)
            {
              // cambio (eventualmente) la posizione "logica" dato lo spostamento (il codice magazzino...)
              int idxBlocco = taCelle.getByIdxCella(IdxCellaTo)[0].IdxBlocco;
              int IdxPosizione = Convert.ToInt32(taBlocchi.getByIdx(idxBlocco)[0].CodMag);
              taCartellini.updateIdxPosizione(UDC, IdxPosizione, CodSoggCurrUser);
            }
          }
          catch (Exception e)
          {
            logger.lg.scriviLog(string.Format(" | {1} | Errore durante indicazione posizione UDC: {0}", e, clientIp), tipoLog.EXCEPTION);
          }
        }
      }
      else
      {
        logger.lg.scriviLog(string.Format(" | {1} | Errore, cella {0} di destinazione piena!!!", IdxCellaTo, clientIp), tipoLog.ERROR);
      }
      return answ;
    }
    /// <summary>
    /// effettua lo scaricamento di un UDC (x spedizione)
    /// </summary>
    /// <param name="UDC">Codice UDC</param>
    /// <param name="IdxPosizUdc">Codice posizione UDC finale</param>
    /// <param name="CodEvento">Codice evento associato allo scaricamento</param>
    /// <param name="clientIp">IP del chiamante</param>
    /// <returns>esito comando</returns>
    public bool scaricaUDC(string UDC, int IdxPosizUdc, string CodEvento, string clientIp)
    {
      bool answ = false;
      try
      {
        taPosUdcCorr.stp_scaricaUdc(UDC, IdxPosizUdc, CodEvento, CodSoggCurrUser);
        logger.lg.scriviLog(string.Format(" | {0} | Scaricato UDC {1} | posizione {2} | CodEvento {3} | soggetto {4}", clientIp, UDC, IdxPosizUdc, CodEvento, CodSoggCurrUser), tipoLog.INFO);
        answ = true;
      }
      catch (Exception exc)
      {
        logger.lg.scriviLog(string.Format(" | {2} | Errore in scaricaUDC:{0}{1}", Environment.NewLine, exc, clientIp), tipoLog.EXCEPTION);
      }
      return answ;
    }
    /// <summary>
    /// rettifica la qta di un UDC
    /// </summary>
    /// <param name="UDC">Codice UDC</param>
    /// <param name="qta">Nuova quantita associata</param>
    /// <param name="clientIp">IP del chiamante</param>
    /// <returns>esito comando</returns>
    public bool rettificaQtaUDC(string UDC, decimal qta, string clientIp)
    {
      bool answ = false;
      try
      {
        int fatti = 0;
        fatti = taCartellini.updateQty(UDC, CodSoggCurrUser, "U", "UDC_QTY", qta).Rows.Count;
        if (fatti > 0)
        {
          answ = true;
          logger.lg.scriviLog(string.Format(" | {0} | Rettifica qta UDC {1} | qta {2} | soggetto {3}", clientIp, UDC, qta, CodSoggCurrUser), tipoLog.INFO);
        }
      }
      catch
      { }
      return answ;
    }
    /// <summary>
    /// rettifica la qta di un UDC
    /// </summary>
    /// <param name="UdcFrom">Codice UDC sorgente</param>
    /// <param name="UdcDest">Codice UDC destinazione</param>
    /// <param name="qta">Quantita da travasare</param>
    /// <param name="clientIp">IP del chiamante</param>
    /// <returns>esito comando</returns>
    public bool travasoQtaUDC(string UdcFrom, string UdcDest, decimal qta, string clientIp)
    {
      bool answ = false;
      try
      {
        taCartellini.travasoQty(UdcFrom, UdcDest, CodSoggCurrUser, "U", "UDC_TraQTY", qta);
        logger.lg.scriviLog(string.Format(" | {0} | travaso qta UDC: da {1} a {2} | qta {3} | soggetto {4}", clientIp, UdcFrom, UdcDest, qta, CodSoggCurrUser), tipoLog.INFO);
        answ = true;
      }
      catch
      { }
      return answ;
    }
    /// <summary>
    /// Sistema il cartellino finito liquidi per la stampa
    /// </summary>
    /// <param name="SourceAL">AL sorgente in postazione (ATL)</param>
    /// <param name="TipoAlAnc">Tipo cart da legare (TT)</param>
    /// <param name="UDC">Cod UDC da processare</param>
    /// <param name="CodImb">Cod Imballo</param>
    /// <param name="Note">Note x cartellino</param>
    /// <param name="CodSoggetto">Cod soggetto</param>
    /// <returns></returns>
    public bool liquidiFullUpdate(string SourceAL, string TipoAlAnc, string UDC, string CodImb, string Note, string CodSoggetto)
    {
      bool answ = false;
      try
      {
        DS_magazzino.ElencoCartelliniRow riga = taCartellini.UdcLiqFullUpdate(SourceAL, TipoAlAnc, UDC, CodImb, Note, DateTime.Now, CodSoggetto)[0];
        answ = true;
      }
      catch
      { }
      return answ;
    }
    /// <summary>
    /// Riprende in carico alla postazione un cartellino liquidi FINITO valido
    /// </summary>
    /// <param name="UDC">Cod UDC da processare</param>
    /// <param name="CodSoggetto">Cod soggetto</param>
    /// <param name="tempAL">AL (temporaneo) di destinazione</param>
    /// <param name="idxCella">Cod cella di destinazione</param>
    /// <returns></returns>
    public bool liquidiRiprendiInCaricoUDC(string UDC, string CodSoggetto, string tempAL, int idxCella)
    {
      bool answ = false;
      try
      {
        DS_magazzino.ElencoCartelliniRow riga = taCartellini.UdcLiqRicarica(UDC, idxCella, tempAL, DateTime.Now, CodSoggetto)[0];
        answ = true;
      }
      catch (Exception exc)
      {
        logger.lg.scriviLog(exc.ToString(), tipoLog.EXCEPTION);
      }
      return answ;
    }
    /// <summary>
    /// Riprende in carico alla postazione un cartellino Finiti Rx valido
    /// </summary>
    /// <param name="UDC">Cod UDC da processare</param>
    /// <param name="CodSoggetto">Cod soggetto</param>
    /// <param name="tempAL">AL (temporaneo) di destinazione</param>
    /// <param name="idxCella">Cod cella di destinazione</param>
    /// <returns></returns>
    public bool finRxRiprendiInCaricoUDC(string UDC, string CodSoggetto, string tempAL, int idxCella)
    {
      bool answ = false;
      try
      {
        DS_magazzino.ElencoCartelliniRow riga = taCartellini.UdcFinRxRicarica(UDC, idxCella, tempAL, DateTime.Now, CodSoggetto)[0];
        answ = true;
      }
      catch
      { }
      return answ;
    }
    /// <summary>
    /// Sistema il cartellino Gitterbox Rx Finiti (B48) per la stampa
    /// </summary>
    /// <param name="UDC">Cod UDC da processare</param>
    /// <param name="CodImb">Cod Imballo</param>
    /// <param name="Note">Note x cartellino</param>
    /// <param name="CodSoggetto">Cod soggetto</param>
    /// <returns></returns>
    public bool Udc_B48_FullUpdate(string UDC, string CodImb, string Note, string CodSoggetto)
    {
      bool answ = false;
      try
      {
        DS_magazzino.ElencoCartelliniRow riga = taCartellini.UdcRxFinLiqFullUpdate(UDC, CodImb, Note, DateTime.Now, CodSoggetto)[0];
        answ = true;
      }
      catch
      { }
      return answ;
    }
    /// <summary>
    /// verifica se l'UDC indicato sia valido, ovvero esistente
    /// </summary>
    /// <param name="UDC"></param>
    /// <returns></returns>
    public bool checkUDC(string UDC)
    {
      bool answ = false;
      try
      {
        answ = (taCartellini.getDetailsUdcByUdc(UDC).Rows.Count > 0);
      }
      catch
      { }
      return answ;
    }
    /// <summary>
    /// verifica se l'UDC indicato sia ESENTE DA NC attive (ovvero senza deroga DC)
    /// </summary>
    /// <param name="UDC"></param>
    /// <returns>restituisce esito controllo</returns>
    public checkUdcNc checkUDC_NC(string UDC)
    {
      /// default caso pessimo...
      checkUdcNc answ = checkUdcNc.HasNc;
      bool hasNc = false;
      try
      {
        hasNc = (DataProxy.obj.taUDC2NC.getNcPending(UDC, "DC", "NC").Rows.Count != 0);
      }
      catch
      { }
      // se richiesto faccio verifica
      if (memLayer.ML.CRB("checkUDC_NC"))
      {
        if (hasNc)
        {
          answ = checkUdcNc.HasNc;
        }
        else
        {
          answ = checkUdcNc.NoNc;
        }
      }
      // altrimenti NON E' richiesta verifica
      else
      {
        if (hasNc)
        {
          answ = checkUdcNc.ChkDis_HasNc;
        }
        else
        {
          answ = checkUdcNc.ChkDis_NoNc;
        }
      }
      return answ;
    }
    /// <summary>
    /// Fornisce elenco NC associate ad un UDC
    /// </summary>
    /// <param name="UDC"></param>
    /// <returns></returns>
    public DS_Applicazione.ElencoNCDataTable getNc2UDC(string UDC)
    {
      DS_Applicazione.ElencoNCDataTable answ = new DS_Applicazione.ElencoNCDataTable();
      // controllo se ci siano NC
      checkUdcNc esito = checkUDC_NC(UDC);
      // se ci sono recupero!
      if (esito == checkUdcNc.HasNc || esito == checkUdcNc.ChkDis_HasNc)
      {
        answ = DataProxy.obj.taENC.getByUDC(UDC);
      }
      return answ;
    }
    /// <summary>
    /// Restituisce stringa formattata dellal NC associata all'UDC
    /// </summary>
    /// <param name="UDC"></param>
    /// <returns></returns>
    public string getDescrNc2Udc(string UDC)
    {
      DS_Applicazione.ElencoNCDataTable tab = getNc2UDC(UDC);
      string answ = "";
      if (tab.Rows.Count > 0)
      {
        DS_Applicazione.ElencoNCRow riga = null;
        // recupero righe...
        for (int i = 0; i < tab.Rows.Count; i++)
        {
          riga = (DS_Applicazione.ElencoNCRow)tab.Rows[i];
          answ += string.Format("<div><b>NC: {0}</b>, {1}</div>", riga.CodNC, riga.DescrNC);
          //answ += string.Format("<div><b>NC: {0}</b>, {1}</div><div style=\"font-size: 0.8em;\">{2} | {3} | {4} ({5:yyyy.MM.dd HH:mm} --> {6:yyyy.MM.dd HH:mm})</div>", riga.CodNC, riga.DescrNC, riga.TipoCart, riga.Particolare, riga.SearchNote, riga.DataFrom, riga.DataTo);
        }
      }
      return answ;
    }

    /// <summary>
    /// verifica se l'UDC indicato POSSA ESSERE MOVIMENTATO (ovvero NON in LDP in stato "bloccato")
    /// </summary>
    /// <param name="UDC"></param>
    /// <returns></returns>
    public bool checkUDC_mov(string UDC)
    {
      bool answ = false;
      try
      {
        answ = (taRigheListePrelievo.getBloccateMovByUdc(UDC).Rows.Count == 0);
      }
      catch
      { }
      return answ;
    }
    /// <summary>
    /// verifica se l'UDC indicato POSSA ESSERE OGGETTO DI RETTIFICA QTA (ovvero NON in LDP in stato "bloccato")
    /// </summary>
    /// <param name="UDC"></param>
    /// <returns></returns>
    public bool checkUDC_qty(string UDC)
    {
      bool answ = false;
      try
      {
        answ = (taRigheListePrelievo.getBloccateQtaByUdc(UDC).Rows.Count == 0);
      }
      catch
      { }
      return answ;
    }
    /// <summary>
    /// effettua lo scaricamento (da db e da AS400) degli UDC di MP/WIP, registrando l'evento "UDC_CONS"
    /// </summary>
    /// <param name="UDC">Codice UDC</param>
    /// <param name="clientIp">IP del chiamante</param>
    /// <returns></returns>
    public bool scaricaUdcMpWip(string UDC, string clientIp)
    {
      // inizializzo
      bool answ = false;
      int idxCellaFrom = 0;
      int idxPosizUdcCorr = 0;
      int idxPosizUdcDest = 0;
      string CodEvento = "UDC_CONS";
      // calcolo posizione UDC corrente (se c'è...)
      try
      {
        // mi serve per posizione udc corrente
        DS_magazzino.PosizioneUdcCorrenteRow rigaUdcCorrente = taPosUdcCorr.getByUDC(UDC)[0];
        // il secondo idx che mi serve
        idxCellaFrom = rigaUdcCorrente.IdxCella;
      }
      catch (Exception e)
      {
        logger.lg.scriviLog(string.Format(" | {3} | Errore in fase di recupero cella per l'UDC {0}: {1}{2}", UDC, Environment.NewLine, e, clientIp), tipoLog.EXCEPTION);
      }
      // ora calcolo gli altri dati dalla riga ElencoCartellini dell'UDC
      try
      {
        // calcolo posizione destinazione da state machine...
        idxPosizUdcCorr = taCartellini.getDetailsUdcByUdc(UDC)[0].IdxPosizione;
        idxPosizUdcDest = StateMachine.SM.getIdxPostizioneTo(CodEvento, idxPosizUdcCorr);
      }
      catch (Exception e)
      {
        logger.lg.scriviLog(string.Format(" | {3} | Errore in fase di recupero dati posizioni from/to per l'UDC {0}: {1}{2}", UDC, Environment.NewLine, e, clientIp), tipoLog.EXCEPTION);
      }
      // ora provo ad eseguire!
      try
      {
        if (idxPosizUdcDest != 0) // solo se c'è una posizione da cui poter fare lo scaricamento...
        {
          // sposto UDC
          answ = scaricaUDC(UDC, idxPosizUdcDest, CodEvento, clientIp);
        }
      }
      catch (Exception e)
      {
        logger.lg.scriviLog(string.Format(" | {3} | Errore in fase di scaricamento dell'UDC {0}: {1}{2}", UDC, Environment.NewLine, e, clientIp), tipoLog.EXCEPTION);
      }

      return answ;
    }
    /// <summary>
    /// riattiva un UDC (se permesso) da una posizione consumata ad una valida
    /// </summary>
    /// <param name="UDC">Codice UDC</param>
    /// <param name="CodSoggetto">Cod soggetto utente</param>
    /// <param name="clientIp">IP del chiamante</param>
    /// <returns></returns>
    public bool riattivaUdc(string UDC, string CodSoggetto, string clientIp)
    {
      // init
      bool answ = false;
      try
      {
        // salvo dati cartellino PRE
        DS_Applicazione.ElencoCartelliniRow rigaUdcPre = DataProxy.obj.taCartellini.stp_getByUdc(UDC)[0];
        DataProxy.obj.taCartellini.stp_riattivaUdc(UDC, CodSoggetto);
        logger.lg.scriviLog(string.Format(" | {0} | riattivato UDC {1} | soggetto {2}", clientIp, UDC, CodSoggetto), tipoLog.INFO);
        // salvo dati cartellino POST
        DS_Applicazione.ElencoCartelliniRow rigaUdcPost = DataProxy.obj.taCartellini.stp_getByUdc(UDC)[0];
        answ = true;
      }
      catch (Exception e)
      {
        logger.lg.scriviLog(string.Format(" | {2} | Eccezione: {0}{1}", Environment.NewLine, e, clientIp), tipoLog.EXCEPTION);
      }

      return answ;
    }
    /// <summary>
    /// sblocca un UDC (se permesso)
    /// </summary>
    /// <param name="UDC">Codice UDC</param>
    /// <param name="CodSoggetto">Cod soggetto utente</param>
    /// <param name="clientIp">IP del chiamante</param>
    /// <returns></returns>
    public bool sbloccaUdc(string UDC, string CodSoggetto, string clientIp)
    {
      // init
      bool answ = false;
      try
      {
        DataProxy.obj.taCartellini.stp_sbloccaUdc(UDC, CodSoggetto);
        logger.lg.scriviLog(string.Format(" | {0} | sbloccato UDC {1} | soggetto {2}", clientIp, UDC, CodSoggetto), tipoLog.INFO);
        answ = true;
      }
      catch (Exception e)
      {
        logger.lg.scriviLog(string.Format(" | {2} | Eccezione: {0}{1}", Environment.NewLine, e, clientIp), tipoLog.EXCEPTION);
      }
      return answ;
    }
    /// <summary>
    /// controlla se l'udc della qualità indicato ha benestare qualità ("S")
    /// </summary>
    /// <param name="UDC"></param>
    /// <returns></returns>
    public bool udcMpHasBenesQual(string UDC)
    {
      bool answ = false;
      try
      {
        DS_magazzino.RapQualRow rigaRapQual = taRapQual.getByUdc(UDC)[0];
        if (rigaRapQual.BenesQual == "S")
        {
          answ = true;
        }
      }
      catch
      { }
      return answ;
    }
    /// <summary>
    /// controlla se l'udc indicato è già stato consumato
    /// </summary>
    /// <param name="UDC"></param>
    /// <returns></returns>
    public bool udcMpIsConsumabile(string UDC)
    {
      bool answ = false;
      try
      {
        DS_magazzino.ElencoCartelliniRow rigaUDC = taCartellini.getByUdc(UDC)[0];
        if (rigaUDC.IdxPosizione > 0)
        {
          answ = true;
        }
      }
      catch
      { }
      return answ;
    }
    /// <summary>
    /// fornisce IdxPosizione dell'UDC
    /// </summary>
    /// <param name="UDC"></param>
    /// <returns></returns>
    public int IdxPosizioneUdc(string UDC)
    {
      int answ = 0;
      try
      {
        answ = taCartellini.getDetailsUdcByUdc(UDC)[0].IdxPosizione;
      }
      catch
      { }
      return answ;
    }
    /// <summary>
    /// fornisce il CodStato dell'UDC
    /// </summary>
    /// <param name="UDC"></param>
    /// <returns></returns>
    public string CodStatoUdc(string UDC)
    {
      string answ = "";
      try
      {
        answ = taCartellini.getDetailsUdcByUdc(UDC)[0].CodStato;
      }
      catch
      { }
      return answ;
    }
    /// <summary>
    /// fornisce cella in cui si trova l'UDC
    /// </summary>
    /// <param name="UDC"></param>
    /// <returns></returns>
    public string codCellaUdc(string UDC)
    {
      string answ = "";
      try
      {
        int idxCella = taPosUdcCorr.getByUDC(UDC)[0].IdxCella;
        answ = taCelle.getByIdxCella(idxCella)[0].CodCella;
      }
      catch
      { }
      return answ;
    }
    /// <summary>
    /// fornisce codBlocco in cui si trova l'UDC
    /// </summary>
    /// <param name="UDC"></param>
    /// <returns></returns>
    public string codBloccoUdc(string UDC)
    {
      string answ = "";
      try
      {
        int idxCella = taPosUdcCorr.getByUDC(UDC)[0].IdxCella;
        int idxBlocco = taCelle.getByIdxCella(idxCella)[0].IdxBlocco;
        answ = taBlocchi.getByIdx(idxBlocco)[0].CodBlocco;
      }
      catch
      { }
      return answ;
    }

    /// <summary>
    /// verifica se UDC sia ok x LDP secondo stored stp_getUdcDetailOkLP (LPA/LPX)
    /// </summary>
    /// <param name="UDC"></param>
    /// <returns></returns>
    public bool checkUdc_OkLPAX(string UDC)
    {
      bool answ = false;
      try
      {
        answ = taDettUDC.getByUdcOkLp(UDC).Rows.Count > 0;
      }
      catch
      { }
      return answ;
    }
    /// <summary>
    /// controlla se l'udc indicato sia in una LDP
    /// </summary>
    /// <param name="UDC"></param>
    /// <returns></returns>
    public bool udcInLdp(string UDC)
    {
      bool answ = false;
      try
      {
        DS_magazzino.RigheListePrelievoDataTable tabRLDP = taRigheListePrelievo.getByUdc(UDC);
        if (tabRLDP.Rows.Count > 0)
        {
          answ = true;
        }
      }
      catch
      { }
      return answ;
    }
    /// <summary>
    /// fornisce il codice UDC calcolato
    /// </summary>
    /// <param name="CodCS"></param>
    /// <param name="flusso"></param>
    /// <param name="anno">2 cifre</param>
    /// <param name="numUDC"></param>
    /// <returns></returns>
    public string getComposizioneUDC(string CodCS, string flusso, string anno, int numUDC)
    {
      string answ = "";
      try
      {
        answ = string.Format("U{0}{1}{2}{3}", CodCS, flusso, anno, numUDC.ToString().PadLeft(6, '0'));
      }
      catch
      { }
      return answ;
    }
    /// <summary>
    /// fornisce il codice trattamento calcolato
    /// </summary>
    /// <param name="anno">se > 2 cifre trim e tiene ultime 2..</param>
    /// <param name="numTr">Numero trattamento</param>
    /// <returns></returns>
    public string getCompTrattamenti(string anno, string numTr)
    {
      string answ = "";
      try
      {
        answ = string.Format("{0}{1}", anno.Substring(anno.Length - 2, 2), numTr.PadLeft(6, '0'));
      }
      catch
      { }
      return answ;
    }
    /// <summary>
    /// Fornisce un nuovo codice UDC tipo completo (con pezzi e cod magazzino) a partire dalla richiesta e associa ad AL e mette nella cella richiesta
    /// </summary>
    /// <param name="AL">AL da associare</param>
    /// <param name="SourceAL">AL Sorgente (da disattivare)</param>
    /// <param name="DataMatrix">DataMatrix da spostare</param>
    /// <param name="CodStatoUdcOut">Cod Stato UDC OUT in cui spostare datamatrix</param>
    /// <param name="CodCella">codice cella destinazione</param>
    /// <param name="CodBilancia">codice anagrafico della bilanca che effettua la richiesta (codice della pesa)</param>
    /// <param name="CodCliente">codice anagrafico del cliente</param>
    /// <param name="Particolare">codice del particolare (articolo) - da anagrafica!</param>
    /// <param name="CodImpianto">Codice dell'impianto</param>
    /// <param name="CodStampo">Codice dello stampo</param>
    /// <param name="Esponente">codice dell'esponente dello stampo</param>
    /// <param name="Figura">Codice figura</param>
    /// <param name="UDC_parent">codice dell'UDC parent (UDC della tara)</param>
    /// <param name="tara">peso in kg (0 se non noto) da associare all'UDC come tara del contenitore</param>
    /// <param name="CodImballo">codice dell'imballo (tipo cassone) - string LIBERO (non facciamo controlli in input)</param>
    /// <param name="CodTipoDichiarazione">tipo di dichiarazione (vedere relativa anagrafica consentita, es U=uomo, M=macchina...)</param>
    /// <param name="CodSoggetto">codice dell'operatore</param>
    /// <param name="Quantita">numero pezzi associati all'UDC</param>
    /// <param name="PesoTot">Peso totale rilevato</param>
    /// <param name="PesoCad">Peso unitario rilevato</param>
    /// <param name="DataRif">Data di rif per la dichiarazione</param>
    /// <param name="TurnoRif">Turno di rif per la dichiarazione</param>
    /// <param name="CodStato">Codice dello stato del pezzo (da anagrafica: sabbiato, ...)</param>
    /// <param name="CodMag">Codice del magazzino in cui inserire l'UDC</param>
    /// <param name="defIdxPosiz">NOME della posizione default in cui creare UDC</param>
    /// <param name="codEvento">cod evento da associare al movimento mag</param>
    /// <param name="note">note (opzionali)</param>
    /// <param name="UDC">cod UDC pre-calcolato, se "" verrà calcolato dalla query</param>
    /// <param name="anno">anno in cui intestare i cartellini, trimma a 2 cifre DX</param>
    /// <param name="clientIp">Ip del client</param>
    /// <returns>UDC del nuovo cartellino per FINITI</returns>
    public string creaUdcWithAlCella(string AL, string SourceAL, string DataMatrix, string CodStatoUdcOut, string CodCella, string CodBilancia, string CodCliente, string Particolare, string CodImpianto, string CodStampo, string Esponente, string Figura, string UDC_parent, double Tara, string CodImballo, string CodTipoDichiarazione, string CodSoggetto, int Quantita, float PesoTot, float PesoCad, DateTime DataRif, int TurnoRif, string CodStato, int CodMag, string defIdxPosiz, string codEvento, string note, string UDC, int anno, string clientIp)
    {
      // trim fix
      string CodBilanciaTrim = CodBilancia.Trim();
      string CodClienteTrim = CodCliente.Trim();
      string ParticolareTrim = Particolare.Trim();
      string CodImpiantoTrim = CodImpianto.Trim();
      string CodStampoTrim = CodStampo.Trim();
      string EsponenteTrim = Esponente.Trim();
      string FiguraTrim = Figura.Trim();
      string UDC_parentTrim = UDC_parent.Trim();
      string CodImballoTrim = CodImballo.Trim();
      string CodTipoDichiarazioneTrim = CodTipoDichiarazione.Trim();
      string CodSoggettoTrim = CodSoggetto.Trim();
      string CodStatoTrim = CodStato.Trim();
      string defIdxPosizTrim = defIdxPosiz.Trim();
      string codEventoTrim = codEvento.Trim();
      string noteTrim = note.Trim();
      string annoTrim = anno.ToString();
      if (annoTrim.Length > 2)
      {
        annoTrim = annoTrim.Substring(2, 2);
      }
      // determino se cancellare udcTara
      bool doDeleteUdcTara = false; // memLayer.ML.confReadBool("doDeleteUdcTara");
                                    // ricavo cod company...
      string CodCS = "ND";
      string answ = "NA";
      try
      {
        CodCS = DataProxy.obj.taAnagBil.stp_getByCodBilancia(CodBilanciaTrim)[0].CodCS;
      }
      catch
      {
        CodCS = memLayer.ML.cdv("CodCS");
      }
      int IdxPosizione = 0;
      if (CodMag > 0)
      {
        IdxPosizione = CodMag;
      }
      else
      {
        IdxPosizione = memLayer.ML.confReadInt(defIdxPosizTrim);
      }
      // controllo di avere codice soggetto e particolare validi (!="")
      if (ParticolareTrim != "" && CodSoggettoTrim != "")
      {
        // creo nuovo cartellino! 
        DS_Applicazione.ElencoCartelliniDataTable tabUdc = new DS_Applicazione.ElencoCartelliniDataTable();
        // insert nuovo UDC con codice impostato
        try
        {
          tabUdc = DataProxy.obj.taCartellini.stp_insNewFullWithAL(AL, SourceAL, DataMatrix, CodStatoUdcOut, CodCella, CodCS, CodBilanciaTrim, annoTrim, CodClienteTrim, ParticolareTrim, CodImpiantoTrim, CodStampoTrim, EsponenteTrim, FiguraTrim, DataRif, TurnoRif, CodImballoTrim, CodSoggettoTrim, Tara, IdxPosizione, CodTipoDichiarazioneTrim, codEventoTrim, Quantita, PesoTot, PesoCad, CodStatoTrim, UDC_parentTrim, doDeleteUdcTara, noteTrim);
          answ = UDC;
        }
        catch (Exception exc)
        {
          // loggo errore
          logger.lg.scriviLog(string.Format("ERRORE CREAZIONE UDC: | {24} | procedura stp_insNewFull_fixUDC, parametri: {0} | {1} | {2} | {3} | {4} | {5} | {6} | {7} | {8} | {9} | {10} | {11} | {12} | {13} | {14} | {15} | {16} | {17} | {18} | {19} | {20} | {21} | {22} | {23} | {24}{25}{26}", answ, CodCS, CodBilanciaTrim, annoTrim, CodClienteTrim, ParticolareTrim, CodImpiantoTrim, CodStampoTrim, EsponenteTrim, FiguraTrim, DataRif, TurnoRif, CodImballoTrim, CodSoggettoTrim, Tara, IdxPosizione, CodTipoDichiarazioneTrim, codEventoTrim, Quantita, PesoTot, PesoCad, CodStatoTrim, UDC_parentTrim, noteTrim, clientIp, Environment.NewLine, exc), tipoLog.INFO);
        }
        // leggo la riga
        answ = tabUdc[0].UDC;
        // loggo tutto!
        if (memLayer.ML.confReadInt("_logLevel") > 5)
        {
          try
          {
            logger.lg.scriviLog(string.Format(" | {24} | NUOVO cartellino da postazione: {0} | {1} | {2} | {3} | {4} | {5} | {6} | {7} | {8} | {9} | {10} | {11} | {12} | {13} | {14} | {15} | {16} | {17} | {18} | {19} | {20} | {21} | {22} | {23}", answ, CodCS, CodBilanciaTrim, annoTrim, CodClienteTrim, ParticolareTrim, CodImpiantoTrim, CodStampoTrim, EsponenteTrim, FiguraTrim, DataRif, TurnoRif, CodImballoTrim, CodSoggettoTrim, Tara, IdxPosizione, CodTipoDichiarazioneTrim, codEventoTrim, Quantita, PesoTot, PesoCad, CodStatoTrim, UDC_parentTrim, noteTrim, clientIp), tipoLog.INFO);
          }
          catch
          { }
        }
        // solo se UDC parent != vuoto...
        if (UDC_parentTrim != "")
        {
          try
          {
            // salvo associazione parent-child tra UDC!
            DataProxy.obj.taRelazUDC.Insert(UDC_parentTrim, answ, DateTime.Now);
          }
          catch
          { }
        }
      }
      return answ;
    }
    /// <summary>
    /// Fornisce un nuovo codice UDC tipo completo (con pezzi e cod magazzino) a partire dalla richiesta e salva i dati
    /// </summary>
    /// <param name="CodBilancia">codice anagrafico della bilanca che effettua la richiesta (codice della pesa)</param>
    /// <param name="CodCliente">codice anagrafico del cliente</param>
    /// <param name="Particolare">codice del particolare (articolo) - da anagrafica!</param>
    /// <param name="CodImpianto">Codice dell'impianto</param>
    /// <param name="CodStampo">Codice dello stampo</param>
    /// <param name="Esponente">codice dell'esponente dello stampo</param>
    /// <param name="Figura">Codice figura</param>
    /// <param name="UDC_parent">codice dell'UDC parent (UDC della tara)</param>
    /// <param name="tara">peso in kg (0 se non noto) da associare all'UDC come tara del contenitore</param>
    /// <param name="CodImballo">codice dell'imballo (tipo cassone) - string LIBERO (non facciamo controlli in input)</param>
    /// <param name="CodTipoDichiarazione">tipo di dichiarazione (vedere relativa anagrafica consentita, es U=uomo, M=macchina...)</param>
    /// <param name="CodSoggetto">codice dell'operatore</param>
    /// <param name="Quantita">numero pezzi associati all'UDC</param>
    /// <param name="PesoTot">Peso totale rilevato</param>
    /// <param name="PesoCad">Peso unitario rilevato</param>
    /// <param name="DataRif">Data di rif per la dichiarazione</param>
    /// <param name="TurnoRif">Turno di rif per la dichiarazione</param>
    /// <param name="CodStato">Codice dello stato del pezzo (da anagrafica: sabbiato, ...)</param>
    /// <param name="CodMag">Codice del magazzino in cui inserire l'UDC</param>
    /// <param name="defIdxPosiz">NOME della posizione default in cui creare UDC</param>
    /// <param name="codEvento">cod evento da associare al movimento mag</param>
    /// <param name="note">note (opzionali)</param>
    /// <param name="UDC">cod UDC pre-calcolato, se "" verrà calcolato dalla query</param>
    /// <param name="anno">anno in cui intestare i cartellini, trimma a 2 cifre DX</param>
    /// <param name="clientIp">Ip del client</param>
    /// <returns>UDC del nuovo cartellino per FINITI</returns>
    public string creaUdc(string CodBilancia, string CodCliente, string Particolare, string CodImpianto, string CodStampo, string Esponente, string Figura, string UDC_parent, double Tara, string CodImballo, string CodTipoDichiarazione, string CodSoggetto, int Quantita, float PesoTot, float PesoCad, DateTime DataRif, int TurnoRif, string CodStato, int CodMag, string defIdxPosiz, string codEvento, string note, string UDC, int anno, string clientIp)
    {
      // trim fix
      string CodBilanciaTrim = CodBilancia.Trim();
      string CodClienteTrim = CodCliente.Trim();
      string ParticolareTrim = Particolare.Trim();
      string CodImpiantoTrim = CodImpianto.Trim();
      string CodStampoTrim = CodStampo.Trim();
      string EsponenteTrim = Esponente.Trim();
      string FiguraTrim = Figura.Trim();
      string UDC_parentTrim = UDC_parent.Trim();
      string CodImballoTrim = CodImballo.Trim();
      string CodTipoDichiarazioneTrim = CodTipoDichiarazione.Trim();
      string CodSoggettoTrim = CodSoggetto.Trim();
      string CodStatoTrim = CodStato.Trim();
      string defIdxPosizTrim = defIdxPosiz.Trim();
      string codEventoTrim = codEvento.Trim();
      string noteTrim = note.Trim();
      string annoTrim = anno.ToString();
      if (annoTrim.Length > 2)
      {
        annoTrim = annoTrim.Substring(2, 2);
      }
      // determino se cancellare udcTara
      bool doDeleteUdcTara = false; // memLayer.ML.confReadBool("doDeleteUdcTara");
                                    // ricavo cod company...
      string CodCS = "ND";
      string answ = "NA";
      try
      {
        CodCS = DataProxy.obj.taAnagBil.stp_getByCodBilancia(CodBilanciaTrim)[0].CodCS;
      }
      catch
      {
        CodCS = memLayer.ML.cdv("CodCS");
      }
      int IdxPosizione = 0;
      if (CodMag > 0)
      {
        IdxPosizione = CodMag;
      }
      else
      {
        IdxPosizione = memLayer.ML.confReadInt(defIdxPosizTrim);
      }
      //int IdxPosizione = memLayer.ML.confReadInt(defIdxPosizTrim);
      // controllo di avere codice soggetto e particolare validi (!="")
      if (ParticolareTrim != "" && CodSoggettoTrim != "")
      {
        // creo nuovo cartellino! 
        DS_Applicazione.ElencoCartelliniDataTable tabUdc = new DS_Applicazione.ElencoCartelliniDataTable();
        // controllo se UDC già definito o meno...
        if (UDC != "")
        {
          // insert nuovo UDC con codice impostato
          try
          {
            tabUdc = DataProxy.obj.taCartellini.stp_insNewFull_fixUDC(UDC, CodCS, CodBilanciaTrim, annoTrim, CodClienteTrim, ParticolareTrim, CodImpiantoTrim, CodStampoTrim, EsponenteTrim, FiguraTrim, DataRif, TurnoRif, CodImballoTrim, CodSoggettoTrim, Tara, IdxPosizione, CodTipoDichiarazioneTrim, codEventoTrim, Quantita, PesoTot, PesoCad, CodStatoTrim, UDC_parentTrim, doDeleteUdcTara, noteTrim);
            answ = UDC;
          }
          catch
          {
            // loggo errore
            logger.lg.scriviLog(string.Format("ERRORE CREAZIONE UDC: | {24} | procedura stp_insNewFull_fixUDC, parametri: {0} | {1} | {2} | {3} | {4} | {5} | {6} | {7} | {8} | {9} | {10} | {11} | {12} | {13} | {14} | {15} | {16} | {17} | {18} | {19} | {20} | {21} | {22} | {23}", answ, CodCS, CodBilanciaTrim, annoTrim, CodClienteTrim, ParticolareTrim, CodImpiantoTrim, CodStampoTrim, EsponenteTrim, FiguraTrim, DataRif, TurnoRif, CodImballoTrim, CodSoggettoTrim, Tara, IdxPosizione, CodTipoDichiarazioneTrim, codEventoTrim, Quantita, PesoTot, PesoCad, CodStatoTrim, UDC_parentTrim, noteTrim, clientIp), tipoLog.INFO);
          }
        }
        else
        {
          // insert con calcolo UDC
          try
          {
            tabUdc = DataProxy.obj.taCartellini.stp_insNewFull(CodCS, CodBilanciaTrim, annoTrim, CodClienteTrim, ParticolareTrim, CodImpiantoTrim, CodStampoTrim, EsponenteTrim, FiguraTrim, DataRif, TurnoRif, CodImballoTrim, CodSoggettoTrim, Tara, IdxPosizione, CodTipoDichiarazioneTrim, codEventoTrim, Quantita, PesoTot, PesoCad, CodStatoTrim, UDC_parentTrim, doDeleteUdcTara, noteTrim);
          }
          catch (Exception exc)
          {
            // loggo errore
            logger.lg.scriviLog(string.Format("ERRORE CREAZIONE UDC: | {24} | procedura stp_insNewFull, parametri: {0} | {1} | {2} | {3} | {4} | {5} | {6} | {7} | {8} | {9} | {10} | {11} | {12} | {13} | {14} | {15} | {16} | {17} | {18} | {19} | {20} | {21} | {22} | {23}{25}{26}", answ, CodCS, CodBilanciaTrim, annoTrim, CodClienteTrim, ParticolareTrim, CodImpiantoTrim, CodStampoTrim, EsponenteTrim, FiguraTrim, DataRif, TurnoRif, CodImballoTrim, CodSoggettoTrim, Tara, IdxPosizione, CodTipoDichiarazioneTrim, codEventoTrim, Quantita, PesoTot, PesoCad, CodStatoTrim, UDC_parentTrim, noteTrim, clientIp, Environment.NewLine, exc), tipoLog.EXCEPTION);
          }
        }
        // leggo la riga
        answ = tabUdc[0].UDC;
        // loggo tutto!
        if (memLayer.ML.confReadInt("_logLevel") > 5)
        {
          try
          {
            logger.lg.scriviLog(string.Format(" | {24} | NUOVO cartellino da postazione: {0} | {1} | {2} | {3} | {4} | {5} | {6} | {7} | {8} | {9} | {10} | {11} | {12} | {13} | {14} | {15} | {16} | {17} | {18} | {19} | {20} | {21} | {22} | {23}", answ, CodCS, CodBilanciaTrim, annoTrim, CodClienteTrim, ParticolareTrim, CodImpiantoTrim, CodStampoTrim, EsponenteTrim, FiguraTrim, DataRif, TurnoRif, CodImballoTrim, CodSoggettoTrim, Tara, IdxPosizione, CodTipoDichiarazioneTrim, codEventoTrim, Quantita, PesoTot, PesoCad, CodStatoTrim, UDC_parentTrim, noteTrim, clientIp), tipoLog.INFO);
          }
          catch
          { }
        }
        // solo se UDC parent != vuoto...
        if (UDC_parentTrim != "")
        {
          try
          {
            // salvo associazione parent-child tra UDC!
            DataProxy.obj.taRelazUDC.Insert(UDC_parentTrim, answ, DateTime.Now);
          }
          catch
          { }
        }
      }
      else
      {
        logger.lg.scriviLog(string.Format(" | {23} | CodSoggetto / particolare non validi! tentativo di creazione cartellino come {0} | {1} | {2} | {3} | {4} | {5} | {6} | {7} | {8} | {9} | {10} | {11} | {12} | {13} | {14} | {15} | {16} | {17} | {18} | {19} | {20} | {21} | {22}", CodCS, CodBilanciaTrim, annoTrim, CodClienteTrim, ParticolareTrim, CodImpiantoTrim, CodStampoTrim, EsponenteTrim, FiguraTrim, DataRif, TurnoRif, CodImballoTrim, CodSoggettoTrim, Tara, IdxPosizione, CodTipoDichiarazioneTrim, codEventoTrim, Quantita, PesoTot, PesoCad, CodStatoTrim, UDC_parentTrim, noteTrim, clientIp), tipoLog.ERROR);
      }
      return answ;
    }
    /// <summary>
    /// associa udc all'UDCParent
    /// </summary>        
    /// <param name="codUdc">UDC destinazione</param>
    /// <param name="codParent">UDC parent</param>
    /// <returns></returns>
    public bool associaUdcParent(string codUdc, string codParent)
    {
      bool answ = false;
      try
      {
        answ = associaUdcParent(codUdc, codParent, false);
      }
      catch
      { }
      return answ;
    }
    /// <summary>
    /// VERIFICA se ci sia associazione tra udc e l'UDCParent e restituisce TRUE se sia già associato
    /// </summary>        
    /// <param name="codUdc">UDC destinazione</param>
    /// <param name="codParent">UDC parent</param>
    /// <returns></returns>
    public bool checkAssociazioneUdcParent(string codUdc, string codParent)
    {
      bool answ = false;
      try
      {
        answ = DataProxy.obj.taRelazUDC.getByParentChild(codUdc, codParent).Rows.Count > 0;
      }
      catch
      { }
      return answ;
    }
    /// <summary>
    /// calcola l'UDC Parent di quello fornito
    /// </summary>        
    /// <param name="codUdc">UDC destinazione</param>
    /// <param name="codParent">UDC parent</param>
    /// <returns></returns>
    public string getUdcParent(string codUdc)
    {
      string answ = "";
      try
      {
        answ = DataProxy.obj.taRelazUDC.stp_getParent(codUdc)[0].UDC_parent;
      }
      catch
      { }
      return answ;
    }
    /// <summary>
    /// calcola l'UDC Parent di quello fornito IN ORDINE DESCENDING
    /// </summary>        
    /// <param name="codUdc">UDC destinazione</param>
    /// <param name="codParent">UDC parent</param>
    /// <returns></returns>
    public string getUdcParentDesc(string codUdc)
    {
      string answ = "";
      try
      {
        answ = DataProxy.obj.taRelazUDC.stp_getParentDesc(codUdc)[0].UDC_parent;
      }
      catch
      { }
      return answ;
    }
    /// <summary>
    /// associa udc all'UDCParent
    /// </summary>
    /// <param name="codUdc">UDC destinazione</param>
    /// <param name="codParent">UDC parent</param>
    /// <param name="copyAttr">copiare si/no attributi UDC da parent a child</param>
    /// <returns></returns>
    public bool associaUdcParent(string codUdc, string codParent, bool copyAttr)
    {
      bool answ = false;
      try
      {
        DataProxy.obj.taCartellini.stp_UDC_associaParent(codUdc, codParent, CodSoggCurrUser, copyAttr);
        answ = true;
      }
      catch
      { }
      return answ;
    }
    /// <summary>
    /// effettua la stampa di un dato UDC
    /// </summary>
    /// <param name="UDC">Codice UDC</param>
    /// <param name="printer">stampante specifica (da postazioen o std da webconfig, a cura dell'utente</param>
    /// <param name="clientIp">IP del chiamante</param>
    /// <returns></returns>
    public bool stampaUdc(string UDC, string printer, tipoCartellino tipoCart, string clientIp)
    {
      bool answ = false;
      // controllo se esista UDC
      if (checkUDC(UDC))
      {
        answ = reportPrinter.obj.stampaCartellino(tipoCart, UDC, printer);
        logger.lg.scriviLog(string.Format(" | {0} | stampato UDC {1} | stampante {2} | tipo {3}", clientIp, UDC, printer, tipoCart), tipoLog.INFO);
      }
      return answ;
    }

    /// <summary>
    /// effettua la Ristampa di un dato UDC partendo dal primo tipo di cartellino stampato...
    /// </summary>
    /// <param name="UDC">Codice UDC</param>
    /// <param name="printer">stampante specifica (da postazioen o std da webconfig, a cura dell'utente</param>
    /// <param name="clientIp">IP del chiamante</param>
    /// <returns></returns>
    public bool ristampaUdc(string UDC, string printer, string clientIp)
    {
      bool answ = false;
      tipoCartellino tipoCart = tipoCartellino.cartND;
      try
      {
        tipoCart = (tipoCartellino)Enum.Parse(typeof(tipoCartellino), DataProxy.obj.taPJQ.getFirstByUdc(UDC)[0].TipoCart);
      }
      catch
      { }
      if (tipoCart != tipoCartellino.cartND)
      {
        // controllo se esista UDC
        if (checkUDC(UDC))
        {
          answ = reportPrinter.obj.stampaCartellino(tipoCart, UDC, printer);
          logger.lg.scriviLog(string.Format(" | {0} | stampato UDC {1} | stampante {2} | tipo {3}", clientIp, UDC, printer, tipoCart), tipoLog.INFO);
        }
      }
      return answ;
    }
    /// <summary>
    /// restituisce particolare da UDC
    /// </summary>
    /// <param name="UDC"></param>
    /// <returns></returns>
    public string getParticolareByUDC(string UDC)
    {
      string answ = "";
      try
      {
        answ = (taCartellini.getDetailsUdcByUdc(UDC)[0].Particolare);
      }
      catch
      { }
      return answ;
    }
    /// <summary>
    /// restituisce note dell'UDC
    /// </summary>
    /// <param name="UDC"></param>
    /// <returns></returns>
    public string getNoteByUDC(string UDC)
    {
      string answ = "";
      try
      {
        answ = (taCartellini.getDetailsUdcByUdc(UDC)[0].Note);
      }
      catch
      { }
      return answ;
    }
    /// <summary>
    /// aggiorna note dell'UDC
    /// </summary>
    /// <param name="UDC"></param>
    /// <param name="note"></param>
    public void updateNoteUDC(string UDC, string note)
    {
      taCartellini.updateNote(UDC, note, CodSoggCurrUser);
    }
    /// <summary>
    /// aggiorna posizione dell'UDC
    /// </summary>
    /// <param name="UDC"></param>
    /// <param name="idxPosizione"></param>
    public void updatePosizioneUDC(string UDC, int idxPosizione)
    {
      taCartellini.updateIdxPosizione(UDC, idxPosizione, CodSoggCurrUser);
    }
    /// <summary>
    /// aggiorna note e posizione dell'UDC
    /// </summary>
    /// <param name="UDC"></param>
    /// <param name="note"></param>
    /// <param name="idxPosizione"></param>
    public void updateNotePosizioneUDC(string UDC, string note, int idxPosizione)
    {
      taCartellini.updateNotePosizione(UDC, idxPosizione, note, CodSoggCurrUser);
    }
    /// <summary>
    /// aggiorna note, posizione e data fusione dell'UDC
    /// </summary>
    /// <param name="UDC"></param>
    /// <param name="note"></param>
    /// <param name="idxPosizione"></param>
    /// <param name="DataFus"></param>
    public void updateNotePosizioneDataUDC(string UDC, string note, int idxPosizione, DateTime DataFus)
    {
      taCartellini.updateNotePosizioneData(UDC, idxPosizione, note, CodSoggCurrUser, DataFus);
    }
    /// <summary>
    /// aggiorna note, posizione e data fusione dell'UDC
    /// </summary>
    /// <param name="UDC"></param>
    /// <param name="note"></param>
    /// <param name="idxPosizione"></param>
    /// <param name="DataFus"></param>
    /// <param name="CodImballo"></param>
    public void updateNotePosizioneDataImballoUDC(string UDC, string note, int idxPosizione, DateTime DataFus, string CodImballo)
    {
      taCartellini.updateNotePosizioneDataImballo(UDC, idxPosizione, note, CodSoggCurrUser, DataFus, CodImballo);
    }
    /// <summary>
    /// aggiorna note, posizione e data fusione dell'UDC
    /// </summary>
    /// <param name="UDC"></param>
    /// <param name="note"></param>
    /// <param name="DataFus"></param>
    /// <param name="CodImballo"></param>
    /// <param name="AL"></param>
    public void updateFinDtxFull(string UDC, string note, DateTime DataFus, string CodImballo, string AL)
    {
      taCartellini.finDatamatrixFullUpdate(AL, UDC, CodImballo, note, DataFus, CodSoggCurrUser);
    }
    /// <summary>
    /// Verifica se UDC abbia attributo indicato
    /// </summary>
    /// <param name="UDC"></param>
    /// <param name="CodAttr"></param>
    /// <returns></returns>
    public bool udcHasAttr(string UDC, string CodAttr)
    {
      bool answ = false;
      try
      {
        answ = MagClass.magazzino.taAtt2UDC.getByUdc(UDC).Select(string.Format("CodAttr = '{0}'", CodAttr)).Length > 0 ? true : false;
      }
      catch
      { }
      return answ;
    }

    #endregion

    #region procedure di verifica e traduzione dati da anagrafiche

    /// <summary>
    /// Verifica la corrispondenza dati tra RigheListePrelievo ed ElencoCartellini
    /// </summary>
    /// <param name="CodLista"></param>
    /// <param name="UDC"></param>
    /// <returns></returns>
    public bool verificaDatiUdc(string CodLista, string UDC)
    {
      bool answ = false;

      try
      {
        DS_magazzino.ElencoListePrelievoDataTable tabellaElenco = taElencoListePrelievo.getByCodLista(CodLista);
        DS_magazzino.ElencoListePrelievoRow rigaElenco = tabellaElenco[0];

        DS_magazzino.ElencoCartelliniDataTable tabellaUDC = taCartellini.getDetailsUdcByUdc(UDC);
        DS_magazzino.ElencoCartelliniRow rigaUDC = tabellaUDC[0];

        // ricavo dati da confrontare - da Lista ricavo particolare/esponente/figura
        string particolareLista = rigaElenco.Particolare.Trim();
        string esponenteLista = rigaElenco.Esponente.Trim();
        string figuraLista = rigaElenco.Figura.Trim();
        string CodImballoLista = rigaElenco.CodImballo.Trim();

        //stessi dati da UDC
        string particolareUDC = rigaUDC.Particolare.Trim();
        string esponenteUDC = rigaUDC.Esponente.Trim();
        string figuraUDC = rigaUDC.Figura.Trim();
        string CodImballoUDC = rigaUDC.CodImballo.Trim();

        // condizioni di uguaglianza...
        bool particolareOk = false;
        bool esponenteOk = false;
        bool figuraOk = false;
        bool CodImballoOk = false;
        // verifico le condizioni 1 ad 1...
        particolareOk = (particolareLista == particolareUDC);
        if (esponenteLista == "*")
        {
          esponenteOk = true;
        }
        else
        {
          esponenteOk = (esponenteLista == esponenteUDC);
        }
        if (figuraLista == "*")
        {
          figuraOk = true;
        }
        else
        {
          figuraOk = (figuraLista == figuraUDC);
        }
        if (CodImballoLista == "*")
        {
          CodImballoOk = true;
        }
        else
        {
          CodImballoOk = (CodImballoLista == CodImballoUDC);
        }

        // verifica finale del risultato uguaglianza...
        answ = (particolareOk && esponenteOk && figuraOk && CodImballoOk);
      }
      catch
      {
        answ = false;
      }

      return answ;
    }
    /// <summary>
    /// restituisce codice soggetto dell'user corrente
    /// </summary>
    /// <returns></returns>
    public string CodSoggCurrUser
    {
      get
      {
        // ricavo da session...
        string CodSoggetto = "";
        try
        {
          CodSoggetto = memLayer.ML.StringSessionObj("CodSoggetto");
        }
        catch (Exception e)
        {
          logger.lg.scriviLog(string.Format("Non sono riuscito a recuperare il codice soggetto DALLA SESSIONE per l'utente loggato: {0}, errore {1}{2}", user_std.UtSn.userNameAD, Environment.NewLine, e), tipoLog.ERROR);
        }
        if (string.IsNullOrEmpty(CodSoggetto))
        {
          // provo a recuperare da cookie...
          CodSoggetto = memLayer.ML.getCookieVal("CodSoggetto");
        }
        if (string.IsNullOrEmpty(CodSoggetto))
        {
          if (user_std.UtSn.utente != "")
          {
            try
            {
              CodSoggetto = DataProxy.obj.taSogg2Oper.getByUserDominio(user_std.UtSn.utente, user_std.UtSn.dominio)[0].CodSoggetto;
              // salvo in sessione...
              memLayer.ML.setSessionVal("CodSoggetto", CodSoggetto);
            }
            catch (Exception e)
            {
              logger.lg.scriviLog(string.Format("Non sono riuscito a recuperare il codice soggetto per l'utente loggato: {0}, errore {1}{2}", user_std.UtSn.userNameAD, Environment.NewLine, e), tipoLog.ERROR);
            }
          }
        }
        return CodSoggetto;
      }
    }
    /// <summary>
    /// restituisce l'IdxCella dato il CodCella
    /// </summary>
    /// <param name="CodCS">Codice company/sito</param>
    /// <param name="CodCella"></param>
    /// <returns></returns>
    public int IdxCellaByCodCella(string CodCS, string CodCella)
    {
      int answ = 0;
      try
      {
        answ = taCelle.getByCodCella(CodCella)[0].IdxCella; // NON controllo il CodCS...
      }
      catch
      { }
      return answ;
    }
    /// <summary>
    /// restituisce il CodCella dato l'IdxCella
    /// </summary>
    /// <param name="CodCS">Codice company/sito</param>
    /// <param name="IdxCella"></param>
    /// <returns></returns>
    public string CodCellaByIdxCella(string CodCS, int IdxCella)
    {
      string answ = "";
      try
      {
        answ = taCelle.getByIdxCella(IdxCella)[0].CodCella; // NON controllo il CodCS...
      }
      catch
      { }
      return answ;
    }
    /// <summary>
    /// verifica se la cella indicata sia attiva
    /// </summary>
    /// <param name="CodCS">Codice company/sito</param>
    /// <param name="IdxCella"></param>
    /// <returns></returns>
    public bool cellaAttiva(string CodCS, int IdxCella)
    {
      bool answ = false;
      try
      {
        answ = taCelle.getByIdxCella(IdxCella)[0].Attiva; // NON controllo il CodCS...
      }
      catch
      { }
      return answ;
    }
    /// <summary>
    /// verifica se la cella indicata sia piena
    /// </summary>
    /// <param name="CodCS">Codice company/sito</param>
    /// <param name="IdxCella"></param>
    /// <returns></returns>
    public bool cellaPiena(string CodCS, int IdxCella)
    {
      bool answ = false; //default non piena = permette caricamento
      int idxTipoCella = 0;
      bool checkPiena = true;
      try
      {
        // controllo il tipo cella, se richiede check piena (altrimenti do ok...)
        idxTipoCella = taCelle.getByIdxCella(IdxCella)[0].IdxTipoCella;
        checkPiena = taTipoCella.getByIdx(idxTipoCella)[0].CheckPiena;
      }
      catch
      { }
      if (checkPiena)
      {
        try
        {
          // faccio controllo effettivo cella piena
          answ = taCelle.getByIdxCella(IdxCella)[0].Piena; // NON controllo il CodCS...
        }
        catch
        { }
      }
      return answ;
    }
    /// <summary>
    /// restituisce cod UDC associato ad una cella
    /// </summary>
    /// <param name="CodCS">Codice company/sito</param>
    /// <param name="IdxCella"></param>
    /// <returns></returns>
    public string udcInCella(string CodCS, int IdxCella)
    {
      string answ = "";
      try
      {
        answ = taPosUdcCorr.getByIdxCella(IdxCella)[0].UDC;
      }
      catch
      { }
      return answ;
    }
    /// <summary>
    /// verifica la cella indicata sia valida, ovvero esistente
    /// </summary>
    /// <param name="CodCella"></param>
    /// <returns></returns>
    public bool checkCella(string CodCella)
    {
      bool answ = false;
      try
      {
        answ = (taCelle.getByCodCella(CodCella).Rows.Count > 0);
      }
      catch
      { }
      return answ;
    }
    /// <summary>
    /// verifica se il particolare indicato sia valido, ovvero esistente
    /// </summary>
    /// <param name="CodCS">Codice company/sito</param>
    /// <param name="Particolare"></param>
    /// <returns></returns>
    public bool checkParticolare(string CodCS, string Particolare)
    {
      bool answ = false;
      try
      {
        answ = (utils.obj.taSelParticolari.getByConditioValue(Particolare, "*").Rows.Count > 0);
      }
      catch (Exception exc)
      {
        logger.lg.scriviLog(string.Format("Errore in check particolare:{0}{1}", Environment.NewLine, exc), tipoLog.EXCEPTION);
      }
      return answ;
    }
    /// <summary>
    /// restituisce il num di UDC che corrispondono alla richiesta indicata
    /// </summary>
    /// <param name="CodCS"></param>
    /// <param name="Particolare"></param>
    /// <param name="codEsponente"></param>
    /// <param name="codFigura"></param>
    /// <param name="CodImballo"></param>
    /// <param name="codTipoLista"></param>
    /// <returns></returns>
    public int numUdcDaPart(string CodCS, string Particolare, string codEsponente, string codFigura, string CodImballo, string codTipoLista)
    {
      int answ = 0;
      if (Particolare != "")
      {
        try
        {
          answ = taVParticolariOverwiew.getByDatiListaPrelievo(Particolare, CodCS, codEsponente, codFigura, CodImballo, codTipoLista)[0].NumUDC;
        }
        catch
        { }
      }
      return answ;
    }
    /// <summary>
    /// verifica se l'UDC sia riattivabile, ovvero
    /// - sia permesso da web.config
    /// - l'UDC sia in un mag che permette riattivazione
    /// </summary>
    /// <param name="UDC"></param>
    /// <returns></returns>
    public bool udcIsRiattivabile(string UDC)
    {
      bool answ = false;
      // se permesso da web config controllo
      if (memLayer.ML.confReadBool("riattUdcPermessa"))
      {
        try
        {
          // recupero posizione attuale
          int IdxPosizione = taCartellini.getDetailsUdcByUdc(UDC)[0].IdxPosizione;
          // verifico se riattivabile
          answ = taAnagPos.getByIdxPosizione(IdxPosizione)[0].IsRiattivaEnabled;
        }
        catch (Exception e)
        {
          logger.lg.scriviLog(string.Format("Errore nella riattivazione dell'UDC {0}:{1}{2}", UDC, Environment.NewLine, e), tipoLog.EXCEPTION);
        }
      }
      return answ;
    }

    #endregion

    #region liste di prelievo

    /// <summary>
    /// Crea una lista di prelievo andando a prenotare gli UDC del particolare richiesto in logica FIFO
    /// </summary>
    /// <param name="CodCS"></param>
    /// <param name="TipoListaPrelievo"></param>
    /// <param name="Particolare"></param>
    /// <param name="Esponente"></param>
    /// <param name="Figura"></param>
    /// <param name="QtaTot"></param>
    /// <param name="CodImballo"></param>
    /// <param name="Destinatario"></param>
    /// <param name="DestinatarioDescrizione"></param>
    /// <returns></returns>
    public string creaListaPrelievo(string CodCS, string TipoListaPrelievo, string Particolare, string Esponente, string Figura, decimal QtaTot, string CodImballo, string Destinatario, string DestinatarioDescrizione)
    {
      /*
       * - ordini gli UDC per data dal + vecchio (data fusione? direi di si!)
       * 
       * - prenda 1 ad 1 gli UDC, e crei dall'UDC un record in RigheListePrelievo con 
       *   - CodLista (dal record appena generato)
       *   - UDC (il + vecchio trovato)
       *   - QTA (dell'UDC)
       *   - Proposto = 1 (vero)
       *   - Prelevato = 0 (falso)
       * - questo loop di prelievo va eseguito fino a quanto la somam delle qty sia maggiore o uguale alla qty richiesta, o fino a quando siano finiti gli UDC
       * 
       * - potrebbe esser cambiato approccio e si potrebbe fare una query ceh seleziona i + vecchi UDC in numero corretto fin dall'inizio da includere facendo una cosa del tipo
       *   - calcolo media qty degli UDC papabili x le condizioni dette prima
       *   - dato il totale ottengo quanti UDC mi servono arrotondando x eccesso (se ho 200 richiesti, media 70, CEIL(200/70) = 3)
       *   - faccio un SELECT TOP n (qui 3) * FROM ElencoCartellini WHERE ...
       *   - e questa select la uso x farci un INSERT INTO in RigheListePrelievo
       * 
       * - terminati questi step si aggiorna la lista di prelievo emttendo come qty quella data dalla somma degli UDC davvero proposti
       * 
       * - la stored deve restituire il codice della lista di prelievo e passarla qui, che a sua volta passerà al chiamante il codice della lista
       * */

      string answ = "K";

      // variabile di tipo datetime per data corrente
      DateTime adesso = DateTime.Now;
      // non la valorizzo qui ma calcolo ... se non fa verificare
      string RagioneSociale = "";

      // ricavo da session...
      string CodSoggetto = CodSoggCurrUser;
      // proseguo SOLO se ho trovato cod soggetto...
      if (CodSoggetto != "")
      {
        // li ricavo da db successivamente
        string DisegnoGrezzo = "";
        string DescParticolare = "";
        string codCliente = "";


        // ricavo codCliente
        try
        {
          codCliente = DataProxy.obj.taAnagParticolari.getByParticolare(Particolare)[0].CodCliente;
        }
        catch { }

        // ricavo DisegnoGrezzo
        try
        {
          DisegnoGrezzo = DataProxy.obj.taAnagParticolari.getByParticolare(Particolare)[0].DisegnoGrezzo;
        }
        catch { }

        try
        {
          DescParticolare = DataProxy.obj.taAnagParticolari.getByParticolare(Particolare)[0].DescParticolare;
        }
        catch { }

        // dato codcliente ricavo la ragione sociale
        try
        {
          RagioneSociale = DataProxy.obj.taAnagClienti.getRagioneSocialeByCodCliente(codCliente)[0].RagSociale;
        }
        catch { }


        string codListaAttuale = "";
        try
        {
          // eseguo soltanto la query (meglio con try catch così se non c'è non dà errore...)
          DS_magazzino.ElencoListePrelievoDataTable tabellaElencoListe = taElencoListePrelievo.InsertQuery(string.Format("{0:yy}", adesso), string.Format("{0:MM}", adesso), TipoListaPrelievo, memLayer.ML.cdv("CodCS"), codCliente, RagioneSociale, CodSoggetto, Particolare, DescParticolare, DisegnoGrezzo, Esponente, Figura, CodImballo, QtaTot, Destinatario, DestinatarioDescrizione);

          // ricavo prima (e unica) riga dalla select
          DS_magazzino.ElencoListePrelievoRow rigaElencoListe = tabellaElencoListe[0];

          // ricavo valore del CodLista attuale appena inserito
          codListaAttuale = rigaElencoListe.CodLista;
        }
        catch (Exception e)
        {
          logger.lg.scriviLog(string.Format("Eccezione creazione lista prelievo: {0}{1}", Environment.NewLine, e), tipoLog.ERROR);
        }
        if (codListaAttuale != "")
        {
          answ = codListaAttuale;
          DS_magazzino.ElencoCartelliniDataTable tabellaElencoCartellini = taCartellini.getUdcUnusedOlder(codListaAttuale);
          allocaRigheListaPrelievo(QtaTot, codListaAttuale, tabellaElencoCartellini);
        }
      }
      return answ;
    }
    /// <summary>
    /// Crea una lista di prelievo andando a prenotare gli UDC del particolare richiesto in logica FIFO
    /// </summary>
    /// <param name="CodCS"></param>
    /// <param name="TipoListaPrelievo"></param>
    /// <param name="Particolare"></param>
    /// <param name="Esponente"></param>
    /// <param name="Figura"></param>
    /// <param name="QtaTot"></param>
    /// <param name="CodImballo"></param>
    /// <param name="Destinatario"></param>
    /// <param name="DestinatarioDescrizione"></param>
    /// <returns></returns>
    public string creaListaPrelievoSmart(string CodCS, string TipoListaPrelievo, string Particolare, string Esponente, string Figura, decimal QtaTot, string CodImballo, string Destinatario, string DestinatarioDescrizione)
    {
      string answ = "K";

      // variabile di tipo datetime per data corrente
      DateTime adesso = DateTime.Now;
      // non la valorizzo qui ma calcolo ... se non fa verificare
      string RagioneSociale = "";

      // ricavo da session...
      string CodSoggetto = CodSoggCurrUser;
      // proseguo SOLO se ho trovato cod soggetto...
      if (CodSoggetto != "")
      {
        // li ricavo da db successivamente
        string DisegnoGrezzo = "";
        string DescParticolare = "";
        string codCliente = "";


        // ricavo codCliente
        try
        {
          codCliente = DataProxy.obj.taAnagParticolari.getByParticolare(Particolare)[0].CodCliente;
        }
        catch { }

        // ricavo DisegnoGrezzo
        try
        {
          DisegnoGrezzo = DataProxy.obj.taAnagParticolari.getByParticolare(Particolare)[0].DisegnoGrezzo;
        }
        catch { }

        try
        {
          DescParticolare = DataProxy.obj.taAnagParticolari.getByParticolare(Particolare)[0].DescParticolare;
        }
        catch { }

        // dato codcliente ricavo la ragione sociale
        try
        {
          RagioneSociale = DataProxy.obj.taAnagClienti.getRagioneSocialeByCodCliente(codCliente)[0].RagSociale;
        }
        catch { }


        string codListaAttuale = "";
        try
        {
          // eseguo soltanto la query (meglio con try catch così se non c'è non dà errore...)
          DS_magazzino.ElencoListePrelievoDataTable tabellaElencoListe = taElencoListePrelievo.InsertQuery(string.Format("{0:yy}", adesso), string.Format("{0:MM}", adesso), TipoListaPrelievo, memLayer.ML.cdv("CodCS"), codCliente, RagioneSociale, CodSoggetto, Particolare, DescParticolare, DisegnoGrezzo, Esponente, Figura, CodImballo, QtaTot, Destinatario, DestinatarioDescrizione);

          // ricavo prima (e unica) riga dalla select
          DS_magazzino.ElencoListePrelievoRow rigaElencoListe = tabellaElencoListe[0];

          // ricavo valore del CodLista attuale appena inserito
          codListaAttuale = rigaElencoListe.CodLista;
        }
        catch (Exception e)
        {
          logger.lg.scriviLog(string.Format("Eccezione creazione lista prelievo: {0}{1}", Environment.NewLine, e), tipoLog.ERROR);
        }
        if (codListaAttuale != "")
        {
          answ = codListaAttuale;
        }
      }
      return answ;
    }
    /// <summary>
    /// indica come attivata in carico di una lista di prelievo
    /// </summary>
    /// <param name="CodCS">Codice company/sito</param>
    /// <param name="CodLista">codice della lista di prelievo</param>
    /// <param name="CodSoggetto">cod operatore carrellista</param>
    /// <returns></returns>
    public esitoOperazione attivaListaPrelievo(string CodCS, string CodLista, string CodSoggetto)
    {
      // da chiamare quando clicco e inizio lista prelievo .... vedi sopra
      esitoOperazione answ = esitoOperazione.errore;
      try
      {
        // la query recupera la lista in base al CodLista
        DS_magazzino.ElencoListePrelievoDataTable tabella = taElencoListePrelievo.getByCodLista(CodLista);
        DS_magazzino.ElencoListePrelievoRow riga = tabella[0];

        // se la lista esiste...
        if (tabella.Rows.Count > 0)
        {
          // se la lista è ancora non completata
          if (riga.CodStatoLista == (int)statoLista.bozza)
          {
            taElencoListePrelievo.updateStato(CodSoggetto, CodLista, (int)statoLista.generata);
            answ = esitoOperazione.ok;
          }
          // se è solo iniziata permetto di riportarla a generata...
          else if (riga.CodStatoLista == (int)statoLista.iniziata)
          {
            taElencoListePrelievo.updateStato(CodSoggetto, CodLista, (int)statoLista.generata);
            answ = esitoOperazione.ok;
          }
          // se è già completata dà errore
          else
          {
            answ = esitoOperazione.errore_readOnly;
          }
        }
        // se la lista non esiste dai errore
        else
        {
          answ = esitoOperazione.errore;
        }
      }
      catch
      { }
      return answ;
    }
    /// <summary>
    /// indica presa in carico di una lista di prelievo
    /// </summary>
    /// <param name="CodCS">Codice company/sito</param>
    /// <param name="CodLista">codice della lista di prelievo</param>
    /// <param name="CodSoggetto">cod operatore carrellista</param>
    /// <returns></returns>
    public esitoOperazione iniziaListaPrelievo(string CodCS, string CodLista, string CodSoggetto)
    {
      memLayer.ML.setSessionVal("activeTask", string.Format("Lista Prelievo {0}", CodLista));
      memLayer.ML.setSessionVal("CodListaAttiva", CodLista, true);
      // da chiamare quando clicco e inizio lista prelievo .... vedi sopra
      esitoOperazione answ = esitoOperazione.errore;

      try
      {
        // la query recupera la lista in base al CodLista
        DS_magazzino.ElencoListePrelievoDataTable tabella = taElencoListePrelievo.getByCodLista(CodLista);
        DS_magazzino.ElencoListePrelievoRow riga = tabella[0];

        // se la lista esiste...
        if (tabella.Rows.Count > 0)
        {
          // se la lista è ancora non completata
          if (riga.CodStatoLista == (int)statoLista.generata)
          {
            taElencoListePrelievo.updateStato(CodSoggetto, CodLista, (int)statoLista.iniziata);
            answ = esitoOperazione.ok;
          }
          // se è già completata o iniziata dà errore
          else
          {
            answ = esitoOperazione.errore_readOnly;
          }
        }
        // se la lista non esiste dai errore
        else
        {
          answ = esitoOperazione.errore;
        }
      }
      catch
      { }
      return answ;
    }
    /// <summary>
    /// indica come completata (da parte del magazziniere) una lista di prelievo
    /// </summary>
    /// <param name="CodCS">Codice company/sito</param>
    /// <param name="CodLista">codice della lista di prelievo</param>
    /// <param name="CodSoggetto">cod operatore carrellista</param>
    /// <param name="clientIp">IP del client</param>
    /// <returns></returns>
    public esitoOperazione completaListaPrelievo(string CodCS, string CodLista, string CodSoggetto, string clientIp)
    {
      // da chiamare quando clicco e inizio lista prelievo .... vedi sopra
      esitoOperazione answ = esitoOperazione.errore;
      try
      {
        // la query recupera la lista in base al CodLista
        DS_magazzino.ElencoListePrelievoDataTable tabella = taElencoListePrelievo.getByCodLista(CodLista);
        DS_magazzino.ElencoListePrelievoRow riga = tabella[0];

        // se la lista esiste...
        if (tabella.Rows.Count > 0)
        {
          // se la lista è ancora non completata
          if (riga.CodStatoLista == (int)statoLista.iniziata)
          {
            // controllo se ALMENO un UDC sia stsato prelevato
            int numUdcPrelevati = taRigheListePrelievo.getByCodListaPrelevate(CodLista).Rows.Count;
            if (numUdcPrelevati > 0)
            {
              // ricavo il codtipolista
              string codTipoListaAttuale = riga.CodTipoLista;

              //leggo da tipoLista prelievo alcuni dati (es codcella di destinazione)
              DS_magazzino.TipoListaPrelievoDataTable tabellaTipoLista = taTipoListaPrelievo.getByCodTipoLista(codTipoListaAttuale);
              DS_magazzino.TipoListaPrelievoRow rigaTipoLista = tabellaTipoLista[0];

              // leggo da righe lista prelievo il dato udc che mi serve
              DS_magazzino.RigheListePrelievoDataTable tabellaRigheListaPrelievo = taRigheListePrelievo.getByCodListaPrelevate(CodLista);
              DS_magazzino.RigheListePrelievoRow rigaListaPrelievo = tabellaRigheListaPrelievo[0];

              // leggo il codice della cella...
              string codCellaDestAttuale = rigaTipoLista.CodCella;
              // lo trasformo x avere la cella di destinazione...
              int idxCellaTo = taCelle.getByCodCella(codCellaDestAttuale)[0].IdxCella;
              // sposto ("metto a terra") gli UDC
              foreach (DS_magazzino.RigheListePrelievoRow row in tabellaRigheListaPrelievo.Rows)
              {
                // ricavo il codice UDC...
                string _UDC = row.UDC;
                // sposto UDC
                spostaUDC(CodCS, _UDC, idxCellaTo, false, clientIp);
                // dopo aver spostato UDC sistemo eventuali Righe di Prelievo x lo stesso UDC pending...
                taRigheListePrelievo.stp_RLP_sbloccaNonPrelevate(CodLista, _UDC);
              }
              // libero le righe non prelevate...
              taRigheListePrelievo.stp_RLP_eliminaNonPrelevate(CodLista);
              // aggiorno stato lista
              taElencoListePrelievo.updateStato(CodSoggetto, CodLista, (int)statoLista.completata);
              answ = esitoOperazione.ok;
              memLayer.ML.emptySessionVal("CodListaAttiva");
              memLayer.ML.emptySessionVal("activeTask");
            }
            else //nessun UDC prelevato
            {
              answ = esitoOperazione.errore_noUdc;
            }
          }
          // se è già completata o NON iniziata dà errore
          else
          {
            answ = esitoOperazione.errore_readOnly;
          }
        }
        // se la lista non esiste dai errore
        else
        {
          answ = esitoOperazione.errore;
        }
      }
      catch
      { }
      return answ;
    }
    /// <summary>
    /// Effettua lo scaricamento della lista di prelievo indicata, ovvero
    /// - toglie dalle posizioni di magazzino tutti gli UDC indicati come prelevati (liberando tali posizioni)
    /// - assegna tutti gli UDC prelevati alla cella indicata per il tipo di lista di prelievo interessata
    /// - elimina eventuali righe di prelievo della lista per UDC non effettivamente prelevate
    /// - chiude la lista di prelievo (completata = 1)
    /// 
    /// Modifica vers 2.5: check trattamenti (ove attributo sia trovato...)
    /// </summary>
    /// <param name="CodCS">Codice company/sito</param>
    /// <param name="CodLista">codice della lista di prelievo</param>
    /// <param name="CodSoggetto">cod operatore carrellista</param>
    /// <param name="clientIp">IP del client</param>
    /// <param name="SlotPL">Slot PL AS400 prescelto</param>
    /// <returns>esito comando</returns>
    public esitoOperazione scaricaListaPrelievo(string CodCS, string CodLista, string CodSoggetto, string clientIp, int SlotPL)
    {
      /*
       * Questa funzione serve ALLA FINE delle operazioni di prelievo, x chiudere la lista di prelievo
       * - controllo se la lista esiste, ed è ancora NON completata
       * - se risulta già completata errore xché è "readOnly" la lista essendo già completata (vedere l'enum in fondo al codice)
       * - se la lista è ok
       *  - leggo da tipoLista prelievo alcuni dati (es codcella di destinazione)
       *  - sposto TUTTI gli UDC delle righeListaPrelievo, da posizione attuale a posizione indicata da tipo lista 
       *  (quindi da codCella --> IdxCella --> spostamento
       * 
       *  
       * 2014.06.12: aggiunta x gestione PackList AS400
       * - verifico imballi, salvo su tab movimenti gli imballi eventuali da scaricare
       * - chiamo stored x copia dati pack list su AS400
       * - chiamo stored che richiamerà SSIS e quindi CL di as400
       * 
       * 
       *  indico la lista come completata = 1 (true)
       * */
      // setup eventuali valori x rettifica
      bool fatto = false;

      esitoOperazione answ = esitoOperazione.errore;
      int trovate = 0;
      DS_magazzino.ElencoListePrelievoDataTable tabella;
      DS_magazzino.ElencoListePrelievoRow riga;
      try
      {
        tabella = taElencoListePrelievo.getByCodLista(CodLista);
        riga = tabella[0];
        trovate = tabella.Rows.Count;
        // se la lista esiste...
        if (trovate > 0)
        {
          // se la lista è completata
          if (riga.CodStatoLista == (int)statoLista.completata)
          {
            // ricavo il codtipolista
            string codTipoListaAttuale = riga.CodTipoLista;

            // leggo da tipoLista prelievo alcuni dati (es codcella di destinazione)
            DS_magazzino.TipoListaPrelievoDataTable tabellaTipoLista = taTipoListaPrelievo.getByCodTipoLista(codTipoListaAttuale);
            DS_magazzino.TipoListaPrelievoRow rigaTipoLista = tabellaTipoLista[0];

            // leggo da righe lista prelievo il dato udc che mi serve
            DS_magazzino.RigheListePrelievoDataTable tabellaRigheListaPrelievo = taRigheListePrelievo.getByCodListaPrelevate(CodLista);
            DS_magazzino.RigheListePrelievoRow rigaListaPrelievo = tabellaRigheListaPrelievo[0];

            // leggo il codice della cella...
            string CodEvento = rigaTipoLista.CodEvento;
            // posizione che devono avere (uguale) tutti gli UDC
            int idxPosizUdcAll = 0;
            // posizione corrente dell'UDC
            int idxPosizUdcCorr = 0;
            // posizione di destinazione per UDC corrente
            int idxPosizUdcDest = 0;
            // cella di provenienza
            int idxCellaFrom = 0;
            // cella di destinazione
            int idxCellaTo = 0;
            /* ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
             * ora controllo se la lista sia DAVVERO scaricabile, cioè
             * - destinatario IMPOSTATO
             * - TUTTE le righe hanno una posizione di destinazione valida, 
             * OVVERO tutte le righe hanno nella tab trans posiz eventi una riga valida
             * ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ */
            bool listaScaricabile = true;
            if (string.IsNullOrEmpty(riga.Destinatario))
            {
              listaScaricabile = false;
            }
            else
            {
              foreach (DS_magazzino.RigheListePrelievoRow row in tabellaRigheListaPrelievo.Rows)
              {
                // ricavo il codice UDC...
                string UDC = row.UDC;
                // mi serve per posizione udc corrente
                DS_magazzino.PosizioneUdcCorrenteRow rigaUdcCorrente = taPosUdcCorr.getByUDC(UDC)[0];
                // calcolo posizione destinazione da state machine...
                idxPosizUdcCorr = taCartellini.getDetailsUdcByUdc(UDC)[0].IdxPosizione;
                if (idxPosizUdcAll == 0)
                {
                  idxPosizUdcAll = idxPosizUdcCorr;
                }
                idxPosizUdcDest = StateMachine.SM.getIdxPostizioneTo(CodEvento, idxPosizUdcCorr);
                if (idxPosizUdcDest == 0 || idxPosizUdcAll != idxPosizUdcCorr)
                {
                  listaScaricabile = false;
                }
              }
            }
            // SE la lista è scaricabile procedo...
            if (listaScaricabile)
            {
              // 2015.09.18: aggiunto controllo che NON ci siano UDC con NC
              if (taRigheListePrelievo.getUdcSenzaDelibPM(CodLista).Rows.Count == 0)
              {
                if (taRigheListePrelievo.getUdcConNC(CodLista).Rows.Count == 0)
                {
                  if (taRigheListePrelievo.getDmtxUdcConNc(CodLista).Rows.Count == 0)
                  {
                    // scarico i vari UDC dal magazzino (come posizione corrente)
                    foreach (DS_magazzino.RigheListePrelievoRow row in tabellaRigheListaPrelievo.Rows)
                    {
                      // ricavo il codice UDC...
                      string UDC = row.UDC;
                      // mi serve per posizione udc corrente
                      DS_magazzino.PosizioneUdcCorrenteRow rigaUdcCorrente = taPosUdcCorr.getByUDC(UDC)[0];
                      // il secondo idx che mi serve
                      idxCellaFrom = rigaUdcCorrente.IdxCella;
                      // calcolo posizione destinazione da state machine...
                      idxPosizUdcCorr = taCartellini.getDetailsUdcByUdc(UDC)[0].IdxPosizione;
                      idxPosizUdcDest = StateMachine.SM.getIdxPostizioneTo(CodEvento, idxPosizUdcCorr);
                      // a questo punto mi calcolo se c'è una cella di destinazione associata
                      try
                      {
                        idxCellaTo = MagClass.magazzino.taCelle.getByCodMag(CodCS, idxPosizUdcDest.ToString())[0].IdxCella;
                      }
                      catch
                      {
                        idxCellaTo = 0;
                      }
                      // sposto UDC, e così facendo genero movimenti batch x AS400
                      fatto = scaricaUDC(UDC, idxPosizUdcDest, CodEvento, clientIp);
                      // sposto nella PRIMA cella di destinazione associata l'UDC
                      if (idxCellaTo > 0)
                      {
                        spostaUDC(CodCS, UDC, idxCellaTo, false, clientIp);
                      }
                      if (fatto)
                      {
                        // dopo aver scaricato UDC sistemo eventuali Righe di Prelievo x lo stesso pending...
                        magazzino.taRigheListePrelievo.stp_RLP_sbloccaNonPrelevate(CodLista, UDC);
                      }
                    }
                    // ora step finali x LDP
                    try
                    {
                      // STEP 1: segna come scaricata la lista prelievo
                      taElencoListePrelievo.updateStato(CodSoggetto, CodLista, (int)statoLista.scaricata);
                      // STEP 2: chiamo esportazione verso MovMag AS x imballi + copiare in altra tabella (quella per AS...) i dati della packing
                      taElencoListePrelievo.stp_LP_exportToAs400(CodLista, SlotPL, CodCS);
                      // STEP 3: chiamo stored x eseguire SSIS che a sua volta richiama la CL di AS400 x importazione MovMag
                      utils.obj.taAs400.stp_processaCodaMovimPackList();
                      // restituisce ok
                      answ = esitoOperazione.ok;
                    }
                    catch (Exception exc)
                    {
                      logger.lg.scriviLog(string.Format("Errore in trasferimento dati LDP verso AS400: {0}", exc), tipoLog.EXCEPTION);
                    }
                  }
                  else
                  {
                    answ = esitoOperazione.errore_DtmxNc;
                  }
                }
                else
                {
                  answ = esitoOperazione.errore_UdcNc;
                }
              }
              else
              {
                answ = esitoOperazione.errore_noDeliberPM;
              }
            }
            else
            {
              answ = esitoOperazione.errore_nonScaricabile;
            }
          }
          // se è già completata dà errore
          else
          {
            answ = esitoOperazione.errore_readOnly;
          }
        }
        // se la lista non esiste dai errore
        else
        {
          answ = esitoOperazione.errore;
        }
      }
      catch (Exception exc)
      {
        logger.lg.scriviLog(string.Format("Eccezione:{0}{1}", Environment.NewLine, exc), tipoLog.EXCEPTION);
      }
      return answ;
    }
    /// <summary>
    /// resetta (riporta in bozza) una lista di prelievo, spostando gli UDC alla posizione standard precedente
    /// </summary>
    /// <param name="CodCS">Codice company/sito</param>
    /// <param name="CodLista">codice della lista di prelievo</param>
    /// <param name="CodSoggetto">cod operatore carrellista</param>
    /// <param name="clientIp">IP del client</param>
    /// <returns></returns>
    public esitoOperazione resetListaPrelievo(string CodCS, string CodLista, string CodSoggetto, string clientIp)
    {
      memLayer.ML.emptySessionVal("CodListaAttiva");
      memLayer.ML.emptySessionVal("activeTask");
      // da chiamare quando clicco e inizio lista prelievo .... vedi sopra
      esitoOperazione answ = esitoOperazione.errore;
      // posizione corrente dell'UDC
      int idxPosizUdcAll = 0; // posizione che devono avere (uguale) tutti gli UDC
      int idxPosizUdcCorr = 0;
      int IdxPosizioneTo = 0;
      int idxPosizUdcDest = 0;
      int idxCellaTo = 0;
      try
      {
        // la query recupera la lista in base al CodLista
        DS_magazzino.ElencoListePrelievoDataTable tabella = taElencoListePrelievo.getByCodLista(CodLista);
        DS_magazzino.ElencoListePrelievoRow riga = tabella[0];

        // se la lista esiste...
        if (tabella.Rows.Count > 0)
        {
          // ricontrollo che la lista sia completata
          if (riga.CodStatoLista >= (int)statoLista.completata)
          {
            // calcolo tipo lista di prelievo
            string codTipoListaAttuale = riga.CodTipoLista;
            // dal tipo lista determino l'evento
            string codEvento = taTipoListaPrelievo.getByCodTipoLista(codTipoListaAttuale)[0].CodEvento;
            // 2014.07.10 ATTENZIONE cablato evento reset come Pre --> Rst
            codEvento = codEvento.Replace("Pre", "Rst");
            // leggo da righe lista prelievo il dato udc che mi serve
            DS_magazzino.RigheListePrelievoDataTable tabellaRigheListaPrelievo = taRigheListePrelievo.getByCodListaPrelevate(CodLista);
            DS_magazzino.RigheListePrelievoRow rigaListaPrelievo = tabellaRigheListaPrelievo[0];

            /* ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
             * ora controllo se la lista sia DAVVERO scaricabile, cioè
             * - destinatario IMPOSTATO
             * - TUTTE le righe hanno una posizione di destinazione valida, 
             * OVVERO tutte le righe hanno nella tab trans posiz eventi una riga valida
             * ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ */
            bool listaScaricabile = true;
            if (string.IsNullOrEmpty(riga.Destinatario))
            {
              listaScaricabile = false;
            }
            else
            {
              foreach (DS_magazzino.RigheListePrelievoRow row in tabellaRigheListaPrelievo.Rows)
              {
                // ricavo il codice UDC...
                string UDC = row.UDC;
                //// mi serve per posizione udc corrente
                //DS_magazzino.PosizioneUdcCorrenteRow rigaUdcCorrente = taPosUdcCorr.getByUDC(UDC)[0];
                // calcolo posizione destinazione da state machine...
                idxPosizUdcCorr = taCartellini.getDetailsUdcByUdc(UDC)[0].IdxPosizione;
                if (idxPosizUdcAll == 0)
                {
                  idxPosizUdcAll = idxPosizUdcCorr;
                }
                idxPosizUdcDest = StateMachine.SM.getIdxPostizioneTo(codEvento, idxPosizUdcCorr);
                if (idxPosizUdcDest == 0 || idxPosizUdcAll != idxPosizUdcCorr)
                {
                  listaScaricabile = false;
                }
              }
            }
            // procedo SOLO se lista scaricabile...
            if (listaScaricabile)
            {
              // Modifica x gestione "blocco " da stato LDP: PRIMA passo a bozza...
              taElencoListePrelievo.updateStato(CodSoggetto, CodLista, (int)statoLista.bozza);
              // sposto ("metto a terra") gli UDC
              string _UDC = "";
              foreach (DS_magazzino.RigheListePrelievoRow row in tabellaRigheListaPrelievo.Rows)
              {
                // ricavo il codice UDC...
                _UDC = row.UDC;
                // posizione corrente
                idxPosizUdcCorr = taCartellini.getDetailsUdcByUdc(_UDC)[0].IdxPosizione;
                // calcolo posizione destinazione da state machine...
                try
                {
                  IdxPosizioneTo = StateMachine.SM.taTTPE.getByEventoPosizione(codEvento, idxPosizUdcCorr)[0].IdxPosizioneTo;
                }
                catch (Exception exc)
                {
                  IdxPosizioneTo = 0;
                  logger.lg.scriviLog(string.Format(" | {1} | Errore in reset lista prelievo nel calcolo IdxPosizioneTo: {0}", exc, clientIp), tipoLog.EXCEPTION);
                }
                if (IdxPosizioneTo != 0)
                {
                  // lo trasformo x avere la cella di destinazione...
                  if (idxPosizUdcCorr < 0)
                  {
                    // se parto da cella negativa (consumato) calcolo destinazione da cella TO...
                    idxCellaTo = taCelle.getFirstByPosizione(IdxPosizioneTo.ToString())[0].IdxCella;
                  }
                  else
                  {
                    try
                    {
                      // altrimenti uso la posizione corrente (NON faccio vero spostamento...
                      idxCellaTo = taCelle.getFirstByPosizione(idxPosizUdcCorr.ToString())[0].IdxCella;
                    }
                    catch
                    {
                      // se parto da cella negativa (consumato) calcolo destinazione da cella TO...
                      idxCellaTo = taCelle.getFirstByPosizione(IdxPosizioneTo.ToString())[0].IdxCella;
                    }
                  }
                  // sposto UDC
                  spostaUDC(CodCS, _UDC, idxCellaTo, false, clientIp);
                  // 2014.07.09: modifica, per NON impostare da tab del magazzino con sposta fa update posizione esplicita
                  taCartellini.updateIdxPosizione(_UDC, IdxPosizioneTo, CodSoggCurrUser);
                }
              }
              // indico le righe come NON prelevate...
              taRigheListePrelievo.stp_RLP_resetPrelevate(CodLista);
              //// aggiorno stato lista che torna a BOZZA
              //taElencoListePrelievo.updateStato(CodSoggetto, CodLista, (int)statoLista.bozza);
              answ = esitoOperazione.ok;
              logger.lg.scriviLog(string.Format(" | {0} | resettata lista di prelievo UDC {1} | utente {2} | tipo {2}", clientIp, CodLista, CodSoggetto), tipoLog.INFO);
            }
            else
            {
              // loggo che c'è anomalia
              answ = esitoOperazione.errore_readOnly;
              logger.lg.scriviLog(string.Format(" | {0} | Errore in reset lista prelievo: non è stato possibile resettare per la posizione di almeno un UDC", clientIp), tipoLog.EXCEPTION);
            }
          }
          // se è già completata o NON iniziata dà errore
          else
          {
            answ = esitoOperazione.errore_readOnly;
          }
        }
        // se la lista non esiste dai errore
        else
        {
          answ = esitoOperazione.errore;
        }
      }
      catch (Exception e)
      {
        logger.lg.scriviLog(string.Format(" | {1} | Errore in reset lista prelievo: {0}", e, clientIp), tipoLog.EXCEPTION);
      }
      return answ;
    }


    /// <summary>
    /// Conferma che un dato UDC è stato prelevato per soddisfare la lista di prelievo ed aggiorna o aggiunge riga in RigheListePrelievo
    /// </summary>
    /// <param name="CodLista">codice della lista di prelievo</param>
    /// <param name="UDC">Codice UDC</param>
    /// <returns>esito comando</returns>
    public esitoOperazione confermaUdcPrelevatoPerLista(string CodLista, string UDC)
    {
      esitoOperazione answ = esitoOperazione.errore;

      // verifico che i dati corrispondano con il metodo relativo (vedi sopra)
      bool datiUdcOk = verificaDatiUdc(CodLista, UDC);

      if (datiUdcOk)
      {
        // richiamo stored  di upsert
        taRigheListePrelievo.upsertPrelevato(CodLista, UDC);
        // ...dò risposta positiva
        answ = esitoOperazione.ok;

      }
      else
      {
        // altrimenti dò errore mismatch e non proseguo
        return answ = esitoOperazione.errore_mismatch;
      }

      return answ;
    }
    /// <summary>
    /// annulla il prelievo di un UDC, aggiornando RigheListePrelievo (solo preventivato...)
    /// </summary>
    /// <param name="CodLista">codice della lista di prelievo</param>
    /// <param name="UDC">Codice UDC</param>
    /// <returns>esito comando</returns>
    public esitoOperazione annullaUdcPrelevatoPerLista(string CodLista, string UDC)
    {
      esitoOperazione answ = esitoOperazione.errore;

      /*
       * Questa funzione va chiamata da web o da terminalino ogni volta che si fa un annullamento di avvenuto prelievo, ovvero il carrellista ha ANNULLATO un prelievo di un UDC associato ad una lista
       * 
       * - in primis controllo: esiste questa riga di prelievo udc/lista?
       * - se i dati non corrispondono esco e mando falso --> vedere l'enum in fondo al codice ed 
       * usare esitoOperazione.errore_mismatch
       * - se i dati corrispondono allora 
       *  - cerco riga e tolgo check come prelevato
       * - se tutto ok passo esito ok
       * 
       * */
      try
      {
        // ricavo dati
        DS_magazzino.RigheListePrelievoDataTable tabella = taRigheListePrelievo.getByCodLista(CodLista);
        DS_magazzino.RigheListePrelievoRow riga = tabella[0];

        // se i dati esistono procedo - eseguo stored che setta non prelevato = false per la riga selezionata
        if (tabella.Rows.Count > 0)
        {
          taRigheListePrelievo.setAnnullaUdcPrelevato(CodLista, UDC);
          answ = esitoOperazione.ok;
        }

        else
        {
          answ = esitoOperazione.errore_mismatch;
        }
      }
      catch
      { }
      return answ;
    }
    /// <summary>
    /// Rigenera una Lista di prelievo togliendo gli UDC non ancora prelevati rimettendo in logica FIFO gli UDC "liberi" disponibili
    /// </summary>
    /// <param name="CodLista">codice della lista di prelievo</param>
    /// <returns>esito comando</returns>
    public esitoOperazione scambiaUdcPerLista(string CodLista)
    {
      esitoOperazione answ = esitoOperazione.errore;

      /*
       * Questa funzione va chiamata da web o da terminalino ogni volta che si fa una richiesta di cambio per un UDC già prelevato, ovvero un altro carrellista prelevato un UDC associato alla mia lista corrente - rigenera UDC da prelevare
       * */
      try
      {
        // ricavo dati
        DS_magazzino.ElencoListePrelievoRow riga = taElencoListePrelievo.getByCodLista(CodLista)[0];
        // svuoto PRIMA gli UDC non prelevati
        taRigheListePrelievo.stp_RigheListePrelievo_eliminaNonPrelevate(CodLista);
        // rigenero righe UDC da prelevare
        DS_magazzino.ElencoCartelliniDataTable tabellaElencoCartellini = taCartellini.getUdcUnusedOlder(CodLista);
        allocaRigheListaPrelievo(riga.QtaTot, CodLista, tabellaElencoCartellini);
      }
      catch
      { }
      return answ;
    }
    /// <summary>
    /// Aggiunge UN SOLO UDC in logica FIFO tra gli UDC "liberi" disponibili
    /// </summary>
    /// <param name="CodLista">codice della lista di prelievo</param>
    /// <returns>esito comando</returns>
    public esitoOperazione addUdcPerLista(string CodLista)
    {
      esitoOperazione answ = esitoOperazione.errore;
      try
      {
        // ricavo dati
        DS_magazzino.ElencoListePrelievoRow riga = taElencoListePrelievo.getByCodLista(CodLista)[0];
        // rigenero righe UDC da prelevare
        DS_magazzino.ElencoCartelliniDataTable tabellaElencoCartellini = new DS_magazzino.ElencoCartelliniDataTable();
        // aggiungo l'UDC + vecchio (se c'è)
        try
        {
          tabellaElencoCartellini.ImportRow(taCartellini.getUdcUnusedOlder(CodLista)[0]);
        }
        catch (Exception e)
        {
          logger.lg.scriviLog(String.Format("Errore in aggiunta UDC a lista prelievo: {0}", e), tipoLog.EXCEPTION);
        }
        allocaRigheListaPrelievo(riga.QtaTot, CodLista, tabellaElencoCartellini);
      }
      catch
      { }
      return answ;
    }
    /// <summary>
    /// vero/falso che l'utent eha una lista di prelievo attiva
    /// </summary>
    public bool userHasActiveLP
    {
      get
      {
        bool answ = false;
        try
        {
          answ = (MagClass.magazzino.taElencoListePrelievo.getByCodSogg(CodSoggCurrUser).Rows.Count > 0);
        }
        catch
        { }
        return answ;
      }
    }
    /// <summary>
    /// codice della lista di prelievo attiva
    /// </summary>
    public string codListaAttivaUtente
    {
      get
      {
        string answ = "";
        try
        {
          answ = MagClass.magazzino.taElencoListePrelievo.getByCodSogg(CodSoggCurrUser)[0].CodLista;
        }
        catch
        { }
        return answ;
      }
    }
    /// <summary>
    /// 
    /// </summary>
    /// <param name="CodLista"></param>
    /// <returns></returns>
    public bool listaPrelevabile(string CodLista)
    {
      bool answ = false;
      try
      {
        answ = (MagClass.magazzino.taElencoListePrelievo.getByCodLista(CodLista).Select("CodStatoLista = 1").Length > 0); // filtro su stato = 1 (può esser presa in carico)
      }
      catch
      { }
      return answ;
    }

    #endregion

    #region area rapporti qualità

    /// <summary>
    /// Crea gli UDC da associare ai cartellini dei rapporti qualità deliberati, li associa e se richiesto lancia stampa
    /// </summary>
    /// <param name="numRapQual">identificativo rapp qualità</param>
    /// <param name="doPrint">true/false se stampare</param>
    /// <param name="clientIp">IP del client</param>
    /// <returns></returns>
    public bool creaUdcDaRappQualita(int numRapQual, string note, bool doPrint, string printerName, string clientIp)
    {
      bool answ = false;
      string CodStato = "";
      // ottengo elenco righe dei cartellini del rapp qualità indicato SENZA righe UDC
      DS_magazzino.RapQualDataTable tabRapQual = taRapQual.getByNumRapQualNoUdc(numRapQual);
      // per prima cosa verifico che ci sia il rapporto di qualità in esame e che abbia righe da associare ad UDC
      if (tabRapQual.Rows.Count > 0)
      {
        string UDC = "";
        foreach (DS_magazzino.RapQualRow rqRow in tabRapQual)
        {
          // se non ha già un UDC... e se NON E' stato già scaricato...
          if (string.IsNullOrEmpty(rqRow.UDC) && rqRow.LegaScaric.ToUpper() == "N")
          {
            answ = true;
            // controllo se sia con benestare, se "N" imposto con stato Non accettata (da web.config) altrimenti con stato MP ok...
            if (rqRow.BenesQual == "N")
            {
              CodStato = memLayer.ML.confReadString("CodStatoMP-NA");
            }
            else
            {
              CodStato = memLayer.ML.confReadString("CodStatoMP");
            }
            // per ogni riga creo un UDC 
            DS_Applicazione.ElencoCartelliniDataTable tabCartellini = DataProxy.obj.taCartellini.stp_insNewFull(memLayer.ML.cdv("CodCS"), memLayer.ML.confReadString("BilanciaMP"), string.Format("{0:yy}", DateTime.Now), rqRow.CodFor, rqRow.CodLega, "", "", "", "", DateTime.Now, 0, memLayer.ML.cdv("CodImballoMP"), CodSoggCurrUser, 0, memLayer.ML.cdvi("IdxPosizMP"), "M", "UDC_MP", rqRow.Qta, Convert.ToDouble(rqRow.Qta), 1, CodStato, rqRow.ProgUDC, false, note); // UDC_MP HARD CODED!!!
            try
            {
              UDC = tabCartellini[0].UDC;
              // lo associo!
              taRapQual.stp_associaUDC(rqRow.ProgUDC, UDC);
            }
            catch (Exception e)
            {
              logger.lg.scriviLog(string.Format(" | {3} | Non sono riuscito a creare associazione UDC / rapp qual: UDC creato: {0}, progRappQual: {1}, eccezione: {2}", UDC, rqRow.ProgUDC, e, clientIp), tipoLog.EXCEPTION);
            }
            try
            {
              if (rqRow.BenesQual == "N")
              {
                // se non c'è benestare cambio posizione ad un altra cella, la prima (terra) del cod blocco MP - N.C.
                int idxPosizTo = taCelle.getByCodMag(memLayer.ML.cdv("CodCS"), memLayer.ML.confReadString("CodMagMP_NA"))[0].IdxCella;
                spostaUDC(memLayer.ML.cdv("CodCS"), UDC, idxPosizTo, true, clientIp);
              }
            }
            catch (Exception e)
            {
              logger.lg.scriviLog(string.Format(" | {3} | Non sono riuscito a spostare UDC non conforme: UDC creato: {0}, progRappQual: {1}, eccezione: {2}", UDC, rqRow.ProgUDC, e, clientIp), tipoLog.EXCEPTION);
            }
          }
        }

        // se devo stampare lancio stampa...
        if (doPrint)
        {
          stampaUdcDaRappQualita(numRapQual, printerName);
        }
      }
      return answ;
    }
    /// <summary>
    /// aggiorna le note di un RDQ
    /// </summary>
    /// <param name="note"></param>
    /// <returns></returns>
    public bool updateNoteRDQ(int numRapQual, string note)
    {
      bool answ = false;
      try
      {
        DataProxy.obj.taRQN.stp_UDC_updateNoteByRQ(numRapQual, note, CodSoggCurrUser);
        answ = true;
      }
      catch
      { }
      return answ;
    }
    /// <summary>
    /// effettua la (ri)stampa di TUTTI gli UDC dato un rapporto di qualità
    /// </summary>
    /// <param name="numRapQual">identificativo rapp qualità</param>
    /// <returns></returns>
    public bool stampaUdcDaRappQualita(int numRapQual, string printerName)
    {
      bool answ = false;
      // ottengo elenco righe dei cartellini del rapp qualità indicato SENZA righe UDC
      DS_magazzino.RapQualDataTable tabRapQual = taRapQual.getByNumRapQual(numRapQual);
      // per prima cosa verifico che ci sia il rapporto di qualità in esame e che abbia righe da associare ad UDC
      if (tabRapQual.Rows.Count > 0)
      {
        answ = true;
        foreach (DS_magazzino.RapQualRow rqRow in tabRapQual)
        {
          answ = reportPrinter.obj.stampaCartellino(tipoCartellino.cartMP, rqRow.UDC, printerName);
        }
      }
      return answ;
    }


    #endregion

    #region area utility

    /// <summary>
    /// Decodifica il tipo barcode acquisito sino L5
    /// L1: comandi/matricole/DT e BCD
    /// L2: Particolari/Imballi
    /// L3: UDC
    /// L4: AL
    /// L5: DataMatrix
    /// </summary>
    public static tipoCodiceBarcode tipoBCode_L5(string valore)
    {
      tipoCodiceBarcode answ = tipoCodiceBarcode.ND;
      int trovati = 0;
      int matricola = -1;
      // provo a convertire in intero barcode x verifica eventuale matricola...
      try
      {
        matricola = Convert.ToInt32(valore);
      }
      catch
      { }
      // controllo non si tratti di un comando...
      string preCmd = memLayer.ML.AppConf["prefComandi"];
      string preDT = memLayer.ML.AppConf["prefDateTime"];
      string preBCD = memLayer.ML.AppConf["prefBCode"];
      string preCodSogg = memLayer.ML.AppConf["prefCodSogg"];
      string statoDtx = "";
      string formatoDtx = "";
      // cerco di decodificare il Datamatrix...
      try
      {
        DS_DataMatrix.stp_verificaDtxRow rowVerifica = DataMatrix.mgr.taVerifica.GetData(valore)[0];
        statoDtx = rowVerifica.StatoDtx;
        formatoDtx = rowVerifica.FormatoDtmx;
      }
      catch
      { }
      if (valore.StartsWith(preCmd))
      {
        answ = tipoCodiceBarcode.Comando;
      }
      else if (valore.StartsWith(preBCD))
      {
        answ = tipoCodiceBarcode.BarCodeCMD;
      }
      else if (valore.StartsWith(preDT))
      {
        // se lungh = 2+10 (DT+yyMMddHHmm) è SOLO datetime, altrimenti è DateTimeLine
        if (valore.Length > 12)
        {
          answ = tipoCodiceBarcode.DateTimeLine;
        }
        else
        {
          answ = tipoCodiceBarcode.DateTime;
        }
      }
      // cerco se c'è assieme logico
      else if (MagClass.magazzino.checkAL(valore))
      {
        answ = tipoCodiceBarcode.AL;
      }
      else if ((TermClass.Ter.riconosciBarcode(valore) == tipoCodiceBarcode.Particolare)) // è un particolare...
      {
        answ = tipoCodiceBarcode.Particolare;
      }
      else if (((statoDtx == "OK") || (statoDtx == "KO")) && formatoDtx != "")
      {
        answ = tipoCodiceBarcode.DataMatrixTrovato;
      }
      // controllo se sia un codice IMBALLO
      else if (utils.obj.taSelImballi.getByImballo(valore).Rows.Count > 0)
      {
        // è imballo!
        answ = tipoCodiceBarcode.Imballo;
      }
      else if (valore.StartsWith(preCodSogg))
      {
        // cerco cod soggetto...
        if (DataProxy.obj.taTrascSogg.getByKey(valore, 0).Rows.Count == 1)
        {
          answ = tipoCodiceBarcode.Operatore;
        }
      }
      else if (matricola >= 0)
      {
        if (DataProxy.obj.taTrascSogg.getByKey("", matricola).Rows.Count == 1)
        {
          answ = tipoCodiceBarcode.Operatore;
        }
      }
      else if ((statoDtx == "ND") && DataMatrix.mgr.maybeDatamatrix(valore)) // controllo se sia un POSSIBILE datamatrix poiché riesco a ricavare un partnumber noto...
      {
        answ = tipoCodiceBarcode.DataMatrixDecodificato;
      }
      else if (magazzino.taET.getByTratt(valore).Rows.Count > 0)
      {
        answ = tipoCodiceBarcode.TT;
      }
      else
      {
        try
        {
          // cerco tra UDC...
          trovati = MagClass.magazzino.taCartellini.getByUdc(valore).Rows.Count;
          if (trovati > 0)
          {
            answ = tipoCodiceBarcode.UDC;
          }
        }
        catch
        {
        }
      }
      return answ;
    }

    /// <summary>
    /// Decodifica il tipo barcode acquisito sino L4
    /// L1: comandi/matricole/DT e BCD
    /// L2: Particolari/Imballi
    /// L3: UDC
    /// L4: AL
    /// </summary>
    public static tipoCodiceBarcode tipoBCode_L4(string valore)
    {
      tipoCodiceBarcode answ = tipoCodiceBarcode.ND;
      int trovati = 0;
      int matricola = -1;
      // provo a convertire in intero barcode x verifica eventuale matricola...
      try
      {
        matricola = Convert.ToInt32(valore);
      }
      catch
      { }
      // controllo non si tratti di un comando...
      string preCmd = memLayer.ML.AppConf["prefComandi"];
      string preDT = memLayer.ML.AppConf["prefDateTime"];
      string preBCD = memLayer.ML.AppConf["prefBCode"];
      string preCodSogg = memLayer.ML.AppConf["prefCodSogg"];
      if (valore.StartsWith(preCmd))
      {
        answ = tipoCodiceBarcode.Comando;
      }
      else if (valore.StartsWith(preBCD))
      {
        answ = tipoCodiceBarcode.BarCodeCMD;
      }
      else if (valore.StartsWith(preDT))
      {
        // se lungh = 2+10 (DT+yyMMddHHmm) è SOLO datetime, altrimenti è DateTimeLine
        if (valore.Length > 12)
        {
          answ = tipoCodiceBarcode.DateTimeLine;
        }
        else
        {
          answ = tipoCodiceBarcode.DateTime;
        }
      }
      // cerco se c'è assieme logico
      else if (MagClass.magazzino.checkAL(valore))
      {
        answ = tipoCodiceBarcode.AL;
      }
#if false
    else if ((TermClass.Ter.riconosciBarcode(valore) == tipoCodiceBarcode.Particolare)) // è un particolare...  
#endif
      else if (utils.obj.taSelParticolari.getByConditioValue(valore, "*").Rows.Count == 1)
      {
        answ = tipoCodiceBarcode.Particolare;
      }
      // controllo se sia un codice IMBALLO
      else if (utils.obj.taSelImballi.getByImballo(valore).Rows.Count > 0)
      {
        // è imballo!
        answ = tipoCodiceBarcode.Imballo;
      }
      else if (valore.StartsWith(preCodSogg))
      {
        // cerco cod soggetto...
        if (DataProxy.obj.taTrascSogg.getByKey(valore, 0).Rows.Count == 1)
        {
          answ = tipoCodiceBarcode.Operatore;
        }
      }
      else if (matricola >= 0)
      {
        if (DataProxy.obj.taTrascSogg.getByKey("", matricola).Rows.Count == 1)
        {
          answ = tipoCodiceBarcode.Operatore;
        }
      }
      else if (magazzino.taET.getByTratt(valore).Rows.Count > 0)
      {
        answ = tipoCodiceBarcode.TT;
      }
      else
      {
        try
        {
          // cerco tra UDC...
          trovati = MagClass.magazzino.taCartellini.getByUdc(valore).Rows.Count;
          if (trovati > 0)
          {
            answ = tipoCodiceBarcode.UDC;
          }
        }
        catch
        {
        }
      }
      return answ;
    }

    /// <summary>
    /// Decodifica il tipo barcode acquisito
    /// checkL3 = verifica i livelli sino L3
    /// L1: comandi/matricole/DT e BCD
    /// L2: Particolari/Imballi
    /// L3: UDC
    /// </summary>
    public static tipoCodiceBarcode tipoBCode_L3(string valore)
    {
      tipoCodiceBarcode answ = tipoCodiceBarcode.ND;
      int trovati = 0;
      int matricola = -1;
      // provo a convertire in intero barcode x verifica eventuale matricola...
      try
      {
        matricola = Convert.ToInt32(valore);
      }
      catch
      { }
      // controllo non si tratti di un comando...
      string preCmd = memLayer.ML.AppConf["prefComandi"];
      string preDT = memLayer.ML.AppConf["prefDateTime"];
      string preBCD = memLayer.ML.AppConf["prefBCode"];
      string preCodSogg = memLayer.ML.AppConf["prefCodSogg"];
      if (valore.StartsWith(preCmd))
      {
        answ = tipoCodiceBarcode.Comando;
      }
      else if (valore.StartsWith(preBCD))
      {
        answ = tipoCodiceBarcode.BarCodeCMD;
      }
      else if (valore.StartsWith(preDT))
      {
        // se lungh = 2+10 (DT+yyMMddHHmm) è SOLO datetime, altrimenti è DateTimeLine
        if (valore.Length > 12)
        {
          answ = tipoCodiceBarcode.DateTimeLine;
        }
        else
        {
          answ = tipoCodiceBarcode.DateTime;
        }
      }
      else if ((TermClass.Ter.riconosciBarcode(valore) == tipoCodiceBarcode.Particolare)) // è un particolare...
      {
        answ = tipoCodiceBarcode.Particolare;
      }
      // controllo se sia un codice IMBALLO
      else if (utils.obj.taSelImballi.getByImballo(valore).Rows.Count > 0)
      {
        // è imballo!
        answ = tipoCodiceBarcode.Imballo;
      }
      else if (valore.StartsWith(preCodSogg))
      {
        // cerco cod soggetto...
        if (DataProxy.obj.taTrascSogg.getByKey(valore, 0).Rows.Count == 1)
        {
          answ = tipoCodiceBarcode.Operatore;
        }
      }
      else if (matricola >= 0)
      {
        if (DataProxy.obj.taTrascSogg.getByKey("", matricola).Rows.Count == 1)
        {
          answ = tipoCodiceBarcode.Operatore;
        }
      }
      else
      {
        try
        {
          // cerco tra UDC...
          trovati = MagClass.magazzino.taCartellini.getByUdc(valore).Rows.Count;
          if (trovati > 0)
          {
            answ = tipoCodiceBarcode.UDC;
          }
        }
        catch
        {
        }
      }
      return answ;
    }


    /// <summary>
    /// Decodifica il tipo barcode acquisito
    /// checkL3 = verifica i livelli sino L3
    /// L1: comandi/matricole/DT e BCD
    /// L2: KIT (Anime)
    /// </summary>
    public static tipoCodiceBarcode tipoBCode_L2K(string valore)
    {
      tipoCodiceBarcode answ = tipoCodiceBarcode.ND;
      int matricola = -1;
      // provo a convertire in intero barcode x verifica eventuale matricola...
      try
      {
        matricola = Convert.ToInt32(valore);
      }
      catch
      { }
      // controllo non si tratti di un comando...
      string preCmd = memLayer.ML.AppConf["prefComandi"];
      string preDT = memLayer.ML.AppConf["prefDateTime"];
      string preBCD = memLayer.ML.AppConf["prefBCode"];
      string preCodSogg = memLayer.ML.AppConf["prefCodSogg"];
      if (valore.StartsWith(preCmd))
      {
        answ = tipoCodiceBarcode.Comando;
      }
      else if ((TermClass.Ter.riconosciBarcode(valore) == tipoCodiceBarcode.KitAnime))
      {
        answ = tipoCodiceBarcode.KitAnime;
      }
      else if (valore.StartsWith(preBCD))
      {
        answ = tipoCodiceBarcode.BarCodeCMD;
      }
      else if (valore.StartsWith(preDT))
      {
        // se lungh = 2+10 (DT+yyMMddHHmm) è SOLO datetime, altrimenti è DateTimeLine
        if (valore.Length > 12)
        {
          answ = tipoCodiceBarcode.DateTimeLine;
        }
        else
        {
          answ = tipoCodiceBarcode.DateTime;
        }
      }
      else if (valore.StartsWith(preCodSogg))
      {
        // cerco cod soggetto...
        if (DataProxy.obj.taTrascSogg.getByKey(valore, 0).Rows.Count == 1)
        {
          answ = tipoCodiceBarcode.Operatore;
        }
      }
      else if (matricola >= 0)
      {
        if (DataProxy.obj.taTrascSogg.getByKey("", matricola).Rows.Count == 1)
        {
          answ = tipoCodiceBarcode.Operatore;
        }
      }
      return answ;
    }

    #endregion

    #region area utenti

    /// <summary>
    /// recupera CognomeNome da CodSogg
    /// </summary>
    /// <param name="CodSogg"></param>
    /// <returns></returns>
    public string cognomeNomeFromCodSogg(object CodSogg)
    {
      string answ = "";
      try
      {
        DS_Applicazione.AnagOperatoriRow riga = DataProxy.obj.taAnagOperatore.getByCodSoggetto(CodSogg.ToString())[0];
        answ = string.Format("{0} {1}", riga.Cognome, riga.Nome);
      }
      catch
      { }
      return answ;
    }

    #endregion

    #endregion

  }
}

public enum esitoOperazione
{
  ok                      // tutto ok, come true
    , errore                // non è andata errore generico
    , errore_mismatch       // errore x mancanza corrispondenza tra dati (particolare-esponente-figura di lista ed UDC ad esempio)
    , errore_readOnly       // errore xché il dato è read only o bloccato (es lista di prelievo già completata NON posso riprenderla in carico)
    , errore_posUDC         // errore perché UDC è in una posizione che non consente l'operazione indicata
    , errore_noUdc          // errore non ci sono UDC
    , errore_nonScaricabile // errore perché destinatario mancante o UDC con posizione non gestita da tab transiz pos eventi
    , errore_noDeliberPM    // errore perché presente attributo trattamento NT (uno o + per UDC) SENZA delibera PM (serve delibera logistica..)
    , errore_UdcNc          // almeno un UDC ha una NC che non permette spedizione
    , errore_DtmxNc         // almeno un DataMatrix (di un UDC) ha una NC che non permette spedizione 
}

public enum statoLista
{
  bozza = 0,
  generata,
  iniziata,
  completata,
  scaricata
}
/// <summary>
/// esito verifica NC su UDC
/// </summary>
public enum checkUdcNc
{
  /// <summary>
  /// NESSUNA NC
  /// </summary>
  NoNc,
  /// <summary>
  /// controllo disabilitato/non bloccate, NC NON presenti
  /// </summary>
  ChkDis_NoNc,
  /// <summary>
  /// controllo disabilitato/non bloccate, NC presenti
  /// </summary>
  ChkDis_HasNc,
  /// <summary>
  /// ci sono NC, bloccante
  /// </summary>
  HasNc
}

/// <summary>
/// Tipologia assieme logico
/// </summary>
public enum tipoAL
{
  /// <summary>
  /// non definito
  /// </summary>
  ND,
  /// <summary>
  /// Assieme RX
  /// </summary>
  AL_RX,
  /// <summary>
  /// Assieme RX Datamatrix
  /// </summary>
  AL_RxDt,
  /// <summary>
  /// Assieme RX NON Datamatrix
  /// </summary>
  AL_RxNt,
  /// <summary>
  /// Assieme TT Datamatrix
  /// </summary>
  AL_TT,
  /// <summary>
  /// Assieme TT NON Datamatrix
  /// </summary>
  AL_LI,
  /// <summary>
  /// KitAnime
  /// </summary>
  AL_KitAnime
}