CREATE SCHEMA Magasin;
SET search_path TO Magasin, public;
CREATE TABLE Magasin.Caisses (
  NumeroCaisse integer NOT NULL CHECK(NumeroCaisse > 0), 
  Caissiere text NOT NULL, 
  DateHeureDebut timestamp NOT NULL, -- timestamp = jour + heure
  DateHeureFin timestamp NOT NULL, 
  SommeDebut integer NOT NULL CHECK(SommeDebut > 0), 
  SommeFin integer NOT NULL, 
  PRIMARY KEY (NumeroCaisse, DateHeureDebut, DateHeureFin)
);
CREATE TABLE Magasin.Factures (
  NumeroFacture integer NOT NULL CHECK(NumeroFacture > 0),
  NumeroCaisse integer NOT NULL,
  DateHeure timestamp NOT NULL,
  Paiement text NOT NULL,
  PRIMARY KEY (NumeroFacture),
  CONSTRAINT TypePaiement
    CHECK(Paiement='Espece' OR Paiement='CB' OR Paiement='Cheque')
);
CREATE TABLE Magasin.Lignesfacture (
  NumeroFacture integer NOT NULL REFERENCES Magasin.Factures(NumeroFacture),
  Article text NOT NULL,
  PrixUnitaire integer NOT NULL CHECK(PrixUnitaire > 0),
  Quantite integer NOT NULL CHECK(Quantite > 0),
  PRIMARY KEY (NumeroFacture, Article)
);
ALTER TABLE Magasin.Caisses ADD CONSTRAINT bilan
  CHECK(SommeFin >= SommeDebut);
ALTER TABLE Magasin.Caisses ADD CONSTRAINT creneau 
  CHECK(DateHeureDebut < DateHeureFin AND DateHeureFin - DateHeureDebut <= '2h');
-- PostgreSQL n'accepte pas les contraintes d'integrite avec un SELECT
-- Il faut definir une fonction
CREATE FUNCTION Magasin.DateHeureCorrecte(integer, timestamp) 
  RETURNS boolean AS $$ 
SELECT EXISTS (
  SELECT * 
  FROM Magasin.Caisses
  WHERE $1 = NumeroCaisse 
    AND $2 >= DateHeureDebut 
    AND $2 <= DateHeureFin)
$$ LANGUAGE SQL;
-- puis appeler la fonction dans une contrainte d'integrite
ALTER TABLE Magasin.Factures ADD CONSTRAINT DateHeurePossible
  CHECK(Magasin.DateHeureCorrecte(NumeroCaisse, DateHeure) = TRUE);
-- PostgreSQL n'accepte pas les contraintes d'integrite avec un SELECT
-- Il faut definir une fonction
CREATE FUNCTION Magasin.CreneauCorrect(integer, timestamp, timestamp) 
  RETURNS boolean AS $$
SELECT NOT EXISTS (
  SELECT *
  FROM Magasin.Caisses
  WHERE $1 = NumeroCaisse
     AND ((($2 >= DateHeureDebut) AND ($2 <= DateHeureFin)) OR
          (($3 >= DateHeureDebut) AND ($3 <= DateHeureFin))))
$$ LANGUAGE SQL;
-- puis appeler la fonction dans une contrainte d'integrite
ALTER TABLE Magasin.Caisses ADD CONSTRAINT CreneauPossible
  CHECK(Magasin.CreneauCorrect(NumeroCaisse, DateHeureDebut, DateHeureFin) = TRUE);
