cr_func_konto.sql 8.82 KB
-- allgemeine Funktionen zu Konten --
-- [
create function konto_typ_min_len()
    returns int4 as '
        DECLARE
            len int4;
        BEGIN
            select INTO len bit_length(mask) from fibu.konten_typen;

            IF NOT FOUND THEN
                len := 0;
            END IF;

            RETURN len;
        END;
    ' language 'plpgsql';

create function konto_typ(text, int4)
    returns bit varying as '
        /* 
         * konto_typ(name, output_len)
         *
         * ermittelt den konto_typ zu einem entsprechenden namen.
         *
         * dies existierem hauptsaechlich zur besseren lesbar machung von
         * querys bezueglich konten, folgende query ist verstaendlicher,
         * wenn auch etwas laenger:
         *  select * from konto where 
         *        konto_typ=konto_typ(''AKTIVA'');
         * als:
         *  select * from konto where 
         *        konto_typ=1;
         * bei der ersten query sieht man intuitiv das nach allen aktiva-konten
         * gesucht wird, waerend das aus der zweiten nur hervorgeht wenn man
         * alle Kontentypen im Kopf hat.
         *
         * returns: NULL: falls der name nicht in konten_typen existiert
         *          >0: der konten_typ zu dem namen
         */

        DECLARE
            row fibu.konten_typen%ROWTYPE;
            min_len int4 := fibu.konto_typ_min_len();
            sel text;
        BEGIN
            IF $2 < min_len THEN
                RAISE EXCEPTION ''len is to short'';
            END IF;

            sel := ''select mask::BIT('' || $2 || '')>>'' || 
                   $2-min_len ||
                   '' from fibu.konten_typen where name='' || 
                   quote_literal($1);

            FOR row IN EXECUTE sel LOOP
            END LOOP;

            IF NOT FOUND THEN
                RETURN NULL;
            ELSE
                RETURN row.mask;
            END IF;
        END;
    ' language 'plpgsql';

create function "inc_konto_ref_count" (int4)
    returns int4 as '
        /* 
         * inc_konto_ref_count(kto_nr)
         *
         * erhoet das Feld used in used_konten um 1, damit wird signalisiert,
         * das einmal mehr auf dieses Konto referenziert wird.
         *
         * returns: -1: Konto passt nicht in aktuellen kontenplan
         *          0: Konto noch nicht in Konten, daher kein increment
         *          >0: Anzahl der Referenzen nach der erhoehung.
         */

        DECLARE
            ref_count fibu.used_konten.used%TYPE;
            konto fibu.konto%ROWTYPE;
        BEGIN
            select INTO ref_count used from fibu.used_konten where kto_nr=$1;
            IF NOT FOUND THEN
                return -1;
            END IF;

            select INTO konto * from fibu.konto where kto_nr=$1;
            IF NOT FOUND THEN
                return 0;
            END IF;

            ref_count := ref_count + 1;
            update fibu.used_konten set used=ref_count where kto_nr=$1;

            RETURN ref_count;
        END;
    ' language 'plpgsql';

create function "dec_konto_ref_count" (int4)
    returns int4 as '
        /* 
         * dec_konto_ref_count(kto_nr)
         *
         * verringert das Feld used in used_konten um 1, damit wird 
         * signalisiert, das einmal mehr auf dieses Konto referenziert wird.
         * Es existiert ein trigger, der Konto loescht, wenn keine Referenz
         * mehr darauf besteht, das koennte zu problemen fuehren, da Konten
         * fuer die Buchfuehrung auch erhalten bleiben muessen, wenn die
         * Kunden keinerlei Umsatz mehr produzieren, allerdings sollten dann
         * auch die Kundeninformationen bestehen bleiben wodurch auch die
         * Referenz bleibt.
         *
         * returns: -1: Konto passt nicht in aktuellen kontenplan
         *          0: entweder wurde used gerade auf 0 gesetzt, oder es
         *             war bereits 0.
         *          >0: Anzahl der Referenzen nach der verringerung.
         */

        DECLARE
            ref_count fibu.used_konten.used%TYPE;
            konto fibu.konto%ROWTYPE;
        BEGIN
            select INTO ref_count used from fibu.used_konten where kto_nr=$1;
            IF NOT FOUND THEN
                RETURN -1;
            END IF;

            IF ref_count = 0 THEN
                RETURN 0;
            ELSE
                ref_count := ref_count - 1;
                update fibu.used_konten set used=ref_count where kto_nr=$1;
            END IF;

            RETURN ref_count;
        END;
    ' language 'plpgsql';

create function "chk_konto" (int4,text,bit varying,varchar(8),text, text)
    returns int4 as '
        /* 
         * chk_konto(kto_nr, name, konto_typ, blz, b_kto_nr, b_name)
         *
         * ueberpruefen ob das Konto schon in der DB gespeichert ist und
         * ob es in dem sinne gueltig ist, das in den existierenden
         * kontenplan passt.
         *
         * returns: -1: falsche Parameter
         *          -2: Inkonsistenz endeckt. Es existiert bereits ein
         *              Konto mit dem der Schluessel, aber nicht alle der 
         *              Parameter übereinstimmen
         *          -3: Inkonsistenz, Konto passt nicht in den Kontenplan
         *          0: Konto existiert noch nicht in der DB
         *          >0: Konto existiert bereits, gibt id_person zurück.
         */

        DECLARE
            idk fibu.konto%ROWTYPE;
            kot fibu.konto.konto_typ%TYPE;
        BEGIN
            IF $1 IS NULL OR $1 < 0 THEN
                RETURN -1;
            END IF;

            select INTO kot konto_typ from fibu.used_konten where kto_nr = $1;
            IF NOT FOUND OR kot != $3 THEN
                RETURN -3;
            END IF;

            select INTO idk * from fibu.konto where
                kto_nr = $1;

            IF NOT FOUND THEN
                RETURN 0;
            ELSE
                IF idk.name <> $2 OR idk.konto_typ <> $3 OR
                   idk.blz <> $4 OR idk.b_kto_nr <> $5 OR
                   idk.b_name <> $5 THEN
                    RETURN -2;
                END IF;
            END IF;

            RETURN idk.kto_nr;
        END;
    ' language 'plpgsql';

create function ins_konto(int4,text,bit varying,varchar(8),text,text)
    returns int4 as '
        /* 
         * ins_konto(kto_nr, name, konto_typ, blz, b_kto_nr, b_name)
         *
         * fügt eine Konto in die DB ein sofern es nicht schon existiert,
         * inkonsistenzen erzeugt wuerden, oder die Eingabedaten fehlerhast
         * sind.
         * Es muss nur konto_typ angegeben werden, alle anderen Werte koennen
         * NULL sein.
         * Ist kto_nr NULL, dann ermittelt die Funktion einen freie Kontonummer
         * aus dem zu konto_typ gehoerenden Nummernbereich. Dann wird das Konto
         * angelegt.
         * Ist sie nicht NULL so wird geprueft ob die zu dem konto_typ gehoert,
         * wenn das so ist, dann wird chk_konto aufgerufen um zu pruefen
         * ob das Konto bereits existiert, ist das nicht der Fall dann wird
         * es angelegt, wenn ein Konto existiert, das nicht zu den gemachten
         * Angeben passt, dann wird eine Fehlermeldung zurueckgegeben.
         * ACHTUNG: Hier wird natuerlich noch nicht inc_ref_count_erhoeht,
         *          da noch keine referenz auf das konto existiert.
         *          Das heißt, wenn ein naechster update auf used_konten
         *          nicht den ref_count (used) auf mindestens eins setzt
         *          wird das Konto wieder unmittelbar geloescht.
         *
         * returns: 0: wenn die Person nicht eingefuegt werden kann
         *          >0: wenn die Person eingefuegt werden konnte oder bereits
         *              existierte, gibt id_person zurück.
         */

        DECLARE
            ktn fibu.konto.kto_nr%TYPE;
            row fibu.used_konten%ROWTYPE;
        BEGIN
            IF $1 IS NOT NULL THEN
                select INTO ktn fibu.chk_konto($1,$2,$3,$4,$5,$6);

                IF ktn < 0 THEN
                    RETURN 0;
                END IF;
            ELSE
                ktn := 0;

                PERFORM * from fibu.konten_typen where mask=$3;
                IF NOT FOUND THEN
                    RETURN 0;
                END IF;
            END IF;

            IF ktn = 0 THEN
                IF $1 IS NULL THEN
                    select INTO row * from fibu.used_konten where 
                        konto_typ=$3 and used=0;

                    IF NOT FOUND THEN
                        RETURN 0;
                    ELSE
                        ktn := row.kto_nr;
                    END IF;
                ELSE
                    ktn := $1;
                END IF;

                insert into fibu.konto 
                    (kto_nr,name,konto_typ,blz,b_kto_nr,b_name) values 
                    (ktn,$2,$3,$4,$5,$6);
            END IF;

            RETURN ktn;
        END;
    ' language 'plpgsql';
-- ]
-- Ende allgemeine Funktionen --