mirror of
https://github.com/koloideal/Casha.git
synced 2026-06-10 10:25:28 +03:00
update
This commit is contained in:
@@ -13,12 +13,15 @@ class AppDatabase extends _$AppDatabase {
|
|||||||
AppDatabase() : super(_openConnection());
|
AppDatabase() : super(_openConnection());
|
||||||
|
|
||||||
@override
|
@override
|
||||||
int get schemaVersion => 4;
|
int get schemaVersion => 5;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
MigrationStrategy get migration => MigrationStrategy(
|
MigrationStrategy get migration => MigrationStrategy(
|
||||||
onUpgrade: (migrator, from, to) async {
|
onUpgrade: (migrator, from, to) async {
|
||||||
|
print('--- DATABASE MIGRATION: from=$from to=$to ---');
|
||||||
|
|
||||||
if (from == 1) {
|
if (from == 1) {
|
||||||
|
print('Migration: Creating accounts table');
|
||||||
await migrator.createTable(accounts);
|
await migrator.createTable(accounts);
|
||||||
await customStatement(
|
await customStatement(
|
||||||
'INSERT INTO accounts (name, is_main, currency, sort_order, created_at) '
|
'INSERT INTO accounts (name, is_main, currency, sort_order, created_at) '
|
||||||
@@ -26,11 +29,41 @@ class AppDatabase extends _$AppDatabase {
|
|||||||
['main', 1, 'USD', 0, DateTime.now().millisecondsSinceEpoch],
|
['main', 1, 'USD', 0, DateTime.now().millisecondsSinceEpoch],
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (from == 2) {
|
if (from == 2) {
|
||||||
|
print('Migration: Adding currency column to accounts');
|
||||||
await customStatement(
|
await customStatement(
|
||||||
'ALTER TABLE accounts ADD COLUMN currency TEXT NOT NULL DEFAULT "USD"',
|
'ALTER TABLE accounts ADD COLUMN currency TEXT NOT NULL DEFAULT "USD"',
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Add account_id column to transactions if upgrading from version < 5
|
||||||
|
if (from < 5) {
|
||||||
|
print('Migration: Adding account_id column to transactions');
|
||||||
|
try {
|
||||||
|
// Check if column exists first
|
||||||
|
final result = await customSelect(
|
||||||
|
'PRAGMA table_info(transactions)',
|
||||||
|
).get();
|
||||||
|
|
||||||
|
final hasAccountId = result.any((row) => row.data['name'] == 'account_id');
|
||||||
|
|
||||||
|
if (!hasAccountId) {
|
||||||
|
print('Migration: account_id column does not exist, adding it now');
|
||||||
|
await customStatement(
|
||||||
|
'ALTER TABLE transactions ADD COLUMN account_id INTEGER NOT NULL DEFAULT 1',
|
||||||
|
);
|
||||||
|
print('Migration: account_id column added successfully');
|
||||||
|
} else {
|
||||||
|
print('Migration: account_id column already exists, skipping');
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
print('Migration: Error adding account_id column: $e');
|
||||||
|
// If the column already exists, this will fail, which is fine
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
print('--- DATABASE MIGRATION: COMPLETE ---');
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|||||||
@@ -122,7 +122,8 @@ class $TransactionsTable extends Transactions
|
|||||||
aliasedName,
|
aliasedName,
|
||||||
false,
|
false,
|
||||||
type: DriftSqlType.int,
|
type: DriftSqlType.int,
|
||||||
requiredDuringInsert: true,
|
requiredDuringInsert: false,
|
||||||
|
defaultValue: const Constant(1),
|
||||||
);
|
);
|
||||||
static const VerificationMeta _createdAtMeta = const VerificationMeta(
|
static const VerificationMeta _createdAtMeta = const VerificationMeta(
|
||||||
'createdAt',
|
'createdAt',
|
||||||
@@ -241,8 +242,6 @@ class $TransactionsTable extends Transactions
|
|||||||
_accountIdMeta,
|
_accountIdMeta,
|
||||||
accountId.isAcceptableOrUnknown(data['account_id']!, _accountIdMeta),
|
accountId.isAcceptableOrUnknown(data['account_id']!, _accountIdMeta),
|
||||||
);
|
);
|
||||||
} else if (isInserting) {
|
|
||||||
context.missing(_accountIdMeta);
|
|
||||||
}
|
}
|
||||||
if (data.containsKey('created_at')) {
|
if (data.containsKey('created_at')) {
|
||||||
context.handle(
|
context.handle(
|
||||||
@@ -567,15 +566,14 @@ class TransactionsCompanion extends UpdateCompanion<Transaction> {
|
|||||||
this.lastOccurrence = const Value.absent(),
|
this.lastOccurrence = const Value.absent(),
|
||||||
this.currency = const Value.absent(),
|
this.currency = const Value.absent(),
|
||||||
this.currencyCode = const Value.absent(),
|
this.currencyCode = const Value.absent(),
|
||||||
required int accountId,
|
this.accountId = const Value.absent(),
|
||||||
this.createdAt = const Value.absent(),
|
this.createdAt = const Value.absent(),
|
||||||
this.rowid = const Value.absent(),
|
this.rowid = const Value.absent(),
|
||||||
}) : id = Value(id),
|
}) : id = Value(id),
|
||||||
amount = Value(amount),
|
amount = Value(amount),
|
||||||
category = Value(category),
|
category = Value(category),
|
||||||
type = Value(type),
|
type = Value(type),
|
||||||
date = Value(date),
|
date = Value(date);
|
||||||
accountId = Value(accountId);
|
|
||||||
static Insertable<Transaction> custom({
|
static Insertable<Transaction> custom({
|
||||||
Expression<String>? id,
|
Expression<String>? id,
|
||||||
Expression<double>? amount,
|
Expression<double>? amount,
|
||||||
@@ -2324,7 +2322,7 @@ typedef $$TransactionsTableCreateCompanionBuilder =
|
|||||||
Value<DateTime?> lastOccurrence,
|
Value<DateTime?> lastOccurrence,
|
||||||
Value<String> currency,
|
Value<String> currency,
|
||||||
Value<String> currencyCode,
|
Value<String> currencyCode,
|
||||||
required int accountId,
|
Value<int> accountId,
|
||||||
Value<DateTime> createdAt,
|
Value<DateTime> createdAt,
|
||||||
Value<int> rowid,
|
Value<int> rowid,
|
||||||
});
|
});
|
||||||
@@ -2608,7 +2606,7 @@ class $$TransactionsTableTableManager
|
|||||||
Value<DateTime?> lastOccurrence = const Value.absent(),
|
Value<DateTime?> lastOccurrence = const Value.absent(),
|
||||||
Value<String> currency = const Value.absent(),
|
Value<String> currency = const Value.absent(),
|
||||||
Value<String> currencyCode = const Value.absent(),
|
Value<String> currencyCode = const Value.absent(),
|
||||||
required int accountId,
|
Value<int> accountId = const Value.absent(),
|
||||||
Value<DateTime> createdAt = const Value.absent(),
|
Value<DateTime> createdAt = const Value.absent(),
|
||||||
Value<int> rowid = const Value.absent(),
|
Value<int> rowid = const Value.absent(),
|
||||||
}) => TransactionsCompanion.insert(
|
}) => TransactionsCompanion.insert(
|
||||||
|
|||||||
@@ -12,7 +12,7 @@ class Transactions extends Table {
|
|||||||
DateTimeColumn get lastOccurrence => dateTime().nullable()();
|
DateTimeColumn get lastOccurrence => dateTime().nullable()();
|
||||||
TextColumn get currency => text().withDefault(const Constant('\$'))();
|
TextColumn get currency => text().withDefault(const Constant('\$'))();
|
||||||
TextColumn get currencyCode => text().withDefault(const Constant('USD'))();
|
TextColumn get currencyCode => text().withDefault(const Constant('USD'))();
|
||||||
IntColumn get accountId => integer()();
|
IntColumn get accountId => integer().withDefault(const Constant(1))();
|
||||||
DateTimeColumn get createdAt => dateTime().withDefault(currentDateAndTime)();
|
DateTimeColumn get createdAt => dateTime().withDefault(currentDateAndTime)();
|
||||||
|
|
||||||
@override
|
@override
|
||||||
|
|||||||
@@ -24,7 +24,7 @@ class AccountRepository {
|
|||||||
// Fallback: insert default account if none exists
|
// Fallback: insert default account if none exists
|
||||||
await _db.into(_db.accounts).insert(
|
await _db.into(_db.accounts).insert(
|
||||||
AccountsCompanion.insert(
|
AccountsCompanion.insert(
|
||||||
name: 'Main',
|
name: 'main',
|
||||||
isMain: const Value(true),
|
isMain: const Value(true),
|
||||||
currency: const Value('USD'),
|
currency: const Value('USD'),
|
||||||
sortOrder: const Value(0),
|
sortOrder: const Value(0),
|
||||||
@@ -69,7 +69,7 @@ class AccountRepository {
|
|||||||
try {
|
try {
|
||||||
await _db.into(_db.accounts).insert(
|
await _db.into(_db.accounts).insert(
|
||||||
AccountsCompanion.insert(
|
AccountsCompanion.insert(
|
||||||
name: 'Main',
|
name: 'main',
|
||||||
isMain: const Value(true),
|
isMain: const Value(true),
|
||||||
currency: const Value('USD'),
|
currency: const Value('USD'),
|
||||||
sortOrder: const Value(0),
|
sortOrder: const Value(0),
|
||||||
@@ -103,8 +103,9 @@ class AccountRepository {
|
|||||||
Future<model.Account> getMain() async {
|
Future<model.Account> getMain() async {
|
||||||
final row = await (_db.select(_db.accounts)
|
final row = await (_db.select(_db.accounts)
|
||||||
..where((a) => a.isMain.equals(true)))
|
..where((a) => a.isMain.equals(true)))
|
||||||
.getSingle();
|
.getSingleOrNull();
|
||||||
|
|
||||||
|
if (row != null) {
|
||||||
return model.Account(
|
return model.Account(
|
||||||
id: row.id,
|
id: row.id,
|
||||||
name: row.name,
|
name: row.name,
|
||||||
@@ -114,4 +115,49 @@ class AccountRepository {
|
|||||||
createdAt: row.createdAt,
|
createdAt: row.createdAt,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Fallback if no main account is found
|
||||||
|
final all = await getAll();
|
||||||
|
if (all.isNotEmpty) return all.first;
|
||||||
|
|
||||||
|
// Absolute fallback: create and return a default account
|
||||||
|
try {
|
||||||
|
await _db.into(_db.accounts).insert(
|
||||||
|
AccountsCompanion.insert(
|
||||||
|
name: 'main',
|
||||||
|
isMain: const Value(true),
|
||||||
|
currency: const Value('USD'),
|
||||||
|
sortOrder: const Value(0),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
|
||||||
|
// Query the newly created account
|
||||||
|
final newRow = await (_db.select(_db.accounts)
|
||||||
|
..where((a) => a.isMain.equals(true)))
|
||||||
|
.getSingleOrNull();
|
||||||
|
|
||||||
|
if (newRow != null) {
|
||||||
|
return model.Account(
|
||||||
|
id: newRow.id,
|
||||||
|
name: newRow.name,
|
||||||
|
isMain: newRow.isMain,
|
||||||
|
sortOrder: newRow.sortOrder,
|
||||||
|
currency: newRow.currency,
|
||||||
|
createdAt: newRow.createdAt,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
} catch (_) {
|
||||||
|
// Ignore insert errors
|
||||||
|
}
|
||||||
|
|
||||||
|
// Final fallback to prevent crashes
|
||||||
|
return model.Account(
|
||||||
|
id: 1,
|
||||||
|
name: 'main',
|
||||||
|
isMain: true,
|
||||||
|
sortOrder: 0,
|
||||||
|
currency: 'USD',
|
||||||
|
createdAt: DateTime.now(),
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -56,12 +56,24 @@ class TransactionRepository {
|
|||||||
/// Add transaction
|
/// Add transaction
|
||||||
Future<Result<void>> add(model.Transaction transaction) async {
|
Future<Result<void>> add(model.Transaction transaction) async {
|
||||||
return asyncResultOf(() async {
|
return asyncResultOf(() async {
|
||||||
|
print('--- SAVING TRANSACTION: START ---');
|
||||||
|
print('Transaction data: ID=${transaction.id}, Amount=${transaction.amount}, AccId=${transaction.accountId}');
|
||||||
|
print('Category=${transaction.category}, Type=${transaction.type.name}');
|
||||||
|
print('Date=${transaction.date}, Currency=${transaction.currencyCode}');
|
||||||
|
|
||||||
final companion = _toCompanion(transaction);
|
final companion = _toCompanion(transaction);
|
||||||
|
print('Companion created successfully');
|
||||||
|
print('Companion: $companion');
|
||||||
|
|
||||||
final result = await _db.insertTransaction(companion);
|
final result = await _db.insertTransaction(companion);
|
||||||
|
print('DB Insert finished. Result Success: ${result.isSuccess}');
|
||||||
|
|
||||||
if (result.isFailure) {
|
if (result.isFailure) {
|
||||||
|
print('!!! DB INSERT FAILED: ${result.errorOrNull}');
|
||||||
throw Exception(result.errorOrNull);
|
throw Exception(result.errorOrNull);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
print('--- SAVING TRANSACTION: END (SUCCESS) ---');
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -173,7 +185,9 @@ class TransactionRepository {
|
|||||||
|
|
||||||
/// Convert app model to companion for insert
|
/// Convert app model to companion for insert
|
||||||
TransactionsCompanion _toCompanion(model.Transaction transaction) {
|
TransactionsCompanion _toCompanion(model.Transaction transaction) {
|
||||||
return TransactionsCompanion(
|
try {
|
||||||
|
print('_toCompanion: Creating companion for transaction ${transaction.id}');
|
||||||
|
final companion = TransactionsCompanion(
|
||||||
id: Value(transaction.id),
|
id: Value(transaction.id),
|
||||||
amount: Value(transaction.amount),
|
amount: Value(transaction.amount),
|
||||||
category: Value(transaction.category),
|
category: Value(transaction.category),
|
||||||
@@ -186,6 +200,14 @@ class TransactionRepository {
|
|||||||
currencyCode: Value(transaction.currencyCode),
|
currencyCode: Value(transaction.currencyCode),
|
||||||
accountId: Value(transaction.accountId),
|
accountId: Value(transaction.accountId),
|
||||||
);
|
);
|
||||||
|
print('_toCompanion: Companion created successfully');
|
||||||
|
return companion;
|
||||||
|
} catch (e, stack) {
|
||||||
|
print('!!! _toCompanion FAILED !!!');
|
||||||
|
print('Error: $e');
|
||||||
|
print('Stack: $stack');
|
||||||
|
rethrow;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Parse recurrence type
|
/// Parse recurrence type
|
||||||
|
|||||||
@@ -154,14 +154,19 @@ class _AddTransactionScreenState extends ConsumerState<AddTransactionScreen>
|
|||||||
: _noteController.text.trim();
|
: _noteController.text.trim();
|
||||||
|
|
||||||
try {
|
try {
|
||||||
// Get account ID: use active account or fallback to main
|
print('--- SUBMIT CLICKED ---');
|
||||||
|
print('Amount: $amount, Category: ${state.category}, Type: ${state.type.name}');
|
||||||
|
|
||||||
final activeAccount = ref.read(activeAccountProvider);
|
final activeAccount = ref.read(activeAccountProvider);
|
||||||
int accountId;
|
int accountId;
|
||||||
|
|
||||||
if (activeAccount != null) {
|
if (activeAccount != null) {
|
||||||
|
print('Using active account ID: ${activeAccount.id}, Name: ${activeAccount.name}');
|
||||||
accountId = activeAccount.id;
|
accountId = activeAccount.id;
|
||||||
} else {
|
} else {
|
||||||
|
print('No active account. Fetching main account...');
|
||||||
final mainAccount = await ref.read(accountRepositoryProvider).getMain();
|
final mainAccount = await ref.read(accountRepositoryProvider).getMain();
|
||||||
|
print('Main account fetched: ID=${mainAccount.id}, Name: ${mainAccount.name}');
|
||||||
accountId = mainAccount.id;
|
accountId = mainAccount.id;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -177,20 +182,42 @@ class _AddTransactionScreenState extends ConsumerState<AddTransactionScreen>
|
|||||||
accountId: accountId,
|
accountId: accountId,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
print('Transaction object created: ID=${tx.id}, AccId=${tx.accountId}');
|
||||||
|
print('Calling provider to save...');
|
||||||
|
|
||||||
if (state.isEditing) {
|
if (state.isEditing) {
|
||||||
await ref.read(transactionsProvider.notifier).update(tx);
|
await ref.read(transactionsProvider.notifier).update(tx);
|
||||||
|
print('Update completed');
|
||||||
} else {
|
} else {
|
||||||
await ref.read(transactionsProvider.notifier).add(tx);
|
final res = await ref.read(transactionsProvider.notifier).add(tx);
|
||||||
|
print('Add completed. Result: ${res.isSuccess ? "SUCCESS" : "FAILURE"}');
|
||||||
|
|
||||||
|
if (res.isFailure) {
|
||||||
|
print('!!! Provider returned failure: ${res.errorOrNull}');
|
||||||
|
throw Exception(res.errorOrNull);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
print('Provider save completed successfully');
|
||||||
HapticService.medium();
|
HapticService.medium();
|
||||||
|
|
||||||
if (mounted) context.pop();
|
if (mounted) {
|
||||||
} catch (e) {
|
print('Popping screen...');
|
||||||
// Handle error silently or show a snackbar
|
context.pop();
|
||||||
|
}
|
||||||
|
} catch (e, stack) {
|
||||||
|
print('!!! SAVE CRASHED !!!');
|
||||||
|
print('Error: $e');
|
||||||
|
print('Stack trace:');
|
||||||
|
print(stack);
|
||||||
|
|
||||||
if (mounted) {
|
if (mounted) {
|
||||||
ScaffoldMessenger.of(context).showSnackBar(
|
ScaffoldMessenger.of(context).showSnackBar(
|
||||||
SnackBar(content: Text('Error saving transaction: $e')),
|
SnackBar(
|
||||||
|
content: Text('Save error: $e'),
|
||||||
|
backgroundColor: Colors.red,
|
||||||
|
duration: const Duration(seconds: 5),
|
||||||
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
} finally {
|
} finally {
|
||||||
|
|||||||
Reference in New Issue
Block a user