Foros Club Delphi

Foros Club Delphi (https://www.clubdelphi.com/foros/index.php)
-   Varios (https://www.clubdelphi.com/foros/forumdisplay.php?f=11)
-   -   Programa de gestión desde 0 (https://www.clubdelphi.com/foros/showthread.php?t=83457)

beginner01 20-06-2013 06:14:37

Cita:

Empezado por José Luis Garcí (Mensaje 462434)
Muchas gracias Casimiro, viniendo de ti un gran maestro, se agradece mucho más, ya que yo soy un burrito, comparado con el nivel que hay en el club, la suerte o desgracia que he tenido que en los últimos veinte y pico años, es que he trabajado en sectores, que me han permitido hacer sus programas, Cupones tipo la ONCE, Taller, Empresa de Limpieza, Jardinería y Control de Plagas y La Fabrica de productos de limpieza.

La verdad es que pienso muchas veces que el tema parece que no interesa mucho, pero luego miro el número de visitas y veo que no es así, no espero que me estén felicitando todo el día, pero creí que habría un poco de polémica en algunos temas, correcciones, diferencias de opinión, consejos (que los ha habido y se agradecen sinceramente) o maneras diferentes de tratar algunos temas.

Otras veces pienso que o no estoy siendo muy claro, o es demasiada información y no esta siendo procesada.

En Fin, seguiré mientras pueda con el tema.

Pues la verdad es que sí interesa mucho el tema, esta bien y bien explicado y yo soy participe de que no hayan muchos comentarios
que no sean para mostrar algún error o aclarar algo para que no se salga del tema al menos hasta que hayas dado como completado el programa.

Es un gran aporte el que haces.

José Luis Garcí 20-06-2013 10:22:14

Los componentes

NewPAnelDb se encuentran en http://terawiki.clubdelphi.com/Delph...tes-Funciones/ con el nombre NewPanelDB.zip, también su código completo en http://www.clubdelphi.com/foros/show...ght=NewPAnelDb

SpeedButtonBC se encuentran en http://terawiki.clubdelphi.com/Delph...tes-Funciones/ con el nombre SpeedbutonColor_y_Demo.rar, también su código completo en http://www.clubdelphi.com/foros/show...ht=Speedbutton

los DbComboBoxExt, DBIBCheckbox, DBIBMemo,GroupBoxJL se encuentran en http://terawiki.clubdelphi.com/Delph...tes-Funciones/ con el nombre PACKJL.zip expuesto en el link http://www.clubdelphi.com/foros/show...ht=Speedbutton

Los TDBNewEditJL y TMyNewEditJL http://www.clubdelphi.com/foros/showthread.php?t=83280


Enlaces que pueden interesar

http://www.clubdelphi.com/foros/showthread.php?t=79416 para las copias de seguridad
http://www.clubdelphi.com/foros/showthread.php?t=83170 Módulos (ABM) Altas _Bajas y Modificaciones
http://www.delphiaccess.com/forum/fi...5287/#msg35287 Sobre los IBDataSet
http://www.clubdelphi.com/foros/showthread.php?t=78207 Niveles de usuario
http://www.clubdelphi.com/foros/showthread.php?t=72450 Para crear modulos (ABM)
http://www.clubdelphi.com/foros/showthread.php?t=72563 Alguno de los temas tratados en el tutorial
http://www.clubdelphi.com/foros/showthread.php?t=69111 Iconos
http://www.clubdelphi.com/foros/showthread.php?t=68120 Todo el programa en una barra, interesante y lo he usado en algún programita pequeño
http://www.clubdelphi.com/foros/showthread.php?t=74475 Rutinas de programación
http://www.clubdelphi.com/foros/showthread.php?t=73826 Para los Hint de los programas
http://www.clubdelphi.com/foros/show...ebird+tutorial Tutorial de Caral para empezar con Firebird
http://webs.satlink.com/usuarios/c/c...ajarDelphi.htm Curso muy completo de Delphi

Y seguro encontraras muchísimos más

José Luis Garcí 20-06-2013 10:27:47

Cita:

Empezado por Caren (Mensaje 462491)
Como esta al principio no cuesta hecharle un ojo, ademas como trabaja este señorazo.
Mi consulta es para el que ha hecho o esta haciendo este programa si tal cual esta funciona a pesar de que falten algunas cosas como el tema de facturacion y los componentes que se necesitan si siguen estando para bajar y con que nombre, encontre NewPAnelDb, SpeedButtonBC, GroupBoxJL pero no veo los DbComboBoxExt, DBIBCheckbox, DBIBMemo supongo que estaran con algun otro nombre.
Quiero dar las gracias a todos los que sabeis por poner vuestros trabajos para los que no tenemos ni idea vayamos aprendiendo un poquito.

Hola Caren, a que te refieres con lo de este señorazo al programa o ami, por que si es ami prefiero que me digas el señoritooo :D:D:D:D:D

José Luis Garcí 20-06-2013 10:28:47

Caren a abierto un nuevo hilo sobre el tema de los componentes usados en el programa, al que ya le he respondido, pero creo que lo más correcto, para los compañeros que le generen nuevas dudas, aquí pongo su consulta y mi respuesta

Cita:

Empezado por Caren (Mensaje 462491)
Como esta al principio no cuesta hecharle un ojo, ademas como trabaja este señorazo.
Mi consulta es para el que ha hecho o esta haciendo este programa si tal cual esta funciona a pesar de que falten algunas cosas como el tema de facturacion y los componentes que se necesitan si siguen estando para bajar y con que nombre, encontre NewPAnelDb, SpeedButtonBC, GroupBoxJL pero no veo los DbComboBoxExt, DBIBCheckbox, DBIBMemo supongo que estaran con algun otro nombre.
Quiero dar las gracias a todos los que sabeis por poner vuestros trabajos para los que no tenemos ni idea vayamos aprendiendo un poquito.

Cita:

Empezado por José Luis Garcí (Mensaje 462510)
Los componentes

NewPAnelDb se encuentran en http://terawiki.clubdelphi.com/Delph...tes-Funciones/ con el nombre NewPanelDB.zip, también su código completo en http://www.clubdelphi.com/foros/show...ght=NewPAnelDb

SpeedButtonBC se encuentran en http://terawiki.clubdelphi.com/Delph...tes-Funciones/ con el nombre SpeedbutonColor_y_Demo.rar, también su código completo en http://www.clubdelphi.com/foros/show...ht=Speedbutton

los DbComboBoxExt, DBIBCheckbox, DBIBMemo,GroupBoxJL se encuentran en http://terawiki.clubdelphi.com/Delph...tes-Funciones/ con el nombre PACKJL.zip expuesto en el link http://www.clubdelphi.com/foros/show...ht=Speedbutton

Los TDBNewEditJL y TMyNewEditJL http://www.clubdelphi.com/foros/showthread.php?t=83280


Enlaces que pueden interesar

http://www.clubdelphi.com/foros/showthread.php?t=79416 para las copias de seguridad
http://www.clubdelphi.com/foros/showthread.php?t=83170 Módulos (ABM) Altas _Bajas y Modificaciones
http://www.delphiaccess.com/forum/fi...5287/#msg35287 Sobre los IBDataSet
http://www.clubdelphi.com/foros/showthread.php?t=78207 Niveles de usuario
http://www.clubdelphi.com/foros/showthread.php?t=72450 Para crear modulos (ABM)
http://www.clubdelphi.com/foros/showthread.php?t=72563 Alguno de los temas tratados en el tutorial
http://www.clubdelphi.com/foros/showthread.php?t=69111 Iconos
http://www.clubdelphi.com/foros/showthread.php?t=68120 Todo el programa en una barra, interesante y lo he usado en algún programita pequeño
http://www.clubdelphi.com/foros/showthread.php?t=74475 Rutinas de programación
http://www.clubdelphi.com/foros/showthread.php?t=73826 Para los Hint de los programas
http://www.clubdelphi.com/foros/show...ebird+tutorial Tutorial de Caral para empezar con Firebird
http://webs.satlink.com/usuarios/c/c...ajarDelphi.htm Curso muy completo de Delphi

Y seguro encontraras muchísimos más


Y recordar que todo lo que estoy usando en el tutorial es libre, exceptuando el Delphi claro.

Casimiro Notevi 20-06-2013 11:30:47

Cita:

Empezado por Caren (Mensaje 462491)
Mi consulta es para el que ha hecho o esta haciendo este programa

He unido el hilo al tema principal, para que todo esté junto, así no nos perdemos ;)

Caren 20-06-2013 15:51:30

Jose Luis espero no haberte molestado con señorazo, esperaba ser un gran halago tanto por ti como por todo lo que haces y colaboras en los foros.
Muchas gracias.

José Luis Garcí 20-06-2013 20:03:35

Tranquilo me lo tome a coña y gracias a ti. Espero te sirvan los enlaces puestos

José Luis Garcí 21-06-2013 15:33:51

Modificaciones en el módulo UPC,



Como podéis ver hemos puesto un nuevo botón sobre un nuevo NewPanelDb, el datasource=DsPrincipal y el InverseAction=true. Este botón lo que hace es crear un nuevo registro con los datos de la Persona de contacto activa en ese momento, creando así el nuevo registro de manera automatizada.


El código añadido

Código Delphi [-]

procedure TFPC.FormActivate(Sender: TObject);
//------------------------------------------------------------------------------
//********************************************[ Cuando se activa El form ]******
// Lo que queremos que haga nuestro Form Cuando se Actiba
//------------------------------------------------------------------------------
begin
     . . .
    //Se ha añadido las siguientes lineas 
    PanelAux.ColorNotActive:=COLORPANELACT;
    PanelAux.ActiveColor:=COLORPANELNOACT;
end;

procedure TFPC.SpeedButtonBC4Click(Sender: TObject);
//------------------------------------------------------------------------------
//****************************************************[ Añadir a contactos ]****
// añadir al uses     UContactos    (Importante, para que funcione)
//------------------------------------------------------------------------------
begin
  try //Cremoas en contactos uno con los mismos datos que persona de contacto
      DSContactos.DataSet.Insert;
      DSContactos.DataSet.FieldByName('MODULO').Value:=DsPrincipal.DataSet.FieldByName('MODULO').value;
      DSContactos.DataSet.FieldByName('CODIGO').Value:=DsPrincipal.DataSet.FieldByName('CODIGO').value;
      DSContactos.DataSet.FieldByName('NOMBRE').Value:=DsPrincipal.DataSet.FieldByName('NOMBRE').value;
      DSContactos.DataSet.FieldByName('MOVIL').Value:=DsPrincipal.DataSet.FieldByName('MOVIL').value;
      DSContactos.DataSet.FieldByName('MAIL').Value:=DsPrincipal.DataSet.FieldByName('EMAIL').value;
      DSContactos.DataSet.Post;
      IBT.CommitRetaining;    //Donde IBT es el nombre de su Ibtrasaction, con ruta
      ShowMessage('Se ha creado un nuevo contacto con los datos de la persona de contacto actual');
  except
    on E: Exception do
    begin
        MessageBeep(1000);
        ShowMessage('Se ha producido un error y el proceso no se ha podido terminar   Unidad:[ UPC ]   Modulo:[ Grabar nuevo contacto]' + Chr(13) + Chr(13)
                  + 'Clase de error: ' + E.ClassName + Chr(13) + Chr(13)
                  + 'Mensaje del error:' + E.Message+Chr(13) + Chr(13)
                  + '    '+Chr(13) + Chr(13)
                  + 'El proceso ha quedado interrumpido');
        if DSContactos.DataSet.State in [dsEdit, dsInsert] then DSPrincipal.DataSet.Cancel;
        IBT.RollbackRetaining;    //Donde IBT es el nombre de su Ibtrasaction, con ruta
    end;
  end;
end;


También se detecto un error en el código de proveedores, os pongo el procedure con la corrección

Código Delphi [-]
procedure TFProveedor.CambiarPagina(index: Integer; Sender: TObject);
//------------------------------------------------------------------------------
//********************************************************[ Cambiar Página ]****
// Al pulsar los botones para acceder a las pestañas
//------------------------------------------------------------------------------
var VarBActivar:Boolean;
    VarISegundoPageControlIndex:Integer;
    VarSModulo, VarSCodigo:string;
begin
      . . .
         
     case Tipo of    

        . . .

      4:begin  //personas de contacto
           
           // Cambiar la linea ActQuery(DM.IBQContactos,'SELECT * FROM CONTACTOS WHERE (CONTACTOS.MODULO = '+QuotedStr(VarSModulo)+') AND (CONTACTOS.CODIGO = '+QuotedStr(VarSCodigo)+')');  
           //  Por

           ActQuery(DM.IBQPersonasContacto,'SELECT * FROM PC WHERE (PC.MODULO = '+QuotedStr(VarSModulo)+') AND (PC.CODIGO = '+QuotedStr(VarSCodigo)+')');
           if not DM.IBQPersonasContacto.IsEmpty then
           begin
             DBNavigator1.DataSource:=DM.DSIBQPersonasContacto;
           end else DM.IBQPersonasContacto.Active:=False;
           VarISegundoPageControlIndex:=1;
        end;
     
         . . .

    end;
end;

José Luis Garcí 21-06-2013 15:48:35

Módulo empleados



No seguiré comentando sobre las pestañas ya tratadas en post anteriores ya que son lo mismo

Mejoras que hacer en los otros módulos incorporadas a este, al Dsprincipal en su evento DSPrincipalDataChange, se ha añadido, para que las tablas auxiliares cambien cuando cambiamos de datos, siempre y cuando no este en edición o inserción.

Hay cosa nuevas como el modulo de registros de histórico y poco más.

como siempre el código completo en https://gist.github.com/anonymous/5831048

José Luis Garcí 22-06-2013 09:51:31

Bien comenzaba con la gestión de lotes cuando me di cuenta de que me faltaba un campo en su tabla

Como estaba era de la siguiente manera

Cita:

CREATE TABLE LOTES (
ID INTEGER NOT NULL,
CODIGOPRODUCTOFABRICABLE T20 /* T20 = VARCHAR(20) */, //Código del producto Fabricable
CODIGOEMPLEADO T20 /* T20 = VARCHAR(20) */, //Código del empleado responsable
FECHA DATE, //Fecha en que se fabrico
LOTE T20 /* T20 = VARCHAR(20) */, //Lote asignado
CADUCIDAD DATE, //Si es caduco su fecha de caducidad
CANTIDAD NUMERIC(15,2), //Cantidad total fabricada (litros, kilos unidades)
ACTIVO LOG /* LOG = CHAR(1) */ //Si el producto esta activo
);





La tabla completa queda así

Cita:

CREATE TABLE LOTES (
ID INTEGER NOT NULL,
CODIGOPRODUCTOFABRICABLE T20 /* T20 = VARCHAR(20) */, //Código del producto Fabricable
CODIGOEMPLEADO T20 /* T20 = VARCHAR(20) */, //Código del empleado responsable
FECHA DATE, //Fecha en que se fabrico
LOTE T20 /* T20 = VARCHAR(20) */, //Lote asignado
CADUCIDAD DATE, //Si es caduco su fecha de caducidad
CANTIDAD NUMERIC(15,2), //Cantidad total fabricada (litros, kilos unidades)
ACTIVO LOG /* LOG = CHAR(1), */ //Si el producto esta activo
MAESTRO T20 /* T20 = VARCHAR(20) //Si viene de un lote maestro
);
Por cierto el Campo Cantidad no tiene nada que ver con el Stock, sólo dejarlo claro.

José Luis Garcí 22-06-2013 11:23:46

Vamos con dos tablas auxiliares importantes

Cita:

CREATE TABLE STOCK (
ID INTEGER NOT NULL,
CODIGOPRODUCTO T20 /* T20 = VARCHAR(20) */, //Código del producto
LOTE T20 /* T20 = VARCHAR(20) */, //Lote del producto
CANTIDADDEENTRADA INTEGER, //Cantidad de entrada, aquí se ira sumando según las entradas (1)
EXISTENCIAS INTEGER, //Las Existencias que quedan (2)
FECHAENTRADA DATE, //Fecha de la primera entrada , aunque luego sigan entrado más cantidades
CADUCIDAD DATE, //Fecha en la que se caduca el producto(3)
ACTIVO LOG /* LOG = CHAR(1) */ (4)
);

Es de suma importancia saber que en este caso el stock lo hacemos por Lote, con lo que saber el total de existencias reales, seria la suma de de todos los lotes que estén en activo y cuya EXISTENCIAS sean mayor o igual a 1, quiero decir que las existencias del 16-5 es todas las que estén en la tabla Stock con los siguientes datos

CODIGOPRODUCTO='16-5', ACTIVO='S' y EXISTENCIAS>=1

lo que nos puede dar varios registros.


(1) En ciertos tipos de fabricación, las mercancías no se sacan todas a la vez, por eso este campo, lo que hace es incrementar, según hagamos entradas

(2) Aquí debemos tener mucho ojo, es las Existencias (el verdadero Stock), debe indicarnos en todo momento la cantidad real de artículos que quedan , es importante esta cantidad normalmente disminuye, pero hay que tener en cuenta que si hemos echo un documento (albarán, Factura, Etc) que afecta al stock, debemos controlar sus modificamos
veamos diferentes ejemplos pongamos que inicialmente sacamos 10 vajillas

Primero tener en cuenta que si las existencias llegan a 0 debemos marcar como no activo (4)

Caso 1º Salida de 10 vajillas 5L código del producto 16-5 Lote 130001 Seria CODIGOPRODUCTO='16-5', LOTE=130001, EXISTENCIAS=EXISTENCIAS-10

Caso 2º Salida de 10 vajillas 5L código del producto 16-5 Lote 130001(6) y 130002(4) ya que del primer lote nos quedan solo 6, los cambios en la tabla stock serían

CODIGOPRODUCTO='16-5', LOTE=130001, EXISTENCIAS=EXISTENCIAS-6, ACTIVO='N'

Y

CODIGOPRODUCTO='16-5', LOTE=130002, EXISTENCIAS=EXISTENCIAS-4

Caso 3º Sobre el que teníamos con salida de 10 vajillas 5L código del producto 16-5 Lote 130001 lo modificamos y en vez de 10, subimos a 12 los cambios serían


CODIGOPRODUCTO='16-5', LOTE=130001, EXISTENCIAS=EXISTENCIAS-2 (ya que habíamos descontado anteriormente 10 por ello debemos controlar al editar la cantidad anterior siendo el cálculo resultante el siguiente CantiadaADescontar:=CantidadActual-CantidadAnterior; )

Caso 4º Sobre el que teníamos con salida de 10 vajillas 5L código del producto 16-5 Lote 130001 lo modificamos y en vez de 10, Bajamos a 8 los cambios serían

CODIGOPRODUCTO='16-5', LOTE=130001, EXISTENCIAS=EXISTENCIAS+2 (ya que habíamos descontado anteriormente 10 por ello debemos controlar al editar la cantidad anterior siendo el cálculo resultante el siguiente CantiadaADescontar:=CantidadActual-CantidadAnterior; en este caso cantidad actual sería mayor con los que nos daría -2 de resultado al ser el resultado negativo entonces sumamo)

Caso 5º Sobre el que teníamos con salida de 10 vajillas 5L código del producto 16-5 Lote 130001 lo modificamos Cambiamos el Lote por 130004 los cambios serían

CODIGOPRODUCTO='16-5', LOTE=130001, EXISTENCIAS=EXISTENCIAS+10
CODIGOPRODUCTO='16-5', LOTE=130004, EXISTENCIAS=EXISTENCIAS-10

Caso 6º Eliminamos el que teníamos con salida de 10 vajillas 5L código del producto 16-5 Lote 130001 lo cambios serían

CODIGOPRODUCTO='16-5', LOTE=130001, EXISTENCIAS=EXISTENCIAS+10
-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

Si existiesen varios lotes debemos tener Stringrid, dividiendo los lotes con sus cantidades y un edit por Row, para poder poner la nueva cantidad, su estructura seria más o menos como sigue

Lote, Fecha, Caducidad, Existencias, Activo (en caso de que sea 'N' no nos permitirá números positivos, pero si recuperar, si este fuese el caso debemos añadir a existencias y cambiar ACTIVO de 'N' a 'S')

(3) Si el producto es caduco aquí ira su Fecha de caducidad, como un lote sólo puede tener una única fecha de producción, sólo habrá una fecha de caducidad y repito a un número de lote asignado, es una única fabricación.

(4) El Campo ACTIVO tendrá los valores S o N y es de vital importancia, por defecto cuando damos una entrada, si no existe en la tabla STOCK, lo creamos con ACTIVO='S', salvo que indicamos lo contrario, el motivo para esta r en 'N' son los siguientes, que en la mayoría de los casos no tiene que ver con las Existencias

1º) Existencias a 0, en este caso no es lógico que cada vez que entramos en el artículo, o en uno de los documentos de venta siguiera apareciendo si no hay artículo de donde extraer.
2º) Un lote a retirar, podríamos detectar un problema en un lote y tener que retirarlo, para evitar que siga habiendo salidas, lo marcamos como no activo
3º) Es un producto de uso interno y por lo tanto no se vende, tato para uso del personal, como creado para usar en la fabricación/uso de otros productos

Siento el coñazo, pero es muy importante que este tema quede bien claro, para no tener problemas de trazabilidad y existencias reales. Si queda alguna duda, prefiero dedicarle más tiempo y aclararlo ahora que más adelante cuando el programa este más avanzado.

Espero no haberme dejado alguno de los casos posibles, si es así, por favor comunicármelo.

José Luis Garcí 22-06-2013 11:30:10

La otra tabla

Cita:

CREATE TABLE ENTRADAS (
ID INTEGER NOT NULL,
CODIGOPRODUCTO T20 /* T20 = VARCHAR(20) */, //Código del producto
LOTE T20 /* T20 = VARCHAR(20) */, //Lote asignado
FECHA DATE, //Fecha de la entrada y no del lote
CADUCIDAD DATE, //Fecha de la caducidad, esta si la recogemos de la tabla LOTES
CANTIDAD INTEGER, //Cantidad
CODIGOOPERARIO T20 /* T20 = VARCHAR(20) */ //Código del empleado
);;
Como podemos una tabla sencilla, que nos permite tener un buen control de las diferentes entradas.

José Luis Garcí 22-06-2013 11:34:16

Se me olvidaba, por supuesto es importante que si el producto es caduco quiero decir con esto que tiene fecha de caducidad y no esta en blanco, debe controlar que la fecha actual es menor que la de la caducidad y como no si el caso es que la fecha es mayor que la de la caducidad debemos poner ACTIVO='N'

José Luis Garcí 22-06-2013 14:38:02

Como estaba harto de que este componente me diese problemas con el tema de la negrita, lo he vuelto a modificar y aquí lo dejo ya corregido

Código Delphi [-]
{ ****************************************************************** }
{                                                                    }
{   VCL component TDBIBCheckbox                                      }
{                                                                    }
{   Dbcheckbox para Firebird permitiendo Cambiae El Value según Check }
{                                                                    }
{   Code generated by Component Create for Delphi                    }
{                                                                    }
{   Generated from untitled component definition                     }
{   on 23 March 2012 at 15:59                                        }
{                                                                    }
{   Copyright © 2012 by J.L.G.T.                                     }
{                                                                    }
{ ****************************************************************** }

unit TDbIbchkbox;

interface

uses WinTypes, WinProcs, Messages, SysUtils, Classes, Controls,
     Forms, Graphics, Stdctrls, DbTables, DB, DBCtrls, TypInfo, Dialogs;

type
  TDBIBCheckbox = class(TCheckBox)
    private
      { Private fields of TDBIBCheckbox }
        FUpperCaseChk : Boolean;
        FBoldCheck: Boolean;
        FValueChecked : String;
        FValueUnChecked : String;
        { Pointer to application's OnChange handler, if any }
        FOnChange : TNotifyEvent;
        FDataLink : TFieldDataLink;
        FBoldfixed: Boolean;
        { Private methods of TDBIBCheckbox }
        { Method to set variable and property values and create objects }
        procedure AutoInitialize;
        { Method to free any objects created by AutoInitialize }
        procedure AutoDestroy;
        function GetDataField : String;
        procedure SetDataField(Value : String);
        function GetDataSource : TDataSource;
        procedure SetDataSource(Value : TDataSource);
        procedure SetUppercaseChk(value:Boolean);
        function GetUpperCaseChk : Boolean;
        procedure SetValueChecked(value:string);
        procedure SetValueUnChecked(value:string);
        procedure ActiveChange(Sender : TObject);
        procedure DataChange(Sender : TObject);
        procedure EditingChange(Sender : TObject);
        procedure UpdateData(Sender : TObject);
        procedure SetBoldCheck(Value:Boolean);
        procedure SetBoldfixed(Value:Boolean);      //Permite que sea fija o no la negrita
    protected
      { Protected fields of TDBIBCheckbox }

      { Protected methods of TDBIBCheckbox }
        { Method to generate OnChange event }
        procedure Change(Sender : TObject); virtual;
        procedure Click; override;
        procedure KeyPress(var Key : Char); override;
        procedure Loaded; override;

    public
      { Public fields and properties of TDBIBCheckbox }
      { Public methods of TDBIBCheckbox }
        constructor Create(AOwner: TComponent); override;
        destructor Destroy; override;

    published
      { Published properties of TDBIBCheckbox }
        { Cuando Cambia el Checked }
        property OnChange : TNotifyEvent read FOnChange write FOnChange;
        property OnClick;
        property OnDblClick;
        property OnDragDrop;
        property OnEnter;
        property OnExit;
        property OnKeyDown;
        property OnKeyPress;
        property OnKeyUp;
        property OnMouseDown;
        property OnMouseMove;
        property OnMouseUp;
        { Campo de la base de datos }
        property DataField : String           read GetDataField       write SetDataField;
        { Datasource unido a la base de datos }
        property DataSource : TDataSource     read GetDataSource       write SetDataSource;
        { Asegura que Se grave en mayusculas }
        property UpperCaseChk : Boolean       read GetUpperCaseChk    write SetUppercaseChk  default True;
        { Valor de cuando Esta Checked=true }
        property ValueChecked : String        read FValueChecked      write SetValueChecked;
        { Valor de cuando no esta Checked (Checked=False) }
        property ValueUnChecked : String      read FValueUnChecked    write SetValueUnChecked;
        property BoldCheck:Boolean            read FBoldCheck         write SetBoldCheck  default True;
        property Boldfixed:Boolean            read FBoldfixed         write SetBoldfixed  default True;

        Procedure DBICHKNOT;
  end;

procedure Register;

implementation


Function GetTipoCampo (DataSet :TDataSet; Index :Integer) :String;
Begin
    Result := GetEnumName (TypeInfo (TFieldType),
    Integer (DataSet.Fields [Index].DataType));
End;

procedure Register;
begin
     RegisterComponents('InterBase', [TDBIBCheckbox]);
end;

{ Method to set variable and property values and create objects }
procedure TDBIBCheckbox.AutoInitialize;
begin
     FDataLink := TFieldDataLink.Create;
     FBoldCheck:=True;
     FUpperCaseChk:=True;
     FBoldfixed:=True;
     with FDataLink do
     begin
          { Assign handlers }
          OnDataChange := DataChange;
          OnUpdateData := UpdateData;
          OnEditingChange := EditingChange;
          OnActiveChange := ActiveChange;
     end;
end; { of AutoInitialize }

{ Method to free any objects created by AutoInitialize }
procedure TDBIBCheckbox.AutoDestroy;
begin
     FDataLink.Free;
end; { of AutoDestroy }

function TDBIBCheckbox.GetDataField : String;
begin { Return the FDataLink.FieldName property }
     Result := FDataLink.FieldName;
end;

procedure TDBIBCheckbox.SetDataField(Value : String);
begin { Set the FDataLink.FieldName property }
     FDataLink.FieldName := Value;
end;

function TDBIBCheckbox.GetDataSource : TDataSource;
begin { Return the FDataLink.DataSource property }
     Result := FDataLink.DataSource;
end;

procedure TDBIBCheckbox.SetDataSource(Value : TDataSource);
begin { Set the FDataLink.DataSource property }
     FDataLink.DataSource := Value;
end;

function TDBIBCheckbox.GetUpperCasechk : Boolean;
begin
  Result := FUpperCaseChk;
end;

{ Method to generate OnChange event }
procedure TDBIBCheckbox.Change(Sender : TObject);
begin
     if Assigned(FOnChange) then FOnChange(Sender);
end;

{ Override OnClick handler from TCheckBox }
procedure TDBIBCheckbox.Click;
begin { Call method of parent class }
     if FDataLink.Editing then  //Comprueba si se esta editando el registro
     begin
          FDataLink.Modified;
          if fDataLink.field <> nil then
          begin
             if (Checked) then
             begin
               if FUpperCaseChk then fDataLink.field.Value := UPperCase(FValueChecked)
                                else fDataLink.field.Value := FValueChecked;
               if (FBoldCheck) then
               begin
                 if (fBoldfixed=False)  then Self.Font.Style:=[fsBold]
                                        else Self.Font.Style:=[];
               end;
             end else
             begin
              if FUpperCaseChk=False then fDataLink.field.Value := UpperCase(FValueChecked)
                                     else  fDataLink.field.Value := FValueUnChecked;
             end;
          end;
          inherited Click;
//       end;
     end;
end;

{ Override OnKeyPress handler from TCheckBox }
procedure TDBIBCheckbox.KeyPress(var Key : Char);
begin { Call method of parent class }
     inherited KeyPress(Key);
end;

constructor TDBIBCheckbox.Create(AOwner: TComponent);
begin
     inherited Create(AOwner);
     AutoInitialize;
     FUpperCaseChk:=True;
     FValueChecked:='SI';
     FValueUnChecked:='NO';
     { Code to perform other tasks when the component is created }
end;

procedure TDBIBCheckbox.DataChange(Sender : TObject);
begin
    if fDataLink.field <> nil then
    begin
       if FUpperCaseChk then
       begin
          if UpperCase(FDataLink.Field.AsString)=UpperCase(FValueChecked) then Checked:=true
                                                                          else Checked:=False;
       end else
       begin
          if FDataLink.Field.Value=FValueChecked then Checked:=true
                                                 else Checked:=False;
       end;
       if (Checked) then
       begin
               if (FBoldCheck) then
               begin
                 if (fBoldfixed=False)  then Self.Font.Style:=[fsBold]
                                        else Self.Font.Style:=[];
               end;
       end;
       if Assigned(FOnChange) then FOnChange(Sender);
    end;
end;

destructor TDBIBCheckbox.Destroy;
begin
     AutoDestroy;
     inherited Destroy;
end;

procedure TDBIBCheckbox.EditingChange(Sender : TObject);
begin
     //
end;

procedure TDBIBCheckbox.Loaded;
begin
     inherited Loaded;
end;

procedure TDBIBCheckbox.ActiveChange(Sender : TObject);
const
     IntFieldTypes = [ftSmallInt, ftInteger, ftWord];
begin
     if DataField = '' then  Exit;
end;

procedure TDBIBCheckbox.UpdateData(Sender : TObject);
begin
    if fDataLink.field <> nil then
    begin
        if (Checked) then
       begin
         if FUpperCaseChk then fDataLink.field.Value := UPperCase(FValueChecked)
                          else fDataLink.field.Value := FValueChecked;
         if (FBoldCheck) then
         begin
              if (fBoldfixed=False)  then Self.Font.Style:=[fsBold]
                                     else Self.Font.Style:=[];
         end;
       end else
       begin
         if FUpperCaseChk=False then fDataLink.field.Value := UpperCase(FValueChecked)
                                  else  fDataLink.field.Value := FValueUnChecked;
       end;
    end;
end;

procedure TDBIBCheckbox.SetUppercaseChk(value: Boolean);
begin
    if value<>FUpperCaseChk then FUpperCaseChk:=value;
end;

procedure TDBIBCheckbox.SetValueChecked(value: string);
begin
      if value<>FValueChecked then
      begin
         if FDataLink.Field<>nil then
         begin
             if Length(value)>FDataLink.Field.Size then ShowMessage('El ValueCheck [ '+Value+' ] contiene más caracteres de los '+#13+#10+
                                                                    'permitidos, que es de  [ '+IntToStr(FDataLink.Field.Size)+' ] caracteres')
                                                  else FValueChecked:=value;
         end else FValueChecked:=value;
      end;
end;
procedure TDBIBCheckbox.SetBoldCheck(Value: Boolean);
begin
    if FBoldCheck<>value then FBoldCheck:=Value;

end;

procedure TDBIBCheckbox.SetBoldfixed(Value: Boolean);
begin
   if FBoldfixed<>Value then FBoldfixed:=Value;
   if FBoldfixed then Self.Font.Style:=[fsBold] else Self.Font.Style:=[]
end;

procedure TDBIBCheckbox.SetValueUnChecked(value: string);
begin
      if value<>FValueUnChecked then
      begin
         if FDataLink.Field<>nil then
         begin
             if Length(value)>FDataLink.Field.Size then ShowMessage('El ValueUnCheck [ '+Value+' ] contiene más caracteres de los '+#13+#10+
                                                                    'permitidos, que es de  [ '+IntToStr(FDataLink.Field.Size)+' ] caracteres')
                                                  else FValueUnChecked:=value;
         end else FValueUnChecked:=value;
      end;
end;

Procedure TDBIBCheckbox.DBICHKNOT;
begin
   if  FDataLink.Editing=true then
   begin
        FDataLink.Field.Value:=FValueUnChecked;
   end;
end;

end.

José Luis Garcí 23-06-2013 14:37:34

El Módulo de Lotes



Es importante darse cuenta que el nuevo número de lote siempre lo cogemos de configuración evitando de esta manera que se puedan duplicar los número de lotes

Tenemos que poner un apartado en el programa para cerrar el año, ya que este nos permite poner el contador de lotes y de otros si es necesario a 0

El código en https://gist.github.com/anonymous/5844768

Veamos un detalle de como va cambiando el módulo UbusquedaFP

Código Delphi [-]
procedure TFbusquedaFP.FormActivate(Sender: TObject);
//------------------------------------------------------------------------------
//********************[ Cargamos los Campos de la tabla  en el ComboBox  ]******
//------------------------------------------------------------------------------
begin
  //Comprobamos si el combo esta vacio cargamos los datos
  if Edbusqueda.Text='' then ActQuery(IBQBusqueda,'Select * From '+VarSTabla);
  if IBQBusqueda.IsEmpty then
  begin
     ShowMessage('No hay datos para buscar o mostrar');
     SB_SalirClick(Sender);
  end else
  begin
     if comboCampos.Items.Count=0 then DataSource1.DataSet.GetFieldNames(comboCampos.items);
     if VarSTabla='FPAGOS' then
     begin
       CarGarGrid(0,'ID',50,'ID');
       CarGarGrid(1,'CODIGO',130,'Código');
       CarGarGrid(2,'FORMAPAGO',260,'Forma de pago');
       CarGarGrid(3,'DIASPRESENTACION',130,'Días de presentación');
       CarGarGrid(4,'DIASCOBRO',130,'Días de cobro');
       CarGarGrid(5,'NUMERODEPAGOS',130,'Número de pagos');
     end;
     if VarSTabla='FABRICABLES' then
     begin
       CarGarGrid(0,'ID',50,'ID');
       CarGarGrid(1,'CODIGO',130,'Código');
       CarGarGrid(2,'PRODUCTO',520,'Producto');
     end;
     if VarSTabla='EMPLEADOS' then
     begin
       CarGarGrid(0,'ID',50,'ID');
       CarGarGrid(1,'CODIGO',130,'Código');
       CarGarGrid(2,'NOMBRE',520,'Nombre');
       CarGarGrid(3,'PUESTO',130,'Puesto de trabajo');
       CarGarGrid(4,'AGENTE ',130,'Es Agente o comercial');
     end;
  end;
end;

procedure TFbusquedaFP.FormClose(Sender: TObject; var Action: TCloseAction);
//------------------------------------------------------------------------------
//****************************************************************[ Cerrar ]****
//------------------------------------------------------------------------------
begin
   if (VarSNomMod='PROVEEDORES')  and (FProveedor.DsPrincipal.DataSet.State in [dsEdit,dsInsert]) then
   begin
       FProveedor.DBNCodigoFormaPago.Field.Value:=IBQBusqueda.FieldByName('FORMAPAGO').AsString; //Ponemos la forma de pago elegida
       FProveedor.DBNCodigoFormaPago.SetFocus;                        //Damos el foco nuevamente al campo
   end;
   if (VarSNomMod='LOTESF')  and (FLotes.DsPrincipal.DataSet.State in [dsEdit,dsInsert]) then
   begin
       FLotes.DBNCodFabricable.Field.Value:=IBQBusqueda.FieldByName('CODIGO').AsString; //Ponemos el código elegido
       FLotes.DBNCodFabricable.SetFocus;                        //Damos el foco nuevamente al campo
   end;
   if (VarSNomMod='LOTESE')  and (FLotes.DsPrincipal.DataSet.State in [dsEdit,dsInsert]) then
   begin
       FLotes.DBNCodEmpleado.Field.Value:=IBQBusqueda.FieldByName('CODIGO').AsString; //Ponemos el código elegido
       FLotes.DBNCodEmpleado.SetFocus;                        //Damos el foco nuevamente al campo
   end;
   Button3Click(Sender);
   QuerryOC(IBQBusqueda);
   comboCampos.Items.Clear;
end;

procedure TFbusquedaFP.FormShow(Sender: TObject);
//------------------------------------------------------------------------------
//****************************************************************[ OnShow ]****
// Adaptamos el título del form a la tabla que usamos
//------------------------------------------------------------------------------
begin
  if VarSTabla='FPAGOS' then Caption:='Búsquedas en Fomas de pago';  //Caption del Form
  if VarSTabla='EMPLEADOS' then Caption:='Búsquedas en Empleados';  //Caption del Form
  if VarSTabla='FABRICABLES' then Caption:='Búsquedas en Fabricables';  //Caption del Form
end;

como podemos ver usamos el mismo módulo, para diferentes llamadas, e incluso cunado las llamadas son desde el mismo módulo, pero para diferente Tablas ('LOTESF' y 'LOTESE')

El próximo módulo es el de entradas, que tiene muchas similitudes con este pero también con el de Stock, realmente es el paso intermedio entre ambos.

Que paséis un buen Domingo.

José Luis Garcí 24-06-2013 16:33:12

Bueno le toca al modulo de entradas



y el código como siempre en https://gist.github.com/anonymous/5850255

Como se puede apreciar, se va complicando la cosa :eek:, os que yo soy muy complicado como prefierán :D:D:D

elrayo76 29-06-2013 04:18:41

Un consejo por la experiencia de trabajar con distintos sistemas y clientes. En el diseño de los formularios no hagas demasiado grandes los botones porque eso le quita importancia las demas cosas del formulario y a los campos de ingreso de datos. Además intenta que los campos de ingreso de datos sean lo mas justo posibles con el tamaño de lo que puedne ingresar, o sea, que si en un campo pueden ingresar solamente 20 caracteres o dígitos que el campo de ingreso se ajuste a tener ese tamaño y no sobre espacio.

Otra cosas, tampoco pongas muchos colores al fondo de los formularios. Es conveniente que tengan un estilo mas similar al que tiene Windows XP/7.

Veo que todos generalmente opinan como debe ser la base de datos, pero lo que nadie dice es que intentes tener una base normalizada. Esto a largo plazo sera mas conveniente y te evitará grandes dolores de cabeza cuando el proyecto cresca.

Con respecto a los campos de la base lo que yo hago es poner 3 letra delante del nombre para identificar la tabla a la que pertenece. Con esto si algun campo como pueden ser los códigos si se necesitan hacer referencia en otra tabla es mas facil identificarlos

Ejemplo:

Tablas:
- Provincias
* prvCodigo
* prvDescripcion

- Clientes
* cliCodigo
* cliNombre
* cliDireccion
* prvCodigo <-- este hace referencia a un registro de otra tabla.
* cliNota

Por el momento creo que este es todo mi aporte.

Saludos,
El Rayo

José Luis Garcí 29-06-2013 09:28:02

Gracias por los concejos, te comento, que yo era de los que diseñaba, lo más estándar posible a windows, pero varios clientes me hicieron hacer cambios y me dieron sus razones, en gran parte lógicas.

En un principio los monitores eran de 11 pulgadas, ahora el estándar es de 17 en adelante, por lo que el espacio a crecido, y muchos clientes quieren que su programa, sea lo único que se muestre en pantalla, en cuanto a los botones, tengo dos motivos, el primero que tendemos a lo táctil con lo que botones pequeños, es totalmente des aconsejable y en segundo lugar "nos hacemos mayores y el pulso y la vista no son lo que eran" fue la frase de un cliente con poco más que lo que tengo yo ahora y me la dijo hace ya varios años, normalmente suelo usar botones de 75x75 o 80x80, exceptuando los de la barra lateral, ya que quedan según mi opinión más estéticos de esta manera.

En cuanto a los colores, suelo usar básicamente 2, el clbtnfance, como estándar y clskyblue, para los paneles, identificando de esta manera cuales están activos, con respecto a una base de datos, luego uso diferentes colores en un borde bastante fino en los botones, diferenciado los grupos o tipos, suelo usar un color para indicar el edit activo, clinfobk o clmoneygreen para los edit de sólo lectura, dos colores para los grids y por último varios colores en las pestañas, perola mayoría de los parámetros los seleccionas en configuración, así que el cliente puede seleccionar poner todo en el mismo color. Uno de los que no puede cambiar es las pestañas, pero usando un pagecontrol, has visto lo difícil que se le puede hacer a una persona diferenciar en que página esta.

hay que tener en cuenta que estuve durante años trabajando con todo tipo de minusválido, por lo que aprendes a valorar, la opinión de otras personas y muchas necesitan contrastes, para estar posicionados en un formulario de ordenador.

Varias veces, se me ha "acusado" :D de que mis componentes buscan mucho el temas de los colores o la estética, pero podemos echar la vista a tras y decirme a parte de la funcionalidad y las mejoras (que también suelo añadir a mis componentes que es lo que ha ido mejorando con Microsoft Ms-dos, windows, windows 3.1, windows NT windows, 95, windows 98, windows Xp, windows vista, windows 7 (se que me dejo algunos, pero creo que ya se hacen una idea) y como no con Apple y Linux, todos evolucionan, con mayor número de colores, escritorios de mayor tamaños y componentes cada vez más grandes, por que, por estética, petición de los clientes, Accesibilidad y evolución a lo táctil.

Mi opinión, es que nosotros debemos valorar los mismos aspectos, y debemos dejar parámetros que pueda decidir el cliente y tener en cuenta que existen personas con dificultades físicas y psicológicas y también debemos programar para ellos.

En este curso sólo pretendo, aportar mis conocimientos en el área y mi código, que estoy seguro de que muchos compañeros mejoran, ya que no me considero un gran programador, la mayor parte de mi vida e sido autodidacta y en este club me han dado muchísimo, comparado con lo que yo he aportado, al que le pueda ser útil algo que lo aproveche y el que no pues es libre de expresar su opinión.

No creas que me he tomado tu comentario como un ataque, por lo que he puesto en estas lineas, es simplemente una defensa en general, por que nos solemos creer, que nuestros programas son lo más estándar posibles o los mejores diseñados y es increíble la cantidad de parámetros que dejamos en medio que afectan normalmente a un grupo de personas inicialmente y con la edad como nos vamos inclinando hacía este grupo, Problemas de vista, de coordinación, etc.

Con losa años he ido aprendiendo de compañeros y he ido modificando y adaptando según los consejos que me han ido dando, también lo e echo durante este tutorial y Dios me permita no ser orgulloso y prepotente y me permita seguir aprendiendo y mejorando, por que los palos que nos podemos llevar son muy grandes. Os pongo un ejemplo, hace muchos años en una revista de juegos, existía un anuncio de IBM en la que constaba de dos paginas, en la primera aparecía un señor bien vestido y se decía poco más o menos que era un ingeniero de software de alto nivel con poca competencia, en la siguiente página aparecía un bebe de mese y al pie ponía, Y este es su mayor enemigo. La realidad es así de dura, el ejemplo lo tengo en mi sobrino, le saco más de 24 años y en cambio, maneja actualmente más de 10 lenguajes de programación, fluidamente, es un monstruo en programación sobre webs, para que os hagáis una idea, viene a mi casa para que le explique delphi, estamos toda la mañana y toda la tarde, hasta la noche, explicando y desarrollando una pequeñísima aplicación, formularios, tablas, Maestro detalle, llamadas, excepciones, etc, bien la última hora estuvo programando el sólo sin ejecutar la aplicación, aplicando punteros, arrays, llamadas a objetos, funciones y demás, el iba programando y corrigiendo, ejecuto y funciono todo perfecto. Es verdad que ya conocía el C, mientras el hacia eso yo me dedique a coger una de mis agendas apuntar ideas y trozos de código, cosa que le llamo la atención y me pregunto por que tenia tantas agendas viejas y libretas en mi despacho, le comente que en los años que tenia que viajar tanto no tenia portátil, por le que hacía lo que me enseñaron en su día plasmar el código por escrito para luego aplicarlo en un ordenador, su comentario fue "Jo que antiguo, mi cabeza no es capas de esperar a que yo escriba en un boli, yo necesito el ordenador", le pregunte es acaso no has tenido una idea, en un trayecto o mientras duermes sin tener el ordenador cerca, como haces para no olvidarla, es fácíl me dijo, ya me vendrá nuevamente, y si no le comente, entonces es que no era tan buena idea:eek:

José Luis Garcí 29-06-2013 09:39:29

No, no me he olvidado del tutorial, es que estoy ocupado preparando el material para un curso de fabricación que tengo que dar, antes de irme, pienso poner algo más del tutorial, después estaré como una semana, fuera y cuando vuelva reemprendere, pero mi actual trabajo será así, no se cuando estaré disponible.

Casimiro Notevi 29-06-2013 10:26:55

Cita:

Empezado por José Luis Garcí (Mensaje 462955)
En este curso sólo pretendo, aportar mis conocimientos en el área y mi código... , al que le pueda ser útil algo que lo aproveche y el que no pues es libre de expresar su opinión.

Y muy buen aporte que es ^\||/
Por cierto, yo también me he encontrado muchas veces con la pregunta: "¿me puedes poner las letras y los botones más grandes?, es que no los veo".

Por supuesto, como dice elrayo76 es muy importante la nomenclatura, la codificación, la notación usada, etc. pero creo que escapa al ámbito de este proyecto en particular, eso es algo que en este caso se deja para cada uno. Y además puede ser otro gran aporte a los foros, ¿quién se anima? :)

José Luis Garcí 29-06-2013 12:09:07

Cita:

Empezado por Casimiro
Por supuesto, como dice elrayo76 es muy importante la nomenclatura, la codificación, la notación usada, etc. pero creo que escapa al ámbito de este proyecto en particular, eso es algo que en este caso se deja para cada uno. Y además puede ser otro gran aporte a los foros, ¿quién se anima?
Muy buena idea Casimiro

José Luis Garcí 06-07-2013 11:52:18

Primero que nada pedir disculpas por haberme atrasado, tanto en seguir, pero estoy preparando la documentación y el material de un curso para una nueva Fabrica de productos de limpieza (es a lo que me dedico ahora a montar fabricas de productos de limpieza por toda España y otros países) y claro me lleva bastante tiempo preparar un informe por producto, más todo lo demás.

Vamos con el módulo de Regulación de Stock, debería ser un módulo con doble nivel de acceso, el nivel de usuario, en mi caso un 8 y además solicito la clave de usuario nuevamente, aún así se debería al grabar los datos, grabar , en un log, ini, XLS o tabla, tanto el usuario, fecha, hora, cantidad anterior, nueva cantidad y motivo, ya que este apartado afectara seriamente a la trazabilidad, en el ejemplo pongo el resumen pero no lo hago pero creo importante este punto.

Dicho lo dicho aquí la imagen



y aquí el código https://gist.github.com/anonymous/5939351

José Luis Garcí 06-07-2013 12:11:06

Lo siguiente será empezar con nuestras tablas de documentos (para presupuestos, pedidos, albaranes y facturas), usare el sistema de 3 tablas, la maestro, la detalle y la de lotes, creando sólo las 3 para los cuatro tipos de documentos, la estructura ya os la pondré, pero será fundamental, que las tres tendrán tres campos comunes que ademas las hará maestro-detalle entre las 3, los campos serán Documento(Presupuesto, pedido, etc.), número del documento y serie.

El apartado de documentos lo haré una vez (Facturas, el más completo), y explicare los respectivos cambios aplicables a los otros formatos, pero como comprenderéis, es un apartado enorme, por lo que tendré que ir haciéndolo por partes, empezare, por la facturación tal cual, los lotes, , trazabilidad y regulación de stock, estarán incluidos en estas partes, gestión de comisiones, etc.

Según nos vayamos introduciendo, tendremos que ir creando otras tablas a las que haremos referencia y las iremos comentando, una vez terminado el proceso, nos quedara, los módulos de convención de documentos, rutas y cartas de porte, etc. y podremos dar por terminado el tutorial, salvo que queráis un poco más, tendríamos que verlo.

HE dicho que no pondré como hacer los informes (impresiones) ya que cada uno elegirá su método, pero creo que podre mostraros por lo menos dos, una factura y comentaros, que debe llevar y por que y una carta de portes.

Casimiro Notevi 06-07-2013 12:14:00

Cita:

Empezado por José Luis Garcí (Mensaje 463319)
Primero que nada pedir disculpas por haberme atrasado, tanto en seguir, pero estoy preparando la documentación y el material de un curso para una nueva Fabrica de productos de limpieza (es a lo que me dedico ahora a montar fabricas de productos de limpieza por toda España y otros países) y claro me lleva bastante tiempo preparar un informe por producto, más todo lo demás.

Faltaría más, tú haces el trabajo, lo regalas y... ¿pides disculpas por el atraso?, ¡¡¡un monumento tendríamos que hacerte por esta labor desinteresada!!! :)
Ojalá pudiésemos compensar a todos los que colaboran con clubdelphi :rolleyes:

Por cierto, tu nuevo trabajo parece interesante ^\||/
Saludos.

José Luis Garcí 06-07-2013 12:17:50

Si no es molestia, podrían hacerme el favor de valorar el trabajo hasta este momento, lo más sinceramente posible, el motivo, es que como siempre he dicho y he mantenido, yo no soy un experto y necesito saber cuales son mis puntos fuertes, para intentar mejorar.

Me gustaría que lo valorarais de la siguiente manera, del 1 al 10, siendo 1 la menor valoración claro, cada una de las siguientes facetas, y si se os ocurre alguna, ya sabéis.

Explicaciones
Claridad
Código
Tablas
Descripciones
Diseño
Conceptos
forma de aplicar los conceptos
y utilidad

Esto me permitirá, en cuanto al tutorial, intentar corregir y mejorarlo , si puedo y ha nivel personal, seguir aprendiendo y como no autoestima, que me la podéis hundir más :D :D :D o nivelar :rolleyes:

José Luis Garcí 06-07-2013 12:29:43

Cita:

Empezado por Casimiro Notevi (Mensaje 463322)
Faltaría más, tú haces el trabajo, lo regalas y... ¿pides disculpas por el atraso?, ¡¡¡un monumento tendríamos que hacerte por esta labor desinteresada!!! :)
Ojalá pudiésemos compensar a todos los que colaboran con clubdelphi :rolleyes:

Por cierto, tu nuevo trabajo parece interesante ^\||/
Saludos.

Gracias Casimiro, pero creo que si empiezo un tutorial, es por que tengo un compromiso con el club y como tal debo responder, lo mejor que pueda, claro y como supongo que hay gente siguiendo el tema, que menos que disculparme por los atrasos.

Si lo que pasa, es que la gente tiene miedo a montar empresas, te aseguro que es un sector con un margen de beneficio, mínimo de un 35% en 3 o cuatro productos y de más de 500% de beneficios en otros, la media es superior al 100% del coste de la mercancía, necesitas vender volumen, en unos casos y en otros ganas por beneficio, pero con una experiencia de más de diez años en la formulación y gestión de empresas de limpieza y cosmética, no se ha que otra cosa dedicarme, y por muy poco dinero (20.000'00 euros) se puede montar una fabrica de limpieza (no de cosmética) donde se incluye, el alquiler y fianza del local, constitución de la empresa, vehículo de segunda mano, materiales, materias primas, etc.) también incluye el curso que tengo que dar, +- 8-10 fórmulas, dependiendo cuales quieran y lo mejor es que no hay que tener preparación previa y son muy pocos requisitos legales.

José Luis Garcí 07-07-2013 12:07:09

Empezamos con la tabla documentos, como es una tabla para nuestros tipos de documentos, usaremos los identificadores X=Presupuestos, P=Pedidos, A=Albaranes y F=Facturas para indicar en que documento lo usaremos.

Cita:

CREATE TABLE DOCUMENTOS (
ID INTEGER NOT NULL,
TIPODOCUMENTO T20 NOT NULL /* T20 = VARCHAR(20) */, //......................tipo de documento (XPAF)
NUMERODOCUMENTO T20 NOT NULL /* T20 = VARCHAR(20) */, //.....................código del documento (XPAF)
SERIE T3 NOT NULL /* T3 = VARCHAR(3) */, //.....................Serie del documento (XPAF)
CODIGOCLIENTE T20 NOT NULL /* T20 = VARCHAR(20) */, //.....................Código del cliente (XPAF)
DESCRIPCIONCLIENTE T80 /* T80 = VARCHAR(80) */, //......................1 (XPAF)
IDDIRECCIONES INTEGER NOT NULL, //.....................el campo id de la tabla direcciones ya tratada, al tener la posibilidad de varias direcciones (XPAF)
CODIGOAGENTE T20 NOT NULL /* T20 = VARCHAR(20) */, //.....................código del agente o comercial (XPAF)
DESCRIPCIONAGENTE T80 /* T80 = VARCHAR(80) */, //.....................1 (XPAF)
FECHA DATE NOT NULL, //.....................Fecha de emisión de la factura (XPAF)
NUMERODECOBRO T20 /* T20 = VARCHAR(20) */, //.....................Numero (código) de tablas COBROS (Pendiente) donde registraremos la forma en que se nos ha pagado (F)
COBRADO LOG NOT NULL /* LOG = CHAR(1) */, //.....................(S/N) indica si la factura ya esta cobrada, al tener el campo NUMERODECOBRO podemos ver más detalles (F)
NUMERORUTA T20 /* T20 = VARCHAR(20) */, //.....................Numero (código) de tablas RUTAS (Pendiente) donde registraremos las rutas de entrega (PAF)
FECHAENTREGA DATE, //.....................Fecha de la entrega, si cambiamos la ruta, cambiara la fecha (2) (PAF)
FORMADEPAGO T20 NOT NULL /* T20 = VARCHAR(20) */, //.....................Código de la taba forma de pago (XPAF)
DESCRIPCIONFORMADEPAGO T80 /* T80 = VARCHAR(80) */, //...................../1 (XPAF)
NUMEROFINANCIADO T20 /* T20 = VARCHAR(20) */, //.....................Numero (código) de tablas FINANCIADO (Pendiente) donde registraremos las financiación de pagos (PAF)
TOTALFINANCIADO POR /* POR = NUMERIC(15,4) */, //.....................Total del dinero financiado, no tiene por que ser el total de la factura
NUMERORETENCIONES T20 /* T20 = VARCHAR(20) */, //...................../Numero (código) de tablas RETENCIONES (Pendiente) donde registraremos las retenciones hechas a clientes (PAF)
TOTALRETENCIONES POR /* POR = NUMERIC(15,4) */, //...................../Importe de las retenciones
PORCENTAJERETENCIONES POR /* POR = NUMERIC(15,4) */, //.....................porcentaje de retenciones aplicadas, puede variar a la que ya tiene aplicada el cliente (3) (F)
TOTALCOMISIONES POR NOT NULL /* POR = NUMERIC(15,4) */, //.....................Total de comisiones (XPAF). (4)
NUMEROPROTECCIONDATOS INTEGER NOT NULL //.....................Elegimos entre el 1 y el 3 de la tabla CONFIGURACION donde 1 =LDPD1 ... 3=LDPD3, que texto debemos poner (XPAF)
CAMPOLIBRE T80 /* T80 = VARCHAR(80) */, //.....................Campo libre ya que la ley va cambiando o podemos necesitar (XPAF)
MODIFICACIONES INTEGER NOT NULL, //.....................Número de veces que se ha modificado la factura, nos permite controlar si se ha alterado (5) (XPAF)
ESTADO T40 /* T40 = VARCHAR(40) */, //...................../Estado actual de la factura (Pendiente, cobrada, nula (5), etc) (XAPF)
NUMERORELACIONFACTURAS T20 /* T20 = VARCHAR(20) */, //...................../Numero (código) de tablas RELACIONFACTURAS (Pendiente) donde agruparemos facturas de un cliente (F)
SERIERELACIONFACTURAS T3 /* T3 = VARCHAR(3) */, //.....................Serie de la relación de facturas (F)
SUBTOTAL POR NOT NULL /* POR = NUMERIC(15,4) */, //.....................Subtotal del importe (XPAF)
TOTALDESCUENTOS POR NOT NULL /* POR = NUMERIC(15,4) */, //.....................Importe del total de descuentos (XPAF)
TOTALPESO POR NOT NULL /* POR = NUMERIC(15,4) */, //.....................Total del peso perteneciente al documento (XPAF)
TOTALIMPUESTOS POR NOT NULL /* POR = NUMERIC(15,4) */, //.....................Total de impuestos (XPAF)
TOTALIMPUESTO1 POR NOT NULL /* POR = NUMERIC(15,4) */, //.....................Total de impuestos tipo 1 (XPAF)
TOTALIMPUESTO2 POR NOT NULL /* POR = NUMERIC(15,4) */, //.....................Total de impuestos tipo 2 (XPAF)
TOTALIMPUESTO3 POR NOT NULL /* POR = NUMERIC(15,4) */, //.....................Total de impuestos tipo 3 (XPAF)
TOTALIMPUESTO4 POR NOT NULL /* POR = NUMERIC(15,4) */, //.....................Total de impuestos tipo 4 (XPAF)
MININOTA VARCHAR(150) //...................../Campo de 150 caracteres, ya que las notas las haremos a través de la tabla NOTAS (XPAF)
);

1) las descripciones es para posibles cambios sin tener que editar o crear un registro nuevo
ejemplo: Código cliente= 0 Descripción general 'Contado' campo DESCRIPCIONCLIENTE 'Contado - (trabajador taller Antonio)'

2) Si ponemos la ruta para hoy i por cualquier motivo no se puede entregar en la fecha prevista, la pondremos en la siguiente hoja de ruta, por lo que debemos controlar el cambio
de la fecha de entrega

3) El cliente puede solicitar que le aumentes o disminuyas el porcentaje de retenciones en una factura, únicamente. Estará presente en PAF, pero se puede variar y determina sólo
el de la factura, por defecto coge el del cliente, que es lo habitual.

4) Las comisiones irán a su tabla de comisiones, donde pondremos de que documento viene, de aquí podremos realizar el pago de comisiones, recordar que el pago de comisiones
hay que hacerle la retención para el pago de Hacienda.

5) Las Facturas no se pueden borrar, ya que afectan a varios departamentos y alteran la aplicación, no quiero decir que no se puedan, pero no se deben bajo ningún concepto,
ejemplo : tenemos la factura 120001, que es el mismo valor actual de nuestro numerador de facturas y nos damos cuenta al terminar, de que esta mal, claro que podríamos
borrarla y modificar el numerador, pero si el numerador ya va por el 120025, o otro cualquiera, borramos la factura y queda un salto en el registro de facturación, motivo de
auditoria en hacienda, si no queda bien explicado y suele pasar, cuando trabajamos todo el año con cientos o miles de facturas, quien se acuerda de una determinada, de hace
x meses.

---------------------------------------------------------------------------------------------------------------------------------------------------------


Como podemos ver se va complicando la cosa, es posible que se me olvide algún campo, así que ya iremos viendo.

José Luis Garcí 07-07-2013 12:32:59

ahora la tabla detalle

Cita:

CREATE TABLE DETALLE (
ID INTEGER NOT NULL,
IDENTIFICADOR INTEGER NOT NULL, //............................................. FOREIGN KEY con el id de documentos
TIPODOCUMENTO T20 NOT NULL /* T20 = VARCHAR(20) */, //............................................. tipo de documento (XPAF)
NUMERODOCUMENTO T20 NOT NULL /* T20 = VARCHAR(20) */, //............................................. código del documento (XPAF)
SERIE T3 NOT NULL /* T3 = VARCHAR(3) */, //............................................. Serie del documento (XPAF)
CODIGOARTICULO T20 NOT NULL /* T20 = VARCHAR(20) */, //............................................. Código del artículo (XPAF)
DESCRIPCIONARTICULO T80 /* T80 = VARCHAR(80) */, //............................................. 1 (ver en post anterior) (XPAF)
CANTIDAD INTEGER NOT NULL, //............................................. Cantidad o unidades del artículo (XPAF)
PRECIOUNIDAD POR NOT NULL /* POR = NUMERIC(15,4) */, //............................................. Precio de la unidad (XPAF)
IMPUESTO POR NOT NULL /* POR = NUMERIC(15,4) */, //............................................. Porcentaje del impuesto (XPAF)
DESCUENTO POR NOT NULL /* POR = NUMERIC(15,4) */, //............................................. Porcentaje del descuento (XPAF)
COMISION POR NOT NULL /* POR = NUMERIC(15,4) */, //............................................. Porcentaje de la comisión (XPAF)
PESOUNIDAD POR /* POR = NUMERIC(15,4) */, //............................................. peso de cada unidad (XPAF)
MININOTA VARCHAR(150), //............................................. Campo texto de 150 caracteres, para ampliar detalles (XPAF)
CAMPOLIBRE T80 /* T80 = VARCHAR(80) */, //............................................. Campo libre ya que la ley va cambiando o podemos necesitar (XPAF)
MODIFICADO INTEGER NOT NULL, //............................................. Número de veces que se ha modificado (XPAF)
SERVICIO LOG /* LOG = CHAR(1) */, //............................................. Es un servicio (XPAF)
IDPRECIOESPECIAL INTEGER, //............................................. Número del ID, si el precio tomado es precio especial para el cliente (1) (XPAF)
ALMACEN T20 /* T20 = VARCHAR(20) */, //............................................. Almacén del que sale la mercancía (XPAF)
NUMEROPRESUPUESTO T20 /* T20 = VARCHAR(20) */, //............................................. Número (Código) del presupuesto que viene (2) (PAF)
NUMEROPEDIDO T20 /* T20 = VARCHAR(20) */, //............................................. Número (Código) del pedido que viene (2) (AF)
FECHAPEDIDO DATE, //............................................. Fecha del pedido del que viene (2) (AF)
NUMEROALABARAN T20 /* T20 = VARCHAR(20) */, //............................................. Número (Código) del albarán que viene (2) (A)
FECHAALBARAN T20 /* T20 = VARCHAR(20) */ //............................................. Fecha del albarán del que viene (2) (A)
);

/******************************************************************************/
/* Foreign Keys */
/******************************************************************************/

// ALTER TABLE DETALLE ADD CONSTRAINT FK_DETALLE_1 FOREIGN KEY (IDENTIFICADOR) REFERENCES DOCUMENTOS (ID) ON DELETE CASCADE ON UPDATE CASCADE;

1) si tiene precio especial, no le afecta ni rapel, ni otros

2) El cliente normalmente quiere que en el documento de unión (albarán o factura) aparezca reflejado por documentos para el poder revisarlos y comprobar, por ello debemos crear un registro que
especifique según sea el caso de manera que si es un albarán sería 'Pedido 120001 fecha 07/072012' y si fuera una factura sería 'Albarán 120025 fecha 30/07/2012', detallando despues de
cada linea del pedido o albarán.
Este no sería el caso si el cliente tiene un rapel o escandallo con cierre final, ya que para ello debemos unir todos los campos con el mismo código de articulo, para obtener la cantidad de
unidades y ver que precio se le asigna, por lo que el precio del albarán o de la factura difieren, pero aún así debemos registrar de que albaranes o pedido bien, pero lo haríamos al pie del
documento dentro de sus notas.

José Luis Garcí 07-07-2013 12:50:38

Ahora la última de las tres la tabla lotes de documentos (LOTESDOCUMENTOS)

Cita:

CREATE TABLE LOTESDOCUMENTOS (
ID INTEGER NOT NULL,
IDENTIFICADOR INTEGER NOT NULL, //............................................. FOREIGN KEY con el id de documentos
TIPODOCUMENTO T20 NOT NULL /* T20 = VARCHAR(20) */, //............................................. tipo de documento
NUMERODOCUMETO T20 NOT NULL /* T20 = VARCHAR(20) */, //............................................. código del documento
SERIE T3 NOT NULL /* T3 = VARCHAR(3) */, //............................................. Serie del documento
LOTE T20 NOT NULL /* T20 = VARCHAR(20) */, //............................................. número de lote
CANTIDAD INTEGER NOT NULL, //............................................. Cantidad de este artículo con este lote
CODIGOARTICULO T20 NOT NULL /* T20 = VARCHAR(20) */, //............................................. código del artículo
ADR T80 /* T80 = VARCHAR(80) */, //............................................. Descripción y texto ADR
EXCEPCION INTEGER, //............................................. Cantidad exceptuada del ADR
LIMITE INTEGER, //............................................. limite de carga en vehículo con medidas mínimas según el ADR
CADUCIDAD DATE, //............................................. fecha de caducidad de este lote
CAMPOLIBRE T80 /* T80 = VARCHAR(80) */ //............................................. Campo libre ya que la ley va cambiando o podemos necesitar
);


//******************************************************************************/
//* Foreign Keys */
//******************************************************************************/

//ALTER TABLE LOTESDOCUMENTOS ADD CONSTRAINT FK_LOTESDOCUMENTOS_1 FOREIGN KEY (IDENTIFICADOR) REFERENCES DETALLE (ID) ON DELETE CASCADE ON UPDATE CASCADE;

Como podemos ver tenemos una relación entre las tablas siendo de la siguiente manera

DOCUMENTOS.ID------>DETALLES.IDENTIFICADOR y
DETALLES.ID ------------------ LOTESDOCUMENTOS.IDENTIFICADOR

También contamos con los campos TIPODOCUMENTO, NUMERODOCUMETO y SERIE, para poder hacer sus búsquedas y relaciones en SQL.

Podríamos hacerlo creando un juego de tablas por tipo de documentos, que sería la manera más simple y rápida de hacer, pero esta manera, nos permite reducir consumo de recursos, ya que muchos campos son repetitivo, e incluso eliminar la tabla de LOTESDOCUMENTOS y unir sus campos a los de DETALLES, pero de esta manera es más clara.

Como siempre espero este clara la explicación actual y si hay dudas, comentarios, o consejos, rectificaciones, etc, ya sabéis, aquí estoy.

José Luis Garcí 09-07-2013 13:19:43

Para que valláis abriendo boca una imagen del visor de documentos, sin estar activo aún muchos campos



en el apartado 1 veréis un DBtext, con el fondo en verde, realmente va en transparente, pero como no contiene datos aún, para controlar se u ancho

El código en https://gist.github.com/anonymous/5956364


Para que este sistema funcione debemos usar en su llamada el siguiente sistema

Código Delphi [-]
procedure TFMenu.act_V_FacturasExecute(Sender: TObject);
//------------------------------------------------------------------------------
//**************************************************************[ Facturas ]****
// Gestión de Proveedores apto desde nivel 6
//------------------------------------------------------------------------------
begin
    VarSTipoDocumento:='FACTURA';
    FXPAF.PC.ActivePageIndex:=0;
    FXPAF.PC2.ActivePageIndex:=0;
    Acceso(6,FXPAF);
end;

Y el procedimiento acceso
Código Delphi [-]
function TFMenu.Acceso(NivelAc:Integer;MForm:TForm):Boolean;
//------------------------------------------------------------------------------
//*****************************************************[ funcion de acceso ]****
//------------------------------------------------------------------------------
begin
   if Nivel>=NivelAc then
   begin
      MForm.Show;
      Result:=true;
   end else
   begin
      ShowMessage('Debe tener nivel '+IntToStr(NivelAc)+' para poder acceder a este apartado');
      Result:=False;
   end;
end;

En algunos casos, deberemos confirmar con la clave de acceso al programa, la entrada en un apartado esto lo haremos de la siguiente manera

Código Delphi [-]
procedure TFMenu.ACT_Esp_RegularStockExecute(Sender: TObject);
//------------------------------------------------------------------------------
//*********************************************************[ REgular Stock ]****
// Regulación de Stock apto desde nivel 8 + clave de usuario
//------------------------------------------------------------------------------
begin
    if Acceso(8,FRegulaStock) then
    begin
      FRegulaStock.Hide;
      PostMessage(Handle, InputBoxMessage, 0, 0); // Para imputboxt con password chard
      if InputBox('Comprobando seguridad', 'Por favor indroduzca su clave de usuario', '')= VarSClaveUSuario then
         FRegulaStock.Show
      else
      begin
        ShowMessage('La clave de seguridad no es la adecuada,' + #13 +
            'no tiene permiso, para acceder a este apartado');
        FRegulaStock.Close;
      end;
    end;
end;


Para ello necesitamos estos cambios en nuestro programa

Código Delphi [-]
procedure TFMenu.InputBoxSetPasswordChar(var Msg: TMessage);
// Para imputboxt con password chard
// ------------------------------------------------------------------------------
// *****************[ Para convertir los caracteres en *  de un imput box]*******
// ------------------------------------------------------------------------------
var HInputForm, HEdit, HButton: HWND;
begin
  HInputForm := Screen.Forms[0].Handle;
  if (HInputForm <> 0) then
  begin
    HEdit := FindWindowEx(HInputForm, 0, 'TEdit', nil);
    SendMessage(HEdit, EM_SETPASSWORDCHAR, Ord('*'), 0);
  end;
  // ------------------------------------------------------------------------------
  // ****************************[ Otras partes importantes de este código ]*******
  // {Despues del uses}
  // const
  // InputBoxMessage = WM_USER + 200;    //Para imputboxt con password chard
  // {En el Type}
  // procedure InputBoxSetPasswordChar(var Msg: TMessage); message InputBoxMessage;
  // {USO CON LAS DOS LINEAS}
  // PostMessage(Handle, InputBoxMessage, 0, 0);    //Para imputboxt con password chard
  // if InputBox('Comprobando seguridad', 'Porfavor indroduzca su clave de usuario', '')  = VarClaveUSusario then
  // ------------------------------------------------------------------------------
end;

Espero os sea útil y como siempre espero vuestros comentarios.

Por cierto, que nadie se anima a valorar el trabajo, es una buena manera de saber, donde tengo que mejorar y todos podéis hacerlo, ni me ofende, ni me molesta y es un buen ejercicio, para ver con la perspectiva de los compañeros el trabajo que estoy realizando os recuerdo como pido que me valoréis el trabajo.

Cita:

í Si no es molestia, podrían hacerme el favor de valorar el trabajo hasta este momento, lo más sinceramente posible, el motivo, es que como siempre he dicho y he mantenido, yo no soy un experto y necesito saber cuales son mis puntos fuertes, para intentar mejorar.

Me gustaría que lo valorarais de la siguiente manera, del 1 al 10, siendo 1 la menor valoración claro, cada una de las siguientes facetas, y si se os ocurre alguna, ya sabéis.

Explicaciones
Claridad
Código
Tablas
Descripciones
Diseño
Conceptos
forma de aplicar los conceptos
y utilidad

Esto me permitirá, en cuanto al tutorial, intentar corregir y mejorarlo , si puedo y ha nivel personal, seguir aprendiendo y como no autoestima, que me la podéis hundir más o nivelar
No se si es la época o qué, pero parece que los compañeros, no están muy animados a participar, como hace un par de años, claro esta es mi opinión, humildemente.

José Luis Garcí 09-07-2013 13:37:50

Ya he explicado, esto en post anteriores, pero creo que es importante para el tutorial, así que nuevamente, expongo mi sistema de acceso a las diferentes partes del programa, si recordáis en la tabla usuarios (que por cierto, se me colo una S de más y se quedo como ususarios :p) tenemos la estructura

Cita:

CREATE TABLE USUSARIOS (
ID INTEGER NOT NULL,
CLAVE T20 /* T20 = VARCHAR(20) */,
USUARIO T20 /* T20 = VARCHAR(20) */,
NIVEL INTEGER,
NOMBRE T80 /* T80 = VARCHAR(80) */
);
en ella existen dos apartados fundamentales, para el acceso, ojo todos son importantes, pero estos dos fundamentales, que son CLAVE y NIVEL, como es lógico, solicito el usuario y la clave, en un form de acceso, compruebo y si esta ok, cargo una serie de variables locales, con el usuario, la clave y el nivel, después la llamada a los diferentes apartados la hago con la función ACCESO, donde comprobamos e, nivel, con el que ponemos al apartado, todo desde un ActionList, para no tener que estar repitiendo código., si tenemos que volver a solicitar la clave uso un inputbox con la peculiaridad, de poner los caracteres como asteriscos, para ello uso las instrucciones que a parece en el procedure TFMenu.InputBoxSetPasswordChar(var Msg: TMessage);

De esta manera, si nos vamos a tomar un café y un compañero quiere acceder a un apartado, al que no tiene nivel y es delicado, aunque este activo el nivel de usuario, le solicitara la clave para acceder, con lo que se quedara con las ganas, creo que unas de las ventajas de este sistema es el ahorro de código, en apartados de seguridad.

Yo suelo usar el siguiente sistema para valorar el nivel de usuario

0...5 los valoro como acceso de visitante
6...7 Introductor de datos
8 Persona de mucha confianza
9 Acceso total

Claro esta que si tienes nivel 7 en vez de 6 puedes acceder a más apartados, o ver partes dentro de un apartado, que de otra manera no aparecen. Los apartados, que por tema de datos, o seguridad, siempre solicito clave de acceso e incluso en algún programa he usado la clave de acceso con un sistema de clave por fecha o clave diferencial.

Espero no haberos liado.

PepeLolo 09-07-2013 15:38:34

Sólo puedo decir ¡Chapeau! Por el trabajo que estas realizando. Estoy siguiendo el desarrollo desde el principio y me parece fantástico. Es un ejemplo ejemplarizante de desarrollo de aplicación.
Componentes, Datamodulos, explicaciones, imágenes.

Es un trabajo que puede servir tanto para un nivel de programador bajo-medío-alto ya das un montón de aportes al mismo y das buenos ejemplos de resolución como son los componentes adaptados a las necesidades concretas.:D

José Luis Garcí 09-07-2013 15:57:49

Cita:

Empezado por PepeLolo (Mensaje 463495)
Sólo puedo decir ¡Chapeau! Por el trabajo que estas realizando. Estoy siguiendo el desarrollo desde el principio y me parece fantástico. Es un ejemplo ejemplarizante de desarrollo de aplicación.
Componentes, Datamodulos, explicaciones, imágenes.

Es un trabajo que puede servir tanto para un nivel de programador bajo-medío-alto ya das un montón de aportes al mismo y das buenos ejemplos de resolución como son los componentes adaptados a las necesidades concretas.:D

Gracias PepeLoto, por tu comentario, imagino que el tutorial a de ser útil, ya que cuando yo comencé con estos temas, no encontraba casi nada de información, es verdad que ahora existe bastante más, pero es difícil de digerir y aplicar algunas veces.
Una cosa que no me ha quedado clara a lo largo del tutorial, es el conocimiento real de los temas tratados por los compañeros, es por lo que digo muchas veces, que no se si interesa o es que estoy siendo muy espeso en el tema e incluso que alguno piense en que estoy siendo prepotente.

Vuelvo y te repito gracias por el comentario, pero podrias poner una evaluación como la pido, ya que me sería más útil, para saber realmente, en que tendría que mejorar.

José Luis Garcí 09-07-2013 16:48:08

Además creo que mi sistema de trabajo no es el mejor, estoy seguro de que muchos compañeros, pueden hacer maravillas comparado con lo que yo hago, la única ventaja que yo puedo tener, es que suelo trabajar en las empresas para que hago los programas, ya que es la manera más eficaz de conocer las carencias y necesidades de una empresa. Por supuesto si te dedicas a la programación, esto es casi imposible, pero tampoco debemos quedarnos con lo que nos dice el jefe de una empresa, ya que suelen tener un ideal de la empresa, que muchas veces choca con la realidad, de la misma.

Normalmente suelo hablar de cosas que conozco, aunque sea un poco, hace ya cerca de 17-18 empece a trabajar para una empresa que vendía cupones, tipo a los de la once, el primer día me pusieron a trabajar, con un señor que llevaba unos cuantos años buenos trabajando para esta asociación de Madrid, empezó a explicarme el programa, claro, al final y al cabo se trata de un programa de gestión y yo programaba en clipper en esa época, que era el mismo lenguaje de la aplicación, al cabo de una hora y media, ya empece a trabajar con el programa y terminamos el día de trabajo, me preguntaron que que tal y le comente que no entendía, por que algunos procesos se hacían de determinada manera.
Al cabo de una semana, me presentaron a un señor, que me pregunto por las dudas, que tenia del programa, le comente y explique, el por que de mis dudas, me pregunto como lo haría yo, esquematizando le dije más o menos, mis ideas y planteamientos, al cabo de dos días volvió este señor, con otro mucho más joven, era la persona que había hecho el programa, tuve que volver a explicar mis dudas y decir mis planteamientos, esa misma tarde me sacaron de la oficina, para ir al hotel donde se quedaban, tenia una reunión, entre el gerente de zona, la persona que me enseño (era el tercero dentro de la asociación con más de 8 años en ella), el señor más mayor que me pregunto por mis dudas (resulto ser el Presidente de la Asociación, cosa que yo aun desconocía) y el programador), claro, como podéis imaginaros, estaba un poco acojonado, ya que había sido padre hacía pocos meses y estuve en el paro antes de este puesto cerca de 3 años, pensaba que me despedían, sinceramente.
Aquella reunión termino por la noche, me invitaron a cenar y me convocaron nuevamente, a la mañana siguiente en el hotel, durante esos dos días, se estuvo planteando y rebatiendo los diferentes puntos, tiradas, premiso, cierres, partes, etc. a la hora de comer, se presentan a un chaval joven, ante el delegado de zona y el señor que me enseñaba a mi, era mi sustituto, podéis imaginaros, se me cayo el alma a los pies, aún así, mantuve el tipo y calle, seguimos la reunión y al final del segundo día, me preguntaron, por que encontré con tanta facilidad, tantos puntos flacos, posibles errores y mejoras, mi respuesta fue sincera, por que estaban ahí, el presidente se rió y el informático cayo, estaba serio, muy serio, cuando el presidente se sereno, le pregunto al informático, que como era posible que un programa que estaba terminado hacia dos años, más un año terminarlo, no se hubiese dado cuenta de esos errores, mejoras y huecos de seguridad, el informático me miro, estaba triste, se le notaba que estaba enfadado imagine que consigo mismo (luego supe que así era), se hizo el silencio, yo me vire y le pregunte, algo que Jesús, el amigo que me enseño a programar en clipper me dijo al principio del todo, "oye Carlos (el nombre del informático), cuantas horas pasaste con el personal preguntándoles y viéndoles trabajar", me miro sorprendido y me dijo 0, fue el Presidente (no recuerdo su nombre), quien me dio las pautas, a el se le entregaba el programa y me comentaban los errores, me vire a este y le pregunte, cuantas horas paso usted con el programa, su respuesta fue tajante, yo no trabajo con eso se la doy a Fulanito (La persona que me enseño el primer día del cual no recuerdo el nombre) y el a su vez se lo da al personal el cual le dice los fallos, entonces tú (Carlos), no haz hablado nunca con nadie que trabajara directamente con el programa, me volvió a mirar, haciendo un esfuerzo por recordar y dijo no, nunca, dije, esta claro, ahí radica el problema, los usuarios finales, son los que detectan los fallos, si hay un jefe por medio, siempre se cohiben más que con un igual o alguien externo que este para solucionar los problemas, los dos me miraron, se miraron y me dijeron que volviera la hotel al día siguiente.

Regrese al día siguiente y me dijeron que no volvería a mi puesto de inspector (introductor), que me subían el sueldo (25.000 pesetas si no recuerdo mal) y que tendría que estar los próximos quince días yendo a trabajar a una casa que habían alquilado, con Carlos, que luego era probable, que tuviese que viajar a Madrid, cuando el programa estuviese en su fase final de pruebas, nunca fui, diez días despues, hubo un problema muy serio entre la persona que me había contratado y la asociación (el problema fue por parte de esta), no se bajaron del burro, así que mi jefe Jerónimo, decidió despues de preguntarme si yo era capaz de hacer un programa parecido como el que tenia la asociación, le dije que si, me dijo en 20 días, le dije, completo no, pero algunas partes si, acepto y rompió los acuerdos con la asociación, montando una nueva, dicho programa en terminarlo completo, tarde 6 meses, al cabo de otros tres años y medio, me pidió y pago que le hiciera una nuevo para windows, y que yo sepa a día de hoy lo signe usando, tiene fallos, debido a que fue echo en DBF y Delphi 3, hoy en día hubiese echo muchas cosas de manera diferente, pero me imagino que nos pasa a todos.

En cuanto a Carlos, estuve en contacto hasta el 2007, año en que por desgracia murió, durante muchos años, cuando venia a canarias, siempre nos veíamos, el programa lo corrigió siguiendo muchos de mis concejos y aplicando su técnica y forma de programar, pero fue siempre un buen amigo, a partir de aquel tercer día de conocernos.

Siento el coñazo, pero para que entandáis a que me refiero, se debe contar la historia completa.

Casimiro Notevi 09-07-2013 17:36:20

jeje... me gustan las historias de los "abuelos" :D

Fdo. Otro abuelo ;)

José Luis Garcí 09-07-2013 17:39:30

Cita:

Empezado por Casimiro Notevi (Mensaje 463502)
jeje... me gustan las historias de los "abuelos" :D

Fdo. Otro abuelo ;)

:D:D:D, ya no vamos para jovencitos, yo ya voy por tres pastillas al día y tú? :rolleyes:

Casimiro Notevi 09-07-2013 17:43:03

Cita:

Empezado por José Luis Garcí (Mensaje 463503)
:D:D:D, ya no vamos para jovencitos, yo ya voy por tres pastillas al día y tú? :rolleyes:

De momento, ninguna :cool:
Cuando muera, seré el más sano del cementerio :D

José Luis Garcí 09-07-2013 17:47:35

Ninguna :eek:, pues ami me tocan dos de la diabetes y una del colesterol, aunque el último análisis decía que no tengo. al paso que vamos cualquier día nos dan las llaves del ambulatorio. Me pegaba años y años sin ir al médico y llevo menos de dos, con 2-3 visitas al médico mensuales, por la diabetes, revisiones, etc.

Casimiro Notevi 09-07-2013 18:04:09

Vaya, yo por suerte, de momento, no tengo ningún problema de salud. Toco madera :)

fjcg02 09-07-2013 23:10:58

Entre el "abuelo cebolleta" y Casimiro, en vez del ClubDelphi parece la editorial bruguera.

Saludos
PD: este comentario seguramente que sólo lo entendamos los "juveniles"


La franja horaria es GMT +2. Ahora son las 01:37:53.

Powered by vBulletin® Version 3.6.8
Copyright ©2000 - 2024, Jelsoft Enterprises Ltd.
Traducción al castellano por el equipo de moderadores del Club Delphi