import 'package:drift/drift.dart'; import 'package:drift_postgres/drift_postgres.dart'; import '../database.dart'; import '../tables/payments.dart'; import 'mixins/soft_delete_mixin.dart'; part 'payment_dao.g.dart'; @DriftAccessor(tables: [Payments]) class PaymentDao extends DatabaseAccessor with _$PaymentDaoMixin, SoftDeleteMixin { PaymentDao(super.db); @override TableInfo get table => payments; /// Получить платеж по ID (только активные) Future getPaymentById(String id) async { print('🔍 PaymentDao.getPaymentById: paymentId=$id'); print('🔍 PaymentDao.getPaymentById: Calling getActiveById'); final result = await getActiveById(id); print('✅ PaymentDao.getPaymentById: Result=${result != null ? "found" : "not found"}'); return result; } /// Получить платежи пользователя (только активные) Future> getPaymentsByUserId( String userId, { int? limit, int? offset, }) { final query = selectActive() ..where((p) => p.userId.equals(userId)) ..orderBy([(p) => OrderingTerm.desc(p.date)]); if (limit != null) { query.limit(limit, offset: offset); } return query.get(); } /// Получить платежи по статусу (только активные) Future> getPaymentsByStatus(String status) { return (selectActive() ..where((p) => p.status.equals(status)) ..orderBy([(p) => OrderingTerm.desc(p.date)])) .get(); } /// Создать платеж Future createPayment(PaymentsCompanion payment) async { print('🔍 PaymentDao.createPayment: Starting payment creation'); print('🔍 PaymentDao.createPayment: externalToken=${payment.externalToken.value}'); print('🔍 PaymentDao.createPayment: userId=${payment.userId.value}'); print('🔍 PaymentDao.createPayment: amount=${payment.amount.value}'); final inserted = await into(payments).insertReturning(payment); print('✅ PaymentDao.createPayment: Payment inserted, date=${inserted.date.dateTime}'); // Query back to get the id since Payment class doesn't have id field // (database needs to be regenerated to include id in Payment class) // Use externalToken if available, otherwise query by unique fields if (inserted.externalToken != null && inserted.externalToken!.isNotEmpty) { print('🔍 PaymentDao.createPayment: Querying by externalToken=${inserted.externalToken}'); print('🔍 PaymentDao.createPayment: SQL: SELECT id FROM payments WHERE external_token = ? LIMIT 1'); final results = await (customSelect( 'SELECT id FROM payments WHERE external_token = ? LIMIT 1', variables: [Variable.withString(inserted.externalToken!)], readsFrom: {payments}, ).map((row) => row.read('id')).get()); if (results.isNotEmpty) { print('✅ PaymentDao.createPayment: Found payment by externalToken, id=${results.first}'); return results.first; } print('⚠️ PaymentDao.createPayment: No payment found by externalToken'); } // Fallback: query by userId, date, and amount print('🔍 PaymentDao.createPayment: Querying by userId, date, amount (fallback)'); print('🔍 PaymentDao.createPayment: SQL: SELECT id FROM payments WHERE user_id = ? AND date = ? AND amount = ? ORDER BY created_at DESC LIMIT 1'); final results = await (customSelect( 'SELECT id FROM payments WHERE user_id = ? AND date = ? AND amount = ? ORDER BY created_at DESC LIMIT 1', variables: [ Variable.withString(payment.userId.value), Variable.withDateTime(inserted.date.dateTime), Variable.withString(inserted.amount), ], readsFrom: {payments}, ).map((row) => row.read('id')).get()); if (results.isNotEmpty) { print('✅ PaymentDao.createPayment: Found payment by fallback query, id=${results.first}'); return results.first; } print('❌ PaymentDao.createPayment: Failed to retrieve payment ID after creation'); throw Exception('Failed to retrieve payment ID after creation'); } /// Обновить платеж Future updatePayment(Payment payment) { return update(payments).replace(payment); } /// Обновить платеж частично Future updatePaymentCompanion( String paymentId, PaymentsCompanion companion, ) { return (update( payments, )..where((p) => p.id.equals(paymentId))).write(companion); } /// Обновить статус платежа Future updatePaymentStatus(String paymentId, String status) { return (update(payments)..where((p) => p.id.equals(paymentId))).write( PaymentsCompanion( status: Value(status), updatedAt: Value(PgDateTime(DateTime.now())), ), ); } /// Получить платеж по externalToken (только активные) Future getPaymentByExternalToken(String token) async { final query = selectActive() ..where((p) => p.externalToken.equals(token)) ..limit(1); final results = await query.get(); return results.isNotEmpty ? results.first : null; } /// Получить платежи по продукту (store ID) (только активные) Future> getPaymentsByProduct(String productId) async { // Поиск по продуктам в JSON массиве final query = selectActive()..where((p) => p.products.like('%$productId%')); return query.get(); } /// Получить платежи по статусу с пагинацией (только активные) Future> getPaymentsByStatusPaged( String status, { int? limit, int? offset, }) { final query = selectActive() ..where((p) => p.status.equals(status)) ..orderBy([(p) => OrderingTerm.desc(p.date)]); if (limit != null) { query.limit(limit, offset: offset); } return query.get(); } /// Получить все платежи (для админки) (только активные) Future> getAllPayments({int? limit, int? offset}) { final query = selectActive()..orderBy([(p) => OrderingTerm.desc(p.date)]); if (limit != null) { query.limit(limit, offset: offset); } return query.get(); } /// Подсчитать все платежи (только активные) Future countAllPayments() async { final countExpr = payments.id.count(); final query = selectOnly(payments) ..addColumns([countExpr]) ..where(payments.isDeleted.equals(false)); return await query.map((row) => row.read(countExpr)!).getSingle(); } /// Подсчитать платежи пользователя (только активные) Future countPaymentsByUserId(String userId) async { final countExpr = payments.id.count(); final query = selectOnly(payments) ..addColumns([countExpr]) ..where( payments.userId.equals(userId) & payments.isDeleted.equals(false), ); return await query.map((row) => row.read(countExpr)!).getSingle(); } }