Payments and earns now store their receipts.
The database tables are now created on startup
This commit is contained in:
parent
c81bddf79a
commit
0d6a22fb8b
@ -24,7 +24,9 @@ set(HEADERS
|
|||||||
src/database.h
|
src/database.h
|
||||||
src/exceptions/helpRequested.h
|
src/exceptions/helpRequested.h
|
||||||
src/exceptions/badValue.h
|
src/exceptions/badValue.h
|
||||||
src/utilities.h src/sqliteDb.h)
|
src/utilities.h
|
||||||
|
src/sqliteDb.h
|
||||||
|
src/main.h)
|
||||||
|
|
||||||
|
|
||||||
add_executable(${PROJECT_NAME} ${SOURCES} ${HEADERS})
|
add_executable(${PROJECT_NAME} ${SOURCES} ${HEADERS})
|
||||||
|
@ -197,12 +197,12 @@ void Database::createAccount(const std::string &account, sqlite3 *db) {
|
|||||||
throw std::runtime_error("Failed to create account " + account);
|
throw std::runtime_error("Failed to create account " + account);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Database::earn(const std::string &account, long double &value, std::string &description, std::string &receipt,
|
long long int Database::earn(const std::string &account, long double &value, std::string &description, std::string &receipt,
|
||||||
long long date, sqlite3 *db) {
|
long long date, sqlite3 *db) {
|
||||||
sqlite3_stmt *stmt;
|
sqlite3_stmt *stmt;
|
||||||
int rc = sqlite3_prepare_v2(db, "INSERT INTO earning (value, description, receipt, accountId, date) VALUES "
|
int rc = sqlite3_prepare_v2(db, "INSERT INTO earning (value, description, receipt, accountId, date) VALUES "
|
||||||
"(?, ?, ?, (SELECT id FROM account WHERE name = ?), ?);"
|
"(?, ?, ?, (SELECT id FROM account WHERE name = ?), ?);",
|
||||||
"SELECT cachedValue FROM account WHERE name = ?;", -1, &stmt, nullptr);
|
-1, &stmt, nullptr);
|
||||||
|
|
||||||
if (rc != SQLITE_OK)
|
if (rc != SQLITE_OK)
|
||||||
throw std::runtime_error("Failed preparing earn statement");
|
throw std::runtime_error("Failed preparing earn statement");
|
||||||
@ -219,13 +219,16 @@ void Database::earn(const std::string &account, long double &value, std::string
|
|||||||
if (rc != SQLITE_DONE)
|
if (rc != SQLITE_DONE)
|
||||||
throw std::runtime_error("Failed to create earning");
|
throw std::runtime_error("Failed to create earning");
|
||||||
cacheAccountValue(account, db);
|
cacheAccountValue(account, db);
|
||||||
|
|
||||||
|
return sqlite3_last_insert_rowid(db);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Database::pay(const std::string &account, long double &value, std::string &description, std::string &receipt,
|
long long int Database::pay(const std::string &account, long double &value, std::string &description, std::string &receipt,
|
||||||
long long date, sqlite3 *db) {
|
long long date, sqlite3 *db) {
|
||||||
sqlite3_stmt *stmt;
|
sqlite3_stmt *stmt;
|
||||||
int rc = sqlite3_prepare_v2(db, "INSERT INTO payment (value, description, receipt, accountId, date) VALUES "
|
int rc = sqlite3_prepare_v2(db, "INSERT INTO payment (value, description, receipt, accountId, date) VALUES "
|
||||||
"(?, ?, ?, (SELECT id FROM account WHERE name = ?), ?)", -1, &stmt, nullptr);
|
"(?, ?, ?, (SELECT id FROM account WHERE name = ?), ?);",
|
||||||
|
-1, &stmt, nullptr);
|
||||||
|
|
||||||
if (rc != SQLITE_OK)
|
if (rc != SQLITE_OK)
|
||||||
throw std::runtime_error("Failed preparing pay statement");
|
throw std::runtime_error("Failed preparing pay statement");
|
||||||
@ -242,4 +245,6 @@ void Database::pay(const std::string &account, long double &value, std::string &
|
|||||||
if (rc != SQLITE_DONE)
|
if (rc != SQLITE_DONE)
|
||||||
throw std::runtime_error("Failed to create payment");
|
throw std::runtime_error("Failed to create payment");
|
||||||
cacheAccountValue(account, db);
|
cacheAccountValue(account, db);
|
||||||
|
|
||||||
|
return sqlite3_last_insert_rowid(db);
|
||||||
}
|
}
|
@ -119,7 +119,7 @@ public:
|
|||||||
* The accountId is retrieved from the 'account' table using the provided account name.
|
* The accountId is retrieved from the 'account' table using the provided account name.
|
||||||
* If the query fails to prepare or execute, the function throws a runtime_error.
|
* If the query fails to prepare or execute, the function throws a runtime_error.
|
||||||
*/
|
*/
|
||||||
static void
|
static long long int
|
||||||
earn(const std::string &account, long double &value, std::string &description, std::string &receipt,
|
earn(const std::string &account, long double &value, std::string &description, std::string &receipt,
|
||||||
long long int date,
|
long long int date,
|
||||||
sqlite3 *db);
|
sqlite3 *db);
|
||||||
@ -140,7 +140,7 @@ public:
|
|||||||
* The accountId is retrieved from the 'account' table using the provided account name.
|
* The accountId is retrieved from the 'account' table using the provided account name.
|
||||||
* If the query fails to prepare or execute, the function throws a runtime_error.
|
* If the query fails to prepare or execute, the function throws a runtime_error.
|
||||||
*/
|
*/
|
||||||
static void
|
static long long int
|
||||||
pay(const std::string &account, long double &value, std::string &description, std::string &receipt,
|
pay(const std::string &account, long double &value, std::string &description, std::string &receipt,
|
||||||
long long int date,
|
long long int date,
|
||||||
sqlite3 *db);
|
sqlite3 *db);
|
||||||
|
22
src/main.cpp
22
src/main.cpp
@ -6,9 +6,8 @@
|
|||||||
#include "exceptions/helpRequested.h"
|
#include "exceptions/helpRequested.h"
|
||||||
#include "exceptions/badValue.h"
|
#include "exceptions/badValue.h"
|
||||||
#include "sqliteDb.h"
|
#include "sqliteDb.h"
|
||||||
|
#include "main.h"
|
||||||
|
|
||||||
#include <pwd.h>
|
|
||||||
#include <unistd.h>
|
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <filesystem>
|
#include <filesystem>
|
||||||
#include <sqlite3.h>
|
#include <sqlite3.h>
|
||||||
@ -17,19 +16,24 @@
|
|||||||
|
|
||||||
using namespace Budget;
|
using namespace Budget;
|
||||||
|
|
||||||
const std::string homeDirectory = getpwuid(getuid())->pw_dir;
|
const char* createTables = "CREATE TABLE account (id INTEGER CONSTRAINT account_pk PRIMARY KEY AUTOINCREMENT, name TEXT, description TEXT, cachedValue DOUBLE);"
|
||||||
const std::string configD = homeDirectory + "/.config/budget/";
|
"CREATE UNIQUE INDEX account_name_uindex ON account (name);"
|
||||||
const std::string storageD = homeDirectory + "/.local/share/budget/";
|
"CREATE TABLE earning (id INTEGER CONSTRAINT earning_pk PRIMARY KEY AUTOINCREMENT, value DOUBLE NOT NULL, description TEXT, receipt TEXT, accountId INT NOT NULL REFERENCES account ON UPDATE CASCADE ON DELETE CASCADE, date INTEGER NOT NULL);"
|
||||||
const std::string databaseFile = homeDirectory + "/.local/share/budget/budget.sqlite";
|
"CREATE INDEX earning_date_index ON earning (date DESC);"
|
||||||
|
"CREATE TABLE payment (id INTEGER CONSTRAINT payment_pk PRIMARY KEY AUTOINCREMENT, value DOUBLE NOT NULL, description TEXT, receipt TEXT, accountId INT NOT NULL REFERENCES account ON UPDATE CASCADE ON DELETE CASCADE, date INTEGER NOT NULL);"
|
||||||
|
"CREATE INDEX payment_date_index ON payment (date DESC);";
|
||||||
|
|
||||||
void createRequiredFolders() {
|
void createRequiredFolders() {
|
||||||
std::filesystem::create_directory(configD);
|
std::filesystem::create_directory(configD);
|
||||||
std::filesystem::create_directories(storageD);
|
std::filesystem::create_directories(storageD);
|
||||||
std::filesystem::create_directories(storageD + "receipts");
|
std::filesystem::create_directories(storageD + "receipts");
|
||||||
|
std::filesystem::create_directories(storageD + "receipts/payment");
|
||||||
|
std::filesystem::create_directories(storageD + "receipts/earn");
|
||||||
}
|
}
|
||||||
|
|
||||||
int main(int argc, char *argv[]) {
|
int main(int argc, char *argv[]) {
|
||||||
|
createRequiredFolders();
|
||||||
|
|
||||||
sqlite3 *db;
|
sqlite3 *db;
|
||||||
SqliteDb dbRAII(db);
|
SqliteDb dbRAII(db);
|
||||||
|
|
||||||
@ -47,6 +51,10 @@ int main(int argc, char *argv[]) {
|
|||||||
if (rc != SQLITE_OK)
|
if (rc != SQLITE_OK)
|
||||||
throw std::runtime_error("Couldn't begin transaction");
|
throw std::runtime_error("Couldn't begin transaction");
|
||||||
|
|
||||||
|
rc = sqlite3_exec(db, createTables, nullptr, nullptr, nullptr);
|
||||||
|
if (rc != SQLITE_OK)
|
||||||
|
throw std::runtime_error("Couldn't create the tables");
|
||||||
|
|
||||||
std::vector<char *> args(argv, argv + argc);
|
std::vector<char *> args(argv, argv + argc);
|
||||||
try {
|
try {
|
||||||
OptHandlers::MainOptHandler moh(args, db);
|
OptHandlers::MainOptHandler moh(args, db);
|
||||||
|
17
src/main.h
Normal file
17
src/main.h
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
//
|
||||||
|
// Created by quentin on 1/31/23.
|
||||||
|
//
|
||||||
|
|
||||||
|
#ifndef BUDGET_MAIN_H
|
||||||
|
#define BUDGET_MAIN_H
|
||||||
|
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <pwd.h>
|
||||||
|
|
||||||
|
const static std::string homeDirectory = getpwuid(getuid())->pw_dir;
|
||||||
|
const static std::string configD = homeDirectory + "/.config/budget/";
|
||||||
|
const static std::string storageD = homeDirectory + "/.local/share/budget/";
|
||||||
|
const static std::string databaseFile = homeDirectory + "/.local/share/budget/budget.sqlite";
|
||||||
|
|
||||||
|
|
||||||
|
#endif //BUDGET_MAIN_H
|
@ -2,9 +2,11 @@
|
|||||||
// Created by quentin on 1/17/23.
|
// Created by quentin on 1/17/23.
|
||||||
//
|
//
|
||||||
|
|
||||||
|
#include <fstream>
|
||||||
#include "PaymentOperation.h"
|
#include "PaymentOperation.h"
|
||||||
#include "../database.h"
|
#include "../database.h"
|
||||||
#include "../exceptions/badValue.h"
|
#include "../exceptions/badValue.h"
|
||||||
|
#include "../main.h"
|
||||||
|
|
||||||
using namespace Budget::OptHandlers;
|
using namespace Budget::OptHandlers;
|
||||||
|
|
||||||
@ -12,7 +14,21 @@ void PaymentOperation::commit() {
|
|||||||
if (!Database::doesAccountExist(account, db))
|
if (!Database::doesAccountExist(account, db))
|
||||||
throw Budget::Exceptions::BadValue("Account " + account + " doesn't exist");
|
throw Budget::Exceptions::BadValue("Account " + account + " doesn't exist");
|
||||||
|
|
||||||
Database::pay(account, flags.value, flags.description, flags.receipt, flags.date, db);
|
long long id = Database::pay(account, flags.value, flags.description, flags.receipt, flags.date, db);
|
||||||
|
|
||||||
|
if (!flags.receipt.empty()) {
|
||||||
|
std::string extension;
|
||||||
|
size_t pos = flags.receipt.find_last_of('.');
|
||||||
|
if (pos != std::string::npos) {
|
||||||
|
extension = flags.receipt.substr(pos);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::ifstream source(flags.receipt, std::ios::binary);
|
||||||
|
std::ofstream dest(storageD + "receipts/payment/" + std::to_string(id) + extension, std::ios::binary);
|
||||||
|
dest << source.rdbuf();
|
||||||
|
source.close();
|
||||||
|
dest.close();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
PaymentOperation::PaymentOperation(sqlite3 *db, std::string account) : Operation(db), account(std::move(account)) {}
|
PaymentOperation::PaymentOperation(sqlite3 *db, std::string account) : Operation(db), account(std::move(account)) {}
|
@ -2,9 +2,11 @@
|
|||||||
// Created by quentin on 1/17/23.
|
// Created by quentin on 1/17/23.
|
||||||
//
|
//
|
||||||
|
|
||||||
|
#include <fstream>
|
||||||
#include "earnOperation.h"
|
#include "earnOperation.h"
|
||||||
#include "../database.h"
|
#include "../database.h"
|
||||||
#include "../exceptions/badValue.h"
|
#include "../exceptions/badValue.h"
|
||||||
|
#include "../main.h"
|
||||||
|
|
||||||
using namespace Budget::OptHandlers;
|
using namespace Budget::OptHandlers;
|
||||||
|
|
||||||
@ -12,7 +14,21 @@ void EarnOperation::commit() {
|
|||||||
if (!Database::doesAccountExist(account, db))
|
if (!Database::doesAccountExist(account, db))
|
||||||
throw Budget::Exceptions::BadValue("Account " + account + " doesn't exist");
|
throw Budget::Exceptions::BadValue("Account " + account + " doesn't exist");
|
||||||
|
|
||||||
Database::earn(account, flags.value, flags.description, flags.receipt, flags.date, db);
|
long long id = Database::pay(account, flags.value, flags.description, flags.receipt, flags.date, db);
|
||||||
|
|
||||||
|
if (!flags.receipt.empty()) {
|
||||||
|
std::string extension;
|
||||||
|
size_t pos = flags.receipt.find_last_of('.');
|
||||||
|
if (pos != std::string::npos) {
|
||||||
|
extension = flags.receipt.substr(pos);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::ifstream source(flags.receipt, std::ios::binary);
|
||||||
|
std::ofstream dest(storageD + "receipts/receipt/" + std::to_string(id) + extension, std::ios::binary);
|
||||||
|
dest << source.rdbuf();
|
||||||
|
source.close();
|
||||||
|
dest.close();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
EarnOperation::EarnOperation(sqlite3 *db, std::string account) : Operation(db), account(std::move(account)) {}
|
EarnOperation::EarnOperation(sqlite3 *db, std::string account) : Operation(db), account(std::move(account)) {}
|
Loading…
x
Reference in New Issue
Block a user