2025-12-13 13:27:05 +00:00
|
|
|
|
import 'package:drift/drift.dart';
|
2025-12-13 23:35:14 +00:00
|
|
|
|
import 'package:drift_postgres/drift_postgres.dart';
|
2025-12-13 13:27:05 +00:00
|
|
|
|
import '../database.dart';
|
|
|
|
|
|
import '../tables/payments.dart';
|
2025-12-14 20:36:05 +00:00
|
|
|
|
import 'mixins/soft_delete_mixin.dart';
|
2025-12-13 13:27:05 +00:00
|
|
|
|
|
|
|
|
|
|
part 'payment_dao.g.dart';
|
|
|
|
|
|
|
|
|
|
|
|
@DriftAccessor(tables: [Payments])
|
2025-12-20 18:26:15 +00:00
|
|
|
|
class PaymentDao extends DatabaseAccessor<AppDatabase>
|
2025-12-14 20:36:05 +00:00
|
|
|
|
with _$PaymentDaoMixin, SoftDeleteMixin<Payments, Payment> {
|
2025-12-13 13:27:05 +00:00
|
|
|
|
PaymentDao(super.db);
|
2025-12-20 18:26:15 +00:00
|
|
|
|
|
2025-12-14 20:36:05 +00:00
|
|
|
|
@override
|
|
|
|
|
|
TableInfo<Payments, Payment> get table => payments;
|
2025-12-20 18:26:15 +00:00
|
|
|
|
|
2025-12-14 20:36:05 +00:00
|
|
|
|
/// Получить платеж по ID (только активные)
|
2026-01-06 21:20:43 +00:00
|
|
|
|
Future<Payment?> getPaymentById(String id) async {
|
|
|
|
|
|
print('🔍 PaymentDao.getPaymentById: paymentId=$id');
|
|
|
|
|
|
print('🔍 PaymentDao.getPaymentById: Calling getActiveById');
|
|
|
|
|
|
final result = await getActiveById(id);
|
2026-01-08 13:02:47 +00:00
|
|
|
|
print(
|
|
|
|
|
|
'✅ PaymentDao.getPaymentById: Result=${result != null ? "found" : "not found"}',
|
|
|
|
|
|
);
|
2026-01-06 21:20:43 +00:00
|
|
|
|
return result;
|
2025-12-13 13:27:05 +00:00
|
|
|
|
}
|
2025-12-20 18:26:15 +00:00
|
|
|
|
|
2025-12-14 20:36:05 +00:00
|
|
|
|
/// Получить платежи пользователя (только активные)
|
2025-12-20 18:26:15 +00:00
|
|
|
|
Future<List<Payment>> getPaymentsByUserId(
|
|
|
|
|
|
String userId, {
|
2025-12-13 13:27:05 +00:00
|
|
|
|
int? limit,
|
|
|
|
|
|
int? offset,
|
|
|
|
|
|
}) {
|
2025-12-14 20:36:05 +00:00
|
|
|
|
final query = selectActive()
|
2025-12-13 13:27:05 +00:00
|
|
|
|
..where((p) => p.userId.equals(userId))
|
|
|
|
|
|
..orderBy([(p) => OrderingTerm.desc(p.date)]);
|
2025-12-20 18:26:15 +00:00
|
|
|
|
|
2025-12-13 13:27:05 +00:00
|
|
|
|
if (limit != null) {
|
|
|
|
|
|
query.limit(limit, offset: offset);
|
|
|
|
|
|
}
|
2025-12-20 18:26:15 +00:00
|
|
|
|
|
2025-12-13 13:27:05 +00:00
|
|
|
|
return query.get();
|
|
|
|
|
|
}
|
2025-12-20 18:26:15 +00:00
|
|
|
|
|
2025-12-14 20:36:05 +00:00
|
|
|
|
/// Получить платежи по статусу (только активные)
|
2025-12-13 13:27:05 +00:00
|
|
|
|
Future<List<Payment>> getPaymentsByStatus(String status) {
|
2025-12-14 20:36:05 +00:00
|
|
|
|
return (selectActive()
|
2025-12-20 18:26:15 +00:00
|
|
|
|
..where((p) => p.status.equals(status))
|
|
|
|
|
|
..orderBy([(p) => OrderingTerm.desc(p.date)]))
|
|
|
|
|
|
.get();
|
2025-12-13 13:27:05 +00:00
|
|
|
|
}
|
2025-12-20 18:26:15 +00:00
|
|
|
|
|
2025-12-13 13:27:05 +00:00
|
|
|
|
/// Создать платеж
|
2025-12-13 20:55:50 +00:00
|
|
|
|
Future<String> createPayment(PaymentsCompanion payment) async {
|
2026-01-06 21:20:43 +00:00
|
|
|
|
print('🔍 PaymentDao.createPayment: Starting payment creation');
|
2026-01-08 13:02:47 +00:00
|
|
|
|
print(
|
|
|
|
|
|
'🔍 PaymentDao.createPayment: externalToken=${payment.externalToken.value}',
|
|
|
|
|
|
);
|
2026-01-06 21:20:43 +00:00
|
|
|
|
print('🔍 PaymentDao.createPayment: userId=${payment.userId.value}');
|
|
|
|
|
|
print('🔍 PaymentDao.createPayment: amount=${payment.amount.value}');
|
2026-01-08 13:02:47 +00:00
|
|
|
|
|
2025-12-13 20:55:50 +00:00
|
|
|
|
final inserted = await into(payments).insertReturning(payment);
|
2026-01-08 13:02:47 +00:00
|
|
|
|
print(
|
|
|
|
|
|
'✅ PaymentDao.createPayment: Payment inserted, date=${inserted.date.dateTime}',
|
|
|
|
|
|
);
|
|
|
|
|
|
|
2026-01-06 21:26:13 +00:00
|
|
|
|
// Try to get id from inserted object first
|
|
|
|
|
|
if (inserted.id.isNotEmpty) {
|
2026-01-08 13:02:47 +00:00
|
|
|
|
print(
|
|
|
|
|
|
'✅ PaymentDao.createPayment: Got id from inserted object, id=${inserted.id}',
|
|
|
|
|
|
);
|
2026-01-06 21:26:13 +00:00
|
|
|
|
return inserted.id;
|
|
|
|
|
|
}
|
2026-01-08 13:02:47 +00:00
|
|
|
|
|
2026-01-06 21:26:13 +00:00
|
|
|
|
// Query back to get the id using type-safe queries
|
2025-12-13 20:55:50 +00:00
|
|
|
|
// Use externalToken if available, otherwise query by unique fields
|
|
|
|
|
|
if (inserted.externalToken != null && inserted.externalToken!.isNotEmpty) {
|
2026-01-08 13:02:47 +00:00
|
|
|
|
print(
|
|
|
|
|
|
'🔍 PaymentDao.createPayment: Querying by externalToken=${inserted.externalToken}',
|
|
|
|
|
|
);
|
|
|
|
|
|
final foundPayment = await getPaymentByExternalToken(
|
|
|
|
|
|
inserted.externalToken!,
|
|
|
|
|
|
);
|
2026-01-06 21:26:13 +00:00
|
|
|
|
if (foundPayment != null && foundPayment.id.isNotEmpty) {
|
2026-01-08 13:02:47 +00:00
|
|
|
|
print(
|
|
|
|
|
|
'✅ PaymentDao.createPayment: Found payment by externalToken, id=${foundPayment.id}',
|
|
|
|
|
|
);
|
2026-01-06 21:26:13 +00:00
|
|
|
|
return foundPayment.id;
|
2026-01-06 21:20:43 +00:00
|
|
|
|
}
|
|
|
|
|
|
print('⚠️ PaymentDao.createPayment: No payment found by externalToken');
|
2025-12-13 20:55:50 +00:00
|
|
|
|
}
|
2026-01-08 13:02:47 +00:00
|
|
|
|
|
2026-01-06 21:26:13 +00:00
|
|
|
|
// Fallback: query by userId, date, and amount using type-safe queries
|
2026-01-08 13:02:47 +00:00
|
|
|
|
print(
|
|
|
|
|
|
'🔍 PaymentDao.createPayment: Querying by userId, date, amount (fallback)',
|
|
|
|
|
|
);
|
2026-01-06 21:26:13 +00:00
|
|
|
|
final query = select(payments)
|
2026-01-08 13:02:47 +00:00
|
|
|
|
..where(
|
|
|
|
|
|
(p) =>
|
|
|
|
|
|
p.userId.equals(payment.userId.value) &
|
|
|
|
|
|
p.date.equals(inserted.date) &
|
|
|
|
|
|
p.amount.equals(inserted.amount),
|
|
|
|
|
|
)
|
2026-01-06 21:26:13 +00:00
|
|
|
|
..orderBy([(p) => OrderingTerm.desc(p.createdAt)])
|
|
|
|
|
|
..limit(1);
|
2026-01-08 13:02:47 +00:00
|
|
|
|
|
2026-01-06 21:26:13 +00:00
|
|
|
|
final results = await query.get();
|
|
|
|
|
|
if (results.isNotEmpty && results.first.id.isNotEmpty) {
|
2026-01-08 13:02:47 +00:00
|
|
|
|
print(
|
|
|
|
|
|
'✅ PaymentDao.createPayment: Found payment by fallback query, id=${results.first.id}',
|
|
|
|
|
|
);
|
2026-01-06 21:26:13 +00:00
|
|
|
|
return results.first.id;
|
2026-01-06 21:20:43 +00:00
|
|
|
|
}
|
2026-01-08 13:02:47 +00:00
|
|
|
|
|
|
|
|
|
|
print(
|
|
|
|
|
|
'❌ PaymentDao.createPayment: Failed to retrieve payment ID after creation',
|
|
|
|
|
|
);
|
2025-12-13 20:55:50 +00:00
|
|
|
|
throw Exception('Failed to retrieve payment ID after creation');
|
2025-12-13 13:27:05 +00:00
|
|
|
|
}
|
2025-12-20 18:26:15 +00:00
|
|
|
|
|
2025-12-13 13:27:05 +00:00
|
|
|
|
/// Обновить платеж
|
|
|
|
|
|
Future<bool> updatePayment(Payment payment) {
|
|
|
|
|
|
return update(payments).replace(payment);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// Обновить платеж частично
|
2025-12-20 18:26:15 +00:00
|
|
|
|
Future<void> updatePaymentCompanion(
|
|
|
|
|
|
String paymentId,
|
|
|
|
|
|
PaymentsCompanion companion,
|
|
|
|
|
|
) {
|
|
|
|
|
|
return (update(
|
|
|
|
|
|
payments,
|
|
|
|
|
|
)..where((p) => p.id.equals(paymentId))).write(companion);
|
2025-12-13 13:27:05 +00:00
|
|
|
|
}
|
2025-12-20 18:26:15 +00:00
|
|
|
|
|
2025-12-13 13:27:05 +00:00
|
|
|
|
/// Обновить статус платежа
|
2026-01-08 13:24:33 +00:00
|
|
|
|
Future<void> updatePaymentStatus(String externalToken, String status) async {
|
|
|
|
|
|
print('🔍 PaymentDao.updatePaymentStatus: token=$externalToken, status=$status');
|
|
|
|
|
|
final result = await (update(payments)..where((p) => p.externalToken.equals(externalToken))).write(
|
2025-12-20 18:26:15 +00:00
|
|
|
|
PaymentsCompanion(
|
|
|
|
|
|
status: Value(status),
|
|
|
|
|
|
updatedAt: Value(PgDateTime(DateTime.now())),
|
|
|
|
|
|
),
|
|
|
|
|
|
);
|
2026-01-08 13:13:29 +00:00
|
|
|
|
print('✅ PaymentDao.updatePaymentStatus: result=$result');
|
2025-12-13 13:27:05 +00:00
|
|
|
|
}
|
2025-12-20 18:26:15 +00:00
|
|
|
|
|
2025-12-14 20:36:05 +00:00
|
|
|
|
/// Получить платеж по externalToken (только активные)
|
2026-01-03 14:48:57 +00:00
|
|
|
|
Future<Payment?> 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;
|
2025-12-13 13:27:05 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
2025-12-14 20:36:05 +00:00
|
|
|
|
/// Получить платежи по продукту (store ID) (только активные)
|
2025-12-13 13:27:05 +00:00
|
|
|
|
Future<List<Payment>> getPaymentsByProduct(String productId) async {
|
|
|
|
|
|
// Поиск по продуктам в JSON массиве
|
2025-12-20 18:26:15 +00:00
|
|
|
|
final query = selectActive()..where((p) => p.products.like('%$productId%'));
|
2025-12-13 13:27:05 +00:00
|
|
|
|
|
|
|
|
|
|
return query.get();
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-12-14 20:36:05 +00:00
|
|
|
|
/// Получить платежи по статусу с пагинацией (только активные)
|
2025-12-13 13:27:05 +00:00
|
|
|
|
Future<List<Payment>> getPaymentsByStatusPaged(
|
|
|
|
|
|
String status, {
|
|
|
|
|
|
int? limit,
|
|
|
|
|
|
int? offset,
|
|
|
|
|
|
}) {
|
2025-12-14 20:36:05 +00:00
|
|
|
|
final query = selectActive()
|
2025-12-13 13:27:05 +00:00
|
|
|
|
..where((p) => p.status.equals(status))
|
|
|
|
|
|
..orderBy([(p) => OrderingTerm.desc(p.date)]);
|
|
|
|
|
|
|
|
|
|
|
|
if (limit != null) {
|
|
|
|
|
|
query.limit(limit, offset: offset);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
return query.get();
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-12-14 20:36:05 +00:00
|
|
|
|
/// Получить все платежи (для админки) (только активные)
|
2025-12-20 18:26:15 +00:00
|
|
|
|
Future<List<Payment>> getAllPayments({int? limit, int? offset}) {
|
|
|
|
|
|
final query = selectActive()..orderBy([(p) => OrderingTerm.desc(p.date)]);
|
2025-12-13 13:27:05 +00:00
|
|
|
|
|
|
|
|
|
|
if (limit != null) {
|
|
|
|
|
|
query.limit(limit, offset: offset);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
return query.get();
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-12-14 20:36:05 +00:00
|
|
|
|
/// Подсчитать все платежи (только активные)
|
2025-12-13 13:27:05 +00:00
|
|
|
|
Future<int> countAllPayments() async {
|
|
|
|
|
|
final countExpr = payments.id.count();
|
2025-12-14 20:36:05 +00:00
|
|
|
|
final query = selectOnly(payments)
|
|
|
|
|
|
..addColumns([countExpr])
|
|
|
|
|
|
..where(payments.isDeleted.equals(false));
|
|
|
|
|
|
|
|
|
|
|
|
return await query.map((row) => row.read(countExpr)!).getSingle();
|
|
|
|
|
|
}
|
2025-12-20 18:26:15 +00:00
|
|
|
|
|
2025-12-14 20:36:05 +00:00
|
|
|
|
/// Подсчитать платежи пользователя (только активные)
|
|
|
|
|
|
Future<int> countPaymentsByUserId(String userId) async {
|
|
|
|
|
|
final countExpr = payments.id.count();
|
|
|
|
|
|
final query = selectOnly(payments)
|
|
|
|
|
|
..addColumns([countExpr])
|
2025-12-20 18:26:15 +00:00
|
|
|
|
..where(
|
|
|
|
|
|
payments.userId.equals(userId) & payments.isDeleted.equals(false),
|
|
|
|
|
|
);
|
2025-12-13 13:27:05 +00:00
|
|
|
|
|
|
|
|
|
|
return await query.map((row) => row.read(countExpr)!).getSingle();
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|