Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
428 changes: 377 additions & 51 deletions src/main/kotlin/Main.kt

Large diffs are not rendered by default.

10 changes: 4 additions & 6 deletions src/main/kotlin/Utilities.kt → src/main/kotlin/Utils.kt
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand All @@ -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()
}
}
125 changes: 125 additions & 0 deletions src/main/kotlin/dataSource/FileStorage.kt
Original file line number Diff line number Diff line change
@@ -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<Category> {
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<Category>) {
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<Category>): List<Transaction> {
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<Transaction>) {
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}")
}
}
}
49 changes: 46 additions & 3 deletions src/main/kotlin/dataSource/FinanceTrackerDataSourceImpl.kt
Original file line number Diff line number Diff line change
Expand Up @@ -12,18 +12,42 @@ class FinanceTrackerDataSourceImpl : FinanceTrackerDataSource {
private val transactions: MutableList<Transaction> = emptyList<Transaction>().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<Category> {
Expand All @@ -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<Transaction> {
Expand All @@ -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
}

Expand Down
6 changes: 2 additions & 4 deletions src/main/kotlin/logic/categories/AddNewCategory.kt
Original file line number Diff line number Diff line change
@@ -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)
}
}
6 changes: 6 additions & 0 deletions src/main/kotlin/logic/models/Category.kt
Original file line number Diff line number Diff line change
Expand Up @@ -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
}
6 changes: 6 additions & 0 deletions src/main/kotlin/logic/models/Transaction.kt
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down
19 changes: 19 additions & 0 deletions src/main/kotlin/logic/statements/GetFinancialDetails.kt
Original file line number Diff line number Diff line change
@@ -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<Category> {
val categories = dataSource.getCategories()
return categories
}
}
10 changes: 5 additions & 5 deletions src/main/kotlin/logic/statements/ShowMonthlyTransactions.kt
Original file line number Diff line number Diff line change
@@ -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<Long> {
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)
Expand All @@ -29,13 +30,12 @@ class ShowMonthlyTransactions(private val dataSource: FinanceTrackerDataSource)
return (year % 4 == 0 && year % 100 != 0) || (year % 400 == 0)
}


fun displayMonthlySheet(months: List<Long>, year: Int): List<Transaction> {
val transactions = mutableListOf<Transaction>()

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
Expand Down
11 changes: 4 additions & 7 deletions src/main/kotlin/logic/transactions/AddNewTransaction.kt
Original file line number Diff line number Diff line change
@@ -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
}

14 changes: 6 additions & 8 deletions src/main/kotlin/logic/transactions/DeleteTransaction.kt
Original file line number Diff line number Diff line change
@@ -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)
}
}
Loading