Разработка микро-учётной системы на lua, часть вторая. Постановка задачи
Теперь немного о самой задумке. Предполагается, что программа будет соответствовать следующим условиям:
- Максимально возможная переносимость,
- Быстрый унифицированный интерфейс,
- Возможность максимально быстрого изменения данных,
- Отсутствие необходимости в фиксации времени модификации документа,
- Необходимость в отслеживании баланса по клиентам (сальдо).
Программа должна определённым образом управлять информацией. На входе ей должны предоставляться:
- Данные о клиенте: имя / наименование и связаные телефоны, причём телефонов может быть больше двух;
- Данные о позиции: наименование и стоимость. Данный тип используется для фиксаций операций и затрат — то есть, позиция может иметь как отрицательную, так и положительную стоимость (выплаты заказчика + затраты на оборудование / дорогу / операции и прочие радости);
- Данные для формирования документа, собраные из предыдущих;
На выходе пользователь должен получать следующую структуру:
- Каталог пользовательских данных,
- Каталог телефонов с привязкой к пользователям,
- Каталог позиций с возможностью редактирования,
- Каталог документов с возможностью изменения клиентских выплат.
Теперь договоримся о терминологии.
Клиент — юридическое или физическое лицо, которому услуга предоставляется. В программе клиента представляют его имя / наименование и телефон. Мне больше и не надо.
Позиция — описание графы прихода / затрат денежных средств, имеющих свою стоимость. Стоимость может быть как положительная (выплата от заказчика, оплата расходов и прочее), так и отрицательная (оплата заказа / расходов, не- или недовыплаты по оказаным услугам и так далее). Состоит из наименования и фактической стоимости.
Документ — учётная структура, хранящая данные о стоимости позиции и фактическом покрытии клиентом затрат на неё.
Сальдо — фактическая разница между объёмом оказанных клиенту услуг и выплаченного денежного эквивалента. В программе будет использоваться как общее сальдо, так и отдельное на каждого клиента.
Программа создавалась при следующих условиях:
- Отсутствие в необходимости делегирования пользовательского доступа для обработки информации;
- Интерфейс должен быть быстрым, потому наибольший интерес представляют различные виды текстового интерфейса;
- Ради возможности максимального переноса кода (например, на Win-машину с установленным комплектом «Lua for Windows») сам код был максимально упрощён, как и среда разработки. Это означает минимальное время развёртки программы в другой среде и меньшее количество правок при использовании утилиты luac.
- Отработка минимально необходимого количества функций позволила упростить до крайней степени схему базы и алгоритмы её обслуживания;
- И да, я не делал отработку ошибок при выполнении запросов — я постарался их максимально исключить. Да, я дилетант в Lua, но мне сейчас больше и не нужно. Качество кода приходит со временем.
Теперь о структуре программы:
- Программа состоит из модулей: главного, множества исполнительных и модуля доступа к базе. Взаимодействие происходит в режиме конвейера;
- Главный модуль не имеет доступ к модулю управления базой, но имеет экземпляры исполнительных. Исполнительные модули уже имеют доступ к экземпляру модуля доступа.
- Программа после выполнения команды возвращается в главное меню.
Взаимодействие модулей программы, источника данных и человека выглядит так:
Схема пользовательских прецедентов (use case) выглядит так:
Пользовательские сценарии делятся на следующие категории:
- Управление пользовательскими данными, которая в свою очередь делится на функции управления телефонным справочником и списком клиентов;
- Управление позициями — функции создания, модификации, просмотра и удаления;
- Управление документацией;
- Рассчёт баланса по документам: общий и для отдельного пользователя.
База данных представляет собой набор таблиц, связанных с помощью первичных автоинкрементных ключей. Дополнительно используется отображение при выдаче общей информации (хотя это спорное решение):
Передача данных происходит через прослойку модуля database, являющегося модулем доступа. Исполнительные формы создают запросы, которые в него и посылают. Все данные исполнительные модули разбирают самостоятельно. По факту, database является контейнером для экземпляра класса «luasql-sqlite3», соединённого с базой.
Маленькая деталь. Базу пришлось создавать через программу sqliteman, поскольку инициализация таблицы с первичным ключём автовычисляемого типа (autoincrement) при ручном формировании запроса не работает. Но, на всякий случай, я сформировал дамп базы для последующей развёртки:
PRAGMA foreign_keys=OFF;
BEGIN TRANSACTION;
CREATE TABLE "feedback" (
"number" INTEGER PRIMARY KEY AUTOINCREMENT,
"customer" TEXT,
"phone" INTEGER
);
CREATE TABLE "customer" (
"number" INTEGER PRIMARY KEY AUTOINCREMENT,
"name" TEXT
);
CREATE TABLE "position" (
"number" INTEGER PRIMARY KEY AUTOINCREMENT,
"nominal" TEXT,
"price" REAL
);
CREATE TABLE "document" (
"number" INTEGER PRIMARY KEY AUTOINCREMENT,
"customer" INTEGER,
"position" INTEGER,
"income" REAL
);
DELETE FROM sqlite_sequence;
INSERT INTO "sqlite_sequence" VALUES('customer',8);
INSERT INTO "sqlite_sequence" VALUES('feedback',10);
INSERT INTO "sqlite_sequence" VALUES('position',2);
INSERT INTO "sqlite_sequence" VALUES('document',6);
CREATE VIEW "journal" AS select document.number, customer.name, position.nominal, document.income, position.price
from document, customer, position
where document.customer = customer.number
and document.position = position.number;
COMMIT;
И на сладкое — скриншот работы приложения:
И да, это быстрый текстовый интерфейс! Зато не замучаюсь с переносом программы (с GTK — зависимым интерфейсом) на другую машину!
В следующих статьях буду отдельно рассказывать про работу отдельных модулей программы и выкладывать их исходные коды.