//---------------------------------------------------------------------------
#include <vcl.h>
#include <io.h>


#pragma hdrstop

#include "TpvVntProd.h"
#include "TpvCFG.h"
#include "TpvVntProdQR.h"

//---------------------------------------------------------------------------
#pragma link "Grids"
#pragma link "ElastFrm"
#pragma resource "*.dfm"

TVntProd *VntProd;
//---------------------------------------------------------------------------
__fastcall TVntProd::TVntProd(TComponent* Owner)
    : TForm(Owner)
{
  CantidadTotal = new Currency [48];
  BeneficioTotal = new Currency [48];

  IamOpening = true;

  // Inicializamos la fecha de compra ( Y  el filtro, en base a esta... )
  unsigned short year, mes, dia;
  ( TDateTime::CurrentDate() ).DecodeDate( &year, &mes, &dia );

  TbProdTmp -> TableName = "ProdTMP vnt" + AnsiString(".db");
  #ifdef TB_DISCONTINUAS
    TbVentasC -> TableName = "Ventas (cabecera) '"+ AnsiString(year) +AnsiString(".db");
    TbVentasD -> TableName = "Ventas (cuerpo) '"+ AnsiString(year) +AnsiString(".db");
  #else
    TbVentasC -> TableName = "Ventas (cabecera).db";
    TbVentasD -> TableName = "Ventas (cuerpo).db";
  #endif

  MinFechaFact = TDateTime::CurrentDate();
  MaxFechaFact = TDateTime::CurrentDate();
  TbProductos -> Active = true;
  TbVentasC->Active = true;
  TbVentasD->Active = true;

  MinFecha -> Date = MinFechaFact;
  MaxFecha -> Date = MaxFechaFact;

  FiltrarFacturas();
}
//---------------------------------------------------------------------------
void __fastcall TVntProd::CerrarAplicClick(TObject *Sender)
{
 Close();
}
//---------------------------------------------------------------------------
void __fastcall TVntProd::TbProductosAfterOpen(TDataSet *DataSet)
{
  TTreeNode * NuevoNodo;
  union
  {
    int Familia;		// 0x01020304
    char Fam[4];		//    0 1 2 3
  } FamC;

  int N, MascaraComp;

  // Deshabilitamos los controles...
  TbProductos -> DisableControls();

  // Reconstrucci�n del arbol...
  TbProductos -> First();
  while ( ! TbProductos -> Eof )
  {
    // Si es parte del arbol...
    if ( TbProductos -> FieldByName("EsNodo") -> Value == -1 )
    {
      FamC . Familia = TbProductos -> FieldByName("Familia") -> AsInteger;

      // Si es raiz, lo creamos directamente
      if ( FamC . Fam[3-1] != 0 )
      {
       // De lo contrario, buscamos su posici�n NATURAL dentro del arbol.
       //////////////////////////////////////////////////////////////////
       // Contruimos la mascara de comparaci�n...
       if ( FamC . Fam[3-2] == 0 )
	       MascaraComp = FamC . Familia & 0xFF000000;
       else
       if ( FamC . Fam[3-3] == 0 )
	       MascaraComp = FamC . Familia & 0xFFFF0000;
       else
	       MascaraComp = FamC . Familia & 0xFFFFFF00;
       N = 2;
       while ( N < Indices -> Items -> Count )
       {
         if ( ((int *)Indices -> Items -> Item[N] -> Data ) [0] == MascaraComp )
         {
  	         // A�adimos un nuevo nodo al primer nivel en que nos quedamos
       	     NuevoNodo = Indices->Items->AddChild( Indices -> Items -> Item[N], TbProductos -> FieldByName("Nombre del Producto") -> Value );
             NuevoNodo -> Data = new int [3];

            ((int *)NuevoNodo -> Data)[0] = FamC . Familia;
            ((int *)NuevoNodo -> Data)[1] = 0;
            ((int *)NuevoNodo -> Data)[2] = TbProductos -> FieldByName("ForcedIndex") -> AsInteger;


             break;
         } else
	     N++;
       }
      } else {
        // A�adimos un nuevo nodo al primer nivel en que nos quedamos
        NuevoNodo = Indices->Items->Add( Indices -> Items -> Item[0], TbProductos -> FieldByName("Nombre del Producto") -> Value );
        NuevoNodo -> Data = new int [3];

       ((int *)NuevoNodo -> Data)[0] = FamC . Familia;
       ((int *)NuevoNodo -> Data)[1] = 0;
       ((int *)NuevoNodo -> Data)[2] = TbProductos -> FieldByName("ForcedIndex") -> AsInteger;
      }
    }
    // Avanzamos al siguiente registro
    TbProductos -> Next();
  }


  N = 2;
  while ( N < Indices -> Items -> Count )
  {
     // Establecemos las im�genes  (Por defecto es documento final)
     if ( Indices -> Items -> Item[N] -> HasChildren )
     {
	   Indices -> Items -> Item[N]->ImageIndex = 0;
	   Indices -> Items -> Item[N]->SelectedIndex = 0;
     } else {
	   Indices -> Items -> Item[N]->ImageIndex = 2;
	   Indices -> Items -> Item[N]->SelectedIndex = 2;
     }
   N++;
  }
    /////////////////////////////////////////////////////////////////////////
    /////////////////////////////////////////////////////////////////////////
    // ATENCI�N, LA SIGUIENTE LINEA ES POR UN BUG DETECTADO EN EL TREEVIEW //
    /////////////////////////////////////////////////////////////////////////
    NuevoNodo = Indices->Items->AddChild( Indices -> Items -> Item[0], "Bug TTreeView 1.1 Fixed" );
    Indices -> Items -> Delete( NuevoNodo );
    /////////////////////////////////////////////////////////////////////////
    /////////////////////////////////////////////////////////////////////////

    Indices -> Selected = Indices -> Items -> Item[1];
//  Indices -> Items -> Item[0] -> Selected = true;

  // Rehabilitamos los controles...
  TbProductos -> EnableControls();

}
//---------------------------------------------------------------------------
void __fastcall TVntProd::MinFechaChange(TObject *Sender)
{
  MaxFechaFact = MaxFecha -> Date;

  // Reajustamos el filtro...
  MinFechaFact = MinFecha -> Date;
  FiltrarFacturas();

}
//---------------------------------------------------------------------------
void __fastcall TVntProd::MaxFechaChange(TObject *Sender)
{
  MinFechaFact = MinFecha -> Date;
  // Reajustamos el filtro...
  MaxFechaFact = MaxFecha -> Date;
  FiltrarFacturas();

}
//---------------------------------------------------------------------------
void __fastcall TVntProd::FiltrarFacturas(void)
{
 // Filtramos las facturas...
 TbProdTmp -> Active = false;
 TbProdTmp -> Filtered = false;

 TbVentasC->FilterOptions = TbVentasC->FilterOptions << foCaseInsensitive;
 TbVentasC->Filter = "([FechaFactura] >= '" + MinFechaFact + "' AND [FechaFactura] <= '" + MaxFechaFact +"')";
 TbVentasC->Filtered = true;

 TbProdTmp -> Active = true;       // Forzamos el recrear la base
 IndicesChange( 0, 0 );
}
//---------------------------------------------------------------------------

void __fastcall TVntProd::IndicesExpanding(TObject *Sender,
      TTreeNode *Node, bool &AllowExpansion)
{
   // Si el nodo es padre
   if ( Node -> HasChildren )
   {
       // Usamos las im�genes de los libros abiertos
       Node->ImageIndex = 1;
       Node->SelectedIndex = 1;
   } else {
       // Usamos las im�genes de los documentos
       Node->ImageIndex = 2;
       Node->SelectedIndex = 2;
   }
}
//---------------------------------------------------------------------------
void __fastcall TVntProd::IndicesCollapsing(TObject *Sender,
      TTreeNode *Node, bool &AllowCollapse)
{
   // Si el nodo es padre
   if ( Node -> HasChildren )
   {
     // Restauramos las im�genes originales
     Node->ImageIndex = 0;
     Node->SelectedIndex = 0;
   } else {
     // Un nodo no padre NO puede ser CONTRAIDO
       // Usamos las im�genes de los documentos
       Node->ImageIndex = 2;
       Node->SelectedIndex = 2;
   }

}
//---------------------------------------------------------------------------
void __fastcall TVntProd::IndicesDeletion(TObject *Sender, TTreeNode *Node)
{
  delete [] Node -> Data;
}
//---------------------------------------------------------------------------
void __fastcall TVntProd::TbProdTmpBeforeOpen(TDataSet *DataSet)
{
 AnsiString FileEmp, Cantidad;

 FileEmp = TbProdTmp -> TableName;

	 // Establecemos la ruta
	 TbProdTmp -> DatabaseName = "TpvWin";
	 // Facilitamos el nombre de la nueva tabla y su tipo
	 TbProdTmp -> TableType = ttParadox;

	 // Usamos la propiedad FielDefs para definir
	 // las columnas que contendr� la tabla
     TbProdTmp -> FieldDefs -> Clear();
	 TbProdTmp -> FieldDefs -> Add("Familia0",       ftInteger,  0, false );
	 TbProdTmp -> FieldDefs -> Add("Familia1",       ftInteger,  0, false );
	 TbProdTmp -> FieldDefs -> Add("CodForced",      ftInteger,  0, false );
	 TbProdTmp -> FieldDefs -> Add("CodProducto",    ftString,  15, false );
	 TbProdTmp -> FieldDefs -> Add("NombreProducto", ftString,  30, false );
	 TbProdTmp -> FieldDefs -> Add("IVA",            ftSmallint, 0, false );
	 TbProdTmp -> FieldDefs -> Add("PrecioC",        ftCurrency, 0, false );
	 TbProdTmp -> FieldDefs -> Add("PrecioV",        ftCurrency, 0, false );

     for ( int hh=0; hh < 24; hh++ )
     {
       Cantidad = "Cantidad " + AnsiString( hh ) + ":00+";
  	   TbProdTmp -> FieldDefs -> Add(Cantidad,        ftInteger, 0, false );
       Cantidad = "Cantidad " + AnsiString( hh ) + ":30+";
  	   TbProdTmp -> FieldDefs -> Add(Cantidad,        ftInteger, 0, false );
     }

     TbProdTmp -> IndexDefs-> Clear();

//	 TbProdTmp->IndexDefs->Add("Primary", "Familia0; Familia1; CodProducto", TIndexOptions() << ixPrimary );
	 // Creamos la base...
	 TbProdTmp -> CreateTable();
}
//---------------------------------------------------------------------------
void __fastcall TVntProd::TbProdTmpAfterOpen(TDataSet *DataSet)
{
/*
SELECT CodProducto C�digo, NombreProducto Producto, SUM( Cantidad ) Cantidad, IVA, SUM(   ( (PrecioC *  (1 +  (IVA / 100) ) )  *  (1 -  (Dto / 100) ) )  * Cantidad  ) Ventas."PV Bruto"
FROM "Ventas (cuerpo).db" Ventas
GROUP BY CodProducto, NombreProducto, IVA, NombreProducto, CodProducto
*/

  unsigned short hh, mm, ss, mss;
  int Familia0, Familia1;
  Currency PVP, PRECIO, COSTO;
  AnsiString Cantidad;

  int VntCodProductoAux;


  TbProdTmp->DisableControls();

  for ( hh = 0; hh < 48; hh ++ )
  {
    CantidadTotal[hh]  = 0;
    BeneficioTotal[hh] = 0;
  }


  IamOpening = true;
  TbProdTmp->DisableControls();
  TbVentasC -> First();
  while ( ! TbVentasC -> Eof )       // Siguiente factura
  {
    TbVentasC->FieldByName("HoraFactura")->AsDateTime . DecodeTime( &hh, &mm, &ss, &mss );
    Cantidad = "Cantidad " + AnsiString( hh ) + ":" + ( (mm<30) ? "00+" : "30+" );

    TbVentasD -> First();
    while( ! TbVentasD -> Eof )    // Siguiente linea de la factura
    {
        // Si el producto no esta ya en la lista
        VntCodProductoAux = TbVentasD->FieldByName("CodProductoAux")->AsInteger;
        if ( VntCodProductoAux == 0 ||
             TbVentasD->FieldByName("CodProductoAux")->IsNull         ||
             ! ( TbProdTmp -> Locate( "CodForced", VntCodProductoAux, TLocateOptions() << loCaseInsensitive ) )
           )
        {
            if ( TbVentasD->FieldByName("CodProductoAux")->IsNull ||
                 VntCodProductoAux == 0 ||
                 ! ( TbProductos -> Locate( "ForcedIndex", VntCodProductoAux, TLocateOptions() << loCaseInsensitive ) )
               )
            {
              Familia0 = Familia1 = 0;
              COSTO = 0;
            } else {
              Familia0 = TbProductos -> FieldByName("Familia") -> AsInteger;
              COSTO = TbProductos->FieldByName("Precio Costo")->AsCurrency;
            }

            TbProdTmp -> InsertRecord( ARRAYOFCONST(
                  (
                   Familia0,
                   Familia1,
                   VntCodProductoAux,
                   TbVentasD->FieldByName("CodProducto")->AsString,
                   TbVentasD->FieldByName("NombreProducto")->AsString,
                   TbVentasD->FieldByName("IVA")->AsInteger,
                   COSTO,
                   0
                  ) ) );
        }

        // Actualizamos las cantidades seg�n horas....
        //////////// LOCALIZACION DEL REGISTRO CORRECTO
        PRECIO = (TbVentasD->FieldByName("PrecioC")->AsCurrency * TbVentasD->FieldByName("Cantidad")->AsFloat )* ( 1 - (TbVentasD->FieldByName("Dto")->AsInteger / 100) );
        PVP =  PRECIO * ( 1 + (TbVentasD->FieldByName("IVA")->AsCurrency / 100) );

        TbProdTmp->Edit();
        TbProdTmp->FieldByName( "PrecioV" )->AsCurrency = TbProdTmp->FieldByName( "PrecioV" )->AsCurrency +PVP;
        TbProdTmp->FieldByName( Cantidad )->AsFloat   += TbVentasD->FieldByName("Cantidad")->AsFloat;
        TbProdTmp->Post();

        CantidadTotal[hh*2+ ((mm<30)?0:1)] += TbVentasD->FieldByName("Cantidad")->AsFloat;
        BeneficioTotal[hh*2+ ((mm<30)?0:1)] +=  PRECIO -  TbProdTmp->FieldByName("PrecioC")->AsCurrency * TbVentasD->FieldByName("Cantidad")->AsFloat;

        TbVentasD -> Next();
      }
      TbVentasC -> Next();
  }

 IamOpening = false;
 TbProdTmp->EnableControls();
 RellenaGraficaTOTALES();
 TbProdTmp->EnableControls();

}
//---------------------------------------------------------------------------
void __fastcall TVntProd::RellenaGraficaTOTALES(void)
{
 // Metemos los datos generales en la gr�fica...
 Chart1 -> Series[0] -> Clear();
 if ( mNumProductos -> Checked )
     for ( int i = 0; i < 24; i++ )
     {
      Chart1 -> Series[0] -> AddXY(i*2,   CantidadTotal[i*2], i, clTeeColor);
      Chart1 -> Series[0] -> AddXY(i*2+1, CantidadTotal[i*2+1], "�", clTeeColor);
     }
 else
     for ( int i = 0; i < 24; i++ )
     {
      Chart1 -> Series[0] -> AddXY(i*2,   BeneficioTotal[i*2], i, clTeeColor);
      Chart1 -> Series[0] -> AddXY(i*2+1, BeneficioTotal[i*2+1], "�", clTeeColor);
     }

}
//---------------------------------------------------------------------------
void __fastcall TVntProd::DsProdTempDataChange(TObject *Sender,
      TField *Field)
{
 AnsiString Cantidad;
 Currency Benef;

 StatusBar1->Panels->Items[0]->Text = "Creando gr�fica...";
 Chart1 -> Series[1] -> Clear();
 Chart1 -> Series[2] -> Clear();

 if ( mNumProductos -> Checked )
 {
   // Metemos los datos en la gr�fica...
   for ( int i = 0; i < 24; i++ )
   {
    Cantidad = "Cantidad " + AnsiString( i ) + ":" + "00+";
    Chart1 -> Series[1] -> AddXY(i*2, TbProdTmp->FieldByName( Cantidad )->AsInteger, i, clTeeColor);
    Cantidad = "Cantidad " + AnsiString( i ) + ":" + "30+";
    Chart1 -> Series[1] -> AddXY(i*2+1, TbProdTmp->FieldByName( Cantidad )->AsInteger, "�", clTeeColor);
   }
 } else {
   Benef = TbProdTmp->FieldByName( "PrecioV" )->AsCurrency - TbProdTmp->FieldByName( "PrecioC" )->AsCurrency;
   // Metemos los datos en la gr�fica...
   for ( int i = 0; i < 24; i++ )
   {
    Cantidad = "Cantidad " + AnsiString( i ) + ":" + "00+";
    Chart1 -> Series[1] -> AddXY(i*2, TbProdTmp->FieldByName( Cantidad )->AsInteger * TbProdTmp->FieldByName( "PrecioV" )->AsCurrency, i, clTeeColor);
    Chart1 -> Series[2] -> AddXY(i*2, TbProdTmp->FieldByName( Cantidad )->AsInteger * Benef, i, clTeeColor);
    Cantidad = "Cantidad " + AnsiString( i ) + ":" + "30+";
    Chart1 -> Series[1] -> AddXY(i*2+1, TbProdTmp->FieldByName( Cantidad )->AsInteger * TbProdTmp->FieldByName( "PrecioV" )->AsCurrency, "�", clTeeColor);
    Chart1 -> Series[2] -> AddXY(i*2+1, TbProdTmp->FieldByName( Cantidad )->AsInteger * Benef, "�", clTeeColor);
   }
 }


 StatusBar1->Panels->Items[0]->Text = "";
}
//---------------------------------------------------------------------------

void __fastcall TVntProd::MostrarTotalClick(TObject *Sender)
{
  MostrarTotal->Checked = !MostrarTotal->Checked;
  // Ajustamos la grafica de totales...
  Chart1 -> Series[0] -> Active = MostrarTotal->Checked;
}
//---------------------------------------------------------------------------

void __fastcall TVntProd::VentaProductoClick(TObject *Sender)
{
  VentaProducto->Checked = !VentaProducto->Checked;
  // Ajustamos la grafica de totales...
  Chart1 -> Series[1] -> Active = VentaProducto->Checked;
}
//---------------------------------------------------------------------------

void __fastcall TVntProd::BeneficioProductoClick(TObject *Sender)
{
  BeneficioProducto->Checked = !BeneficioProducto->Checked;
  // Ajustamos la grafica de totales...
  Chart1 -> Series[2] -> Active = BeneficioProducto->Checked;
}
//---------------------------------------------------------------------------


void __fastcall TVntProd::mNumProductosClick(TObject *Sender)
{
  mMostrarCifras -> Checked = false;
  mNumProductos  -> Checked = true;

  BeneficioProducto->Enabled = false;
  Chart1 -> Series[2] -> Active = false;

  DsProdTempDataChange(0, 0);
  RellenaGraficaTOTALES();
}
//---------------------------------------------------------------------------

void __fastcall TVntProd::mMostrarCifrasClick(TObject *Sender)
{
  mMostrarCifras -> Checked = true;
  mNumProductos  -> Checked = false;

  BeneficioProducto->Enabled = true;
  Chart1 -> Series[2] -> Active = BeneficioProducto->Checked;

  DsProdTempDataChange(0, 0);
  RellenaGraficaTOTALES();
}
//---------------------------------------------------------------------------

void __fastcall TVntProd::FormDestroy(TObject *Sender)
{
  delete [] CantidadTotal;
  delete [] BeneficioTotal;
}
//---------------------------------------------------------------------------

void __fastcall TVntProd::IndicesChange(TObject *Sender, TTreeNode *Node)
{
  union
  {
   long Familia;
   char Fam[4];
  } FamL, FamH;

  // Reajustamos el filtro, acuerdo a la nueva familia
  switch ( Indices -> Selected -> AbsoluteIndex )
  {
    case 0:
//	       TbProductos -> Filtered = false;
//           return;
           if ( Indices -> Selected -> Text == "Ver Todos" )
           {
  	         TbProdTmp -> Filtered = false;
             return;
           } else {
             FamL . Familia = 0x00000000;
             FamH . Familia = 0x01000000;
           }
           break;
    case 1:
           // El filtro es para la familia 0000
           FamL . Familia = 0x00000000;
           FamH . Familia = 0x01000000;
           break;
    default:
    	   // Contruimos los limites del filtro ( >= AND < )
    	   FamL . Familia = ( (int *) Indices -> Selected -> Data ) [0];
           FamH . Familia = FamL . Familia;
           if ( !FamH . Fam[3-1] )
             FamH . Fam[3-0] ++;
           else
           if ( !FamH . Fam[3-2] )
             FamH . Fam[3-1] ++;
           else
           if ( !FamH . Fam[3-3] )
             FamH . Fam[3-2] ++;
           else
             FamH . Fam[3-3] ++;
    	   break;
  };

  // Filtramos seg�n los rangos construidos antes...
  TbProdTmp->FilterOptions = TbProdTmp->FilterOptions << foCaseInsensitive;
  TbProdTmp->Filter = "([Familia0] >= '" + AnsiString( (int)( FamL . Familia ) ) + "' AND [Familia0] < '" + AnsiString( (int)( FamH . Familia ) ) + "')";
  TbProdTmp -> Filtered = true;
}
//---------------------------------------------------------------------------

void __fastcall TVntProd::TbProdTmpCalcFields(TDataSet *DataSet)
{
  if ( IamOpening ) return;

  int min, max;
  AnsiString Cantidad;
  float sCantidad;

  // Calculamos la cantidad seg�n el rango especificado...
  unsigned short hh, mm, ss, mss;
  DateTimePicker1->DateTime . DecodeTime( &hh, &mm, &ss, &mss );
  min = hh*2 + ( (mm<30) ?  0 : 1 );
  DateTimePicker2->DateTime . DecodeTime( &hh, &mm, &ss, &mss );
  max = hh*2 + ( (mm<30) ?  0 : 1 );

  sCantidad = 0;
  for ( ; min <= max; min++ )
  {
    Cantidad = "Cantidad " + AnsiString( min/2 ) + ":" + ((min%2) ? "30+" : "00+");
    sCantidad += TbProdTmp->FieldByName( Cantidad ) -> AsFloat;
  }
  TbProdTmp->FieldByName( "Cantidad" ) -> Value = sCantidad;
  #ifdef EXIST_CFG
  if ( CFG->VntProdCosteBeneficio->Checked )
  {
  #endif
    TbProdTmp->FieldByName( "CostoTotal" )  -> AsCurrency = TbProdTmp->FieldByName( "PrecioC" ) -> AsCurrency * sCantidad;
    TbProdTmp->FieldByName( "Beneficio" )  -> AsCurrency = TbProdTmp->FieldByName( "PrecioV" ) -> AsCurrency - TbProdTmp->FieldByName( "CostoTotal" ) -> AsCurrency;
  #ifdef EXIST_CFG
  }
  #endif
}
//---------------------------------------------------------------------------

void __fastcall TVntProd::bGraficasClick(TObject *Sender)
{
    POINT MousePos;
            if ( GetCursorPos(&MousePos) )
            {
                mGraficas->PopupComponent = bGraficas;
//                mGraficas->Popup(MousePos.x + bGraficas->Width, MousePos.y + bGraficas->Height);


                mGraficas->Popup( /*MousePos.x + bGraficas->Width + */bGraficas->Left + Left,
                                  /*MousePos.y + */bGraficas->Height * 2 + Top);

                mGraficas->PopupComponent = 0;
        }
}
//---------------------------------------------------------------------------

void __fastcall TVntProd::SpeedButton7Click(TObject *Sender)
{
  		 TQRVntProd *QRVntProd;
		 QRVntProd = new TQRVntProd(this);
                 QRVntProd->QuickRep1->Preview();
		 delete QRVntProd;
}
//---------------------------------------------------------------------------