

Programa de gestión desde 0 (Activo)
#21
Escrito 19 junio 2013 - 10:01

#22
Escrito 20 junio 2013 - 12:59

#23
Escrito 20 junio 2013 - 07:44
Yo tengo página en FaceBook y apenas entro
jejeje, me tomé el atrevimiento de compartirte den el grupo de Delphi solidario.

#24
Escrito 21 junio 2013 - 06:33

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
[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;[/DELPHI]
También se detecto un error en el código de proveedores, os pongo el procedure con la corrección
[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;[/DELPHI]
#25
Escrito 21 junio 2013 - 06:48

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....onymous/5831048
#26
Escrito 21 junio 2013 - 07:55
@Desart, esto puede verse como una pequeña molestía, en la pantalla personas de contactos tiene un error ortografico, dice: Frcha de Nacimiento.
Nuevamente te reitero el agredecimiento por el aporte.
Keep Moving Foward!!
#27
Escrito 21 junio 2013 - 08:51
#28
Escrito 22 junio 2013 - 02:23
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.
#29
Escrito 22 junio 2013 - 02:29
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.
#30
Escrito 22 junio 2013 - 02:33
#31
Escrito 22 junio 2013 - 05:38
[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.[/DELPHI]
#32
Escrito 23 junio 2013 - 05:36

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....onymous/5844768
Veamos un detalle de como va cambiando el módulo UbusquedaFP
[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;
[/code]
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.
#33
Escrito 24 junio 2013 - 07:33

y el código como siempre en https://gist.github....onymous/5850255
Como se puede apreciar, se va complicando la cosa


#34
Escrito 25 junio 2013 - 02:54

#35
Escrito 06 julio 2013 - 03:23
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....onymous/5939351
#36
Escrito 06 julio 2013 - 03:36
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.
#37
Escrito 06 julio 2013 - 03:44
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



#38
Escrito 06 julio 2013 - 09:04
Más que debilidades, quiero resaltar una fortaleza que percibo en ti, tienes una excelente "macrovisión del problema", tienes bien claras las partes que lo conforman y la manera de afrontar la solución para cada parte del problema, en otras palabras eres un muy buen analista.
Un cordial saludo.
#39
Escrito 06 julio 2013 - 09:23
#40
Escrito 07 julio 2013 - 03:33
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.