diff --git a/.idea/dataSources.xml b/.idea/dataSources.xml index 74c6532..786e53d 100644 --- a/.idea/dataSources.xml +++ b/.idea/dataSources.xml @@ -11,5 +11,15 @@ + + sqlite.xerial + true + org.sqlite.JDBC + jdbc:sqlite:$USER_HOME$/.local/share/budget/budgetDebug.sqlite + $ProjectFileDir$ + + + + \ No newline at end of file diff --git a/CMakeLists.txt b/CMakeLists.txt index 9310807..d99a3a0 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -10,7 +10,7 @@ set(SOURCES src/optHandlers/accountOperation.cpp src/optHandlers/createOperation.cpp src/optHandlers/earnOperation.cpp - src/optHandlers/PaymentOperation.cpp + src/optHandlers/paymentOperation.cpp src/database.cpp src/utilities.cpp) @@ -20,13 +20,17 @@ set(HEADERS src/optHandlers/accountOperation.h src/optHandlers/createOperation.h src/optHandlers/earnOperation.h - src/optHandlers/PaymentOperation.h + src/optHandlers/paymentOperation.h src/database.h src/exceptions/helpRequested.h src/exceptions/badValue.h src/utilities.h src/sqliteDb.h - src/main.h) + src/main.h + src/models/account.h + src/models/transaction.h + src/models/earning.h + src/models/payment.h) add_executable(${PROJECT_NAME} ${SOURCES} ${HEADERS}) diff --git a/README.md b/README.md index ce123a8..a6735f4 100644 --- a/README.md +++ b/README.md @@ -43,6 +43,6 @@ budget -cAcct -eAcct -v10.00 -r"./receipt.pdf" -pAcct -v5.50 -r"./payment.pdf" ```` Does the following in order: -Creates an account named Acct with no description. +Creates an accountName named Acct with no description. Earns 10.00 to it with a receipt. Pays 5.50 to it with a receipt. diff --git a/src/database.cpp b/src/database.cpp index 8619adf..cb7695a 100644 --- a/src/database.cpp +++ b/src/database.cpp @@ -6,72 +6,52 @@ #include #include -bool Database::doesAccountExist(const std::string &account, sqlite3 *db) { +Budget::Models::Account Database::getAccount(const std::string &accountName, sqlite3 *db) { sqlite3_stmt *stmt; int rc = sqlite3_prepare_v2(db, "SELECT * FROM account WHERE name = ?", -1, &stmt, nullptr); if (rc != SQLITE_OK) - throw std::runtime_error("Failed to prepare account exist query."); + throw std::runtime_error("Failed to prepare accountName exist query."); - sqlite3_bind_text(stmt, 1, account.c_str(), -1, SQLITE_TRANSIENT); + sqlite3_bind_text(stmt, 1, accountName.c_str(), -1, SQLITE_TRANSIENT); rc = sqlite3_step(stmt); - sqlite3_finalize(stmt); if (rc == SQLITE_ROW) { - return true; + Budget::Models::Account account( + sqlite3_column_int64(stmt, 0), + (char*)(sqlite3_column_text(stmt, 1)), + (sqlite3_column_type(stmt,2) == SQLITE_NULL) ? "" : (char*)(sqlite3_column_text(stmt, 2)), + (sqlite3_column_type(stmt, 3) == SQLITE_NULL) ? nullptr : new long double(sqlite3_column_double(stmt, 4)) + ); + sqlite3_finalize(stmt); + return account; } else if (rc == SQLITE_DONE) { - return false; + sqlite3_finalize(stmt); + throw std::runtime_error("Account " + accountName + " does not exist"); } else { - throw std::runtime_error("Failed to step account existing statement."); + sqlite3_finalize(stmt); + throw std::runtime_error("Failed to step accountName existing statement."); } - } -void Database::deleteAccount(const std::string &account, sqlite3 *db) { +void Database::deleteAccount(Budget::Models::Account *account, sqlite3 *db) { sqlite3_stmt *stmt; int rc = sqlite3_prepare_v2(db, "DELETE FROM account WHERE name = ?", -1, &stmt, nullptr); if (rc != SQLITE_OK) - throw std::runtime_error("Failed to delete account " + account); + throw std::runtime_error("Failed to delete accountName " + account->name); - sqlite3_bind_text(stmt, 1, account.c_str(), -1, SQLITE_TRANSIENT); + sqlite3_bind_text(stmt, 1, account->name.c_str(), -1, SQLITE_TRANSIENT); rc = sqlite3_step(stmt); sqlite3_finalize(stmt); if (rc != SQLITE_DONE) - throw std::runtime_error("Failed to delete account " + account); + throw std::runtime_error("Failed to delete accountName " + account->name); } -double Database::getValue(const std::string &account, sqlite3 *db) { - sqlite3_stmt *stmt; - int rc = sqlite3_prepare_v2(db, "SELECT id, cachedValue FROM account WHERE name = ?", -1, &stmt, nullptr); - - if (rc != SQLITE_OK) - throw std::runtime_error("Failed preparing cashedValue " + account); - - sqlite3_bind_text(stmt, 1, account.c_str(), -1, SQLITE_TRANSIENT); - - rc = sqlite3_step(stmt); - - if (rc == SQLITE_ROW) { - double value; - if (sqlite3_column_type(stmt, 1) == SQLITE_NULL) { - value = cacheAccountValue(sqlite3_column_int64(stmt, 0), db); - sqlite3_finalize(stmt); - return value; - } - value = sqlite3_column_double(stmt, 1); - sqlite3_finalize(stmt); - return value; - } else if (rc == SQLITE_DONE) - throw std::runtime_error("Account doesnt exist? Shouldn't be possible in this call."); - else - throw std::runtime_error("Failed to step getValue statement."); -} - -double Database::cacheAccountValue(long long accountId, sqlite3 *db) { +void Database::cacheAccountValue(Budget::Models::Account *account, sqlite3 *db) { sqlite3_stmt *stmt; int rc = sqlite3_prepare_v2(db, "SELECT SUM(value) FROM (" "SELECT value * -1 as value FROM payment WHERE accountId = ? " @@ -79,10 +59,10 @@ double Database::cacheAccountValue(long long accountId, sqlite3 *db) { "SELECT value FROM earning WHERE accountId = ?);", -1, &stmt, nullptr); if (rc != SQLITE_OK) - throw std::runtime_error("Failed preparing get cashedValue " + std::to_string(accountId)); + throw std::runtime_error("Failed preparing get cashedValue " + account->name); - sqlite3_bind_int64(stmt, 1, accountId); - sqlite3_bind_int64(stmt, 2, accountId); + sqlite3_bind_int64(stmt, 1, account->id); + sqlite3_bind_int64(stmt, 2, account->id); rc = sqlite3_step(stmt); @@ -92,79 +72,42 @@ double Database::cacheAccountValue(long long accountId, sqlite3 *db) { else if (rc == SQLITE_DONE) value = 0; else - throw std::runtime_error("Failed get cashedValue " + std::to_string(accountId)); + throw std::runtime_error("Failed get cashedValue " + account->name); sqlite3_reset(stmt); rc = sqlite3_prepare_v2(db, "UPDATE account SET cachedValue = ? WHERE id = ?", -1, &stmt, nullptr); if (rc != SQLITE_OK) - throw std::runtime_error("Failed preparing set cashedValue " + std::to_string(accountId)); + throw std::runtime_error("Failed preparing set cashedValue " + account->name); sqlite3_bind_double(stmt, 1, value); - sqlite3_bind_int64(stmt, 2, accountId); + sqlite3_bind_int64(stmt, 2, account->id); rc = sqlite3_step(stmt); - if (rc == SQLITE_DONE) - return value; - throw std::runtime_error("Failed to set cashedValue for " + std::to_string(accountId)); + if (rc == SQLITE_DONE) { + account->cachedValue = new long double(value); + return; + } + throw std::runtime_error("Failed to set cashedValue for " + std::to_string(account->id)); } -double Database::cacheAccountValue(const std::string &account, sqlite3 *db) { - sqlite3_stmt *stmt; - int rc = sqlite3_prepare_v2(db, "SELECT SUM(value) FROM (" - "SELECT value * -1 as value FROM payment WHERE accountId = " - "(SELECT id FROM account where name = ?) " - "UNION ALL " - "SELECT value FROM earning WHERE accountId = " - "(SELECT id FROM account where name = ?));", -1, &stmt, nullptr); - - if (rc != SQLITE_OK) - throw std::runtime_error("Failed preparing get cashedValue " + account); - - sqlite3_bind_text(stmt, 1, account.c_str(), -1, SQLITE_TRANSIENT); - sqlite3_bind_text(stmt, 2, account.c_str(), -1, SQLITE_TRANSIENT); - - rc = sqlite3_step(stmt); - - double value; - if (rc == SQLITE_ROW) - value = sqlite3_column_double(stmt, 0); - else if (rc == SQLITE_DONE) - value = 0; - else - throw std::runtime_error("Failed get cashedValue " + account); - - sqlite3_reset(stmt); - rc = sqlite3_prepare_v2(db, "UPDATE account SET cachedValue = ? WHERE name = ?", -1, &stmt, nullptr); - if (rc != SQLITE_OK) - throw std::runtime_error("Failed preparing set cashedValue " + account); - - sqlite3_bind_double(stmt, 1, value); - sqlite3_bind_text(stmt, 2, account.c_str(), -1, SQLITE_TRANSIENT); - - rc = sqlite3_step(stmt); - if (rc == SQLITE_DONE) - return value; - throw std::runtime_error("Failed to set cashedValue for " + account); -} - -void Database::accountDescription(const std::string &account, const std::string &description, sqlite3 *db) { +void Database::accountDescription(Budget::Models::Account *account, sqlite3 *db) { sqlite3_stmt *stmt; int rc = sqlite3_prepare_v2(db, "UPDATE account SET description = ? WHERE name = ?", -1, &stmt, nullptr); if (rc != SQLITE_OK) throw std::runtime_error("Failed preparing accountDescription statement"); - sqlite3_bind_text(stmt, 1, description.c_str(), -1, SQLITE_TRANSIENT); - sqlite3_bind_text(stmt, 2, account.c_str(), -1, SQLITE_TRANSIENT); + sqlite3_bind_text(stmt, 1, account->description.c_str(), -1, SQLITE_TRANSIENT); + sqlite3_bind_text(stmt, 2, account->name.c_str(), -1, SQLITE_TRANSIENT); rc = sqlite3_step(stmt); sqlite3_finalize(stmt); if (rc != SQLITE_DONE) - throw std::runtime_error("Failed to set description on " + account); + throw std::runtime_error("Failed to set description on " + account->name); } -void Database::createAccount(const std::string &account, const std::string &description, sqlite3 *db) { +long long int Database::createAccount(Budget::OptHandlers::CreateOperation::Flags *flags, std::string &account, sqlite3 *db) { sqlite3_stmt *stmt; int rc = sqlite3_prepare_v2(db, "INSERT INTO account (name, description) VALUES (?, ?)", -1, &stmt, nullptr); @@ -172,46 +115,33 @@ void Database::createAccount(const std::string &account, const std::string &desc throw std::runtime_error("Failed preparing createAccount statement"); sqlite3_bind_text(stmt, 1, account.c_str(), -1, SQLITE_TRANSIENT); - sqlite3_bind_text(stmt, 2, description.c_str(), -1, SQLITE_TRANSIENT); + sqlite3_bind_text(stmt, 2, (flags->description.empty() ? nullptr : flags->description.c_str()), -1, SQLITE_TRANSIENT); rc = sqlite3_step(stmt); + + if (rc != SQLITE_DONE) { + throw std::runtime_error("Failed to create accountName " + account); + } + sqlite3_finalize(stmt); - if (rc != SQLITE_DONE) - throw std::runtime_error("Failed to create account " + account); + return sqlite3_last_insert_rowid(db); } -void Database::createAccount(const std::string &account, sqlite3 *db) { - sqlite3_stmt *stmt; - int rc = sqlite3_prepare_v2(db, "INSERT INTO account (name) VALUES (?)", -1, &stmt, nullptr); - - if (rc != SQLITE_OK) - throw std::runtime_error("Failed preparing createAccount statement"); - - sqlite3_bind_text(stmt, 1, account.c_str(), -1, SQLITE_TRANSIENT); - - rc = sqlite3_step(stmt); - sqlite3_finalize(stmt); - - if (rc != SQLITE_DONE) - throw std::runtime_error("Failed to create account " + account); -} - -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 int Database::earn(Budget::Models::Account *account, Budget::OptHandlers::EarnOperation::Flags *flags, sqlite3 *db) { sqlite3_stmt *stmt; int rc = sqlite3_prepare_v2(db, "INSERT INTO earning (value, description, receipt, accountId, date) VALUES " - "(?, ?, ?, (SELECT id FROM account WHERE name = ?), ?);", + "(?, ?, ?, ?, ?);", -1, &stmt, nullptr); if (rc != SQLITE_OK) throw std::runtime_error("Failed preparing earn statement"); - sqlite3_bind_double(stmt, 1, value); - sqlite3_bind_text(stmt, 2, (description.empty() ? nullptr : description.c_str()), -1, SQLITE_TRANSIENT); - sqlite3_bind_text(stmt, 3, (receipt.empty() ? nullptr : receipt.c_str()), -1, SQLITE_TRANSIENT); - sqlite3_bind_text(stmt, 4, (account.empty() ? nullptr : account.c_str()), -1, SQLITE_TRANSIENT); - sqlite3_bind_int64(stmt, 5, date); + sqlite3_bind_double(stmt, 1, flags->value); + sqlite3_bind_text(stmt, 2, (flags->description.empty() ? nullptr : flags->description.c_str()), -1, SQLITE_TRANSIENT); + sqlite3_bind_text(stmt, 3, (flags->receipt.empty() ? nullptr : flags->receipt.c_str()), -1, SQLITE_TRANSIENT); + sqlite3_bind_int64(stmt, 4, account->id); + sqlite3_bind_int64(stmt, 5, flags->date); rc = sqlite3_step(stmt); sqlite3_finalize(stmt); @@ -223,21 +153,20 @@ long long int Database::earn(const std::string &account, long double &value, std return sqlite3_last_insert_rowid(db); } -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 int Database::pay(Budget::Models::Account *account, Budget::OptHandlers::PaymentOperation::Flags *flags, sqlite3 *db) { sqlite3_stmt *stmt; int rc = sqlite3_prepare_v2(db, "INSERT INTO payment (value, description, receipt, accountId, date) VALUES " - "(?, ?, ?, (SELECT id FROM account WHERE name = ?), ?);", + "(?, ?, ?, ?, ?);", -1, &stmt, nullptr); if (rc != SQLITE_OK) throw std::runtime_error("Failed preparing pay statement"); - sqlite3_bind_double(stmt, 1, value); - sqlite3_bind_text(stmt, 2, (description.empty() ? nullptr : description.c_str()), -1, SQLITE_TRANSIENT); - sqlite3_bind_text(stmt, 3, (receipt.empty() ? nullptr : receipt.c_str()), -1, SQLITE_TRANSIENT); - sqlite3_bind_text(stmt, 4, (account.empty() ? nullptr : account.c_str()), -1, SQLITE_TRANSIENT); - sqlite3_bind_int64(stmt, 5, date); + sqlite3_bind_double(stmt, 1, flags->value); + sqlite3_bind_text(stmt, 2, (flags->description.empty() ? nullptr : flags->description.c_str()), -1, SQLITE_TRANSIENT); + sqlite3_bind_text(stmt, 3, (flags->receipt.empty() ? nullptr : flags->receipt.c_str()), -1, SQLITE_TRANSIENT); + sqlite3_bind_int64(stmt, 4, account->id); + sqlite3_bind_int64(stmt, 5, flags->date); rc = sqlite3_step(stmt); sqlite3_finalize(stmt); diff --git a/src/database.h b/src/database.h index 51ad163..55cdd6c 100644 --- a/src/database.h +++ b/src/database.h @@ -5,6 +5,10 @@ #ifndef BUDGET_DATABASE_H #define BUDGET_DATABASE_H +#include "models/account.h" +#include "optHandlers/createOperation.h" +#include "optHandlers/earnOperation.h" +#include "optHandlers/paymentOperation.h" #include #include @@ -12,101 +16,67 @@ class Database { public: /** - * @brief Checks if an account exists in the database + * @brief Checks if an accountName exists in the database * - * @param account The name of the account to check for + * @param accountName The name of the accountName to check for * @param db The database connection to use * - * @return True if the account exists, false otherwise + * @return True if the accountName exists, false otherwise * * @throws std::runtime_error If the database query fails */ - static bool doesAccountExist(const std::string &account, sqlite3 *db); + static Budget::Models::Account getAccount(const std::string &accountName, sqlite3 *db); /** - * @brief Deletes an account from the database + * @brief Deletes an accountName from the database * - * @param account The name of the account to delete + * @param account The name of the accountName to delete * @param db The database connection to use * - * @return True if the account was successfully deleted, false otherwise + * @return True if the accountName was successfully deleted, false otherwise * * @throws std::runtime_error If the database query fails */ - static void deleteAccount(const std::string &account, sqlite3 *db); + static void deleteAccount(Budget::Models::Account *account, sqlite3 *db); /** - * @brief Retrieves the cached value of an account from the database + * @brief Caches the value of an accountName by calculating the sum of all payments and earnings * - * @param account The name of the account to retrieve the value of + * @param accountId The ID of the accountName to cache the value of * @param db The database connection to use * - * @return The cached value of the account - * - * @throws std::runtime_error If the database query fails or the account doesn't exist - */ - static double getValue(const std::string &account, sqlite3 *db); - - /** - * @brief Caches the value of an account by calculating the sum of all payments and earnings - * - * @param accountId The ID of the account to cache the value of - * @param db The database connection to use - * - * @return The cached value of the account + * @return The cached value of the accountName * * @throws std::runtime_error If the database query fails */ - static double cacheAccountValue(long long accountId, sqlite3 *db); + static void cacheAccountValue(Budget::Models::Account *account, sqlite3 *db); /** - * @brief Caches the value of an account by calculating the sum of all payments and earnings + * @brief Sets a new description for an accountName * - * @param account The name of the account to cache the value of - * @param db The database connection to use - * - * @return The cached value of the account - * - * @throws std::runtime_error If the database query fails - */ - static double cacheAccountValue(const std::string &account, sqlite3 *db); - - /** - * @brief Sets a new description for an account - * - * @param account The account name + * @param account The accountName name * @param description The new description * @param db The database connection to use * * @throws std::runtime_error If the statement fails to prepare or the step fails to execute */ - static void accountDescription(const std::string &account, const std::string &description, sqlite3 *db); + static void accountDescription(Budget::Models::Account *account, sqlite3 *db); /** - * @brief Creates a new account in the database with the given name and description + * @brief Creates a new accountName in the database with the given name and description * - * @param account The name of the account to create - * @param description The description of the account to create + * @param account The name of the accountName to create + * @param description The description of the accountName to create * @param db The sqlite3 database connection to use * - * @throws std::runtime_error If the account could not be created in the database + * @throws std::runtime_error If the accountName could not be created in the database */ - static void createAccount(const std::string &account, const std::string &description, sqlite3 *db); - - /** - * @brief Creates a new account in the database with the given name - * - * @param account The name of the account to create - * @param db The sqlite3 database connection to use - * - * @throws std::runtime_error If the account could not be created in the database - */ - static void createAccount(const std::string &account, sqlite3 *db); + static long long int createAccount(Budget::OptHandlers::CreateOperation::Flags *flags, std::string &account, sqlite3 *db); /** * @brief The function records an earning in the database * - * @param account The name of the account to record the earning in + * @param account The name of the accountName to record the earning in * @param value The value of the earning * @param description A description of the earning, can be an empty string * @param receipt A receipt of the earning, can be an empty string @@ -116,18 +86,17 @@ public: * @throws std::runtime_error If the earning could not be created in the database * * This function records an earning in the database by inserting a new row in the 'earning' table with the provided information. - * The accountId is retrieved from the 'account' table using the provided account name. + * The accountId is retrieved from the 'accountName' table using the provided accountName name. * If the query fails to prepare or execute, the function throws a runtime_error. */ static long long int - earn(const std::string &account, long double &value, std::string &description, std::string &receipt, - long long int date, + earn(Budget::Models::Account *account, Budget::OptHandlers::EarnOperation::Flags *flags, sqlite3 *db); /** * @brief The function records an payment in the database * - * @param account The name of the account to record the payment in + * @param account The name of the accountName to record the payment in * @param value The value of the payment * @param description A description of the payment, can be an empty string * @param receipt A receipt of the payment, can be an empty string @@ -137,13 +106,11 @@ public: * @throws std::runtime_error If the payment could not be created in the database * * This function records an payment in the database by inserting a new row in the 'payment' table with the provided information. - * The accountId is retrieved from the 'account' table using the provided account name. + * The accountId is retrieved from the 'accountName' table using the provided accountName name. * If the query fails to prepare or execute, the function throws a runtime_error. */ static long long int - pay(const std::string &account, long double &value, std::string &description, std::string &receipt, - long long int date, - sqlite3 *db); + pay(Budget::Models::Account *account, Budget::OptHandlers::PaymentOperation::Flags *flags, sqlite3 *db); }; diff --git a/src/main.cpp b/src/main.cpp index 0ddf811..be4321e 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -16,11 +16,11 @@ using namespace Budget; -const char* createTables = "CREATE TABLE IF NOT EXISTS account (id INTEGER CONSTRAINT account_pk PRIMARY KEY AUTOINCREMENT, name TEXT, description TEXT, cachedValue DOUBLE);" - "CREATE UNIQUE INDEX IF NOT EXISTS account_name_uindex ON account (name);" - "CREATE TABLE IF NOT EXISTS 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 char* createTables = "CREATE TABLE IF NOT EXISTS accountName (id INTEGER CONSTRAINT account_pk PRIMARY KEY AUTOINCREMENT, name TEXT, description TEXT, cachedValue DOUBLE);" + "CREATE UNIQUE INDEX IF NOT EXISTS account_name_uindex ON accountName (name);" + "CREATE TABLE IF NOT EXISTS earning (id INTEGER CONSTRAINT earning_pk PRIMARY KEY AUTOINCREMENT, value DOUBLE NOT NULL, description TEXT, receipt TEXT, accountId INT NOT NULL REFERENCES accountName ON UPDATE CASCADE ON DELETE CASCADE, date INTEGER NOT NULL);" "CREATE INDEX IF NOT EXISTS earning_date_index ON earning (date DESC);" - "CREATE TABLE IF NOT EXISTS 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 TABLE IF NOT EXISTS payment (id INTEGER CONSTRAINT payment_pk PRIMARY KEY AUTOINCREMENT, value DOUBLE NOT NULL, description TEXT, receipt TEXT, accountId INT NOT NULL REFERENCES accountName ON UPDATE CASCADE ON DELETE CASCADE, date INTEGER NOT NULL);" "CREATE INDEX IF NOT EXISTS payment_date_index ON payment (date DESC);"; void createRequiredFolders() { diff --git a/src/models/account.h b/src/models/account.h new file mode 100644 index 0000000..295fecc --- /dev/null +++ b/src/models/account.h @@ -0,0 +1,27 @@ +// +// Created by quentin on 2/2/23. +// + +#ifndef BUDGET_ACCOUNT_H +#define BUDGET_ACCOUNT_H + +#include +#include +namespace Budget::Models { + class Account { + public: + Account(long long int id, std::string name, std::string description, long double* cachedValue) + : id(id), name(std::move(name)), description(std::move(description)), cachedValue(new long double(3.3)) {} + +// ~Account() { +// delete cachedValue; +// } + public: + long long id; + std::string name; + std::string description; + long double* cachedValue; + }; +} + +#endif //BUDGET_ACCOUNT_H diff --git a/src/models/earning.h b/src/models/earning.h new file mode 100644 index 0000000..90ed231 --- /dev/null +++ b/src/models/earning.h @@ -0,0 +1,14 @@ +// +// Created by quentin on 2/2/23. +// + +#ifndef BUDGET_EARNING_H +#define BUDGET_EARNING_H + +#include "transaction.h" + +namespace Budget::Models { + class Earning : Transaction {}; +} + +#endif //BUDGET_EARNING_H diff --git a/src/models/payment.h b/src/models/payment.h new file mode 100644 index 0000000..ce4914d --- /dev/null +++ b/src/models/payment.h @@ -0,0 +1,14 @@ +// +// Created by quentin on 2/2/23. +// + +#ifndef BUDGET_EARNING_H +#define BUDGET_EARNING_H + +#include "transaction.h" + +namespace Budget::Models { + class Payment : Transaction {}; +} + +#endif //BUDGET_EARNING_H diff --git a/src/models/transaction.h b/src/models/transaction.h new file mode 100644 index 0000000..23bad71 --- /dev/null +++ b/src/models/transaction.h @@ -0,0 +1,22 @@ +// +// Created by quentin on 2/2/23. +// + +#ifndef BUDGET_TRANSACTION_H +#define BUDGET_TRANSACTION_H + +#include + +namespace Budget::Models { + class Transaction { + public: + long long int id; + long double value; + std::string description; + std::string receipt; + long long int accountId; + long long int date; + }; +} + +#endif //BUDGET_TRANSACTION_H diff --git a/src/optHandlers/PaymentOperation.cpp b/src/optHandlers/PaymentOperation.cpp deleted file mode 100644 index 9bd9213..0000000 --- a/src/optHandlers/PaymentOperation.cpp +++ /dev/null @@ -1,34 +0,0 @@ -// -// Created by quentin on 1/17/23. -// - -#include -#include "PaymentOperation.h" -#include "../database.h" -#include "../exceptions/badValue.h" -#include "../main.h" - -using namespace Budget::OptHandlers; - -void PaymentOperation::commit() { - if (!Database::doesAccountExist(account, db)) - throw Budget::Exceptions::BadValue("Account " + account + " doesn't exist"); - - 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)) {} \ No newline at end of file diff --git a/src/optHandlers/accountOperation.cpp b/src/optHandlers/accountOperation.cpp index 1855db3..57aeed2 100644 --- a/src/optHandlers/accountOperation.cpp +++ b/src/optHandlers/accountOperation.cpp @@ -13,23 +13,24 @@ using namespace Budget::OptHandlers; void AccountOperation::commit() { - if (!Database::doesAccountExist(account, db)) - throw Budget::Exceptions::BadValue("Account " + account + " doesn't exist"); + Budget::Models::Account account = Database::getAccount(accountName, db); if (flags.del) { - if (flags.forceDel || Utilities::confirm("Are you sure you'd like to delete " + account)) { - Database::deleteAccount(account, db); + if (flags.forceDel || Utilities::confirm("Are you sure you'd like to delete " + accountName)) { + Database::deleteAccount(&account, db); return; } } if (flags.value) { - std::cout << Database::getValue(account, db) << std::endl; + if (account.cachedValue == nullptr) + Database::cacheAccountValue(&account, db); + std::cout << *account.cachedValue << std::endl; } if (!flags.description.empty()) { - Database::accountDescription(account, flags.description, db); + Database::accountDescription(&account, db); } } -AccountOperation::AccountOperation(sqlite3 *db, std::string account) : Operation(db), account(std::move(account)) {} +AccountOperation::AccountOperation(sqlite3 *db, std::string account) : Operation(db), accountName(std::move(account)) {} diff --git a/src/optHandlers/accountOperation.h b/src/optHandlers/accountOperation.h index 2399347..333fb36 100644 --- a/src/optHandlers/accountOperation.h +++ b/src/optHandlers/accountOperation.h @@ -25,7 +25,7 @@ namespace Budget::OptHandlers { Flags flags; private: - std::string account; + std::string accountName; }; } diff --git a/src/optHandlers/createOperation.cpp b/src/optHandlers/createOperation.cpp index 8055f73..1151145 100644 --- a/src/optHandlers/createOperation.cpp +++ b/src/optHandlers/createOperation.cpp @@ -9,14 +9,7 @@ using namespace Budget::OptHandlers; void CreateOperation::commit() { - if (Database::doesAccountExist(account, db)) { - throw Budget::Exceptions::BadValue("Account already exists, cant create " + account); - } - if (flags.description.empty()) { - Database::createAccount(account, db); - return; - } - Database::createAccount(account, flags.description, db); + long long int id = Database::createAccount(&flags, accountName, db); } -CreateOperation::CreateOperation(sqlite3 *db, std::string account) : Operation(db), account(std::move(account)) {} +CreateOperation::CreateOperation(sqlite3 *db, std::string account) : Operation(db), accountName(std::move(account)) {} diff --git a/src/optHandlers/createOperation.h b/src/optHandlers/createOperation.h index cee218e..c1d183c 100644 --- a/src/optHandlers/createOperation.h +++ b/src/optHandlers/createOperation.h @@ -21,7 +21,7 @@ namespace Budget::OptHandlers { Flags flags; private: - std::string account; + std::string accountName; }; } diff --git a/src/optHandlers/earnOperation.cpp b/src/optHandlers/earnOperation.cpp index ef62e51..4ba0ea6 100644 --- a/src/optHandlers/earnOperation.cpp +++ b/src/optHandlers/earnOperation.cpp @@ -11,24 +11,28 @@ using namespace Budget::OptHandlers; void EarnOperation::commit() { - if (!Database::doesAccountExist(account, db)) - throw Budget::Exceptions::BadValue("Account " + account + " doesn't exist"); - - long long id = Database::earn(account, flags.value, flags.description, flags.receipt, flags.date, db); + Models::Account account = Database::getAccount(accountName, 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(); + if (source.good()) { + std::string extension; + size_t pos = flags.receipt.find_last_of('.'); + if (pos != std::string::npos) { + extension = flags.receipt.substr(pos); + } + + std::ofstream dest(storageD + "receipts/receipt/" + std::to_string(account.id) + extension, std::ios::binary); + dest << source.rdbuf(); + source.close(); + dest.close(); + } + else { + throw Exceptions::BadValue("File " + flags.receipt + " does not exist"); + } } + + Database::earn(&account, &flags, db); } -EarnOperation::EarnOperation(sqlite3 *db, std::string account) : Operation(db), account(std::move(account)) {} \ No newline at end of file +EarnOperation::EarnOperation(sqlite3 *db, std::string account) : Operation(db), accountName(std::move(account)) {} \ No newline at end of file diff --git a/src/optHandlers/earnOperation.h b/src/optHandlers/earnOperation.h index c44640b..052566d 100644 --- a/src/optHandlers/earnOperation.h +++ b/src/optHandlers/earnOperation.h @@ -26,7 +26,7 @@ namespace Budget::OptHandlers { Flags flags; private: - std::string account; + std::string accountName; }; } diff --git a/src/optHandlers/mainOptHandler.cpp b/src/optHandlers/mainOptHandler.cpp index 3aa14f5..65b6693 100644 --- a/src/optHandlers/mainOptHandler.cpp +++ b/src/optHandlers/mainOptHandler.cpp @@ -5,7 +5,7 @@ #include "accountOperation.h" #include "createOperation.h" #include "earnOperation.h" -#include "PaymentOperation.h" +#include "paymentOperation.h" #include "../exceptions/helpRequested.h" #include "../exceptions/badValue.h" #include @@ -17,7 +17,7 @@ using namespace Budget::OptHandlers; MainOptHandler::MainOptHandler(const std::vector &_argv, sqlite3 *db) : argv(_argv), db(db) { struct option actionLongOpts[] = { {"help", no_argument, nullptr, 'h'}, - {"account", required_argument, nullptr, 'a'}, + {"accountName", required_argument, nullptr, 'a'}, {"create", required_argument, nullptr, 'c'}, {"earn", required_argument, nullptr, 'e'}, {"payment", required_argument, nullptr, 'p'} @@ -56,7 +56,7 @@ MainOptHandler::MainOptHandler(const std::vector &_argv, sqlite3 *db) : void MainOptHandler::accountOptHandler(std::string account) { struct option accountLongOpts[] = { {"help", no_argument, nullptr, 'h'}, - {"account", required_argument, nullptr, 'a'}, + {"accountName", required_argument, nullptr, 'a'}, {"create", required_argument, nullptr, 'c'}, {"earn", required_argument, nullptr, 'e'}, {"payment", required_argument, nullptr, 'p'}, @@ -77,7 +77,7 @@ void MainOptHandler::accountOptHandler(std::string account) { switch (opt) { case 'h': help(); - throw Budget::Exceptions::HelpRequested("Help requested at account"); + throw Budget::Exceptions::HelpRequested("Help requested at accountName"); case 'a': case 'c': case 'e': @@ -100,7 +100,7 @@ void MainOptHandler::accountOptHandler(std::string account) { break; case '?': help(); - throw Budget::Exceptions::HelpRequested("Help requested at account, unknown argument."); + throw Budget::Exceptions::HelpRequested("Help requested at accountName, unknown argument."); default: break; } @@ -111,7 +111,7 @@ void MainOptHandler::accountOptHandler(std::string account) { void MainOptHandler::createOptHandler(std::string account) { struct option createLongOpts[] = { {"help", no_argument, nullptr, 'h'}, - {"account", required_argument, nullptr, 'a'}, + {"accountName", required_argument, nullptr, 'a'}, {"create", required_argument, nullptr, 'c'}, {"earn", required_argument, nullptr, 'e'}, {"payment", required_argument, nullptr, 'p'}, @@ -153,7 +153,7 @@ void MainOptHandler::createOptHandler(std::string account) { void MainOptHandler::earnOptHandler(std::string account) { struct option earnLongOpts[] = { {"help", no_argument, nullptr, 'h'}, - {"account", required_argument, nullptr, 'a'}, + {"accountName", required_argument, nullptr, 'a'}, {"create", required_argument, nullptr, 'c'}, {"earn", required_argument, nullptr, 'e'}, {"payment", required_argument, nullptr, 'p'}, @@ -224,7 +224,7 @@ void MainOptHandler::earnOptHandler(std::string account) { void MainOptHandler::paymentOptHandler(std::string account) { struct option paymentLongOpts[] = { {"help", no_argument, nullptr, 'h'}, - {"account", required_argument, nullptr, 'a'}, + {"accountName", required_argument, nullptr, 'a'}, {"create", required_argument, nullptr, 'c'}, {"earn", required_argument, nullptr, 'e'}, {"payment", required_argument, nullptr, 'p'}, @@ -298,17 +298,17 @@ void MainOptHandler::help() { " budget [options] ...\n" "Actions:\n" " -h --help Prints this.\n" - " -a --account<=STRING> Management tools for an account.\n" - " -c --create<=STRING> Creates a new account with NAME.\n" - " -e --earn<=STRING> Add an earning to an account.\n" - " -p --payment<=STRING> Add a payment to an account.\n" + " -a --accountName<=STRING> Management tools for an accountName.\n" + " -c --create<=STRING> Creates a new accountName with NAME.\n" + " -e --earn<=STRING> Add an earning to an accountName.\n" + " -p --payment<=STRING> Add a payment to an accountName.\n" "Account Options: [-dvD]\n" - " -d --delete Deletes specified account.\n" - " --force-delete Deletes the specified account without confirmation.\n" - " -v --value Gets the current value of the account.\n" - " -D --description<=STRING> Changes the description of the account.\n" + " -d --delete Deletes specified accountName.\n" + " --force-delete Deletes the specified accountName without confirmation.\n" + " -v --value Gets the current value of the accountName.\n" + " -D --description<=STRING> Changes the description of the accountName.\n" "Create Options: [-d]\n" - " -d --description<=STRING> Sets a description for an account.\n" + " -d --description<=STRING> Sets a description for an accountName.\n" "Earn Options: -v [-drD]\n" " -v --value= Value for earning.\n" " -d --description= Description for earning.\n" @@ -325,7 +325,7 @@ void MainOptHandler::help() { "budget -cAcct -eAcct -v10.00 -r\"./receipt.pdf\" -pAcct -v5.50 -r\"./payment.pdf\"\n" "\n" "Does the following in order:\n" - "Creates an account named Acct with no description.\n" + "Creates an accountName named Acct with no description.\n" "Earns 10.00 to it with a receipt.\n" "Pays 5.50 to it with a receipt." << std::endl; } diff --git a/src/optHandlers/paymentOperation.cpp b/src/optHandlers/paymentOperation.cpp new file mode 100644 index 0000000..9289166 --- /dev/null +++ b/src/optHandlers/paymentOperation.cpp @@ -0,0 +1,38 @@ +// +// Created by quentin on 1/17/23. +// + +#include +#include "paymentOperation.h" +#include "../database.h" +#include "../exceptions/badValue.h" +#include "../main.h" + +using namespace Budget::OptHandlers; + +void PaymentOperation::commit() { + Models::Account account = Database::getAccount(accountName, db); + + if (!flags.receipt.empty()) { + std::ifstream source(flags.receipt, std::ios::binary); + if (source.good()) { + std::string extension; + size_t pos = flags.receipt.find_last_of('.'); + if (pos != std::string::npos) { + extension = flags.receipt.substr(pos); + } + + std::ofstream dest(storageD + "receipts/receipt/" + std::to_string(account.id) + extension, std::ios::binary); + dest << source.rdbuf(); + source.close(); + dest.close(); + } + else { + throw Exceptions::BadValue("File " + flags.receipt + " does not exist"); + } + } + + Database::pay(&account, &flags, db); +} + +PaymentOperation::PaymentOperation(sqlite3 *db, std::string account) : Operation(db), accountName(std::move(account)) {} \ No newline at end of file diff --git a/src/optHandlers/PaymentOperation.h b/src/optHandlers/paymentOperation.h similarity index 95% rename from src/optHandlers/PaymentOperation.h rename to src/optHandlers/paymentOperation.h index 38802ab..7630c33 100644 --- a/src/optHandlers/PaymentOperation.h +++ b/src/optHandlers/paymentOperation.h @@ -27,7 +27,7 @@ namespace Budget::OptHandlers { Flags flags; private: - std::string account; + std::string accountName; }; }