SEND063
This commit is contained in:
56
frontend/pshared/lib/data/dto/payment/operation.dart
Normal file
56
frontend/pshared/lib/data/dto/payment/operation.dart
Normal file
@@ -0,0 +1,56 @@
|
||||
class PaymentOperationDTO {
|
||||
final String? stepRef;
|
||||
final String? operationRef;
|
||||
final String? code;
|
||||
final String? state;
|
||||
final String? label;
|
||||
final String? failureCode;
|
||||
final String? failureReason;
|
||||
final String? startedAt;
|
||||
final String? completedAt;
|
||||
|
||||
const PaymentOperationDTO({
|
||||
this.stepRef,
|
||||
this.operationRef,
|
||||
this.code,
|
||||
this.state,
|
||||
this.label,
|
||||
this.failureCode,
|
||||
this.failureReason,
|
||||
this.startedAt,
|
||||
this.completedAt,
|
||||
});
|
||||
|
||||
factory PaymentOperationDTO.fromJson(Map<String, dynamic> json) =>
|
||||
PaymentOperationDTO(
|
||||
stepRef: _asString(json['stepRef'] ?? json['step_ref']),
|
||||
operationRef: _asString(json['operationRef'] ?? json['operation_ref']),
|
||||
code: _asString(json['code']),
|
||||
state: _asString(json['state']),
|
||||
label: _asString(json['label']),
|
||||
failureCode: _asString(json['failureCode'] ?? json['failure_code']),
|
||||
failureReason: _asString(
|
||||
json['failureReason'] ?? json['failure_reason'],
|
||||
),
|
||||
startedAt: _asString(json['startedAt'] ?? json['started_at']),
|
||||
completedAt: _asString(json['completedAt'] ?? json['completed_at']),
|
||||
);
|
||||
|
||||
Map<String, dynamic> toJson() => <String, dynamic>{
|
||||
'stepRef': stepRef,
|
||||
'operationRef': operationRef,
|
||||
'code': code,
|
||||
'state': state,
|
||||
'label': label,
|
||||
'failureCode': failureCode,
|
||||
'failureReason': failureReason,
|
||||
'startedAt': startedAt,
|
||||
'completedAt': completedAt,
|
||||
};
|
||||
}
|
||||
|
||||
String? _asString(Object? value) {
|
||||
final text = value?.toString().trim();
|
||||
if (text == null || text.isEmpty) return null;
|
||||
return text;
|
||||
}
|
||||
@@ -1,5 +1,6 @@
|
||||
import 'package:json_annotation/json_annotation.dart';
|
||||
|
||||
import 'package:pshared/data/dto/payment/operation.dart';
|
||||
import 'package:pshared/data/dto/payment/payment_quote.dart';
|
||||
|
||||
part 'payment.g.dart';
|
||||
@@ -12,6 +13,8 @@ class PaymentDTO {
|
||||
final String? state;
|
||||
final String? failureCode;
|
||||
final String? failureReason;
|
||||
@JsonKey(defaultValue: <PaymentOperationDTO>[])
|
||||
final List<PaymentOperationDTO> operations;
|
||||
final PaymentQuoteDTO? lastQuote;
|
||||
final Map<String, String>? metadata;
|
||||
final String? createdAt;
|
||||
@@ -22,6 +25,7 @@ class PaymentDTO {
|
||||
this.state,
|
||||
this.failureCode,
|
||||
this.failureReason,
|
||||
this.operations = const <PaymentOperationDTO>[],
|
||||
this.lastQuote,
|
||||
this.metadata,
|
||||
this.createdAt,
|
||||
|
||||
37
frontend/pshared/lib/data/mapper/payment/operation.dart
Normal file
37
frontend/pshared/lib/data/mapper/payment/operation.dart
Normal file
@@ -0,0 +1,37 @@
|
||||
import 'package:pshared/data/dto/payment/operation.dart';
|
||||
import 'package:pshared/models/payment/execution_operation.dart';
|
||||
|
||||
|
||||
extension PaymentOperationDTOMapper on PaymentOperationDTO {
|
||||
PaymentExecutionOperation toDomain() => PaymentExecutionOperation(
|
||||
stepRef: stepRef,
|
||||
operationRef: operationRef,
|
||||
code: code,
|
||||
state: state,
|
||||
label: label,
|
||||
failureCode: failureCode,
|
||||
failureReason: failureReason,
|
||||
startedAt: _parseDateTime(startedAt),
|
||||
completedAt: _parseDateTime(completedAt),
|
||||
);
|
||||
}
|
||||
|
||||
extension PaymentExecutionOperationMapper on PaymentExecutionOperation {
|
||||
PaymentOperationDTO toDTO() => PaymentOperationDTO(
|
||||
stepRef: stepRef,
|
||||
operationRef: operationRef,
|
||||
code: code,
|
||||
state: state,
|
||||
label: label,
|
||||
failureCode: failureCode,
|
||||
failureReason: failureReason,
|
||||
startedAt: startedAt?.toUtc().toIso8601String(),
|
||||
completedAt: completedAt?.toUtc().toIso8601String(),
|
||||
);
|
||||
}
|
||||
|
||||
DateTime? _parseDateTime(String? value) {
|
||||
final normalized = value?.trim();
|
||||
if (normalized == null || normalized.isEmpty) return null;
|
||||
return DateTime.tryParse(normalized);
|
||||
}
|
||||
@@ -1,8 +1,10 @@
|
||||
import 'package:pshared/data/dto/payment/payment.dart';
|
||||
import 'package:pshared/data/mapper/payment/operation.dart';
|
||||
import 'package:pshared/data/mapper/payment/quote.dart';
|
||||
import 'package:pshared/models/payment/payment.dart';
|
||||
import 'package:pshared/models/payment/state.dart';
|
||||
|
||||
|
||||
extension PaymentDTOMapper on PaymentDTO {
|
||||
Payment toDomain() => Payment(
|
||||
paymentRef: paymentRef,
|
||||
@@ -11,6 +13,7 @@ extension PaymentDTOMapper on PaymentDTO {
|
||||
orchestrationState: paymentOrchestrationStateFromValue(state),
|
||||
failureCode: failureCode,
|
||||
failureReason: failureReason,
|
||||
operations: operations.map((item) => item.toDomain()).toList(),
|
||||
lastQuote: lastQuote?.toDomain(),
|
||||
metadata: metadata,
|
||||
createdAt: createdAt == null ? null : DateTime.tryParse(createdAt!),
|
||||
@@ -24,6 +27,7 @@ extension PaymentMapper on Payment {
|
||||
state: state ?? paymentOrchestrationStateToValue(orchestrationState),
|
||||
failureCode: failureCode,
|
||||
failureReason: failureReason,
|
||||
operations: operations.map((item) => item.toDTO()).toList(),
|
||||
lastQuote: lastQuote?.toDTO(),
|
||||
metadata: metadata,
|
||||
createdAt: createdAt?.toUtc().toIso8601String(),
|
||||
|
||||
@@ -10,11 +10,31 @@
|
||||
"@operationStatusProcessing": {
|
||||
"description": "Label for the “processing” operation status"
|
||||
},
|
||||
"operationStatusPending": "Pending",
|
||||
"@operationStatusPending": {
|
||||
"description": "Label for the “pending” operation status"
|
||||
},
|
||||
"operationStatusRetrying": "Retrying",
|
||||
"@operationStatusRetrying": {
|
||||
"description": "Label for the “retrying” operation status"
|
||||
},
|
||||
|
||||
"operationStatusSuccess": "Success",
|
||||
"@operationStatusSuccess": {
|
||||
"description": "Label for the “success” operation status"
|
||||
},
|
||||
"operationStatusSkipped": "Skipped",
|
||||
"@operationStatusSkipped": {
|
||||
"description": "Label for the “skipped” operation status"
|
||||
},
|
||||
"operationStatusCancelled": "Cancelled",
|
||||
"@operationStatusCancelled": {
|
||||
"description": "Label for the “cancelled” operation status"
|
||||
},
|
||||
"operationStatusNeedsAttention": "Needs attention",
|
||||
"@operationStatusNeedsAttention": {
|
||||
"description": "Label for the “needs attention” operation status"
|
||||
},
|
||||
|
||||
"operationStatusError": "Error",
|
||||
"@operationStatusError": {
|
||||
|
||||
@@ -10,11 +10,31 @@
|
||||
"@operationStatusProcessing": {
|
||||
"description": "Label for the “processing” operation status"
|
||||
},
|
||||
"operationStatusPending": "В ожидании",
|
||||
"@operationStatusPending": {
|
||||
"description": "Label for the “pending” operation status"
|
||||
},
|
||||
"operationStatusRetrying": "Повтор",
|
||||
"@operationStatusRetrying": {
|
||||
"description": "Label for the “retrying” operation status"
|
||||
},
|
||||
|
||||
"operationStatusSuccess": "Успех",
|
||||
"@operationStatusSuccess": {
|
||||
"description": "Label for the “success” operation status"
|
||||
},
|
||||
"operationStatusSkipped": "Пропущен",
|
||||
"@operationStatusSkipped": {
|
||||
"description": "Label for the “skipped” operation status"
|
||||
},
|
||||
"operationStatusCancelled": "Отменен",
|
||||
"@operationStatusCancelled": {
|
||||
"description": "Label for the “cancelled” operation status"
|
||||
},
|
||||
"operationStatusNeedsAttention": "Требует внимания",
|
||||
"@operationStatusNeedsAttention": {
|
||||
"description": "Label for the “needs attention” operation status"
|
||||
},
|
||||
|
||||
"operationStatusError": "Ошибка",
|
||||
"@operationStatusError": {
|
||||
|
||||
23
frontend/pshared/lib/models/payment/execution_operation.dart
Normal file
23
frontend/pshared/lib/models/payment/execution_operation.dart
Normal file
@@ -0,0 +1,23 @@
|
||||
class PaymentExecutionOperation {
|
||||
final String? stepRef;
|
||||
final String? operationRef;
|
||||
final String? code;
|
||||
final String? state;
|
||||
final String? label;
|
||||
final String? failureCode;
|
||||
final String? failureReason;
|
||||
final DateTime? startedAt;
|
||||
final DateTime? completedAt;
|
||||
|
||||
const PaymentExecutionOperation({
|
||||
required this.stepRef,
|
||||
required this.operationRef,
|
||||
required this.code,
|
||||
required this.state,
|
||||
required this.label,
|
||||
required this.failureCode,
|
||||
required this.failureReason,
|
||||
required this.startedAt,
|
||||
required this.completedAt,
|
||||
});
|
||||
}
|
||||
@@ -1,3 +1,4 @@
|
||||
import 'package:pshared/models/payment/execution_operation.dart';
|
||||
import 'package:pshared/models/payment/quote/quote.dart';
|
||||
import 'package:pshared/models/payment/state.dart';
|
||||
|
||||
@@ -8,6 +9,7 @@ class Payment {
|
||||
final PaymentOrchestrationState orchestrationState;
|
||||
final String? failureCode;
|
||||
final String? failureReason;
|
||||
final List<PaymentExecutionOperation> operations;
|
||||
final PaymentQuote? lastQuote;
|
||||
final Map<String, String>? metadata;
|
||||
final DateTime? createdAt;
|
||||
@@ -19,6 +21,7 @@ class Payment {
|
||||
required this.orchestrationState,
|
||||
required this.failureCode,
|
||||
required this.failureReason,
|
||||
required this.operations,
|
||||
required this.lastQuote,
|
||||
required this.metadata,
|
||||
required this.createdAt,
|
||||
|
||||
@@ -2,24 +2,35 @@ import 'package:flutter/widgets.dart';
|
||||
|
||||
import 'package:pshared/generated/i18n/ps_localizations.dart';
|
||||
|
||||
|
||||
enum OperationStatus {
|
||||
pending,
|
||||
processing,
|
||||
retrying,
|
||||
success,
|
||||
skipped,
|
||||
cancelled,
|
||||
needsAttention,
|
||||
error,
|
||||
}
|
||||
|
||||
|
||||
extension OperationStatusX on OperationStatus {
|
||||
/// Returns the localized string for this status,
|
||||
/// e.g. “Processing”, “Success”, “Error”.
|
||||
String localized(BuildContext context) {
|
||||
final loc = PSLocalizations.of(context)!;
|
||||
switch (this) {
|
||||
case OperationStatus.pending:
|
||||
return loc.operationStatusPending;
|
||||
case OperationStatus.processing:
|
||||
return loc.operationStatusProcessing;
|
||||
case OperationStatus.retrying:
|
||||
return loc.operationStatusRetrying;
|
||||
case OperationStatus.success:
|
||||
return loc.operationStatusSuccess;
|
||||
case OperationStatus.skipped:
|
||||
return loc.operationStatusSkipped;
|
||||
case OperationStatus.cancelled:
|
||||
return loc.operationStatusCancelled;
|
||||
case OperationStatus.needsAttention:
|
||||
return loc.operationStatusNeedsAttention;
|
||||
case OperationStatus.error:
|
||||
return loc.operationStatusError;
|
||||
}
|
||||
|
||||
@@ -4,17 +4,30 @@ import 'package:pshared/models/file/downloaded_file.dart';
|
||||
import 'package:pshared/service/authorization/service.dart';
|
||||
import 'package:pshared/service/services.dart';
|
||||
|
||||
|
||||
class PaymentDocumentsService {
|
||||
static final _logger = Logger('service.payment_documents');
|
||||
static const String _objectType = Services.payments;
|
||||
|
||||
static Future<DownloadedFile> getAct(String organizationRef, String paymentRef) async {
|
||||
final encodedRef = Uri.encodeQueryComponent(paymentRef);
|
||||
final url = '/documents/act/$organizationRef?payment_ref=$encodedRef';
|
||||
static Future<DownloadedFile> getAct(
|
||||
String organizationRef,
|
||||
String paymentRef, {
|
||||
String? operationRef,
|
||||
}) async {
|
||||
final query = <String, String>{'payment_ref': paymentRef};
|
||||
final operationRefValue = operationRef;
|
||||
if (operationRefValue != null && operationRefValue.isNotEmpty) {
|
||||
query['operation_ref'] = operationRefValue;
|
||||
query['operationRef'] = operationRefValue;
|
||||
}
|
||||
final queryString = Uri(queryParameters: query).query;
|
||||
final url = '/documents/act/$organizationRef?$queryString';
|
||||
_logger.fine('Downloading act document for payment $paymentRef');
|
||||
final response = await AuthorizationService.getGETBinaryResponse(_objectType, url);
|
||||
final filename = _filenameFromDisposition(response.header('content-disposition')) ??
|
||||
final response = await AuthorizationService.getGETBinaryResponse(
|
||||
_objectType,
|
||||
url,
|
||||
);
|
||||
final filename =
|
||||
_filenameFromDisposition(response.header('content-disposition')) ??
|
||||
'act_$paymentRef.pdf';
|
||||
final mimeType = response.header('content-type') ?? 'application/pdf';
|
||||
return DownloadedFile(
|
||||
|
||||
@@ -69,6 +69,7 @@ void main() {
|
||||
orchestrationState: PaymentOrchestrationState.created,
|
||||
failureCode: null,
|
||||
failureReason: null,
|
||||
operations: [],
|
||||
lastQuote: null,
|
||||
metadata: null,
|
||||
createdAt: null,
|
||||
@@ -80,6 +81,7 @@ void main() {
|
||||
orchestrationState: PaymentOrchestrationState.settled,
|
||||
failureCode: null,
|
||||
failureReason: null,
|
||||
operations: [],
|
||||
lastQuote: null,
|
||||
metadata: null,
|
||||
createdAt: null,
|
||||
@@ -99,6 +101,7 @@ void main() {
|
||||
orchestrationState: PaymentOrchestrationState.executing,
|
||||
failureCode: 'failure_ledger',
|
||||
failureReason: 'ledger failed',
|
||||
operations: [],
|
||||
lastQuote: null,
|
||||
metadata: null,
|
||||
createdAt: null,
|
||||
@@ -110,6 +113,7 @@ void main() {
|
||||
orchestrationState: PaymentOrchestrationState.failed,
|
||||
failureCode: null,
|
||||
failureReason: null,
|
||||
operations: [],
|
||||
lastQuote: null,
|
||||
metadata: null,
|
||||
createdAt: null,
|
||||
|
||||
Reference in New Issue
Block a user