import 'package:drift/drift.dart'; import '../database.dart'; import '../tables/payments.dart'; part 'payment_dao.g.dart'; @DriftAccessor(tables: [Payments]) class PaymentDao extends DatabaseAccessor with _$PaymentDaoMixin { PaymentDao(super.db); /// Получить платеж по ID Future getPaymentById(String id) { return (select(payments)..where((p) => p.id.equals(id))).getSingleOrNull(); } /// Получить платежи пользователя Future> getPaymentsByUserId(String userId, { int? limit, int? offset, }) { final query = select(payments) ..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 (select(payments) ..where((p) => p.status.equals(status)) ..orderBy([(p) => OrderingTerm.desc(p.date)]) ).get(); } /// Создать платеж Future createPayment(PaymentsCompanion payment) async { final inserted = await into(payments).insertReturning(payment); // 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) { final result = await (customSelect( 'SELECT id FROM payments WHERE external_token = ? LIMIT 1', variables: [Variable.withString(inserted.externalToken!)], readsFrom: {payments}, ).map((row) => row.read('id')).getSingleOrNull()); if (result != null) return result; } // Fallback: query by userId, date, and amount final result = 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), Variable.withString(inserted.amount), ], readsFrom: {payments}, ).map((row) => row.read('id')).getSingleOrNull()); if (result != null) return result; 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(DateTime.now()), )); } /// Подсчитать платежи пользователя Future countPaymentsByUserId(String userId) async { final countExpr = payments.id.count(); final query = selectOnly(payments) ..addColumns([countExpr]) ..where(payments.userId.equals(userId)); return await query.map((row) => row.read(countExpr)!).getSingle(); } /// Получить платеж по externalToken Future getPaymentByExternalToken(String token) { return (select(payments)..where((p) => p.externalToken.equals(token))) .getSingleOrNull(); } /// Получить платежи по продукту (store ID) Future> getPaymentsByProduct(String productId) async { // Поиск по продуктам в JSON массиве final query = select(payments) ..where((p) => p.products.like('%$productId%')); return query.get(); } /// Получить платежи по статусу с пагинацией Future> getPaymentsByStatusPaged( String status, { int? limit, int? offset, }) { final query = select(payments) ..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 = select(payments) ..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]); return await query.map((row) => row.read(countExpr)!).getSingle(); } }