Some checks failed
Backend CI / test (push) Has been cancelled
Deploy Mnemo Cards / Deploy Backend (push) Has been cancelled
Backend CI / build (push) Has been cancelled
Deploy Mnemo Cards / Deploy Web App (push) Has been cancelled
Deploy Mnemo Cards / Final Verification (push) Has been cancelled
168 lines
5.7 KiB
Dart
168 lines
5.7 KiB
Dart
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<AppDatabase>
|
||
with _$PaymentDaoMixin, SoftDeleteMixin<Payments, Payment> {
|
||
PaymentDao(super.db);
|
||
|
||
@override
|
||
TableInfo<Payments, Payment> get table => payments;
|
||
|
||
/// Получить платеж по ID (только активные)
|
||
Future<Payment?> getPaymentById(String id) {
|
||
return getActiveById(id);
|
||
}
|
||
|
||
/// Получить платежи пользователя (только активные)
|
||
Future<List<Payment>> 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<List<Payment>> getPaymentsByStatus(String status) {
|
||
return (selectActive()
|
||
..where((p) => p.status.equals(status))
|
||
..orderBy([(p) => OrderingTerm.desc(p.date)]))
|
||
.get();
|
||
}
|
||
|
||
/// Создать платеж
|
||
Future<String> 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<String>('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.dateTime),
|
||
Variable.withString(inserted.amount),
|
||
],
|
||
readsFrom: {payments},
|
||
).map((row) => row.read<String>('id')).getSingleOrNull());
|
||
if (result != null) return result;
|
||
throw Exception('Failed to retrieve payment ID after creation');
|
||
}
|
||
|
||
/// Обновить платеж
|
||
Future<bool> updatePayment(Payment payment) {
|
||
return update(payments).replace(payment);
|
||
}
|
||
|
||
/// Обновить платеж частично
|
||
Future<void> updatePaymentCompanion(
|
||
String paymentId,
|
||
PaymentsCompanion companion,
|
||
) {
|
||
return (update(
|
||
payments,
|
||
)..where((p) => p.id.equals(paymentId))).write(companion);
|
||
}
|
||
|
||
/// Обновить статус платежа
|
||
Future<void> 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<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;
|
||
}
|
||
|
||
/// Получить платежи по продукту (store ID) (только активные)
|
||
Future<List<Payment>> getPaymentsByProduct(String productId) async {
|
||
// Поиск по продуктам в JSON массиве
|
||
final query = selectActive()..where((p) => p.products.like('%$productId%'));
|
||
|
||
return query.get();
|
||
}
|
||
|
||
/// Получить платежи по статусу с пагинацией (только активные)
|
||
Future<List<Payment>> 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<List<Payment>> 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<int> 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();
|
||
}
|
||
|
||
/// Подсчитать платежи пользователя (только активные)
|
||
@override
|
||
Future<int> 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();
|
||
}
|
||
}
|