WPCubed GmbH
Wordprocessing and PDF components
As described in the previous topic SQLight is used as the database. Delphi XE7 Professional includes the FireDAC components which serve as interface to the database. Since the interface components do not allow the automatic creation of tables and fields from the FieldDefinitions a SQL CREATE script is used instead. This script will be executed when a new database is generated.
All the tables use one field with the name UID as primary index field. Relational tables use fields with the name “…_ID” to connect to the main table, i.e. “CUSTOMER_ID” in the ORDER table. I use an INTEGER PRIMARY KEY AUTOINCREMENT as primary index field which provides fast lookups with SQLLight. (There are no secondary indexes defined in the database yet, to optimize sorting performance they can be added anytime later).
This is an excerpt of the SQL script which creates the tables for the WPCubed Calculus Multi-Demo. As mentioned in the introduction, only the bare minimum of tables and fields for this tasks are used by the application to not obscure what is essential for the task:
CREATE TABLE "COUNTRIES" (
"UID" INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL,
"NAME" varchar(60),
"EU" INTEGER,
"VAT_RATE_REDUCED" REAL,
"VAT_RATE_REDUCED_LOW" REAL,
"VAT_RATE" REAL,
"CODE" varchar(6),
"DATE" DATE
);
CREATE TABLE "CUSTOMERS" (
"UID" INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL,
"NAME" varchar(100), // We only have a limited number of adress
"ADR1" varchar(100), // field in this demo application
"ADR2" varchar(100),
"CITY" varchar(100),
"STATE" varchar(100),
"EMAIL" varchar(100),
"COUNTRY_ID" INTEGER,
"VAT_ID" varchar(20), // this is the VAT tax number
"COMMENT" varchar(100),
"REBATE" REAL
);
CREATE TABLE "PRODUCTS" (
"UID" INTEGER PRIMARY KEY AUTOINCREMENT,
"NAME" varchar(100),
"DESCRIPTION" varchar(200),
"PRICE" REAL,
"VAT_SELECT" INTEGER // Select VAT, 0=normal, 1=reduced
);
CREATE TABLE "ORDERS" (
"UID" INTEGER PRIMARY KEY AUTOINCREMENT,
"ORDER_DATE" DATE,
"ORDER_DATE_YEAR" INTEGER,
"ORDER_DATE_MONTH" INTEGER,
"CUSTOMER_ID" INTEGER,
"COUNTRY_ID" INTEGER,
"VAT_ID" varchar(100),
"EUTRADE" INTEGER,
"REFERENCE" varchar(100),
"CUSTOMER_ADR" varchar(300),
"VAT_RATE" REAL,
"VAT_RATE_REDUCED" REAL,
"VAT_RATE_REDUCED_LOW" REAL,
"VOID" Integer
);
CREATE TABLE "ORDERITEM" (
"UID" INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL,
"ORDER_ID" INTEGER NOT NULL,
"CUSTOMER_ID" INTEGER NOT NULL,
"PRODUCT_ID" INTEGER NOT NULL,
"VAT_SELECT" INTEGER NOT NULL,
"COUNT" REAL,
"TEXT" varchar(100),
"UNIT_PRICE" REAL,
"REBATE_PERCENT" REAL,
"REBATE_ABSOLUT" REAL,
"PAYMENT_ID" INTEGER
);
These are the main component in the data module to set up the data connection:
As described in the introduction the demo was created to also integrate value added tax handling (VAT). To do so, I located the VAT rates (http://ec.europa.eu/taxation_customs/taxation/vat/how_vat_works/rates/index_en.htm) and created a constant record array to initialize the country table. Please use this table with care since the values may be outdated in the meantime.
type TEUCountry = record
name, en_name, code : String;
red1, red2, vat : Single;
end;
// VAT table of July 2014 - Source:
// http://ec.europa.eu/taxation_customs/taxation/vat/how_vat_works/rates/index_en.htm
// We did not copy the "parking rate" and the "super reduced rate"
const EUCountries : array[1..28] of TEUCountry
= ( (name:'Belgien'; en_name:'Belgium'; code:'BE'; red1:6; red2:12; vat:21),
(name:'Bulgarien'; en_name:'Bulgaria'; code:'BG'; red1:9; red2:9; vat:20),
(name:'Tschechische Republik'; en_name:'CzechRepublic'; code:'CZ'; red1:15; red2:15; vat:21),
(name:'D?nemark'; en_name:'Denmark'; code:'DK'; red1:25; red2:25; vat:25), // DK does not have a reduced rate!
(name:'Deutschland'; en_name:'Germany'; code:'DE'; red1:7; red2:7; vat:19),
(name:'Estland'; en_name:'Estonia'; code:'EE'; red1:9; red2:9; vat:20),
(name:'Griechenland'; en_name:'Greece'; code:'EL'; red1:6.5; red2:13; vat:23),
(name:'Spanien'; en_name:'Spain'; code:'ES'; red1:10; red2:10; vat:21),
(name:'Frankreich'; en_name:'France'; code:'FR'; red1:5.5; red2:10; vat:20),
(name:'Kroatien'; en_name:'Croatia'; code:'HR'; red1:5; red2:13; vat:25),
(name:'Irland'; en_name:'Ireland'; code:'IE'; red1:9; red2:13.5; vat:23),
(name:'Italien'; en_name:'Italy'; code:'IT'; red1:10; red2:10; vat:22),
(name:'Zypern'; en_name:'Cyprus'; code:'CY'; red1:5; red2:9; vat:19),
(name:'Lettland'; en_name:'Latvia'; code:'LV'; red1:12; red2:12; vat:21),
(name:'Litauen'; en_name:'Lithuania'; code:'LT'; red1:5; red2:9; vat:21),
(name:'Luxemburg'; en_name:'Luxembourg'; code:'LU'; red1:6; red2:12; vat:15),
(name:'Ungarn'; en_name:'Hungary'; code:'HU'; red1:5; red2:18; vat:27),
(name:'Malta'; en_name:'Malta'; code:'MT'; red1:5; red2:7; vat:18),
(name:'Niederlande'; en_name:'Netherlands'; code:'NL'; red1:6; red2:6; vat:21),
(name:'?sterreich'; en_name:'Austria'; code:'AT'; red1:10; red2:10; vat:20),
(name:'Polen'; en_name:'Poland'; code:'PL'; red1:5; red2:8; vat:23),
(name:'Portugal'; en_name:'Portugal'; code:'PT'; red1:6; red2:13; vat:23),
(name:'Rum?nien'; en_name:'Romania'; code:'RO'; red1:5; red2:9; vat:24),
(name:'Slowenien'; en_name:'Slovenia'; code:'SI'; red1:9.5; red2:9.5; vat:22),
(name:'Slowakei'; en_name:'Slovakia'; code:'SK'; red1:10; red2:10; vat:20),
(name:'Finnland'; en_name:'Finland'; code:'FI'; red1:10; red2:14; vat:24),
(name:'Schweden'; en_name:'Sweden'; code:'SE'; red1:6; red2:12; vat:25),
(name:'Vereinigtes K?nigreich'; en_name:'United Kingdom'; code:'UK'; red1:5; red2:5; vat:20) );
Adding the EU countries to the table is easy:
procedure TWPDataModule.AddEUCountries;
var i : Integer;
begin
for I := Low(EUCountries) to High(EUCountries) do
begin
tblCountry.Append;
tblCountryNAME.AsString := EUCountries.en_name;
tblCountryCODE.AsString := EUCountries.code;
tblCountryEU.AsInteger := 1;
tblCountryVAT_RATE_REDUCED.AsFloat := EUCountries.red2;
tblCountryVAT_RATE_REDUCED_LOW.AsFloat := EUCountries.red1;
tblCountryVAT_RATE.AsFloat := EUCountries.vat;
// This is the date the VAT value was valid ? according to
// the quoted document.
tblCountryDATE.AsDateTime := EncodeDate( 2014, 7, 1); tblCountry.Post;
end;
end;
A database is opened or created with this method:
procedure TWPDataModule.DataOpen(Filename : String);
var createnew : Boolean;
begin
createnew := not FileExists(Filename);
with dbMain do begin
Close;
// create temporary connection definition
with Params do begin
Clear;
Add('DriverID=SQLite');
Add('Database=' + FileName);
end;
Open;
if createnew then
begin
FDQuery1.ExecSQL;
end;
try
tblCountry.Open;
tblCustomers.Open;
tblCustomersLookup.Open;
tblOrderItems.Open;
tblOrders.Open;
tblProducts.Open;
// ? open other tables
except
Close;
createnew := false;
end;
if createnew then
begin
AddEUCountries;
AddSampleData;
end;
end;
end;
The Methods AddEUCountries fills the country table with the items of the VAT list above, AddSampleData adds some customer and product data so the program does not start completely empty.