From e814f8f037feeb0c7c6c5ec2ddded2529d0b1fcf Mon Sep 17 00:00:00 2001 From: Mousaber00 Date: Sat, 12 Apr 2025 16:11:32 +0200 Subject: [PATCH] finalize project and run test --- src/main/kotlin/Main.kt | 428 +++++++++++++++--- src/main/kotlin/{Utilities.kt => Utils.kt} | 10 +- src/main/kotlin/dataSource/FileStorage.kt | 125 +++++ .../FinanceTrackerDataSourceImpl.kt | 49 +- .../kotlin/logic/categories/AddNewCategory.kt | 6 +- src/main/kotlin/logic/models/Category.kt | 6 + src/main/kotlin/logic/models/Transaction.kt | 6 + .../logic/statements/GetFinancialDetails.kt | 19 + .../statements/ShowMonthlyTransactions.kt | 10 +- .../logic/transactions/AddNewTransaction.kt | 11 +- .../logic/transactions/DeleteTransaction.kt | 14 +- .../logic/transactions/EditTransaction.kt | 14 +- 12 files changed, 602 insertions(+), 96 deletions(-) rename src/main/kotlin/{Utilities.kt => Utils.kt} (88%) create mode 100644 src/main/kotlin/dataSource/FileStorage.kt create mode 100644 src/main/kotlin/logic/statements/GetFinancialDetails.kt diff --git a/src/main/kotlin/Main.kt b/src/main/kotlin/Main.kt index bb6d9cd..b6beea7 100644 --- a/src/main/kotlin/Main.kt +++ b/src/main/kotlin/Main.kt @@ -1,23 +1,50 @@ package org.qudus.squad +import kotlinx.datetime.Month +import org.qudus.squad.dataSource.FinanceTrackerDataSourceImpl +import org.qudus.squad.logic.FinanceTrackerDataSource +import org.qudus.squad.logic.categories.AddNewCategory +import org.qudus.squad.logic.categories.DeleteCategory +import org.qudus.squad.logic.categories.EditCategory +import org.qudus.squad.logic.models.Category +import org.qudus.squad.logic.models.Transaction +import org.qudus.squad.logic.models.TransactionType +import org.qudus.squad.logic.statements.GetFinancialTrackerDetails +import org.qudus.squad.logic.transactions.AddNewTransaction +import org.qudus.squad.logic.transactions.DeleteTransaction +import org.qudus.squad.logic.transactions.EditTransaction +import java.text.SimpleDateFormat +import java.util.* +fun returnFinanceTrackerData( + dataSource: FinanceTrackerDataSource +): FinanceTrackerDataSource { + return dataSource +} -import org.qudus.squad.testCases.testDeleteCategoryFunction -import org.qudus.squad.testCases.testMonthlyTransactionsCases +val dataSource = returnFinanceTrackerData(FinanceTrackerDataSourceImpl()) +val addNewTransactionImpl = AddNewTransaction(dataSource) +val editTransactionImpl = EditTransaction(dataSource) +val deleteTransactionImpl = DeleteTransaction(dataSource) +val addNewCategoryImpl = AddNewCategory(dataSource) +val editCategoryImpl = EditCategory(dataSource) +val deleteCategoryImpl = DeleteCategory(dataSource) +val getFinancialDetailsImp = GetFinancialTrackerDetails(dataSource) fun main() { - while (true) { println("\n=== Main Menu ===") - println("1. Transaction CRUD") - println("2. Category CRUD") - println("3. Monthly Summary") + println("1. Manage Transaction") + println("2. Manage Category") + println("3. Monthly Sheet") + println("4. Balance") println("0. Exit") print("Enter your choice: ") when (readlnOrNull()?.trim()) { - "1" -> transactionMenu() - "2" -> categoryMenu() - "3" -> getMonthlySummary() + "1" -> manageTransactionMenu() + "2" -> manageCategoryMenu() + "3" -> getMonthlyTransactions() + "4" -> getBalance() "0" -> { println("Goodbye!") return @@ -26,96 +53,395 @@ fun main() { else -> println("Invalid choice. Please try again.") } } - } -fun transactionMenu() { +//////////////////////////// MANAGE TRANSACTION MENU //////////////////////////( 0 -> 1 ) + +fun manageTransactionMenu() { while (true) { println("\n--- Transaction Menu ---") - println("1. Add Transaction") - println("2. View Transactions") - println("3. Update Transaction") + println("1. View Recent Transactions") + println("2. Add Transaction") + println("3. Edit Transaction") println("4. Delete Transaction") - println("5. View Transaction by ID") println("0. Back to Main Menu") print("Enter your choice: ") when (readlnOrNull()?.trim()) { - "1" -> {} + "1" -> viewAllTransactions() + "2" -> addNewTransaction() + "3" -> editExistingTransaction() + "4" -> deleteExistingTransaction() + "0" -> return + else -> println("Invalid choice. Please try again.") + } + } +} + +//////////////////////////// VIEW RECENT TRANSACTION //////////////////////////( 0 -> 1 -> 1 ) - "2" -> {} +fun viewAllTransactions() { + val transactions = dataSource.getAllTransactions() - "3" -> {} + if (transactions.isEmpty()) { + println("No transactions found.") + return + } + println("\n--- Recent Transactions ---") + displayTransactions(transactions) + println("\nTotal Income: ${dataSource.getTotalIncome()}") + println("Total Expenses: ${dataSource.getTotalExpenses()}") +} - "4" -> {} +fun displayTransactions(transactions: List) { + val dateFormat = SimpleDateFormat("dd-MM-yyyy") + transactions.forEach { transaction -> + val type = if (transaction.type == TransactionType.Deposit) "INCOME" else "EXPENSE" + val sign = if (transaction.type == TransactionType.Deposit) "+" else "-" + val date = dateFormat.format(Date(transaction.timestamp)) + println("ID: ${transaction.id} | $type | $sign${transaction.amount} | Category: ${transaction.category.name} | Date: $date") + } +} - "5" -> displayTransactionById() +fun displayTransactionById() { + print("Enter transaction id to view: ") + val id = readlnOrNull()?.toIntOrNull() + if (id == null || id.toString().isEmpty()) { + println("ID should not be empty!") + return + } +} - "0" -> return +//////////////////////////// ADD NEW TRANSACTION MENU //////////////////////////( 0 -> 1 -> 2) - else -> println("Invalid choice. Please try again.") +fun addNewTransaction() { + val categories = dataSource.getCategories() + if (categories.isEmpty()) { + println("No categories available. Please add a category first.") + return + } + ///TRANSACTION TYPE SELECTION + println("Select transaction type:") + println("1. Income (Deposit)") + println("2. Expense (Withdraw)") + print("Enter choice: ") + val typeSelected = readlnOrNull()?.trim() ?: "" + val transactionType = when (typeSelected) { + "1" -> TransactionType.Deposit + "2" -> TransactionType.Withdraw + else -> { + println("Invalid choice. Transaction canceled.") + return + } + } + + ///TRANSACTION CATEGORY SELECTION + println("\nAvailable Categories:") + categories.forEachIndexed { index, category -> + println("${index + 1}. ${category.name}") + } + print("Select Category: ") + val categorySelected = readlnOrNull()?.trim()?.toIntOrNull()?.minus(1) + + if (categorySelected == null || categorySelected < 0 || categorySelected >= categories.size) { + println("Invalid category selection. Transaction canceled.") + return + } + + ///TRANSACTION AMOUNT SELECTION + print("Enter amount: ") + val amountSelected = readlnOrNull()?.trim() ?: "" + val amount = amountSelected.toDoubleOrNull() + + if (amount == null || amount <= 0) { + println("Invalid amount. Amount must be a positive number.") + return + } + + ///TRANSACTION DATE SELECTION + print("Enter date (dd-MM-yyyy) or leave empty for today's Date: ") + val dateSelected = readlnOrNull()?.trim() ?: "" + + val timestamp = if (dateSelected.isEmpty()) { + System.currentTimeMillis() + } else { + try { + Utils.parseDateStringToTimestamp(dateSelected) + } catch (e: Exception) { + println("Invalid date format. Using current date.") + System.currentTimeMillis() + } + } + ///COMPLETE TRANSACTION + val transaction = Transaction( + type = transactionType, + amount = amount, + timestamp = timestamp, + category = categories[categorySelected] + ) + if (addNewTransactionImpl.addNewTransaction(transaction)) { + println("Transaction added successfully with ID: ${transaction.id}") + } else { + println("Failed to add transaction.") + } +} + +//////////////////////////// EDIT EXISTING TRANSACTION //////////////////////////( 0 -> 1 -> 3 ) + +fun editExistingTransaction() { + print("Enter transaction ID to update: ") + val id = readlnOrNull()?.toIntOrNull() + + if (id == null) { + println("Invalid ID") + return + } + + val transaction = dataSource.getTransactionById(id) + if (transaction == null) { + println("Transaction with ID $id not found.") + return + } + println("Current transaction details:") + displayTransactions(listOf(transaction)) + + //SELECT NEW TYPE + println("\nSelect new transaction type:") + println("1. Income (Deposit)") + println("2. Expense (Withdraw)") + println("3. Keep current (${transaction.type})") + print("Enter choice: ") + + val typeChoice = readlnOrNull()?.trim() ?: "3" + val newType = when (typeChoice) { + "1" -> TransactionType.Deposit + "2" -> TransactionType.Withdraw + else -> transaction.type + } + + //SELECT NEW AMOUNT + print("Enter new amount (current: ${transaction.amount}) or leave empty to keep current: ") + val amountSelected = readlnOrNull()?.trim() ?: "" + val newAmount = + if (amountSelected.isEmpty()) transaction.amount else amountSelected.toDoubleOrNull() ?: transaction.amount + + //SELECT NEW CATEGORY + val categories = dataSource.getCategories() + println("\nAvailable Categories:") + categories.forEachIndexed { index, category -> + println("${index + 1}. ${category.name} (ID: ${category.id})") + } + println("${categories.size + 1}. Keep current (${transaction.category.name})") + + print("Enter category number: ") + val categoryIndexStr = readlnOrNull()?.trim() ?: "" + val categoryIndex = categoryIndexStr.toIntOrNull()?.minus(1) ?: categories.size + + val newCategory = + if (categoryIndex < 0 || categoryIndex >= categories.size) transaction.category else categories[categoryIndex] + + //SELECT NEW DATE + print("Enter new date (dd-MM-yyyy) or leave empty to keep current: ") + val dateSelected = readlnOrNull()?.trim() ?: "" + + val newTimestamp = if (dateSelected.isEmpty()) { + transaction.timestamp + } else { + try { + Utils.parseDateStringToTimestamp(dateSelected) + } catch (e: Exception) { + println("Invalid date format. Keeping current date.") + transaction.timestamp } } + + // Use the EditTransaction class methods instead of direct data source + val amountUpdated = editTransactionImpl.editTransactionAmount(transaction.id, newAmount) + val typeUpdated = editTransactionImpl.editTransactionType(transaction.id, newType) + val categoryUpdated = editTransactionImpl.editTransactionCategory(transaction.id, newCategory) + + // Only try to update timestamp if it was changed + val timestampUpdated = if (newTimestamp != transaction.timestamp) { + val dateFormat = SimpleDateFormat("dd-MM-yyyy") + val formattedDate = dateFormat.format(Date(newTimestamp)) + editTransactionImpl.editTransactionTimeStamp(transaction.id, formattedDate) + } else { + true // No change needed + } + + if (amountUpdated && typeUpdated && categoryUpdated && timestampUpdated) { + println("Transaction updated successfully.") + } else { + println("Some fields failed to update.") + } } -fun categoryMenu() { + +//////////////////////////// DELETE EXISTING TRANSACTION //////////////////////////( 0 -> 1 -> 4 ) + +fun deleteExistingTransaction() { + print("Enter transaction ID to delete: ") + val id = readlnOrNull()?.toIntOrNull() + if (id == null) { + println("Invalid ID") + return + } + if (deleteTransactionImpl.deleteTransaction(id)) { + println("Transaction with ID $id deleted successfully.") + } else { + println("Failed to delete transaction. ID may not exist.") + } +} + +/**/////////////////////////// MANAGE CATEGORIES MENU //////////////////////////**( 0 -> 2 ) + +fun manageCategoryMenu() { while (true) { println("\n--- Category Menu ---") - println("1. Add Category") - println("2. View Categories") - println("3. Update Category") + println("1. View Categories") + println("2. Add Category") + println("3. Edit Category") println("4. Delete Category") println("5. View Category by ID") println("0. Back to Main Menu") print("Enter your choice: ") when (readlnOrNull()?.trim()) { - "1" -> { - print("Enter category name: ") - val name = readlnOrNull() ?: "" - } + ///VIEW ALL CATEGORIES + "1" -> displayCategories() + + ///ADD NEW CATEGORY "2" -> { - println("\nCategories:") + print("Enter category name: ") + val selectedName = readlnOrNull()?.trim() ?: "" + if (selectedName.isEmpty()) { + println("Category name cannot be empty.") + } else { + val category = Category(name = selectedName) + if (addNewCategoryImpl.addNewCategory(category)) { + println("Category added successfully with ID: ${category.id}") + } else { + println("Failed to add category.") + } + } } + ///EDIT CATEGORY "3" -> { print("Enter category id to update: ") - val id = readlnOrNull()?.toIntOrNull() ?: 0 + val id = readlnOrNull()?.toIntOrNull() + if (id == null) { + println("Invalid ID") + continue + } + val existingCategory = dataSource.getCategoryById(id) + if (existingCategory == null) { + println("Category with ID $id not found.") + continue + } print("Enter new category name: ") - val name = readlnOrNull() ?: "" + val name = readlnOrNull()?.trim() ?: "" + if (name.isEmpty()) { + println("Category name cannot be empty.") + continue + } + if (editCategoryImpl.editCategory(id, name)) { + println("Category updated successfully.") + } else { + println("Failed to update category.") + } } - + ///DELETE EXISTING CATEGORY "4" -> { + displayCategories() print("Enter category id to delete: ") - val id = readlnOrNull()?.toIntOrNull() ?: 0 - + val id = readlnOrNull()?.toIntOrNull() + if (id == null) { + println("Invalid ID") + continue + } + val transactions = dataSource.getTransactionsByCategory(id) + if (transactions.isNotEmpty()) { + println("Cannot delete category with ID $id - it has ${transactions.size} associated transactions.") + continue + } + val categoryToDelete = dataSource.getCategoryById(id) + if (categoryToDelete != null) { + if (deleteCategoryImpl.removeCategory(categoryToDelete)) { + println("Category deleted successfully.") + } else { + println("Failed to delete category. ID may not exist.") + } + } else { + println("Category not found with ID: $id") + } } - "5" -> displayCategoryById() - "0" -> return else -> println("Invalid choice. Please try again.") } } } -fun getMonthlySummary() { - // TODO() +fun displayCategories() { + val categories = dataSource.getCategories() + println("\nCategories:") + if (categories.isEmpty()) { + println("No categories found.") + } else { + categories.forEach { category -> + println("ID: ${category.id} | Name: ${category.name}") + } + } } -fun displayTransactionById() { - print("Enter transaction id to view: ") - val id = readlnOrNull()?.toIntOrNull() - if(id == null || id.toString().isEmpty()){ - println("ID should not be empty!") +/**/////////////////////////// MONTHLY SHEET MENU //////////////////////////**( 0 -> 3 ) + +fun getMonthlyTransactions() { + print("Enter month (e.g., JAN, FEB, MAR): ") + val month = readlnOrNull()?.trim()?.uppercase() ?: "" + + print("Enter year (e.g., 2023): ") + val year = readlnOrNull()?.trim()?.toIntOrNull() ?: Calendar.getInstance().get(Calendar.YEAR) + + val monthEnum = Month.entries.find { it.name == month } + if (monthEnum == null) { + println("Invalid month. Please enter a valid three-letter month abbreviation (e.g., JAN, FEB).") return } -} -fun displayCategoryById() { - print("Enter category id to view: ") - val id = readlnOrNull()?.toIntOrNull() - if(id == null || id.toString().isEmpty()){ - println("ID should not be empty!") + val calendar = Calendar.getInstance() + calendar.set(Calendar.YEAR, year) + calendar.set(Calendar.MONTH, monthEnum.value) + calendar.set(Calendar.DAY_OF_MONTH, 1) + val startTime = calendar.timeInMillis + + calendar.add(Calendar.MONTH, 1) + calendar.add(Calendar.MILLISECOND, -1) + val endTime = calendar.timeInMillis + + val transactions = dataSource.getTransactionsInTimeRange(startTime, endTime) + + println("\n=== Monthly Summary for $month $year ===") + if (transactions.isEmpty()) { + println("No transactions found for this period.") return } + + val income = transactions.filter { it.type == TransactionType.Deposit }.sumOf { it.amount } + val expenses = transactions.filter { it.type == TransactionType.Withdraw }.sumOf { it.amount } + val balance = income - expenses + + displayTransactions(transactions) + + println("\nSummary:") + println("Total Income: $income") + println("Total Expenses: $expenses") + println("Net Balance: $balance") +} + +/**/////////////////////////// VIEW CURRENT BALANCE MENU //////////////////////////**( 0 -> 4 ) + +fun getBalance() { + val balance = getFinancialDetailsImp.getBalance() + println("Your Balance Is : $balance") } \ No newline at end of file diff --git a/src/main/kotlin/Utilities.kt b/src/main/kotlin/Utils.kt similarity index 88% rename from src/main/kotlin/Utilities.kt rename to src/main/kotlin/Utils.kt index 9e1add7..cefe6a3 100644 --- a/src/main/kotlin/Utilities.kt +++ b/src/main/kotlin/Utils.kt @@ -2,7 +2,7 @@ package org.qudus.squad import kotlinx.datetime.* -object Utilities { +object Utils { fun timestampToFormattedDate(timestamp: Long): String { val dateTime = Instant.fromEpochMilliseconds(timestamp).toLocalDateTime(TimeZone.currentSystemDefault()) return "%02d-%02d-%d".format(dateTime.dayOfMonth, dateTime.monthNumber, dateTime.year) @@ -11,17 +11,15 @@ object Utilities { fun parseDateStringToTimestamp(dateString: String): Long { val parts = dateString.split("-") require(parts.size == 3) { "Date must be in dd-MM-yyyy format" } - val day = parts[0].toInt() val month = parts[1].toInt() val year = parts[2].toInt() - val date = LocalDate(year, month, day) val dateTime = date.atStartOfDayIn(TimeZone.currentSystemDefault()) return dateTime.toEpochMilliseconds() } - fun getCurrentDate() : Long{ - return Clock.System.now().toEpochMilliseconds() - } + fun getCurrentDate(): Long { + return Clock.System.now().toEpochMilliseconds() + } } \ No newline at end of file diff --git a/src/main/kotlin/dataSource/FileStorage.kt b/src/main/kotlin/dataSource/FileStorage.kt new file mode 100644 index 0000000..56428aa --- /dev/null +++ b/src/main/kotlin/dataSource/FileStorage.kt @@ -0,0 +1,125 @@ +package org.qudus.squad.dataSource + +import org.qudus.squad.logic.models.* +import java.io.File + +object FileDatabase { + private const val CATEGORIES_FILE = "categories.txt" + private const val TRANSACTIONS_FILE = "transactions.txt" + private const val COUNTERS_FILE = "counters.txt" + + fun loadCategories(): List { + val file = File(CATEGORIES_FILE) + if (!file.exists()) return emptyList() + + return try { + file.readLines().mapNotNull { line -> + val parts = line.split("|") + if (parts.size >= 2) { + val id = parts[0].toIntOrNull() ?: return@mapNotNull null + val name = parts[1] + Category(id = id, name = name) + } else null + } + } catch (e: Exception) { + println("Error loading categories: ${e.message}") + emptyList() + } + } + + fun saveCategories(categories: List) { + val file = File(CATEGORIES_FILE) + try { + file.bufferedWriter().use { writer -> + categories.forEach { category -> + writer.write("${category.id}|${category.name}") + writer.newLine() + } + } + } catch (e: Exception) { + println("Error saving categories: ${e.message}") + } + } + + fun loadTransactions(categories: List): List { + val file = File(TRANSACTIONS_FILE) + if (!file.exists()) return emptyList() + + return try { + file.readLines().mapNotNull { line -> + val parts = line.split("|") + if (parts.size >= 5) { + val id = parts[0].toIntOrNull() ?: return@mapNotNull null + val typeStr = parts[1] + val type = when (typeStr) { + "Deposit" -> TransactionType.Deposit + "Withdraw" -> TransactionType.Withdraw + else -> return@mapNotNull null + } + val amount = parts[2].toDoubleOrNull() ?: return@mapNotNull null + val timestamp = parts[3].toLongOrNull() ?: return@mapNotNull null + val categoryId = parts[4].toIntOrNull() ?: return@mapNotNull null + + val category = categories.find { it.id == categoryId } + ?: return@mapNotNull null + + Transaction( + id = id, + type = type, + amount = amount, + timestamp = timestamp, + category = category + ) + } else null + } + } catch (e: Exception) { + println("Error loading transactions: ${e.message}") + emptyList() + } + } + + fun saveTransactions(transactions: List) { + val file = File(TRANSACTIONS_FILE) + try { + file.bufferedWriter().use { writer -> + transactions.forEach { transaction -> + writer.write("${transaction.id}|${transaction.type}|${transaction.amount}|${transaction.timestamp}|${transaction.category.id}") + writer.newLine() + } + } + } catch (e: Exception) { + println("Error saving transactions: ${e.message}") + } + } + + fun loadCounters() { + val file = File(COUNTERS_FILE) + if (!file.exists()) return + + try { + val lines = file.readLines() + if (lines.size >= 2) { + val categoryCounter = lines[0].toIntOrNull() ?: 0 + val transactionCounter = lines[1].toIntOrNull() ?: 0 + + CategoryIdGenerator.resetCounter(categoryCounter) + TransactionIdGenerator.resetCounter(transactionCounter) + } + } catch (e: Exception) { + println("Error loading counters: ${e.message}") + } + } + + fun saveCounters() { + val file = File(COUNTERS_FILE) + try { + file.bufferedWriter().use { writer -> + writer.write(CategoryIdGenerator.getCurrentCounter().toString()) + writer.newLine() + writer.write(TransactionIdGenerator.getCurrentCounter().toString()) + } + } catch (e: Exception) { + println("Error saving counters: ${e.message}") + } + } +} \ No newline at end of file diff --git a/src/main/kotlin/dataSource/FinanceTrackerDataSourceImpl.kt b/src/main/kotlin/dataSource/FinanceTrackerDataSourceImpl.kt index 81c1e0a..a159d5f 100644 --- a/src/main/kotlin/dataSource/FinanceTrackerDataSourceImpl.kt +++ b/src/main/kotlin/dataSource/FinanceTrackerDataSourceImpl.kt @@ -12,18 +12,42 @@ class FinanceTrackerDataSourceImpl : FinanceTrackerDataSource { private val transactions: MutableList = emptyList().toMutableList() val categoryList get() = this._categories + init { + FileDatabase.loadCounters() + + val loadedCategories = FileDatabase.loadCategories() + if (loadedCategories.isNotEmpty()) { + _categories.clear() + _categories.addAll(loadedCategories) + } + + val loadedTransactions = FileDatabase.loadTransactions(_categories) + if (loadedTransactions.isNotEmpty()) { + transactions.clear() + transactions.addAll(loadedTransactions) + } + } + override fun addCategory(category: Category): Boolean { if (category.name.isNotEmpty()) { this._categories.add(category) + FileDatabase.saveCategories(_categories) + FileDatabase.saveCounters() return true } return false } override fun removeCategory(categoryId: Int): Boolean { - return this._categories.removeIf { + val result = this._categories.removeIf { it.id == categoryId } + + if (result) { + FileDatabase.saveCategories(_categories) + } + + return result } override fun getCategories(): List { @@ -39,17 +63,32 @@ class FinanceTrackerDataSourceImpl : FinanceTrackerDataSource { val index = categoryList.indexOfFirst { it.id == category.id } if (index.indexNotFound()) return false categoryList[index] = category + FileDatabase.saveCategories(_categories) return true } override fun addNewTransaction(transaction: Transaction): Boolean { - return transactions.add(transaction) + val result = transactions.add(transaction) + + // Save changes + if (result) { + FileDatabase.saveTransactions(transactions) + FileDatabase.saveCounters() + } + + return result } override fun removeTransaction(transactionId: Int): Boolean { - return transactions.removeIf { + val result = transactions.removeIf { it.id == transactionId } + + if (result) { + FileDatabase.saveTransactions(transactions) + } + + return result } override fun getAllTransactions(): List { @@ -71,7 +110,11 @@ class FinanceTrackerDataSourceImpl : FinanceTrackerDataSource { override fun editExistingCategory(transaction: Transaction): Boolean { val index = transactions.indexOfFirst { it.id == transaction.id } if (index.indexNotFound()) return false + transactions[index] = transaction + + FileDatabase.saveTransactions(transactions) + return true } diff --git a/src/main/kotlin/logic/categories/AddNewCategory.kt b/src/main/kotlin/logic/categories/AddNewCategory.kt index c63cd17..05217fa 100644 --- a/src/main/kotlin/logic/categories/AddNewCategory.kt +++ b/src/main/kotlin/logic/categories/AddNewCategory.kt @@ -1,13 +1,11 @@ package org.qudus.squad.logic.categories - import org.qudus.squad.logic.FinanceTrackerDataSource import org.qudus.squad.logic.models.Category class AddNewCategory( private val dataSource:FinanceTrackerDataSource ) { - - fun addNewCategory(category: Category){ - dataSource.addCategory(category) + fun addNewCategory(category: Category): Boolean { + return dataSource.addCategory(category) } } \ No newline at end of file diff --git a/src/main/kotlin/logic/models/Category.kt b/src/main/kotlin/logic/models/Category.kt index be4e1a1..822b129 100644 --- a/src/main/kotlin/logic/models/Category.kt +++ b/src/main/kotlin/logic/models/Category.kt @@ -8,4 +8,10 @@ data class Category( object CategoryIdGenerator { private var counter = 0 fun nextId(): Int = ++counter + + fun resetCounter(value: Int) { + counter = value + } + + fun getCurrentCounter(): Int = counter } \ No newline at end of file diff --git a/src/main/kotlin/logic/models/Transaction.kt b/src/main/kotlin/logic/models/Transaction.kt index d192fc2..de21ba5 100644 --- a/src/main/kotlin/logic/models/Transaction.kt +++ b/src/main/kotlin/logic/models/Transaction.kt @@ -11,6 +11,12 @@ data class Transaction( object TransactionIdGenerator { private var counter = 0 fun nextId(): Int = ++counter + + fun resetCounter(value: Int) { + counter = value + } + + fun getCurrentCounter(): Int = counter } enum class TransactionType { diff --git a/src/main/kotlin/logic/statements/GetFinancialDetails.kt b/src/main/kotlin/logic/statements/GetFinancialDetails.kt new file mode 100644 index 0000000..192f8e7 --- /dev/null +++ b/src/main/kotlin/logic/statements/GetFinancialDetails.kt @@ -0,0 +1,19 @@ +package org.qudus.squad.logic.statements + + +import org.qudus.squad.logic.FinanceTrackerDataSource +import org.qudus.squad.logic.models.Category + +class GetFinancialTrackerDetails( + private val dataSource: FinanceTrackerDataSource +) { + fun getBalance(): Double { + val balance = dataSource.getBalance() + return balance + } + + fun getAllCategories(): List { + val categories = dataSource.getCategories() + return categories + } +} \ No newline at end of file diff --git a/src/main/kotlin/logic/statements/ShowMonthlyTransactions.kt b/src/main/kotlin/logic/statements/ShowMonthlyTransactions.kt index a1b5288..840275d 100644 --- a/src/main/kotlin/logic/statements/ShowMonthlyTransactions.kt +++ b/src/main/kotlin/logic/statements/ShowMonthlyTransactions.kt @@ -1,20 +1,21 @@ package org.qudus.squad.logic.statements + import kotlinx.datetime.LocalDate import kotlinx.datetime.Month import kotlinx.datetime.TimeZone import kotlinx.datetime.atStartOfDayIn -import org.qudus.squad.Utilities +import org.qudus.squad.Utils import org.qudus.squad.logic.FinanceTrackerDataSource import org.qudus.squad.logic.models.Transaction -class ShowMonthlyTransactions(private val dataSource: FinanceTrackerDataSource) { +class ShowMonthlyTransactions(private val financeTrackerImplementation: FinanceTrackerDataSource) { fun getDaysInMonthInMillis(year: Int, month: Int): List { val months = Month.entries[month - 1] val isLeapYear = isLeapYear(year) val daysInMonth = months.length(isLeapYear) - val currentDate = Utilities.getCurrentDate() + val currentDate = Utils.getCurrentDate() return (1..daysInMonth).mapNotNull { day -> val dateInMillis = LocalDate(year, months, day) @@ -29,13 +30,12 @@ class ShowMonthlyTransactions(private val dataSource: FinanceTrackerDataSource) return (year % 4 == 0 && year % 100 != 0) || (year % 400 == 0) } - fun displayMonthlySheet(months: List, year: Int): List { val transactions = mutableListOf() for (startOfDay in months) { val endOfDay = startOfDay + 86_400_000L - val dailyTransactions = dataSource.getTransactionsInTimeRange(startOfDay, endOfDay) + val dailyTransactions = financeTrackerImplementation.getTransactionsInTimeRange(startOfDay, endOfDay) transactions.addAll(dailyTransactions) } return transactions diff --git a/src/main/kotlin/logic/transactions/AddNewTransaction.kt b/src/main/kotlin/logic/transactions/AddNewTransaction.kt index 7a7e41c..0cef359 100644 --- a/src/main/kotlin/logic/transactions/AddNewTransaction.kt +++ b/src/main/kotlin/logic/transactions/AddNewTransaction.kt @@ -1,18 +1,15 @@ package org.qudus.squad.logic.transactions - import org.qudus.squad.logic.FinanceTrackerDataSource import org.qudus.squad.logic.models.Transaction - class AddNewTransaction( private val dataSource: FinanceTrackerDataSource ) { - fun addNewTransaction(transaction: Transaction) { - if (isAmountValid(transaction)) { + fun addNewTransaction(transaction: Transaction):Boolean { + return if (isAmountValid(transaction)) { dataSource.addNewTransaction(transaction) - } + }else false } - - fun isAmountValid(transaction: Transaction): Boolean = transaction.amount < 0 + fun isAmountValid(transaction: Transaction): Boolean = transaction.amount > 0 } diff --git a/src/main/kotlin/logic/transactions/DeleteTransaction.kt b/src/main/kotlin/logic/transactions/DeleteTransaction.kt index 1f1f97b..0982437 100644 --- a/src/main/kotlin/logic/transactions/DeleteTransaction.kt +++ b/src/main/kotlin/logic/transactions/DeleteTransaction.kt @@ -1,13 +1,11 @@ package org.qudus.squad.logic.transactions - -import org.qudus.squad.dataSource.FinanceTrackerDataSourceImpl import org.qudus.squad.logic.FinanceTrackerDataSource -class DeleteTransaction(private val dataSource: FinanceTrackerDataSourceImpl) { - fun deleteTransaction(transactionId: Int):Boolean{ - val transaction=dataSource.getTransactionById(transactionId) - return if(transaction ==null){ - false - }else dataSource.removeTransaction(transactionId) +class DeleteTransaction(private val dataSource: FinanceTrackerDataSource) { + fun deleteTransaction(transactionId: Int): Boolean { + val transaction = dataSource.getTransactionById(transactionId) + return if (transaction == null) { + false + } else dataSource.removeTransaction(transactionId) } } \ No newline at end of file diff --git a/src/main/kotlin/logic/transactions/EditTransaction.kt b/src/main/kotlin/logic/transactions/EditTransaction.kt index b69e6fd..d2b981a 100644 --- a/src/main/kotlin/logic/transactions/EditTransaction.kt +++ b/src/main/kotlin/logic/transactions/EditTransaction.kt @@ -1,5 +1,5 @@ package org.qudus.squad.logic.transactions -import org.qudus.squad.Utilities +import org.qudus.squad.Utils import org.qudus.squad.logic.FinanceTrackerDataSource import org.qudus.squad.logic.models.Category import org.qudus.squad.logic.models.TransactionType @@ -22,16 +22,13 @@ class EditTransaction( fun editTransactionTimeStamp(transactionId: Int, newTimestamp: String): Boolean { val parts = newTimestamp.split("-") if (parts.size != 3) return false - val day = parts[0].toInt() val month = parts[1].toInt() val year = parts[2].toInt() - if (day !in 1..31 || month !in 1..12 || year !in 1..2025) return false - val currentTransaction = datastore.getTransactionById(transactionId) if (currentTransaction != null) { - val newTimestampLong = Utilities.parseDateStringToTimestamp(newTimestamp) + val newTimestampLong = Utils.parseDateStringToTimestamp(newTimestamp) val editedTransaction = currentTransaction.copy(timestamp = newTimestampLong) return datastore.editExistingCategory(editedTransaction) } @@ -39,9 +36,7 @@ class EditTransaction( } fun editTransactionCategory(transactionId: Int, category: Category): Boolean { - val currentTransaction = datastore.getTransactionById(transactionId) - if (currentTransaction != null) { val editedTransaction = currentTransaction.copy(category = category) datastore.editExistingCategory(editedTransaction) @@ -51,7 +46,6 @@ class EditTransaction( fun editTransactionType(transactionId: Int, transactionType: TransactionType): Boolean { val currentTransaction = datastore.getTransactionById(transactionId) - if (currentTransaction != null) { val editedTransaction = currentTransaction.copy(type = transactionType) datastore.editExistingCategory(editedTransaction) @@ -59,12 +53,8 @@ class EditTransaction( return false } - private fun isValidAmount(transactionAmount: Double): Boolean { if (transactionAmount < 0) return false return true } - - - } \ No newline at end of file