chippyash/simple-accounts-3

View on GitHub
src/sql/mysql/build-procs.sql

Summary

Maintainability
Test Coverage
# Build script for simple accounts database - MySql Variant
# Copyright, 2018, Ashley Kitson, UK
# License: BSD-3-Clause, see License.md
DELIMITER //

DROP FUNCTION IF EXISTS sa_fu_add_chart//
CREATE DEFINER = CURRENT_USER FUNCTION
  sa_fu_add_chart(
  name VARCHAR(20)
)
  RETURNS INT(10) UNSIGNED
MODIFIES SQL DATA DETERMINISTIC
  BEGIN
    INSERT INTO sa_coa (`name`) VALUES (name);
    RETURN last_insert_id();
  END;
//

DROP PROCEDURE IF EXISTS sa_sp_add_ledger//
CREATE DEFINER = CURRENT_USER PROCEDURE
  sa_sp_add_ledger(
  chartInternalId INT(10) UNSIGNED,
  nominal         VARCHAR(10),
  type            VARCHAR(10),
  name            VARCHAR(30),
  prntNominal     VARCHAR(10)
)
MODIFIES SQL DATA DETERMINISTIC
  BEGIN
    DECLARE vPrntId INT(10) UNSIGNED;
    DECLARE cntPrnts INT;
    DECLARE rightChildId INT;
    DECLARE myLeft INT;
    DECLARE myRight INT;

    # check to see if we already have a root account
    IF (prntNominal = '')
    THEN
      SELECT count(id)
      FROM sa_coa_ledger l
      WHERE l.prntId = 0
            AND l.chartId = chartInternalId
      INTO cntPrnts;

      IF (cntPrnts > 0)
      THEN
        SIGNAL SQLSTATE '45000'
        SET MYSQL_ERRNO = 1859, MESSAGE_TEXT = _utf8'Chart already has root account';
      END IF;
    END IF;

    SET vPrntId := 0;
    # Find the parent ledger id if the nominal id is not empty
    # as id cannot be zero, return zero if not found
    IF (prntNominal != '')
    THEN
      SELECT IFNULL((SELECT id
                     from sa_coa_ledger l
                     WHERE l.nominal = prntNominal
                           AND l.chartId = chartInternalId), 0)
      INTO vPrntId;

      IF (vPrntId = 0)
      THEN
        SIGNAL SQLSTATE '45000'
        SET MYSQL_ERRNO = 1107, MESSAGE_TEXT = _utf8'Invalid parent account nominal';
      END IF;
    END IF;

    IF (vPrntId = 0)
    THEN
      # We are inserting the root node - easy case
      INSERT INTO sa_coa_ledger (`prntId`, `lft`, `rgt`, `chartId`, `nominal`, `type`, `name`)
      VALUES (0, 1, 2, chartInternalId, nominal, type, name);
    ELSE
      # Does the parent have any children?
      SELECT IFNULL((SELECT max(id)
                     FROM sa_coa_ledger
                     WHERE prntId = vPrntId), 0)
      INTO rightChildId;

      IF (rightChildId = 0)
      THEN
        # no children
        SELECT lft
        FROM sa_coa_ledger
        WHERE id = vPrntId
        INTO myLeft;

        UPDATE sa_coa_ledger
        SET rgt = rgt + 2
        WHERE rgt > myLeft;

        UPDATE sa_coa_ledger
        SET lft = lft + 2
        WHERE lft > myLeft;

        INSERT INTO sa_coa_ledger (`prntId`, `lft`, `rgt`, `chartId`, `nominal`, `type`, `name`)
        VALUES
          (vPrntId, myLeft + 1, myLeft + 2, chartInternalId, nominal, type, name);
      ELSE
        # has children, add to right of last child
        SELECT rgt
        FROM sa_coa_ledger
        WHERE id = rightChildId
        INTO myRight;

        UPDATE sa_coa_ledger
        SET rgt = rgt + 2
        WHERE rgt > myRight;

        UPDATE sa_coa_ledger
        SET lft = lft + 2
        WHERE lft > myRight;

        INSERT INTO sa_coa_ledger (`prntId`, `lft`, `rgt`, `chartId`, `nominal`, `type`, `name`)
        VALUES
          (vPrntId, myRight + 1, myRight + 2, chartInternalId, nominal, type, name);
      END IF;
    END IF;
  END;
//

DROP PROCEDURE IF EXISTS sa_sp_del_ledger//
CREATE DEFINER = CURRENT_USER PROCEDURE
  sa_sp_del_ledger(
  chartId INT(10) UNSIGNED,
  nominal VARCHAR(10)
)
MODIFIES SQL DATA DETERMINISTIC
  BEGIN
    DECLARE accId INT(10) UNSIGNED;
    DECLARE accDr INT(10) UNSIGNED;
    DECLARE accCr INT(10) UNSIGNED;
    SELECT
      id,
      acDr,
      acCr
    FROM sa_coa_ledger l
    WHERE l.nominal = nominal
          AND l.chartId = chartId
    INTO accId, accDr, accCr;

    IF (accDr > 0 OR accCr > 0)
    THEN
      SIGNAL SQLSTATE '45000'
      SET MYSQL_ERRNO = 2000, MESSAGE_TEXT = _utf8'Account balance is non zero';
    END IF;

    DELETE FROM sa_coa_ledger
    WHERE prntId = accId;

    DELETE FROM sa_coa_ledger
    WHERE id = accId;
  END;
//

DROP FUNCTION IF EXISTS sa_fu_add_txn//
CREATE DEFINER = CURRENT_USER FUNCTION
  sa_fu_add_txn(
  chartId    INT(10) UNSIGNED,
  note       TEXT,
  date       DATETIME,
  src        VARCHAR(6),
  ref        INT(10) UNSIGNED,
  arNominals TEXT,
  arAmounts  TEXT,
  arTxnType  TEXT
)
  RETURNS INT(10) UNSIGNED
MODIFIES SQL DATA DETERMINISTIC
  BEGIN
    DECLARE jrnId INT(10) UNSIGNED;
    DECLARE numInArray INT;

    SET date = IFNULL(date, CURRENT_TIMESTAMP);

    INSERT INTO sa_journal (`chartId`, `note`, `date`, `src`, `ref`)
    VALUES (chartId, note, date, src, ref);

    SELECT last_insert_id()
    INTO jrnId;

    SET numInArray =
    char_length(arNominals) - char_length(replace(arNominals, ',', '')) + 1;

    SET @x = numInArray;
    REPEAT
      SET @txnType = substring_index(substring_index(arTxnType, ',', @x), ',', -1);
      SET @nominal = substring_index(substring_index(arNominals, ',', @x), ',', -1);
      SET @drAmount = 0;
      SET @crAmount = 0;
      IF @txnType = 'dr'
      THEN
        SET @drAmount = substring_index(substring_index(arAmounts, ',', @x), ',',
                                        -1);
      ELSE
        SET @crAmount = substring_index(substring_index(arAmounts, ',', @x), ',',
                                        -1);
      END IF;

      INSERT INTO sa_journal_entry (`jrnId`, `nominal`, `acDr`, `acCr`)
        VALUE (jrnId, @nominal, @drAmount, @crAmount);
      SET @x = @x - 1;
    UNTIL @x = 0 END REPEAT;

    RETURN jrnId;
  END;
//

DROP PROCEDURE IF EXISTS sa_sp_get_tree//
CREATE DEFINER = CURRENT_USER PROCEDURE
  sa_sp_get_tree(
  chartId INT(10) UNSIGNED
)
READS SQL DATA
BEGIN
  SELECT
    prntId as origid,
    id as destid,
    nominal,
    name,
    type,
    acDr,
    acCr
  FROM sa_coa_ledger
  WHERE `chartId` = chartId
  ORDER BY origid, destid;
END;
//
DELIMITER ;