mnemo_cards/mnemo_cards_backend/lib/database/daos/payment_dao.dart

238 lines
7.9 KiB
Dart
Raw Permalink Normal View History

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 {
2026-01-08 16:58:13 +00:00
print(
'🔍 PaymentDao.updatePaymentStatus: token=$externalToken, status=$status',
2025-12-20 18:26:15 +00:00
);
2026-01-08 16:58:13 +00:00
final result =
await (update(
payments,
)..where((p) => p.externalToken.equals(externalToken))).write(
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
2026-01-08 19:56:01 +00:00
/// Получить последний платеж пользователя для продукта (пака)
/// Используется для получения paymentId при возврате с ЮКассы
Future<Payment?> getLatestPaymentForUserAndPack({
required String userId,
required String packId,
}) async {
final query = selectActive()
2026-01-09 17:21:18 +00:00
..where(
(p) => p.userId.equals(userId) & p.products.like('%"id":"$packId"%'),
)
2026-01-08 19:56:01 +00:00
..orderBy([(p) => OrderingTerm.desc(p.createdAt)])
..limit(1);
final results = await query.get();
return results.isNotEmpty ? results.first : null;
}
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();
}
}