457 lines
15 KiB
C++
457 lines
15 KiB
C++
//---------------------------------------------------------------------------
|
|
#include <vcl\vcl.h>
|
|
#include <stdio.h>
|
|
|
|
#pragma hdrstop
|
|
|
|
#include "TpvStockActual1.h"
|
|
#include "TDlgBuscar.h"
|
|
#include "TpvStockQR.h"
|
|
//---------------------------------------------------------------------------
|
|
#pragma link "Grids"
|
|
#pragma link "ElastFrm"
|
|
#pragma resource "*.dfm"
|
|
TStockActual *StockActual;
|
|
//---------------------------------------------------------------------------
|
|
__fastcall TStockActual::TStockActual(TComponent* Owner)
|
|
: TForm(Owner)
|
|
{
|
|
TbProductos -> Active = true;
|
|
TbSeguimiento -> Active = true;
|
|
// Cargar el dialogo, buscar Productos
|
|
TDlgBuscar *DlgBuscar;
|
|
DlgBuscar = new TDlgBuscar(this);
|
|
DlgBuscar -> TbBusquedas -> TableName = "Tb_Ref";
|
|
DlgBuscar -> TbBusquedas -> Active = true;
|
|
}
|
|
//---------------------------------------------------------------------------
|
|
void __fastcall TStockActual::DBGrid1DrawColumnCell(TObject *Sender,
|
|
const TRect &Rect, int DataCol, TColumn *Column, TGridDrawState State)
|
|
{
|
|
// Etiquetas
|
|
if ( TbProductosEsNodo -> Value == -1 ||
|
|
( TbProductos -> FieldByName("I.V.A") -> AsInteger == 100 &&
|
|
TbProductos -> FieldByName("Precio Costo") -> AsFloat == 0 ) )
|
|
{
|
|
DBGrid1 -> Canvas -> Brush -> Color = clRed;
|
|
DBGrid1 -> DefaultDrawColumnCell( Rect, DataCol, Column, State );
|
|
} else {
|
|
// Stock bajo mínimos
|
|
if ( TbProductos -> FieldByName("Stock Actual")->AsInteger < TbProductos -> FieldByName("StockMinimo")->AsInteger )
|
|
{
|
|
DBGrid1->Canvas -> Font -> Color = clRed;
|
|
DBGrid1->DefaultDrawColumnCell( Rect, DataCol, Column, State );
|
|
}
|
|
}
|
|
}
|
|
//---------------------------------------------------------------------------
|
|
void __fastcall TStockActual::BuscarFichaClick(TObject *Sender)
|
|
{
|
|
Indices -> Selected = Indices -> Items -> GetFirstNode();
|
|
TbProductos->Filtered = false;
|
|
if ( DlgBuscar->Buscar( NEW, TbProductos ) )
|
|
{
|
|
BusqSig -> Enabled = true;
|
|
BusqAnt -> Enabled = true;
|
|
}
|
|
}
|
|
//---------------------------------------------------------------------------
|
|
void __fastcall TStockActual::BusqAntClick(TObject *Sender)
|
|
{
|
|
if ( DlgBuscar->Buscar( PRIOR, TbProductos ) )
|
|
BusqSig -> Enabled = true;
|
|
else
|
|
BusqAnt -> Enabled = false;
|
|
}
|
|
//---------------------------------------------------------------------------
|
|
void __fastcall TStockActual::BusqSigClick(TObject *Sender)
|
|
{
|
|
if ( DlgBuscar->Buscar( NEXT, TbProductos ) )
|
|
BusqAnt -> Enabled = true;
|
|
else
|
|
BusqSig -> Enabled = false;
|
|
}
|
|
//---------------------------------------------------------------------------
|
|
void __fastcall TStockActual::DataSource1DataChange(TObject *Sender,
|
|
TField *Field)
|
|
{
|
|
char BarraEstado[80];
|
|
|
|
// Indicador de FichaActual / Num.Fichas
|
|
if ( DataSource1 -> DataSet -> RecNo > 0 )
|
|
sprintf( BarraEstado, "%d / %d", DataSource1 -> DataSet -> RecNo, DataSource1 -> DataSet -> RecordCount );
|
|
else
|
|
sprintf( BarraEstado, "¿Nuevo? / %d", DataSource1 -> DataSet -> RecordCount );
|
|
|
|
StatusBar1->Panels->Items[1]->Text = BarraEstado;
|
|
|
|
if ( PageControl1->ActivePage == TabSheet2 )
|
|
DBChart1->RefreshData();
|
|
PaintBox1Paint( Sender );
|
|
}
|
|
//---------------------------------------------------------------------------
|
|
void __fastcall TStockActual::BackMainClick(TObject *Sender)
|
|
{
|
|
Close();
|
|
}
|
|
//---------------------------------------------------------------------------
|
|
void __fastcall TStockActual::PaintBox1Paint(TObject *Sender)
|
|
{
|
|
// Dibujamos una barra donde representamos el coste frente al beneficio
|
|
TRect Rect;
|
|
Rect.Left = 0;
|
|
Rect.Right = PaintBox1 -> Width;
|
|
Rect.Top = 0;
|
|
Rect.Bottom = PaintBox1 -> Height;
|
|
|
|
// Si el Beneficio es negativo, todo es perdida
|
|
if ( TbProductosBeneficioStock -> Value > 0 )
|
|
{
|
|
// Lo pintamos todo de VERDE == BENEFICIO
|
|
PaintBox1 -> Canvas -> Brush -> Color = clGreen;
|
|
PaintBox1 -> Canvas -> FillRect( Rect );
|
|
|
|
// Ancho de la franja de COSTES == ROJO
|
|
Rect.Right = (int)(( PaintBox1 -> Width * TbProductos -> FieldByName("Precio Costo") -> AsCurrency ) / TbProductos -> FieldByName("Precio Venta 1") -> AsCurrency);
|
|
PaintBox1 -> Canvas -> Brush -> Color = clRed;
|
|
PaintBox1 -> Canvas -> FillRect( Rect );
|
|
} else {
|
|
// Lo pintamos todo de ROJO == COSTES
|
|
PaintBox1 -> Canvas -> Brush -> Color = clRed;
|
|
PaintBox1 -> Canvas -> FillRect( Rect );
|
|
}
|
|
}
|
|
//---------------------------------------------------------------------------
|
|
void __fastcall TStockActual::DBGrid1KeyPress(TObject *Sender, char &Key)
|
|
{
|
|
switch( Key )
|
|
{
|
|
case VK_RETURN:
|
|
if ( TbProductos->State == dsEdit || TbProductos->State == dsInsert )
|
|
TbProductos->Post();
|
|
Key = 0;
|
|
if ( DBGrid1 -> Fields[DBGrid1 -> SelectedField -> Index] == NULL )
|
|
{
|
|
DBGrid1 -> SelectedField = DBGrid1 -> Fields[0];
|
|
} else
|
|
DBGrid1 -> SelectedField = DBGrid1 -> Fields[DBGrid1 -> SelectedField -> Index];
|
|
break;
|
|
}
|
|
}
|
|
//---------------------------------------------------------------------------
|
|
void __fastcall TStockActual::FormClose(TObject *Sender,
|
|
TCloseAction &Action)
|
|
{
|
|
// Destruimos el dialogo de busquedas...
|
|
delete DlgBuscar;
|
|
}
|
|
//---------------------------------------------------------------------------
|
|
|
|
|
|
void __fastcall TStockActual::RegAntClick(TObject *Sender)
|
|
{
|
|
TbProductos -> Prior();
|
|
}
|
|
//---------------------------------------------------------------------------
|
|
|
|
void __fastcall TStockActual::RegSigClick(TObject *Sender)
|
|
{
|
|
TbProductos -> Next();
|
|
}
|
|
//---------------------------------------------------------------------------
|
|
|
|
void __fastcall TStockActual::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 ( TbProductosEsNodo -> 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 TStockActual::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 TStockActual::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 TStockActual::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" )
|
|
{
|
|
TbProductos->Filter = "";
|
|
TbProductos -> Filtered = true;//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...
|
|
TbProductos->FilterOptions = TbProductos->FilterOptions << foCaseInsensitive;
|
|
TbProductos->Filter = "([Familia] >= '" + AnsiString( (int)( FamL . Familia ) ) + "' AND [Familia] < '" + AnsiString( (int)( FamH . Familia ) ) + "')";
|
|
TbProductos -> Filtered = true;
|
|
|
|
//************************************************************************
|
|
// BEGIN -- Suma Stock-TOTAL
|
|
//************************************************************************
|
|
Currency ValorStock, BeneficioStock;
|
|
Currency StockCant; AnsiString Buffer;
|
|
|
|
// recorremos toda la base de datos, para estimar el valor total
|
|
// del stock y su benefico aproximado...
|
|
ValorStock = 0; BeneficioStock = 0;
|
|
TbProductos -> First();
|
|
while ( ! TbProductos -> Eof )
|
|
{
|
|
StockCant = Currency( TbProductos -> FieldByName("Stock Actual") -> AsFloat * TbProductos -> FieldByName("CantUnitaria") -> AsFloat );
|
|
ValorStock += StockCant * TbProductos -> FieldByName("Precio Costo") -> AsCurrency ;
|
|
BeneficioStock += StockCant * TbProductos -> FieldByName("Precio Venta 1") -> AsCurrency ;
|
|
TbProductos -> Next();
|
|
}
|
|
BeneficioStock -= ValorStock;
|
|
Buffer = "Valor total: " + FormatCurr("###,###,###.#0", ValorStock );//CurrToStrF(ValorStock, 4, 2);
|
|
Label2 -> Caption = Buffer.c_str();
|
|
Buffer = "Beneficio aprox.: " + FormatCurr("###,###,###.#0", BeneficioStock );//CurrToStrF(BeneficioStock, 4, 2);
|
|
Label3 -> Caption = Buffer.c_str();
|
|
TbProductos -> First();
|
|
//************************************************************************
|
|
// END -- Suma Stock-TOTAL
|
|
//************************************************************************
|
|
}
|
|
//---------------------------------------------------------------------------
|
|
|
|
|
|
|
|
void __fastcall TStockActual::TabSheet2Show(TObject *Sender)
|
|
{
|
|
#ifdef DEM001
|
|
ShowMessage( "El seguimiento estadístico de productos\n no esta incluido en esta versión.");
|
|
ShowMessage( "Esta función ha sido deshabilitada para esta versión.\nPongase en contacto con el autor, si desea\nel módulo correspondiente: Jose-David.Guillen@cs.us.es" );
|
|
#endif
|
|
DBChart1->RefreshData();
|
|
}
|
|
//---------------------------------------------------------------------------
|
|
|
|
void __fastcall TStockActual::BajoMinimosClick(TObject *Sender)
|
|
{
|
|
IndicesChange( 0, 0 );
|
|
}
|
|
//---------------------------------------------------------------------------
|
|
|
|
void __fastcall TStockActual::TbProductosFilterRecord(TDataSet *DataSet,
|
|
bool &Accept)
|
|
{
|
|
if ( BajoMinimos->Checked )
|
|
Accept = (DataSet->FieldByName("Stock Actual")->AsInteger <= DataSet->FieldByName("StockMinimo")->AsInteger);
|
|
else
|
|
Accept = 1;
|
|
}
|
|
//---------------------------------------------------------------------------
|
|
|
|
void __fastcall TStockActual::TbProductosBeforeInsert(TDataSet *DataSet)
|
|
{
|
|
ShowMessage( "No esta autorizado a insertar nuevos registros.\nAl menos en este módulo del programa.");
|
|
Abort();
|
|
}
|
|
//---------------------------------------------------------------------------
|
|
|
|
void __fastcall TStockActual::ImprimirStockClick(TObject *Sender)
|
|
{
|
|
// Debemos distinguir entre: NORMAL / MINIMOS
|
|
TStockQR *StockQR;
|
|
Visible = false;
|
|
StockQR = new TStockQR(this);
|
|
#ifdef DEBUG
|
|
StockQR -> QuickRep1 -> Preview();
|
|
#else
|
|
StockQR -> QuickRep1 -> Print();
|
|
#endif
|
|
|
|
Visible = true;
|
|
delete StockQR;
|
|
|
|
|
|
}
|
|
//---------------------------------------------------------------------------
|
|
|
|
|
|
void __fastcall TStockActual::TbProductosCalcFields(TDataSet *DataSet)
|
|
{
|
|
// Valor Stock
|
|
TbProductos->FieldByName("ValorStock")->AsCurrency = TbProductos->FieldByName("Stock Actual")->AsFloat * TbProductos->FieldByName("Precio Costo")->AsCurrency;
|
|
// Beneficio Stock
|
|
TbProductosBeneficioStock->AsCurrency = ( TbProductos->FieldByName("Precio Venta 1")->AsCurrency - TbProductos->FieldByName("Precio Costo")->AsCurrency ) * TbProductos->FieldByName("Stock Actual")->AsFloat;
|
|
}
|
|
//---------------------------------------------------------------------------
|
|
|
|
|
|
void __fastcall TStockActual::FormResize(TObject *Sender)
|
|
{
|
|
// BajoMinimos->Left = PageControl1->Width - 105;
|
|
}
|
|
//---------------------------------------------------------------------------
|
|
|
|
|