2.2.4. Stored Procedures
Some parts of the business logic will be implemented by means of stored procedures.
Adding a new invoice
The procedure for adding a new invoice is quite simple:
SET TERM ^;
CREATE OR ALTER PROCEDURE SP_ADD_INVOICE (
INVOICE_ID INTEGER,
CUSTOMER_ID INTEGER,
INVOICE_DATE TIMESTAMP = CURRENT_TIMESTAMP)
AS
BEGIN
INSERT INTO INVOICE (
INVOICE_ID,
CUSTOMER_ID,
INVOICE_DATE,
TOTAL_SALE,
PAID
)
VALUES (
:INVOICE_ID,
:CUSTOMER_ID,
:INVOICE_DATE,
0,
0
);
END
^
SET TERM ;^
COMMENT ON PROCEDURE SP_ADD_INVOICE IS
'Adding Invoice';
COMMENT ON PARAMETER SP_ADD_INVOICE.INVOICE_ID IS
'Invoice number';
COMMENT ON PARAMETER SP_ADD_INVOICE.CUSTOMER_ID IS
'Customer Id';
COMMENT ON PARAMETER SP_ADD_INVOICE.INVOICE_DATE IS
'Date';
GRANT INSERT ON INVOICE TO PROCEDURE SP_ADD_INVOICE;
Editing an invoice
The procedure for editing an invoice is a bit more complicated. We will include a rule to block further editing of an invoice once it is paid. We will create an exception that will be raised if an attempt is made to modify a paid invoice.
CREATE EXCEPTION E_INVOICE_ALREADY_PAYED 'Change is impossible, invoice paid.';
-- The stored procedure for editing an invoice:
SET TERM ^;
CREATE OR ALTER PROCEDURE SP_EDIT_INVOICE (
INVOICE_ID INTEGER,
CUSTOMER_ID INTEGER,
INVOICE_DATE TIMESTAMP)
AS
BEGIN
IF (EXISTS(SELECT *
FROM INVOICE
WHERE INVOICE_ID = :INVOICE_ID
AND PAID = 1)) THEN
EXCEPTION E_INVOICE_ALREADY_PAYED;
UPDATE INVOICE
SET CUSTOMER_ID = :CUSTOMER_ID,
INVOICE_DATE = :INVOICE_DATE
WHERE INVOICE_ID = :INVOICE_ID;
END
^
SET TERM ;^
COMMENT ON PROCEDURE SP_EDIT_INVOICE IS
'Editing invoice';
COMMENT ON PARAMETER SP_EDIT_INVOICE.INVOICE_ID IS
'Invoice number';
COMMENT ON PARAMETER SP_EDIT_INVOICE.CUSTOMER_ID IS
'Customer Id';
COMMENT ON PARAMETER SP_EDIT_INVOICE.INVOICE_DATE IS
'Date';
GRANT SELECT,UPDATE ON INVOICE TO PROCEDURE SP_EDIT_INVOICE;
In Firebird 3.0, the
|
Deleting an invoice
The procedure SP_DELETE_INVOICE
procedure checks whether the invoice is paid and raises an exception if it is:
SET TERM ^ ;
CREATE OR ALTER PROCEDURE SP_DELETE_INVOICE (
INVOICE_ID INTEGER)
AS
BEGIN
IF (EXISTS(SELECT * FROM INVOICE
WHERE INVOICE_ID = :INVOICE_ID
AND PAID = 1)) THEN
EXCEPTION E_INVOICE_ALREADY_PAYED;
DELETE FROM INVOICE WHERE INVOICE_ID = :INVOICE_ID;
END
^
SET TERM ;^
COMMENT ON PROCEDURE SP_DELETE_INVOICE IS
'Deleting invoices';
GRANT SELECT,DELETE ON INVOICE TO PROCEDURE SP_DELETE_INVOICE;
In Firebird 3.0, the
|
Paying an invoice
We will add one more procedure for paying an invoice:
SET TERM ^;
CREATE OR ALTER PROCEDURE SP_PAY_FOR_INVOICE (
INVOICE_ID INTEGER)
AS
BEGIN
IF (EXISTS(SELECT *
FROM INVOICE
WHERE INVOICE_ID = :INVOICE_ID
AND PAID = 1)) THEN
EXCEPTION E_INVOICE_ALREADY_PAYED;
UPDATE INVOICE
SET PAID = 1
WHERE INVOICE_ID = :INVOICE_ID;
END
^
SET TERM ;^
COMMENT ON PROCEDURE SP_PAY_FOR_INVOICE IS
'Payment of invoices';
COMMENT ON PARAMETER SP_PAY_FOR_INVOICE.INVOICE_ID IS
'Invoice number';
GRANT SELECT,UPDATE ON INVOICE TO PROCEDURE SP_PAY_FOR_INVOICE;
In Firebird 3.0, the
|
Invoice Line Items
Procedures for managing invoice items will check whether the invoice is paid and block any attempt to alter the line items of paid invoices. They will also correct the invoice total according to the amount of the product sold and its price.
Adding line items
The procedure for adding a line item to an invoice:
SET TERM ^;
CREATE OR ALTER PROCEDURE SP_ADD_INVOICE_LINE (
INVOICE_ID INTEGER,
PRODUCT_ID INTEGER,
QUANTITY INTEGER)
AS
DECLARE sale_price D_MONEY;
DECLARE paid D_BOOLEAN;
BEGIN
SELECT
paid
FROM
invoice
WHERE
invoice_id = :invoice_id
INTO :paid;
-- It does not allow you to edit already paid invoice.
IF (paid = 1) THEN
EXCEPTION E_INVOICE_ALREADY_PAYED;
SELECT
price
FROM
product
WHERE
product_id = :product_id
INTO :sale_price;
INSERT INTO invoice_line (
invoice_line_id,
invoice_id,
product_id,
quantity,
sale_price)
VALUES (
NEXT VALUE FOR gen_invoice_line_id,
:invoice_id,
:product_id,
:quantity,
:sale_price);
-- Increase the amount of the account.
UPDATE invoice
SET total_sale = COALESCE(total_sale, 0) + :sale_price * :quantity
WHERE invoice_id = :invoice_id;
END
^
SET TERM ;^
COMMENT ON PROCEDURE SP_ADD_INVOICE_LINE IS
'Adding line invoices';
COMMENT ON PARAMETER SP_ADD_INVOICE_LINE.INVOICE_ID IS
'Invoice number';
COMMENT ON PARAMETER SP_ADD_INVOICE_LINE.PRODUCT_ID IS
'Product Id';
COMMENT ON PARAMETER SP_ADD_INVOICE_LINE.QUANTITY IS
'Quantity';
GRANT SELECT, UPDATE ON INVOICE TO PROCEDURE SP_ADD_INVOICE_LINE;
GRANT SELECT ON PRODUCT TO PROCEDURE SP_ADD_INVOICE_LINE;
GRANT INSERT ON INVOICE_LINE TO PROCEDURE SP_ADD_INVOICE_LINE;
-- only Firebird 3.0 and above
GRANT USAGE ON EXCEPTION E_INVOICE_ALREADY_PAYED TO PROCEDURE SP_ADD_INVOICE_LINE;
GRANT USAGE ON SEQUENCE GEN_INVOICE_LINE_ID TO PROCEDURE SP_ADD_INVOICE_LINE;
Editing line items
The procedure for editing an invoice line item:
SET TERM ^;
CREATE OR ALTER PROCEDURE SP_EDIT_INVOICE_LINE (
INVOICE_LINE_ID INTEGER,
QUANTITY INTEGER)
AS
DECLARE invoice_id INT;
DECLARE price D_MONEY;
DECLARE paid D_BOOLEAN;
BEGIN
SELECT
product.price,
invoice.invoice_id,
invoice.paid
FROM
invoice_line
JOIN invoice ON invoice.invoice_id = invoice_line.invoice_id
JOIN product ON product.product_id = invoice_line.product_id
WHERE
invoice_line.invoice_line_id = :invoice_line_id
INTO
:price,
:invoice_id,
:paid;
-- It does not allow you to edit an already paid invoice.
IF (paid = 1) THEN
EXCEPTION E_INVOICE_ALREADY_PAYED;
-- Update price and quantity.
UPDATE invoice_line
SET sale_price = :price,
quantity = :quantity
WHERE invoice_line_id = :invoice_line_id;
-- Now update the amount of the account.
MERGE INTO invoice
USING (
SELECT
invoice_id,
SUM(sale_price * quantity) AS total_sale
FROM invoice_line
WHERE invoice_id = :invoice_id
GROUP BY invoice_id) L
ON invoice.invoice_id = L.invoice_id
WHEN MATCHED THEN
UPDATE SET total_sale = L.total_sale;
END
^
SET TERM ;^
COMMENT ON PROCEDURE SP_EDIT_INVOICE_LINE IS
'Editing invoice line';
COMMENT ON PARAMETER SP_EDIT_INVOICE_LINE.INVOICE_LINE_ID IS
'Invoice line id';
COMMENT ON PARAMETER SP_EDIT_INVOICE_LINE.QUANTITY IS
'Quantity';
GRANT SELECT,UPDATE ON INVOICE_LINE TO PROCEDURE SP_EDIT_INVOICE_LINE;
GRANT SELECT,UPDATE ON INVOICE TO PROCEDURE SP_EDIT_INVOICE_LINE;
GRANT SELECT ON PRODUCT TO PROCEDURE SP_EDIT_INVOICE_LINE;
-- only Firebird 3.0 and above
GRANT USAGE ON EXCEPTION E_INVOICE_ALREADY_PAYED TO PROCEDURE SP_EDIT_INVOICE_LINE;
Deleting line items
The procedure for deleting an invoice line item from an invoice:
SET TERM ^;
CREATE OR ALTER PROCEDURE SP_DELETE_INVOICE_LINE (
INVOICE_LINE_ID INTEGER)
AS
DECLARE invoice_id INT;
DECLARE price D_MONEY;
DECLARE quantity INT;
BEGIN
IF (EXISTS(SELECT *
FROM invoice_line
JOIN invoice ON invoice.invoice_id = invoice_line.invoice_id
WHERE invoice.paid = 1
AND invoice_line.invoice_line_id = :invoice_line_id)) THEN
EXCEPTION E_INVOICE_ALREADY_PAYED;
DELETE FROM invoice_line
WHERE invoice_line.invoice_line_id = :invoice_line_id
RETURNING invoice_id, quantity, sale_price
INTO invoice_id, quantity, price;
-- Reduce the amount of the account.
UPDATE invoice
SET total_sale = total_sale - :quantity * :price
WHERE invoice_id = :invoice_id;
END
^
SET TERM ;^
COMMENT ON PROCEDURE SP_DELETE_INVOICE_LINE IS
'Deleting invoice item';
COMMENT ON PARAMETER SP_DELETE_INVOICE_LINE.INVOICE_LINE_ID IS
'Code invoice item';
Privileges for Procedures
GRANT SELECT,DELETE ON INVOICE_LINE TO PROCEDURE SP_DELETE_INVOICE_LINE;
GRANT SELECT,UPDATE ON INVOICE TO PROCEDURE SP_DELETE_INVOICE_LINE;
-- only Firebird 3.0 and above
GRANT USAGE ON EXCEPTION E_INVOICE_ALREADY_PAYED TO PROCEDURE SP_DELETE_INVOICE_LINE;