create or replace view betriebskosten_anteil_mieter as
    select (b.betrag / o.flaeche * w.flaeche) as anteil,
            o.id as objekt,
            w.id as wohnung,
            m.id as mieter,
            b.id as abrechnung,
            (timestampdiff(month,
                          if (year(m.einzug) = b.jahr, m.einzug, makedate(b.jahr, 1)),
                          if  (m.auszug is not null, m.auszug, last_day(makedate(b.jahr, 365)))
                          ) + 1) as nutzungszeit,
            b. jahr as jahr
      from betriebskosten_abrechnung b,
            objekt o,
            wohnung w,
            mieter m
      where b.objekt = o.id and
            w.objekt = o.id and
            m.wohnung = w.id and
            (year(m.einzug) = b.jahr or year(m.auszug) = b.jahr);

create table jahresabrechnung_summary (
  id integer unsigned not null auto_increment,
  abrechnung integer unsigned not null,
  mieter integer unsigned not null,
  nutzungszeit integer not null,
  anteil_pro_flaeche decimal(20, 10) not null,
  anteil_pro_flaeche_nutzungszeit decimal(20, 10) not null,
  vorauszahlung decimal(20, 2) not null,
  nachzahlung decimal(20, 2) not null,
  summe_zahlungen decimal(20, 2) not null,
  summe_zahlungen_anteil_miete decimal(20, 2) not null,
  constraint primary key(id),
  constraint unique key uk_jahresabrechnung_summary_mieter_abrechnung (abrechnung, mieter),
  constraint foreign key fk_jahresabrechnung_summary_betriebskosten_abrechnung (abrechnung)
    references betriebskosten_abrechnung(id)
    on delete restrict
    on update cascade,
  constraint foreign key fk_jahresabrechnung_summary_mieter (mieter)
    references mieter(id)
    on delete restrict
    on update cascade
) engine=InnoDB;

delimiter //

create or replace procedure jahresabrechnung(in p_year year)
modifies sql data
begin
    declare v_anteil_mieter_nutzungszeit decimal(20, 10);
    declare v_summe_zahlungen decimal(20, 10);
    declare v_summe_mietforderungen decimal(20, 10);
    declare v_summe_betriebskosten_zahlungen decimal(20, 10);
    declare v_betriebskosten_nachzahlung decimal(20, 10);
    declare v_error_message varchar(128);
    declare c_anteil_mieter 
        cursor (cp_year year) for
          select anteil, objekt, wohnung, mieter, abrechnung, 
                 nutzungszeit, jahr
          from betriebskosten_anteil_mieter
          where jahr = cp_year;

    for rec in c_anteil_mieter(p_year) do
        set v_anteil_mieter_nutzungszeit = rec.anteil / 12 * rec.nutzungszeit;

        select sum(betrag) into v_summe_zahlungen
          from zahlung
          where mieter = rec.mieter and
                year(datum_soll) = p_year;
        if (v_summe_zahlungen is null) then
            set v_error_message = concat('No Zahlungen for Mieter ', rec.mieter);
            signal sqlstate '45000' set message_text = v_error_message;
        end if;

        select sum(anteil_miete) into v_summe_mietforderungen
          from forderung
          where mieter = rec.mieter and
                year(datum) = p_year;

        set v_summe_betriebskosten_zahlungen = v_summe_zahlungen - v_summe_mietforderungen;
        set v_betriebskosten_nachzahlung = v_anteil_mieter_nutzungszeit - v_summe_betriebskosten_zahlungen;

        insert into jahresabrechnung_summary (abrechnung, mieter, nutzungszeit, anteil_pro_flaeche,
                                              anteil_pro_flaeche_nutzungszeit, vorauszahlung,
                                              nachzahlung, summe_zahlungen, summe_zahlungen_anteil_miete)
          values(rec.abrechnung, rec.mieter, rec.nutzungszeit, rec.anteil,
                 v_anteil_mieter_nutzungszeit, v_summe_betriebskosten_zahlungen,
                 v_betriebskosten_nachzahlung, v_summe_zahlungen, v_summe_mietforderungen);
    end for;
end;
//

delimiter ;

alter table objekt modify column flaeche decimal(20, 2) not null;
alter table wohnung modify column flaeche decimal(20, 2) not null;
alter table betriebskosten_abrechnung modify column betrag decimal(20, 2) not null;

create or replace view jahresabrechnung_flat_v as
  select o.shortname as objekt,
         o.flaeche as gesamt_flaeche,
         w.shortname as wohnung,
         w.flaeche as flaeche,
         m.anrede as anrede,
         m.vorname as vorname,
         m.nachname as nachname,
         m.strasse as strasse,
         m.plz as plz,
         m.ort as ort,
         j.nutzungszeit as nutzungszeit,
         j.anteil_pro_flaeche as anteil_pro_flaeche,
         j.anteil_pro_flaeche_nutzungszeit as anteil_pro_flaeche_nutzungszeit,
         j.summe_zahlungen as summe_zahlungen,
         j.summe_zahlungen_anteil_miete as summe_zahlungen_anteil_miete,
         j.vorauszahlung as vorauszahlung,
         j.nachzahlung as nachzahlung,
         b.jahr as jahr,
         b.betrag as gesamt_betriebskosten
    from objekt o,
         wohnung w,
         mieter m,
         jahresabrechnung_summary j,
         betriebskosten_abrechnung b
    where j.abrechnung = b.id and
          j.mieter = m.id and
          m.wohnung = w.id and
          w.objekt = o.id;

create or replace view rueckzahlungen_v as
    select concat(m.vorname, ' ', m.nachname) as mieter,
        format_iban(m.iban) as iban,
        j.nachzahlung as nachzahlung,
        b.jahr as jahr
    from mieter m,
        jahresabrechnung_summary j,
        betriebskosten_abrechnung b
    where j.abrechnung = b.id and
        j.mieter = m.id and
        j.nachzahlung < 0;

create or replace view nachzahlungen_v as
    select concat(m.vorname, ' ', m.nachname) as mieter,
        j.nachzahlung as nachzahlung,
        b.jahr as jahr
    from mieter m,
        jahresabrechnung_summary j,
        betriebskosten_abrechnung b
    where j.abrechnung = b.id and
        j.mieter = m.id and
        j.nachzahlung > 0;        