reports page

This commit is contained in:
Arseni
2026-02-16 21:05:38 +03:00
parent 11d4b9a608
commit 0eea39fb97
56 changed files with 2227 additions and 501 deletions

View File

@@ -0,0 +1,117 @@
import 'package:pshared/models/payment/operation.dart';
import 'package:pshared/models/payment/payment.dart';
import 'package:pshared/models/payment/status.dart';
OperationItem mapPaymentToOperation(Payment payment) {
final debit = payment.lastQuote?.debitAmount;
final settlement = payment.lastQuote?.expectedSettlementAmount;
final amountMoney = debit ?? settlement;
final amount = _parseAmount(amountMoney?.amount);
final currency = amountMoney?.currency ?? '';
final toAmount = settlement == null ? amount : _parseAmount(settlement.amount);
final toCurrency = settlement?.currency ?? currency;
final payId = _firstNonEmpty([
payment.paymentRef,
payment.idempotencyKey,
]) ??
'-';
final name = _firstNonEmpty([
payment.lastQuote?.quoteRef,
payment.paymentRef,
payment.idempotencyKey,
]) ??
'-';
final comment = _firstNonEmpty([
payment.failureReason,
payment.failureCode,
payment.state,
]) ??
'';
return OperationItem(
status: statusFromPayment(payment),
fileName: _extractFileName(payment.metadata),
amount: amount,
currency: currency,
toAmount: toAmount,
toCurrency: toCurrency,
payId: payId,
paymentRef: payment.paymentRef,
cardNumber: null,
name: name,
date: resolvePaymentDate(payment),
comment: comment,
);
}
OperationStatus statusFromPayment(Payment payment) {
final normalized = _normalizePaymentState(payment.state);
switch (normalized) {
case 'SUCCESS':
return OperationStatus.success;
case 'FAILED':
case 'CANCELLED':
return OperationStatus.error;
default:
return OperationStatus.processing;
}
}
DateTime resolvePaymentDate(Payment payment) {
final createdAt = payment.createdAt;
if (createdAt != null) return createdAt.toLocal();
final expiresAt = payment.lastQuote?.fxQuote?.expiresAtUnixMs;
if (expiresAt != null && expiresAt > 0) {
return DateTime.fromMillisecondsSinceEpoch(expiresAt, isUtc: true).toLocal();
}
return DateTime.fromMillisecondsSinceEpoch(0);
}
String? paymentIdFromOperation(OperationItem operation) {
final candidates = [
operation.paymentRef,
operation.payId,
];
for (final candidate in candidates) {
final trimmed = candidate?.trim();
if (trimmed != null && trimmed.isNotEmpty && trimmed != '-') {
return trimmed;
}
}
return null;
}
String? _extractFileName(Map<String, String>? metadata) {
if (metadata == null || metadata.isEmpty) return null;
return _firstNonEmpty([
metadata['upload_filename'],
metadata['upload_file_name'],
metadata['filename'],
]);
}
String? _firstNonEmpty(List<String?> values) {
for (final value in values) {
final trimmed = value?.trim();
if (trimmed != null && trimmed.isNotEmpty) return trimmed;
}
return null;
}
String _normalizePaymentState(String? raw) {
final trimmed = (raw ?? '').trim().toUpperCase();
if (trimmed.startsWith('PAYMENT_STATE_')) {
return trimmed.substring('PAYMENT_STATE_'.length);
}
return trimmed;
}
double _parseAmount(String? amount) {
if (amount == null || amount.trim().isEmpty) return 0;
return double.tryParse(amount) ?? 0;
}