TPVwin/TpvVntProd.cpp
2021-09-12 22:19:30 +02:00

589 lines
20 KiB
C++

//---------------------------------------------------------------------------
#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;
}
//---------------------------------------------------------------------------