Como emitir factura a una persona natural o jurídica

publicado por: Anonymous

Hola amigos sigo aquí tratando de avanzar en esto de base de datos y me encuentro ahora con una nueva inquietud, pues resulta que decidí ampliar a mi base de datos de compras con una cuenta, pues nada busque en la red algo similar pero no encuentro algo que me ayude a resolver este problema, primero que nada explico las tablas que eh agregado..
Dentro de mi base de datos tienda un cliente puede tener una cuenta, pero existe al menos en mi país dos tipos de clientes estos son, (Personas naturales y personas juridicas). Bueno una persona natural es cualquiera y una institución o algo por el estilo vienen a ser las jurídicas.
introducir la descripción de la imagen aquí

Teniendo en cuenta la breve introducción paso a explicar cual es la situación.

Quiero registrar una cuenta a nombre de un Colégio que en este caso viene a ser (Juridico), pero todo cliente jurídico tiene un representante legal es por eso que relacione Jurídico con la tabla persona_natural el cual contiene los atributos de una persona y evitar así tener que agregar los atributos nombres,apellidos etc del representante legal. Hasta ahí almenos para mi parece estar bien, pero ahora el gran problema ¡Hacer la factura a nombre de la institución!. Según mi modelo no se puede por que tengo relacionado solo al cliente con la factura y Se supone que la factura debe salir a nombre de la institución y no del representante legal, estoy en la duda de si agregarle a mi tabla factura los atributos (Nombre, Ruc_o_cedula) para que al momento de hacer la factura obtener los datos de la institución a través del representante legal e insertarlo en la tabla factura, no se si esto sea lo correcto.

Bueno amigos ese es el problema, a todo esto quiero agregar que antes de hacer la pregunta en el foro acudí a un ex profesor de informática del colegio en el cual estudie para ver que opinaba al respecto, el me propuso que en ves de segmentar tanto a la entidad cliente simplemente le cargara todos los atributos algo asi..

introducir la descripción de la imagen aquí

entonces en esa tabla si es un cliente natural lo registro normalmente, pero si es un jurídico en el atributo nombre ingresar el nombre de la institución, en el ruc_o_cedula ingresar el RUC, etc etc.. quedando atributos en blanco como los apellidos…… esa fue la solución que me propuso, pero pienso que esta mal por que ya estaría violando las reglas de normalización si dejo atributos en blanco … espero tengan paciencia y puedan ayudarme un saludo.

solución

Te diría que el problema principal que te está trancando es el diseño de la tabla cliente, en particular su clave primaria idpersona. Este diseño te impide definir que un cliente pueda ser una persona jurídica. De hecho, se puede ver en tu modelo que no hay línea entre la tabla cliente y la tabla juridico. Eso no es correcto.

Lo que necesitas hacer es asignarle una clave primaria diferente a la tabla cliente que simplemente sirva para identificar un registro en la tabla cliente. Y luego aparte, defines 2 columnas en la misma tabla, idpersona y idjuridico con claves foráneas a sus tablas respectivas (persona_natural y juridico). La idea es que para cada registro en la tabla cliente, le asignas valor a uno de los 2 campos (idpersona o idjuridico) para establecer que tipo de cliente es.

Ejemplo:

create table cliente (
  idcliente int auto_increment not null primary key,
  idpersona int unique,
  idjuridico int unique,
  ultima_compra date,
  estado varchar(45),
  constraint persona_fk foreign key (idpersona) references persona_natural(idpersona),
  constraint juridico_fk foreign key (idjuridico) references juridico(idjuridico)
);

De ser necesario, puedes definir un trigger para garantizar que solo puedes tener un valor sea en idpersona o idjuridico a la vez. Normalmente, esto se hace con un check constraint, pero no funcionan con MySQL.

Siendo que hay cierta complejidad en hacer una consulta a la tabla cliente teniendo que juntar de forma condicional con las demás tablas, vale la pena esconder esa complejidad dentro de una vista. Algo como esto:

create view vw_cliente as
select case when p.idpersona is not null then 'PERSONA' else 'JURIDICO' end as tipo_cliente,
       c.ultima_compra,
       c.estado,
       p.*,
       j.*
  from cliente c
  left join persona_natural p
    on p.idpersona = c.idpersona
  left join (select j.idjuridico,
                    j.razon_social,
                    j.ruc,
                    j.tipo_entidad,
                    j.correo_electronico,
                    p.numero as numero_representante_legal,
                    p.cedula as cedula_representante_legal,
                    p.direccion as direccion_representate_legal
               from juridico j
               join persona_natural p
                 on j.idrepresentante_legal = p.idpersona) j
    on j.idjuridico = c.idjuridico;

Otro punto, es que la tabla cuenta debería tener un campo idcliente en vez de cliente_idpersona (lo mismo para la tabla factura). Es mas, no creo que la tabla cuenta deba tener un campo tipo_cliente. Si acaso, tal vez lo puedes mover a la tabla cliente, y te puede servir como discriminador, pero no es estrictamente necesario, sobre todo si usas la vista que te propuse más arriba que ya incluye un discriminador.

Aquí te dejo un script de ensayo para demostrar cómo pudieras poner en práctica los puntos mencionados:

drop view if exists vw_cliente;
drop table if exists cliente;
drop table if exists juridico;
drop table if exists persona_natural;
drop procedure if exists cliente_check;

create table persona_natural (
  idpersona int auto_increment not null primary key,
  numero varchar(45),
  cedula int,
  direccion varchar(45)
);

create table juridico (
  idjuridico int auto_increment not null primary key,
  razon_social varchar(45),
  ruc varchar(45),
  tipo_entidad varchar(45),
  correo_electronico varchar(45),
  idrepresentante_legal int not null,
  constraint representate_legal_fk foreign key (idrepresentante_legal) references persona_natural(idpersona)
);

create table cliente (
  idcliente int auto_increment not null primary key,
  idpersona int unique,
  idjuridico int unique,
  ultima_compra date,
  estado varchar(45),
  constraint persona_fk foreign key (idpersona) references persona_natural(idpersona),
  constraint juridico_fk foreign key (idjuridico) references juridico(idjuridico)
);

delimiter $$
create procedure cliente_check(in idpersona int, in idjuridico int)
begin
  if (idpersona is null and idjuridico is null) or (idpersona is not null and idjuridico is not null) then
    signal sqlstate '45000' set message_text = 'Hay que asignar un valor sea a idpersona o idjuridico.';
  end if;
end
$$

create trigger cliente_insert_trigger
before insert on cliente
for each row
begin
  call cliente_check(new.idpersona, new.idjuridico);
end
$$

create trigger cliente_update_trigger
before update on cliente
for each row
begin
  call cliente_check(new.idpersona, new.idjuridico);
end
$$
delimiter ;

create view vw_cliente as
select case when p.idpersona is not null then 'PERSONA' else 'JURIDICO' end as tipo_cliente,
       c.ultima_compra,
       c.estado,
       p.*,
       j.*
  from cliente c
  left join persona_natural p
    on p.idpersona = c.idpersona
  left join (select j.idjuridico,
                    j.razon_social,
                    j.ruc,
                    j.tipo_entidad,
                    j.correo_electronico,
                    p.numero as numero_representante_legal,
                    p.cedula as cedula_representante_legal,
                    p.direccion as direccion_representate_legal
               from juridico j
               join persona_natural p
                 on j.idrepresentante_legal = p.idpersona) j
    on j.idjuridico = c.idjuridico;

-- Ejemplo de cliente que es una persona natural.
insert into persona_natural (numero, cedula, direccion) values ('11223344', 123456789, '100 Main St.');
insert into cliente (idpersona, ultima_compra, estado) values (last_insert_id(), '2016-11-01', 'ACTIVO');

-- Ejemplo de cliente que es una persona jurídica.
insert into persona_natural (numero, cedula, direccion) values ('55667788', 987654321, '200 Legal St.');
insert into juridico (razon_social, correo_electronico, idrepresentante_legal) values ('Microsoft', '[email protected]', last_insert_id());
insert into cliente (idjuridico, ultima_compra, estado) values (last_insert_id(), '2016-11-02', 'ACTIVO');

select * from vw_cliente;

drop view if exists vw_cliente;
drop table cliente;
drop table juridico;
drop table persona_natural;
drop procedure cliente_check;
Respondido por: Anonymous

Leave a Reply

Your email address will not be published. Required fields are marked *