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)

Casimiro Notevi 02-06-2013 11:11:28

Este hilo se merece estar siempre arriba, así que ahí está, como tema importante.

José Luis Garcí 02-06-2013 11:21:58

Aquí el módulo que reúne los contactos y que más adelante sus datos lo usaremos en la agenda

aquí la imagen


Aquí una imagen espesificando este detalle



y aquí el código

https://gist.github.com/anonymous/5693067

existe un pequeño error en el código el correcto es

Código Delphi [-]
procedure TFContactos.FormClose(Sender: TObject; var Action: TCloseAction);
//------------------------------------------------------------------------------
//*************************************************[ Al Cerrarse El Form ]******
// Cerramos todos los procesos para que no consuman memoria y posibles errores
//------------------------------------------------------------------------------
begin
   if Timer1.Enabled=true then  Timer1.Enabled:=False;
   ActIbdataset(DM.IBDContacto,'select * from  CONTACTOS');
   //Retornos al modulo de llamada
   if VarSNomMod='CLIENTES' then FClientes.SpeedButtonBC7Click(sender); //antes ponía  FClientes.SpeedButtonBC4Click(sender);
   //Según se van creando los módulos de llamada ir añadiendo, ejmplo Proveedores, Agentes, Personal, etc
end;

José Luis Garcí 02-06-2013 11:41:06

Aquí el módulo que reúne las personas de contacto

Aquí la imagen


Aquí un detalle de datos de familia


Aquí el código
https://gist.github.com/anonymous/5693094

y por último las nuevas funciones usadas de mi fichero Fun.pas
Código Delphi [-]
//------------------------------------------------------------------------------
//****************************************************[ ImputFamiliaaMemo ]****
//  Parte de la idea original de   Felipe Monteiro  del 25/05/2006
// bajada de http://www.planetadelphi.com.br/dica...tbox-com-combo)
//------------------------------------------------------------------------------
// J.L.G.T. 01/05/2013 Basando me en el código de Felipe Monteiro , lo adapte a
// mis necesidades, creando un imput de doble entrada en mi caso para insertar
// dos edit y grabarlo a a un memo
//------------------------------------------------------------------------------
//  [Memo]          TMemo      Donde grabaremos los datos
//  [Acaption]       String     Texto en la barra del caption
//  [Aprompt]        String     Texto aclaratorio para el mensaje o petición
//------------------------------------------------------------------------------
//---EJEMPLO--------------------------------------------------------------------
//  procedure TForm1.Button1Click(Sender: TObject);
//  begin
//     Label1.Caption:=ImputFamiliaaMemo(MEmo1,'Datos de familia','Nombre de la Esposa');
//  end;
//------------------------------------------------------------------------------
function ImputFamiliaaMemo(Memo:TMemo;const ACaption, APrompt: string): string;
  function GetCharSize(Canvas: TCanvas): TPoint;
  var
    I: Integer;
    Buffer: array[0..51] of Char;
  begin
    for I := 0 to 25 do Buffer[i] := Chr(I + Ord('A'));
    for I := 0 to 25 do Buffer[I + 26] := Chr(I + Ord('a'));
    GetTextExtentPoint(Canvas.Handle, Buffer, 52, TSize(Result));
    Result.X := Result.X div 52;
  end;

var
  Form: TForm;
  Prompt: TLabel;
  Combo: TSpinEdit;
  Ed:  TEdit;
  NomH:TEdit;
  Labelfec2: TLabel;
  labelnh:Tlabel;
  DialogUnits: TPoint;
  ButtonTop, ButtonWidth, ButtonHeight: Integer;
  R: TRect;
begin
  Result := '';
  Form   := TForm.Create(Application);
  with Form do
    try
      Canvas.Font     := Font;
      DialogUnits     := GetCharSize(Canvas);
      BorderStyle     := bsDialog;
      FormStyle        :=fsStayOnTop;
      Caption         := ACaption;
      ClientWidth     := MulDiv(195, DialogUnits.X, 4);
      Position        := poScreenCenter;
      Prompt          := TLabel.Create(Form);
      with Prompt do
      begin
        Parent   := Form;
        Caption  := APrompt;
        Left     := MulDiv(8, DialogUnits.X, 4);
        Top      := MulDiv(8, DialogUnits.Y, 8);
        Constraints.MaxWidth := MulDiv(180, DialogUnits.X, 4);
        WordWrap := True;
      end;
      Ed:=TEdit.Create(Form);
      with Ed do
      begin
        Parent     := Form;
        Left      := Prompt.Left;
        Top       := Prompt.top+Prompt.Height+5;
        Width     := MulDiv(180, DialogUnits.X, 4);
        Text      :='';
      end;
      Labelfec2   := TLabel.Create(Form);
      with Labelfec2 do
      begin
        Parent   := Form;
        Caption  := 'Número de hijos';
        Left     := Prompt.Left;
        Top      := ED.top+ED.Height+5;
        WordWrap := True;
      end;
      Combo := TSpinEdit.Create(Form);
      with Combo do
      begin
        Parent     := Form;
        Left      := Prompt.Left;
        Value      :=0;
        Top       := Labelfec2.top+Labelfec2.Height+5;
        Width     := MulDiv(178, DialogUnits.X, 4);
      end;
      labelnh   := TLabel.Create(Form);
      with labelnh do
      begin
        Parent   := Form;
        Caption  := 'Nombre de los hijos';
        Left     := Prompt.Left;
        Top      := Combo.top+Combo.Height+5;
        WordWrap := True;
      end;
      NomH := TEdit.Create(Form);
      with NomH do
      begin
        Parent     := Form;
        Left      := Prompt.Left;
        Top       := labelnh.top+labelnh.Height+5;
        Width     := MulDiv(180, DialogUnits.X, 4);
        Text      :='';
      end;
      ButtonTop    := NomH.top+NomH.Height+10;;
      ButtonWidth  := MulDiv(50, DialogUnits.X, 4);
      ButtonHeight := MulDiv(14, DialogUnits.Y, 8);
      with TButton.Create(Form) do
      begin
        Parent      := Form;
        Caption     := 'OK';
        ModalResult := mrOk;
        default     := True;
        SetBounds(MulDiv(Prompt.Left-2, DialogUnits.X, 4), ButtonTop, ButtonWidth,
          ButtonHeight);
      end;
      with TButton.Create(Form) do
      begin
        Parent      := Form;
        Caption     := 'Cancelar';
        ModalResult := mrCancel;
        Cancel      := True;
        SetBounds(MulDiv(137, DialogUnits.X, 4), ButtonTop,ButtonWidth, ButtonHeight);
        Form.ClientHeight :=ButtonTop+ButtonHeight+5;     //Altura
      end;
      if ShowModal = mrOk then
      begin
         if Ed.Text<>'' then  Memo.Lines.Add('Esposa:[ '+ed.Text+' ]');
         if Combo.Value<>0 then
         begin
           Memo.Lines.Add('Nº de hijos:[ '+IntToStr(Combo.Value)+' ]');
           if NomH.Text<>'' then Memo.Lines.Add('Nombre de los hijos:[ '+NomH.Text+' ]');
         end;
      end;
    finally
      Form.Free;
    end;
end;

//------------------------------------------------------------------------------
//**********************************[ FECHA_DBEDIT_ENTER ]*******
// Nueva 24/11/2010  Se encarga de Asignar una fecha si el edit esta vació
// se pone en el evento OnEnter del Dbedit
//-----------Ejemplo-------------
//   FECHA_DBEDIT(dbedit1,Fecha);
//------------------------------------------------------------------------------
//******************[ AÑADIR AL PRINCIPIO DEL unit de la función  ]*******
//    const
//   VMiAutoFECHA='';
//-----------------------------------------------------------------------------
function FECHA_DBEDIT_ENTER(dbedit:tdbedit;Fecha:String=VMiautoFecha):Tdate;
begin
    try
      try
          if dbedit.Text<>'' then dbedit.Text:=Fecha
                           else begin
                                  Fecha:=DateToStr(now);
                                  dbedit.Text:=fecha;
                                end;

       StrToDate(fecha);  //Para que se produzca una excepción si no es una fecha
      except
         on E: Exception do
         begin
              ShowMessage('Se ha producido un error: ' + 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)
                  + 'Se anula la Fecha introducida y se asigna la del sistema');
             dbedit.Text:=DateToStr(Now);
             Fecha:=DateToStr(now);
         end;
      end;
    finally
        Result:=StrToDate(Fecha);
    end;
end;

//------------------------------------------------------------------------------
//*******************************************************[ FECHA_DBEDIT ]*******
// Nueva 23/11/2010  Se encarga de que con las teclas Arriba/abajo aumentar
//reducir un día, se pone en el evento OnKeyDown del Dbedit
//-----------Ejemplo-------------
//   FECHA_DBEDIT(dbedit1,Key);
//------------------------------------------------------------------------------
function FECHA_DBEDIT(dbedit:tdbedit; Tecla:Word):Boolean;
begin
  if (Tecla=VK_UP) then DBEdit.text:=DateToStr(StrToDate(DBEdit.Text)+1);  //Añadimos un día
  if (Tecla=VK_DOWN) then DBEdit.Text:=DateToStr(StrToDate(DBEdit.Text)-1);//Disminuimos un día
end;

José Luis Garcí 02-06-2013 11:55:22

Aquí el módulo que reúne los bancos

Aquí la imagen



Aquí el código https://gist.github.com/anonymous/5693125

y nuevas funciones usadas de mi archivo Fun.pas

Código Delphi [-]
//------------------------------------------------------------------------------
//************************************************************[ EditLogico ]****
// JLGT 01052013 Modificada de un procedure para admitir sólo unos caracteres en un edit
// BAsado en el código de la página   http://www.nochesdecode.com.ar/2012/...en-delphi.html
//--Partes----------------------------------------------------------------------
//--Ejemplo---------------------------------------------------------------------
//  procedure TFCLIENTES.DBEdit6Change(Sender: TObject);
//  begin
//     DBEdit6.text:=EditLogico(tedit(Dbedit6));  //sólo admitira  'S N s n'
//     //O
//      DBEdit6.text:=EditLogico(tedit(Dbedit6), '0123456789');  //sólo admitira  '0 1 2 3 4 5 6 7 8 9'
//  end;
//------------------------------------------------------------------------------
function EditLogico(edit:TEdit;Cadena:string='SNsn'):String;     
var
i : integer;
aux,aux2: string;
begin
        aux2:='';
        with Edit do
        begin
                aux:=text;
                for i:=1 to length(aux) do
                if pos(aux[i],Cadena)>0 then aux2:=aux2+aux[i];
                SelStart:=length(aux2);
        end;
        Result:=aux2;
end;

//------------------------------------------------------------------------------
//**************************************************************[ CalculaDC]****
//  Parte de la idea original de   ??? 15/05/2013
// bajada de http://www.delphiaccess.com/forum/in...=showfaq;id=78
//------------------------------------------------------------------------------
// tal como estaba sin modificaciones por mi parte
//------------------------------------------------------------------------------
//  [BancoOficina]  String     Banco más oficina de 4+4 usar la funcion ceros
//  [Cuenta]         String     El nº de cuenta de 10 digitos usar la funcion ceros
//------------------------------------------------------------------------------
//---EJEMPLO--------------------------------------------------------------------
//  procedure TForm1.Button1Click(Sender: TObject);
//  begin
//    Label1.Caption := IntToStr(CalculaDC('00851755','0000321764'));
//  end;
//------------------------------------------------------------------------------
function CalculaDC(BancoOficina, Cuenta: string):integer;
  const
    Pesos: array[0..9] of integer=(6,3,7,9,10,5,8,4,2,1);
  var
    n: byte;
    iTemp: integer;
  begin
    iTemp := 0;
    for n := 0 to 7 do
      iTemp := iTemp + StrToInt(Copy(BancoOficina, 8 - n, 1)) * Pesos[n];
    Result := 11 - iTemp mod 11;
    if (Result > 9) then Result := 1 - Result mod 10;
    iTemp := 0;
    for n := 0 to 9 do
       iTemp := iTemp + StrToInt(Copy(Cuenta, 10 - n, 1)) * Pesos[n];
    iTemp := 11 - iTemp mod 11;
    if (iTemp > 9) then iTemp := 1 - iTemp mod 10;
    Result := Result * 10 + iTemp;
  end;

//**************************************************************[ CEROS ]*******
//  Delvuelve unacadena reyena de ceros al frente
//  Propia
//        EJEMPLO
//        a2:=ceros(inttostr(32),4);
//        a2 = 0032
//------------------------------------------------------------------------------
function ceros(text:string;Cant:integer):string;
var
   valor,x:integer;
   dev,con:string;
begin
   con:='';
   valor:=length(text);
   if valorthen
   begin
        for x:=1 to (cant-valor) do
        begin
            con:=con+'0';
        end;
        dev:=con+text;
   end
   else
   dev:=text;
   result:=dev;
end;

José Luis Garcí 02-06-2013 12:10:04

Gracias Casimiro, estaba tan metido en subir los datos que no me había fijado en que contestaste. Muchas gracias por considerarlo interesante

José Luis Garcí 06-06-2013 11:54:41

Para que quede más claro el uso de la tabla clientes, con direcciones, contactos, personas de contacto y bancos os pongo un esquema, que acabo de hacer con un nuevo programa Free, que esta muy bien



el programa se llama Ibeasy+ y lo podéis bajar de http://ibeasy.software.informer.com/.

Ahora que creo quede más claro mi idea de uso de las tablas modulares (no si sera correcto), paso a explicar un par de términos y su uso básico, para que luego al usarlos estén un pocos más claros.

Stock: Creo que es el más común y se refiere a la cantidad de mercancía que tenemos disponible

ADR: Se refiere al transporte de mercancía por carretera y una gran cantidad de países se han acogido al sistema, es obligatorio en los países de la comunidad europea y en todos los acogidos a este sistema. El llevar mercancías que necesitan ADR y no llevarlo conlleva severas multas al conductor y a la empresa, e incluso in movilización del vehículo y la mercancías. para más información

http://es.wikipedia.org/wiki/Acuerdo..._por_carretera

Trazabilidad: Este es el punto más peliagudo, la mayor parte de la gente cree, que sólo es obligatorio a los productos comestibles, pero realmente hay que aplicarla a otros muchos sectores, como todos los derivados de los químicos, manufacturados, alimentación, agricultura, residuales, Nucleares y un largo etc.

Hay que tener en cuenta que la trazabilidad es desde la creación del producto (inclusive anterior de los proveedores) hasta el consumidor final (quedando exento en este punto supermercados, tiendas y pocos más al no tener un control exacto de a quién se le ha vendido la mercancía) la trazabilidad viene controlada por lo que se llaman seriales, lotes, etc e implica que toda una producción hecha o creada (Artificial o naturalmente) tenga un mismo número de registro, asignando el número de registro (lote) la cantidad/formato de producto sacado, aunque el (lote) no varia hay que especificar cantidad lote, pongo un ejemplo:

Hacemos 1000 Litros de lavavajillas lote 130001 y sacamos en los siguientes formatos
Lote................Cantidad.............Formato...............Total Litros
--------------------------------------------------------------
130001............20.....................Garrafas 25 L.........500 L.
130001............80.....................Garrafas 5 L...........400 L.
130001............100...................Botellas 1 L............100 L.

Esto obliga a tener controlado las ordenes de producción y al control de la trazabilidad de los 1000 Litros del lote 130001, mediante partes de rotura, utilización interna, en fabricación uso como materias primas o re conversión y por supuesto ventas (albaranes, facturas, etc.)

Hay que usar el sistema de recursividad, con la trazabilidad, al igual que con el Stock, es decir si eliminamos una factura, cambiamos la cantidad a menos o nos devuelven una mercancía. eta debe ser controlada tanto en el stock como en su control de lotes.

La trazabilidad permite a los organismos públicos, en contacto con las empresas a tener controlado todo el proceso de una mercancía, aunque se hay trasformado en otra, desde su origen al consumidor final (hipotéticamente), el responsable del problema pagará una multa, pero si alguna de las partes no tiene la trazabilidad, la multa puede ser mucho mayor y si se produjesen muertes o lesiones graves, puede llevar incluso a prisión, en caso de tenerla controlada, esto muy difícilmente ocurriría, salvo que seamos los responsables.

Y por último, es muy frecuente que tengamos que controlar junto con la trazabilidad la caducidad, ya que muchos productos, alimentarios, químicos, etc, tiene caducidad.

Para más información podéis dirigiros a http://es.wikipedia.org/wiki/Trazabilidad

Ley de Protección de Datos (LPD): Esta ley obliga a todas las empresas que controlen cual quier tipo de datos de clientes, proveedores, etc. a tener contratado una empresa gestora de dicha ley, esto obliga al texto que deben aparecer, en emails, facturas y demás documentos y aplicarla a nuestro programa es bastante simple, se trata de tener 2 o 3 memos, que su texto se pueda editar y guardar, para posibles cambios futuros y que aparezcan en nuestros documentos físicos como digitales. aparte de esto, obliga a que el cliente si así lo pide, no sea puesto en listados de ningún tipo, e incluso sea borrada su información, pero tener cuidado, por que hacienda esta por encima de esta Ley y si borráis, datos antes del cierre con hacienda y no aparecen los datos del cliente podéis tener un grabe problema. Las multas por no tener este sistema aplicado van desde los 6.000 euros a los 600.000 o el cierre de la empresa con posibilidad de prisión.

Para más información ir a http://noticias.juridicas.com/base_d...lo15-1999.html

Lotes: Así es como voy a denominar el control identificativo de nuestra trazabilidad. Los lotes pueden tener derivados, pudiendo ser padres e hijos, o maestros y esclavos. Quiero decir que de un producto con un lote se puede vender en varios productos diferentes, si haber alteración, cada producto tendrá un lote pero tenemos que tener controlado de que lo te viene. Ejemplo:

Hacemos un Desengrasante base lote 130002 de este embotellamos una parte como limpia suelos desengrasante u otro artículo y a este último le asignarnos el lote 130003, quedando de la siguiente manera
Lote Padre <> Lote Hijo
130002...........130003 (este realmente es un derivado sin modificación del lote 130002 y cuando pidamos un informe del lote 130002 debe darnos la información del lote 130003, para tener la trazabilidad correcta e igualmente pero al revés si la solicitamos del 130003.

Ordenes de producción: Esto implica el proceso para la creación del lote con el producto fabricable (no confundir con el producto final), implica el operario, lote y formatos y cantidades.

Diferencias entre un producto fabricable y el producto final: El producto fabricable, es el producto que vamos a fabricar y el producto final es el producto ya en su formato. Ejemplo

Producto Fabricable: Lavavajillas [u]producto finales[/U], Lavavajillas 5L, Lavavajillas 25L, Lavavajillas 1L , Lavavajillas a granel, etc.

Estos conceptos deben quedar muy claros, ya que si no es fácil perderse más adelante, así que si tenéis dudas, preguntar ahora antes de seguir, y por supuesto, los que no sois de España, debéis informaros de las leyes en vuestro país. Pero la mayoría de programas no tiene estos conceptos que algunos de ellos son obligatorios hace más de una década.

José Luis Garcí 07-06-2013 11:45:51

Empezamos ahora con artículos

Estructura de la base de datos

Cita:

CREATE TABLE ARTICULOS (
ID INTEGER NOT NULL,
CODIGO T20 /* T20 = VARCHAR(20) */, //Código del artículo
PRODUCTO T80 /* T80 = VARCHAR(80) */, //Nombre del producto
COSTE POR /* POR = NUMERIC(15,4) */, //Coste del producto
CODIGOPROVEEDOR T20 /* T20 = VARCHAR(20) */, //Código del proveedor
PV1 POR /* POR = NUMERIC(15,4) */, //Precio de venta tarifa 1
PV2 POR /* POR = NUMERIC(15,4) */, //Precio de venta tarifa 2
PV3 POR /* POR = NUMERIC(15,4) */, //Precio de venta tarifa 3
PV4 POR /* POR = NUMERIC(15,4) */, //Precio de venta tarifa 4
PV5 POR /* POR = NUMERIC(15,4) */, //Precio de venta tarifa 5
DTO1 POR /* POR = NUMERIC(15,4) */, //Descuento de venta tarifa 1
DTO2 POR /* POR = NUMERIC(15,4) */, //Descuento de venta tarifa 2
DTO3 POR /* POR = NUMERIC(15,4) */, //Descuento de venta tarifa 3
DTO4 POR /* POR = NUMERIC(15,4) */, //Descuento de venta tarifa 4
DTO5 POR /* POR = NUMERIC(15,4) */, //Descuento de venta tarifa 5
FAMILIA T20 /* T20 = VARCHAR(20) */, //Familia del artículo
CODIGOBARRAS39 T20 /* T20 = VARCHAR(20) */, //Código de barras libre
CODIGOBARRASEAN13 T20 /* T20 = VARCHAR(20) */, //Códigos de barra estándar Ean 13
PESO POR /* POR = NUMERIC(15,4) */, //Peso del formato del producto
PROPIO LOG /* LOG = CHAR(1) */, //Si es un artículo de fabricación propia
TRAZABILIDAD LOG /* LOG = CHAR(1) */, //Si lleva trazabilidad
SERVICIO LOG /* LOG = CHAR(1) */, //Si es un servicio
CADUCO LOG /* LOG = CHAR(1) */, //Si el artículo es caduco (se lleva la caducidad con el lote
TIPOIMPUESTO INTEGER, //Tipo de aimpuesto aplicable (va con el nombre del impuesto en configuración)
COMISIONMAXIMA POR /* POR = NUMERIC(15,4) */, //Comisión máxima a pagar en este artículo, prevalece sobre la comisión en el agente
DTOMAXIMO POR /* POR = NUMERIC(15,4) */, //Descuento máximo del artículo (prevalece sobre los descuentos en clientes o aplicados en DTO1...DTO5)
RAPEL1 INTEGER, //Rapel de ventas en tarifa 1
RAPEL2 INTEGER, //Rapel de ventas en tarifa 2
RAPEL3 INTEGER, //Rapel de ventas en tarifa 3
RAPEL4 INTEGER, //Rapel de ventas en tarifa 4
RAPEL5 INTEGER, //Rapel de ventas en tarifa 5
ADR VARCHAR(150) CHARACTER SET NONE, //Descripción de la frase de adr
ADREXEPCION INTEGER, // formatos que estan exentos del adr según el propio ADR
ADRLIMITE INTEGER //Limite de mercancía a transportar por un conductor y vehículo sin el carnet y permiso de mercancías peligrosas
);
Rapel: Los clientes que se les hace descuento por rapel, deben hacerles albaranes, unificando a la hora de facturar, la mercancía por código, de manera que si el total de unidades vendidas es igual o superior al rapel de su tarifa se aplica el precio de esta tarifa, en caso contrario se aplica el PVP normal.

Escala de Rapel: Es cuando el cliente parte de un precio normal y según sus ventas finales a la hora de facturar se aplica la tarifa según el rapel alcanzado (no lo he usado nunca y nunca me lo han pedido)


Ahora la tabla NOTAS
Cita:

CREATE TABLE NOTAS (
ID INTEGER NOT NULL,
NOMBREMODULO T20 /* T20 = VARCHAR(20) */, //Nombre del módulo
CODIGO T20 /* T20 = VARCHAR(20) */, //Código del módulo al que pertenece
DESCRIPCION T20 /* T20 = VARCHAR(20) */, //Descripción dentro del modulo, (Avisos, Notas, Alertas,etc.)
NOTAS MEMO /* MEMO = BLOB SUB_TYPE 1 SEGMENT SIZE 80 */ //Campo memo para notas
);
Y por último La tabla imágenes

Cita:

CREATE TABLE IMAGENES (
ID INTEGER NOT NULL,
NOMBREMODULO T20 /* T20 = VARCHAR(20) */, //Nombre del módulo
CODIGO T20 /* T20 = VARCHAR(20) */, //Código del módulo al que pertenece
DESCRIPCION T20 /* T20 = VARCHAR(20) */, //Descripción dentro del modulo, (Foto, interior, exterior, detalle, etc.)
IMAGENES IMG /* IMG = BLOB SUB_TYPE 0 SEGMENT SIZE 80 */ //Imagen a mostrar
);

José Luis Garcí 07-06-2013 18:16:23

Me gustaría saber si esta quedando claro lo que llevo explicado, o tengo que ser más claro.

Casimiro Notevi 07-06-2013 22:31:34

Yo lo entiendo bien, y eso que soy bastante torpe :D

Gracias, muy completo, la verdad :)

José Luis Garcí 08-06-2013 00:32:14

Hola compañero antes de seguir considero oportuno poner algunas imágenes del programa de facturación que hice para mi antigua empresa.

Primero veréis que hay datos tachados, por que lo que os muestro son con información real y hay que respetar la protección de datos, así que pido disculpas, aun así creo que queda bastante claro

Para empezar una imagen del tema de los lotes



Como podéis ver marco en rojo el lote del producto que buscamos, en verde sería el maestro (en este caso es el mismo que hemos introducido) y en naranja el lote derivado que vemos que es el 120402, se puede dar el caso que el lote 120401, tenga el derivado que tenga, pero también tenga un maestro que pueda ser por ejemplo el 120399.

Ya que hablo de mi antiguo programa, que por cierto este que empiezo nuevo es por hacerlo más sencillo y eficaz, os pongo una imagen de un proceso que más abajo os explico.



como podéis ver se trata de la edición de Facturas, con datos reales, os pongo imagen del menú, del visor de documentos (presupuestos, pedidos, albaranes y facturas), del editor de documentos y por último el editor de artículos, que contiene aparte de la información habitual, contiene lotes disponible (La única condición será que 1º el stock disponibles sea igual o superior a 1 y 2º que la fecha de caducidad sea inferior a la actual), por supuesto esto lo veis en el apartado llamado lotes y vencimientos, después del Stringrid hay una última linea que nos permite introducir un lote de forma manual (Se da en más de una ocasión, de que aun no hemos dado la entrada de la mercancía y tengamos que facturarla))
Por otro lado en el apartado precios veréis algo que es muy poco común, por un lado 5 tarifas de precios (esto es normal) y por otro precio especial del cliente, esto si os dais cuenta no esta en la estructura ni de clientes, ni en la de artículos, si no que esta en una tabla independiente y para que se muestre debe darse las siguientes condiciones el código del cliente y el del artículo, pero ya lo veremos mucho más adelante.

Por cierto algo que es muy posible que en breve sea obligatorio en la facturación y demás documentos de ventas, es que deben tener el peso por artículos, el total de la factura y una hoja de ruta detallando la factura, peso total de la misma y peso total de mercancía transportada. Pero aún no es obligatorio.

José Luis Garcí 08-06-2013 11:33:47

Cambios a realizar en la unidad UBAncos de Bancos

debe quedar de la siguiente manera:
Código Delphi [-]
procedure TFBancos.DSPrincipalDataChange(Sender: TObject; Field: TField);
//------------------------------------------------------------------------------
//******************************************************[ Datasorce change ]****
//------------------------------------------------------------------------------
begin
   if (not (DsPrincipal.DataSet.State in [dsEdit,dsInsert])) and (FBancos.Active) then
   begin
       Label12.Caption :=ceros(DBEdit5.Text,4)+'/'+ ceros(DBEdit6.Text,4)+'/'+ceros(DBEdit7.Text,2)+'/'+ceros(DBEdit8.Text,10);
   end;
end;

y

Código Delphi [-]
procedure TFBancos.DBEdit5Change(Sender: TObject);
//------------------------------------------------------------------------------
//********************************************************[ Change Dbedit5 ]****
// Comprueba el digíto de control
//------------------------------------------------------------------------------
begin
  TDBEdit(Sender).Text:=EditLogico(tedit(TDBEdit(Sender)), '0123456789');
  if (DBEdit5.Text<>'') and (DBEdit6.Text<>'') and (DBEdit8.Text<>'') and (FBancos.Active) then
  begin
    DBEdit7.Field.Value:=StrToInt( IntToStr(CalculaDC(ceros(DBEdit5.Text,4)+ ceros(DBEdit6.Text,4),ceros(DBEdit8.Text,10))));
  end;
   Label12.Caption :=ceros(DBEdit5.Text,4)+'/'+ ceros(DBEdit6.Text,4)+'/'+ceros(DBEdit7.Text,2)+'/'+ceros(DBEdit8.Text,10);
  if (Length(DBEdit5.Text)>=4) and (Sender=DBEdit5) then DBEdit6.SetFocus;
  if (Length(DBEdit6.Text)>=4) and (Sender=DBEdit6) then DBEdit8.SetFocus;
end;

Como podéis comprobar me faltaba en ambos casos and (FBancos.Active) para evitar que cargue datos sin estar activo

José Luis Garcí 09-06-2013 15:47:08

Se que puede parecer un tostón este hilo, pero estamos hablando de miles de lineas y conceptos que no se pueden dejar de lados, aparte de eso, como creo que nos pasa a todos, vamos mejorando métodos y el código, o corrigiendo errores según vamos avanzando, así que no me queda otro remedio sino ir poniendo los diferentes cambios

Vamos ahora con artículos

Como siempre la imagen



Como podéis ver no pongo la pestaña facturado, ya que aún no tenemos preparado la facturación y como en todos el código que llevo puesto, no pondré el código de impresión, por que al tener múltiples operadores a la hora de imprimir, que cada uno use y diseñe el que le gusta.

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

Funciones usada de mi archivo fun_dbgrid.pas

Código Delphi [-]
function GridImagen(Grid:TDBGrid; Campo:TField; Rect:TRect; Column:TColumn; State:TGridDrawState):Boolean;
begin
  if Column.Field = Campo then
  begin
    if not (gdSelected in State) then // se não for a célula selecionada
      Grid.Canvas.FillRect(Rect); // limpa a célula
    with TPicture.Create do
    begin
      Assign(Campo);
      Grid.Canvas.StretchDraw(Rect,Bitmap); // desenha imagem
      Free;
    end;
     Result:=True;
  end else  Result:=False;
 end;


function MemoGridB(Grid:TDBGrid; Campo:TField; Rect:TRect; Column:TColumn; State:TGridDrawState):Boolean;
var FixRect:TRect;
begin
  fixRect:=Rect; // declara uma variável local fixRect : TRect
  Dec(fixRect.Bottom,2);
  if Column.Field=Campo then
  begin
    if not (gdSelected in State) then
      Grid.Canvas.FillRect(Rect);
    DrawText(Grid.Canvas.Handle,pchar(Campo.AsString), length(campo.AsString),fixRect,DT_WORDBREAK);
     Result:=True;
  end else  Result:=False;
end;

José Luis Garcí 09-06-2013 15:52:32

Ahora le toca al apartado de notas



tengo un pequeño error en este módulo que aún no he encontrado, que es que no muestra las imágenes de los botones y no se si tendré que rehacerlo, pero la ida esta hay y los botones son los de siempre y el código no varia.

el código https://gist.github.com/anonymous/5743504

y de este apartado nada más

José Luis Garcí 09-06-2013 16:04:22

Ahora a las imágenes



el código https://gist.github.com/anonymous/5743525

Aquí si hay un cambio importante en el botón de cargar imagen, yo ya he hecho el cambio en el resto de los módulos, el código queda de la siguiente manera

Código Delphi [-]
procedure TFImagenes.SpeedButtonBC1Click(Sender: TObject);
//------------------------------------------------------------------------------
//*********************************************************[ Cargar imagen ]****
//------------------------------------------------------------------------------
begin
  CargaIimagenADBImagen(OpenPictureDialog1,DBImage1);
end;

y la función es
Código Delphi [-]
//------------------------------------------------------------------------------
//*************************************************[ CargaIimagenADBImagen ]****
//  Parte de la idea original de   ??? 09/06/2013
// bajada de http://www.planetadelphi.com.br/dica...-um-campo-blob
//------------------------------------------------------------------------------
// Pequeñas modificaciones y convertido a unción por mi permitiendo cargar varios
// tipos de imágenes diferentes
//------------------------------------------------------------------------------
//  [Dialog]  TOpenPictureDialog   Dialogo de cargad de la imagen
//  [Dbimage] TDBImage            El nº de cuenta de 10 digitos usar la funcion ceros
//------------------------------------------------------------------------------
//---EJEMPLO--------------------------------------------------------------------
//  CargaIimagenADBImagen:(OpenPictureDialog1,Dbimage1);
//------------------------------------------------------------------------------

function CargaIimagenADBImagen(Dialog:TOpenPictureDialog;Dbimage:TDBImage):Boolean;
var imagem : TPicture;
begin
  if Dialog.Execute then
  begin
    try
      imagem:=TPicture.Create;
      imagem.LoadFromFile(Dialog.FileName);
      Clipboard.Assign(imagem);
      Dbimage.PasteFromClipboard;
      imagem.Free;
      Result:=True;
    except on E: Exception do
      Result:=False;
    end;
  end;
end;

También se realizaron cambios en mi módulo de datos (DM.pas) el código añadido es el siguiente

Código Delphi [-]

uses Fun;

....

procedure TDM.DataModuleDestroy(Sender: TObject);
//------------------------------------------------------------------------------
//*********************************************************[ Al destruirlo ]****
// Nos aseguramos de que no se nos queden Querys abiertos     //Añadir el archivo Fun.Pas
//------------------------------------------------------------------------------
begin
   QuerryOC(IBQIMAGENES);
   QuerryOC(IBQNOTAS);
end;

y una imagen de como va quedando




Como ya comente, el código y uno va evolucionando, así que seguirá habiendo cambios.

De momento que tal os va pareciendo, es muy pesado, esta claro?, es que como hay tan pocos comentarios, no se si estoy aburriendo al personal.

Casimiro Notevi 09-06-2013 22:15:45

Un gran trabajo que servirá de referencia para muchos ^\||/
GRACIAS :)

José Luis Garcí 09-06-2013 22:30:54

Muchas gracias Caimiro, estas siendo un grana poyo, la verdad que lo que doy no es ni comparado con lo que he recibido. Lo único, es que no se si es que lo estoy haciendo muy complejo, por que esperaba, más criticas o dudas.

Ni siquiera se si mi método es el más adecuado para un ejemplo, ya que estoy seguro, que otros compañeros serán capaces de hacerlo mucho más sencillo

Casimiro Notevi 10-06-2013 00:31:05

A mí me parece que para los que quieran acercarse a ver un proyecto muy completo y no "de aficionado", van a tener un buena guía gracias a tu trabajo, y no sólo por el código en sí, sino también por los conceptos profesionales de lotes, protección de datos, trazabilidad, tratamiento de imágenes, etc.
No se podrán quejar :)

fjcg02 10-06-2013 09:31:51

Es un lujo disponer de toda esta información.

Gracias José Luis

José Luis Garcí 10-06-2013 09:47:49

Cita:

Empezado por Casimiro Notevi (Mensaje 462000)
A mí me parece que para los que quieran acercarse a ver un proyecto muy completo y no "de aficionado", van a tener un buena guía gracias a tu trabajo, y no sólo por el código en sí, sino también por los conceptos profesionales de lotes, protección de datos, trazabilidad, tratamiento de imágenes, etc.
No se podrán quejar :)

Gracias Casimiro, sólo espero estar haciéndolo bien

José Luis Garcí 10-06-2013 09:54:21

Cita:

Empezado por fjcg02 (Mensaje 462003)
Es un lujo disponer de toda esta información.

Gracias José Luis


Gracias Javier, no considero que sea un lujo, creo que es información que esta ahí, que por cuestiones de la vida me ha tocado empollarlas, por trabajar en un sector que las necesita y no me ha quedado más remedio que aprenderlas, pero la mayor parte de autodidacta, así que es posible que me puedan corregir, tanto en la definición de los conceptos, como en alguna parte del proceso.

Lo que no quiero es sonar como prepotente, cuando doy los conceptos o he dicho que la mayoría de los programas omiten estas partes, no es que todo el mundo lo haga, pero estuve buscando software para la que era mi empresa de Fabricación de productos de limpieza y sólo encontré un programa en español que se adaptara + o - y aún así le faltaban cosas.

José Luis Garcí 10-06-2013 11:10:13

Antes de seguir comentaros que el tema de la Ley de Protección de Datos obliga a que nuestro programa tenga acceso con claves y nuestra base de datos también, en este caso estoy usando Firebird y para esta demo no lo haré, pero ademas uso unas funciones y encripto los nombres y documentos (NIF, DNI) dentro de la base de datos, desencriptandolas en los formas, ya que nos encargamos que al form sólo se accede si se tiene el nivel necesario.

Vamos con la estructura de las siguientes 6 tablas

Proveedores

Cita:

CREATE TABLE PROVEEDORES (
ID INTEGER NOT NULL,
CODIGO T20 /* T20 = VARCHAR(20) */, //Código del proveedor
EMPRESA T80 /* T80 = VARCHAR(80) */, //Nombre de la empresa
LIBRE T80 /* T80 = VARCHAR(80) */, //Campo libre sin uso inicialmente
CIF T20 /* T20 = VARCHAR(20) */, //Número del CIF o documento identificativo
FECHAALTA DATE, //Fecha de alta
FORMAPAGO T40 /* T40 = VARCHAR(40) */, //Forma de pago
DIASPAGO T20 /* T20 = VARCHAR(20) */ //Los días de pago
);
Empleados incluye a los agentes

Cita:

CREATE TABLE EMPLEADOS (
ID INTEGER NOT NULL,
CODIGO T20 /* T20 = VARCHAR(20) */, /Código del empleado
AGENTE LOG /* LOG = CHAR(1) */, //Es un agente/comercial
MEDIACOMISION NUMERIC(15,2), /Media de su comisión, se puede poner la más alta y el programa regulara sobre la comisión por producto
FECHAALTA DATE, //Fecha de alta
FECHABAJA DATE, //Fecha de su baja (Los datos de los empleados en ciertos sectores no se pueden borrar nunca, como en todas las empresas del sector químico
NUMEROSEGURIDADSOCIAL T40 /* T40 = VARCHAR(40) */, //Número de la seguridad social
NUMERODOCUMENTO T40 /* T40 = VARCHAR(40) */, //Número de documento identificativo, Nif, Dni, pasaporte, etc
COMISIONDTO1 NUMERIC(15,2), //Descuento a aplicar en la comisión si se aplica el Dto 1
COMISIONDTORAPEL2 NUMERIC(15,2), //Descuento a aplicar en la comisión si se aplica el Dto o rapel 2
COMISIONDTORAPEL3 NUMERIC(15,2), //Descuento a aplicar en la comisión si se aplica el Dto o rapel 2
COMISIONDTORAPEL4 NUMERIC(15,2), //Descuento a aplicar en la comisión si se aplica el Dto o rapel 3
COMISIONDTORAPEL5 NUMERIC(15,2), //Descuento a aplicar en la comisión si se aplica el Dto o rapel 5
PUESTO T20 /* T20 = VARCHAR(20) */, //Puesto que ocupa dentro de la empresa
NOMBRE T80 /* T80 = VARCHAR(80) */, //Nombre de la persona
SALARIO NUMERIC(15,2)// //Sueldo de la persona (este campo sólo lo dejaremos ver a los empleados de mayor nivel
);
Como podéis ver se aplica un descuento en las comisiones según el rapel o descuento que aplicamos entre el 2 y el 5 (rapel), pero no en el 1 ya que es el precio base, este descuento de la comisión se aplica si el descuento dentro del producto es diferente de 0, ó si se ha aplicado el rapel.

Fabricables
Cita:

CREATE TABLE FABRICABLES (
ID INTEGER NOT NULL,
CODIGO T20 /* T20 = VARCHAR(20) */, //Código del fabricable
PRODUCTO T80 /* T80 = VARCHAR(80) */ //Nombre base del producto a fabricar
);
Formas de pago

Cita:

CREATE TABLE FPAGOS (
ID INTEGER NOT NULL,
CODIGO T20 /* T20 = VARCHAR(20) */, //Código de la forma de pago (este campo es único)
FORMAPAGO T40 /* T40 = VARCHAR(40) */, //Formas de pago a establecer
DIASPRESENTACION T20 /* T20 = VARCHAR(20) */, //Días de presentación
DIASCOBRO T20 /* T20 = VARCHAR(20) */, //Dias de cobros
NUMERODEPAGOS INTEGER// Si tiene pago aplazado el numero de plazos
);
Pagos plazos

Cita:

CREATE TABLE PAGOSPLAZOS (
ID INTEGER NOT NULL,
CODIGOFORMADEPAGO T20 /* T20 = VARCHAR(20) */, //Código de forma de pago a la que esta unida
NUMERODEDIAS INTEGER, //Número de días desde la emisión de la factura, dejar en blanco si no se quiere especificar
PORCENTAJEPAGO NUMERIC(15,2) //Porcentaje del total de la factura a cobrar en este plazo
);
Bueno en primer lugar decir que estas son las primeras tabla que están enlazada ( FPAGOS es el maestro y PAGOSPLAZOS el detalle), después sobre la tabla PAGOSPLAZOS
deciros que mi modo de uso es el siguiente pongo dos ejemplos

1º) Cliente pago a 30(40%),60(30%),90(30%) días factura 1000, fecha 30/06/2013 y días de pago del 20 al 25, quedarían los pagos de la siguiente manera

25/07/2013..Importe 400.00 euros [Pago lógico 30/07/2013] (como podemos ver no llega a los 30 días, pero hemos cogido el dato de sus fechas de pago, en caso contrario se iría a casi dos meses)
25/08/2013..Importe 300.00 euros [Pago lógico 29/08/2013]
25/09/2013..Importe 300.00 euros [Pago lógico 28/09/2013]

2º) Cliente paga a 50% y 50%, factura de 1000 euros, fecha 30/06/2013 y días de pago del 20 al 25, lo pagos serían
25/ (mes a designar entre el cliente y la empresa)/2013..Importe 500.00 euros
25/ (mes a designar entre el cliente y la empresa)/2013..Importe 500.00 euros
Al no poner el número de días sólo tenemos en cuenta el día de pago y no el número de días a transcurrir para cada uno de los plazos.

La tabla Lotes

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
);
Sobre el campo ACTIVO, lo usamos para saber si es un lote que se puede vender (S) o no se puede vender (N), por que sea para trasformación, o sea un lote retirado del mercado.

Aunque nadie me ha preguntado, si os dais cuenta, en mi tabla artículos, no he puesto campos para tallas, colores, tamaños o si esta dividido en partes, si lo necesitáis sabéis que son campos que tienen que usarse con tablas auxiliares. yo en esta demo no las voy a poner, pero no esta demás comentarlo.

José Luis Garcí 10-06-2013 15:07:57

Módulo de productos fabricables



Aquí el código https://gist.github.com/anonymous/5748411

José Luis Garcí 19-06-2013 10:20:52

Cambios importantes en los módulos auxiliares (Notas, Imágenes, Direcciones, Bancos, Contactos, Personas de contacto)

1º) se ha añadido un IBQuerry y su datasource el ModuleData (UDM en mi caso), para facilitar los datos a todos los modulos que lo llaman,, eliminando parte del código de control en cada uno de estos, el aspecto actual de mi UDM es el siguiente



Los cambios en su código son los siguientes:

Código Delphi [-]
procedure TDM.conectar;
//------------------------------------------------------------------------------
//**************************************************************[ Conectar ]****
//Nos permite conectar las tablas, querrys + IBDatabase + IBTransaction
//------------------------------------------------------------------------------
begin
   IBDatabase1.Connected:=True;  //La base de datos
   IBTransaction1.Active:=True;  //Las Tansacciones
   IBDCLIEN.Active:=True;        //La tabla Clientes
   IBDirecciones.Active:=True;   //La tabla Direcciones
   IBDPC.Active:=True;           //La tabla Personas de Contacto
   IBDContacto.Active:=True;     //La Tabla de datos de contacto
   IBDBcos.Active:=True;         //La tabla de Bancos
   IBDCONFI.Active:=True;        //La tabla de Configuración
   IBDUSUA.Active:=True;         //La tabla de usuarios (permisos de acceso)
   IBDNOTAS.Active:=True;        //La tabla de notas
   IBDIMAGENES.Active:=True;     //La tabla de Imagenes
   IBDPROVEEDORES.Active:=True;  //La tabla de Proveedores
   IBDLOTES.Active:=True;        //La tabla de Lotes
   IBDARTICULOS.Active:=True;    //La tabla de Artículos
   IBDFAMILIAS.Active:=True;     //La tabla de Familias
   IBDFABRICABLES.Active:=True;  //La tabla de Fabricables
   IBDSTOCK.Active:=True;        //La tabla de Stock
end;


procedure TDM.DataModuleDestroy(Sender: TObject);
//------------------------------------------------------------------------------
//*********************************************************[ Al destruirlo ]****
// Nos aseguramos de que no se nos queden Querys abiertos     //Añadir el archivo Fun.Pas
//------------------------------------------------------------------------------
begin
   QuerryOC(IBQIMAGENES);
   QuerryOC(IBQNOTAS);
   QuerryOC(IBQDirecciones);
   QuerryOC(IBQPersonasContacto);
   QuerryOC(IBQContactos);
   QuerryOC(IBQBancos);
end;


2º) en el FormClose de cada módulo auxiliar ponemos el siguiente código




















//////////He editado nuevamente este post cambiando lo que había puesto por lo siguiente y explico lo que he eliminado///////////






Código Delphi [-]

//Cambiar donde aparece XXX por lo que proceda (Nombre del MODULO, de la Tabla, de el IBDataSet, del IBQuerry, del módulo de llamada o del SpeedButtonBC)

procedure TFNotas.FXXXClose(Sender: TObject; var Action: TCloseAction);
//------------------------------------------------------------------------------
//*************************************************[ Al Cerrarse El Form ]******
// Cerramos todos los procesos para que no consuman memoria y posibles errores
//------------------------------------------------------------------------------
begin
   if Timer1.Enabled=true then  Timer1.Enabled:=False;
   ActIbdataset(DM.IBDXXX,'select * from XXX');
   //Retornos al modulo de llamada
   if VarSNomMod='XXX' then FArticulos.SpeedButtonBCXXXClick(sender);
end;

he eliminado el siguiente código

Código Delphi [-]
   if DM.IBQXXX.Active then  //Nos aseguramos de refrescar los datos del querry, con los nuevos introducidos si los ha habido
   begin  //No uso refresh, ya que muchas veces no funciona y de esta manera es más efectivo el refresco de datos
      DM.IBQXXX.Active:=False;
      DM.IBQXXX.Active:=True;
   end;

, al ya esta controlado en la lineas

Código Delphi [-]
 if VarSNomMod='XXX' then FArticulos.SpeedButtonBCXXXClick(sender);

Que no había actualizado, con lo que el código anterior era redundante.

José Luis Garcí 19-06-2013 11:36:50

Ahora le toca al modulo de proveedores

LA imagen



he marcado algún olvido y lo que hacen algunos botones, ahora las pestañas

0º) Es la de los datos, vemos que realmente en la tabla proveedores tenemos que introducir pocos datos, pero que el conjunto de datos con las auxiliares la completa bastante

1º) Contactos. Recordar que esta tabla sera luego nuestra agenda, permitiendo, separarlo, por Clientes, proveedores, etc, ademas de todos, buscar por el nombre/empresa/etc y ponderemos un indice que nos permitirá ver clasificado por su inicio.

2º) Notas, como podemos ver en este caso tenemos dos notas y las hemos clasificado (campo descripción) como avisos y recordatorio, pero podríamos tener muchos más solo para este proveedor, aquí es donde se ve la potencia de este modo de programar, que aunque un poco más lioso nos da mucha más potencia.

3º) Las Imágenes, Como podemos ver también hemos puesto 2 la del logo y productos.

4º) Personas de contactos, , al tenerla en una tabla auxiliar, nos permite tener multitud de personas de contacto dentro del mismo registro

5º) Direcciones, al igual que la anterior tabla podríamos tener multitud de direcciones (Almacenes, oficinas, tiendas, etc).

6º) Bancos, sería más correcto decir cuentas, pero un cliente/proveedor/etc, puede trabajar con más de un banco o más de una cuenta corriente.

7º) Aquí ira nuestro modulo de compras a este proveedor, que aún no desarrollaremos.


No voy a entrar en algo que ya se ha hablado ampliamente en los foros, sobre las notas y las imágenes si guardarlas dentro de las tablas o sólo guardar su referencia en la tabla y guardarla físicamente en archivos en el disco duro.

También quiero explicar que poner en las pestañas los campos nombre del módulo y código de las tablas auxiliares, es para que quede más claro en el tutorial, normalmente, serían campos no visibles.

y el código podéis bajarlo de https://gist.github.com/anonymous/5812746

José Luis Garcí 19-06-2013 11:50:47

El módulo de Formas de pago



En este módulo hay cosas que cambian, al tratarse de usar una tabla maestro y otra detalle, como podemos ver tenemos 2 panales con botonera y debemos controlar ambas y aunque en la imagen no se ve tenemos un sólo juego de botenes de confirmación y cancelación, para que quede más claro hay que estudiar el código

podemos ver que hemos hecho la relación maestro detalle en el módulo UDM




Aquí el código https://gist.github.com/anonymous/5812904

José Luis Garcí 19-06-2013 11:57:43

Y por último en el día de hoy el modulo de búsqueda.



como podemos ver un módulo sencillo de tan sólo 160 lineas actualmente, que ira creciendo según avancemos el proyecto, sólo tendremos que añadir el control de los módulos de llamada y su retorno, ya que este módulo sera llamado por varios módulos.

No usamos la función de coloración del grid, ya que al ser este variable, en número de campos nos daría un error, más adelante lo modificare y añadiré el código, para que se ajuste al resto del diseño.

El código aquí https://gist.github.com/anonymous/5812974

Casimiro Notevi 19-06-2013 12:11:51

Gran trabajo ^\||/

José Luis Garcí 19-06-2013 12:23:58

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.

Casimiro Notevi 19-06-2013 12:52:42

Por supuesto que interesa el tema, precisamente la mayoría de programas para delphi son de gestión para empresas.
La mayoría de nosotros es eso lo que hemos hecho y seguimos haciendo.
Por cierto, si tú eres un burrito, entonces yo soy un escarabajo :D

fjcg02 19-06-2013 13:02:16

Hola José Luis,
lo que ocurre es que lo estás poniendo tan clarito que apenas quedan dudas. Aparte de la aplicación, que ya es bastante, para mí es tan importante o más la parte de gestión que estás explicando y cómo la resuelves.

No se te ocurra parar...

Gracias y un saludo

José Luis Garcí 19-06-2013 15:47:32

Cita:

Empezado por Casimiro Notevi (Mensaje 462435)
Por supuesto que interesa el tema, precisamente la mayoría de programas para delphi son de gestión para empresas.
La mayoría de nosotros es eso lo que hemos hecho y seguimos haciendo.
Por cierto, si tú eres un burrito, entonces yo soy un escarabajo :D

Si Casimiro, pero en todo caso eres un Escarabajo Golia

ahora fuera de bromas, mi nivel es bastante bajo comparado con el tuyo y el de otros muchos compañeros.

Casimiro Notevi 19-06-2013 16:30:09

1 Archivos Adjunto(s)
Cita:

Empezado por José Luis Garcí (Mensaje 462441)
Si Casimiro, pero en todo caso eres un Escarabajo Golia

jajaja... menos mal que no has dicho que soy un escarabajo pelotero :D

José Luis Garcí 19-06-2013 16:47:45

Cita:

Empezado por fjcg02 (Mensaje 462436)
Hola José Luis,
lo que ocurre es que lo estás poniendo tan clarito que apenas quedan dudas. Aparte de la aplicación, que ya es bastante, para mí es tan importante o más la parte de gestión que estás explicando y cómo la resuelves.

No se te ocurra parar...

Gracias y un saludo



Gracias Javier, espero tengas razón y no sea por todo lo contrario.

En cuanto a parar, el tiempo dirá, en principio mi idea es terminar todas las tablas iniciales, como mucho a principio del mes que viene, luego empieza lo duro, la parte de facturación, explicare sólo esta, ya que con pocos cambios se pasan a los otros formatos, de hecho es más un aspecto más básico o técnico, según el caso, me explico,

En el caso más básico, el 90% de los campos de presupuestos, pedidos, albaranes y facturas, son iguales, de hecho se podría hacer una tabla maestra única para los cuatro formatos y una detalle igualmente, con lo que según el tipo de documento ocuparíamos unos campo o los dejaríamos en blanco.

En la más técnica (de hecho la que prefiero), podemos usar una tabla para cada tipo de formulario y puede ser una única en detalle, como una por cada cada tipo de formato (documento)

Ventajas de la primera el ahorro de tiempo y en teoría de consumo de recursos, la velocidad en principio no debería verse afectada si usamos sentencias SQL y un buen mantenimiento de la tabla. En la segunda los datos son mejor estructurados al estar en tablas independientes, lleva más tiempo de programación y es mucho más facil el seguimiento.

En mi caso he trabajado en los dos sistemas y prefiero el segundo, aunque creo que el primero es igual de válido.

Para que se entienda un poco mejor pongo un ejemplo de los campos de las más básica:

Tabla maestra
ID Integer //PRimarikey y autonumerador
DOCUMENTO varchar 20 //Nombre del documento (factura, pedido,etc)
SERIE Varchar 3 //Serie a usar
NUMERO Varchar 10 //Aquí uso una función que sólo deja los números, con lo cual la puedo pasar a integer y sumar 1, así controlo el numerador del tipo de documento
FECHA Date //Fecha de la creación del documento
MODIFICACIONES Integer // (*)
CODIGOCLIENTE Varchar 20 //Código del cliente
CODIGOCOMERCIAL Varchar 20 //Código del comercial
TOTALSUBTOTAL numeric 15-4 //Subtotal del documento, así no tengo que estar haciendo consultas sql, en ciertos casos
TOTALDTO numeric 15-4 //Total descuentos del documento, así no tengo que estar haciendo consultas sql, en ciertos casos
TOTALIMPUESTOS numeric 15-4 //Total impuestos del documento, así no tengo que estar haciendo consultas sql, en ciertos casos
TOTALCOMISIONES numeric 15-4 //Total comisiones del documento, así no tengo que estar haciendo consultas sql, en ciertos casos
PESO numeric 15-4 //Total del peso perteneciente a la factura (recuerdo que se quiere implantar obligatoriamente por la CE), que junto con la hoja de ruta (suma todos los documentos) nos dara el peso de mercancía que transportamos
NUMEROARTICULOS integer //Cantidad de unidades y no cajas transportadas
FORMAPAGO Varchar 20 //Código de la forma de pago
NUMEROALBARAN Varchar 20 // Serie más numerador si viene de un albarán (en Facturas)
NUMEROPEDIDO Varchar 20 //Serie más numerador si viene de un Pedido (en Albaranes)
NUMEROPRESUPUESTO Varchar 20 ////Serie más numerador si viene de un presupuesto (en pedidos)
COBRADA logico SN//LA factura ya ha sido cobrada va junto con la tabla cobros, donde especificamos como se cobro y el número de documento (talón, pagaré, etc) si existe
COMISIONESPAGADAS logico SN// ''Si la comisión ha sido pagada va junto con la tabla pagocomisiones, donde especificamos fecha, forma del pago, código del comercial y número de documento de pago
LIBRE Varchar 255 //(1)


* - Esto me lo pidió mi jefe hace más de 15 años y es algo que hago desde estoces, la primera vez que grabo la guardo con un 0 y añado +1 cada vez que se vuelve a grabar, a la vez grabo en una tabla de seguimiento, el usuario, la fecha, la hora y los cambios realizados, esta última tabla se borraban los datos con más de tres meses.Me pareció interesante y desde entonces lo mantengo

(1) - Aquí podemos grabar desde observaciones a pequeñas notas, la uso con una función y empieza siempre con [xxx]Donde xxx será el texto que aparece como descripción y después del corchete de cierre, el resto del texto


Esto lo pongo sólo para que entiendan la idea +-.

José Luis Garcí 19-06-2013 16:49:11

Cita:

Empezado por Casimiro Notevi (Mensaje 462445)
jajaja... menos mal que no has dicho que soy un escarabajo pelotero :D

No hombre, para pelotero yo que en sus buenos días, llegue a pesar más de 150 kg.

Casimiro Notevi 19-06-2013 17:27:11

Cita:

Empezado por José Luis Garcí (Mensaje 462447)
No hombre, para pelotero yo que en sus buenos días, llegue a pesar más de 150 kg.

La vida del programador es muy dura, tantas horas sentado :confused:

José Luis Garcí 19-06-2013 18:00:21

no sólo eso Casimiro, como se diría en Castellano antiguo "el buen manjar"

Casimiro Notevi 19-06-2013 19:06:38

Cita:

Empezado por José Luis Garcí (Mensaje 462450)
no sólo eso Casimiro, como se diría en Castellano antiguo "el buen manjar"

Es que es difícil resistirse a esa gastronomía canaria :rolleyes:

José Luis Garcí 19-06-2013 21:17:15

De la época que te hablo, era de las islas , parte de la España, Madrid, Sevilla, Hueva, Málaga, Valencia, Elche, Murcia, Barcelona, Vigo y algo de Portugal, me pegue 7 años, que de 365 días al año, me pegaba 200-260 de viaje, llegue a ir a tres oficinas en el mismo día, Las Palmas, Fuerteventura y Lanzarote, comía fijo en bares y restaurantes, así que te puedes imaginar.

Y si pensáis que guay, de eso nada, mis horarios eran , salir temprano al aeropuerto, llegar al destino, alquilar coche o coger transporte, comer ir a la oficina, cerrábamos a a las 9 en la Península 8 en Canarias, ir al hotel y muy probablemente volver a salir temprano, para ir al aeropuerto y destino a casa o a otra provincia y repetir, si era a casa, era a la oficina y no a mi casa directamente, así que pararme a disfrutar no, no lo pude hacer.

Casimiro Notevi 19-06-2013 22:26:47

Entonces lo que tenías era un descontrol total con las comidas, así es normal que se engorde, hay que tener cuidado y controlarse :)

Caren 20-06-2013 03:34:09

Consulta programa gestion de Jose Luis
 
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.


La franja horaria es GMT +2. Ahora son las 04:20:43.

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