payment quotation v2 + payment orchestration v2 draft
This commit is contained in:
122
frontend/pshared/test/payment/payment_state_model_test.dart
Normal file
122
frontend/pshared/test/payment/payment_state_model_test.dart
Normal file
@@ -0,0 +1,122 @@
|
||||
import 'package:pshared/models/payment/payment.dart';
|
||||
import 'package:pshared/models/payment/state.dart';
|
||||
import 'package:test/test.dart';
|
||||
|
||||
void main() {
|
||||
group('PaymentOrchestrationState parser', () {
|
||||
test('maps v2 orchestration states', () {
|
||||
expect(
|
||||
paymentOrchestrationStateFromValue('orchestration_state_created'),
|
||||
PaymentOrchestrationState.created,
|
||||
);
|
||||
expect(
|
||||
paymentOrchestrationStateFromValue('ORCHESTRATION_STATE_EXECUTING'),
|
||||
PaymentOrchestrationState.executing,
|
||||
);
|
||||
expect(
|
||||
paymentOrchestrationStateFromValue(
|
||||
'orchestration_state_needs_attention',
|
||||
),
|
||||
PaymentOrchestrationState.needsAttention,
|
||||
);
|
||||
expect(
|
||||
paymentOrchestrationStateFromValue('orchestration_state_settled'),
|
||||
PaymentOrchestrationState.settled,
|
||||
);
|
||||
expect(
|
||||
paymentOrchestrationStateFromValue('orchestration_state_failed'),
|
||||
PaymentOrchestrationState.failed,
|
||||
);
|
||||
});
|
||||
|
||||
test('maps legacy payment states for compatibility', () {
|
||||
expect(
|
||||
paymentOrchestrationStateFromValue('payment_state_accepted'),
|
||||
PaymentOrchestrationState.created,
|
||||
);
|
||||
expect(
|
||||
paymentOrchestrationStateFromValue('payment_state_submitted'),
|
||||
PaymentOrchestrationState.executing,
|
||||
);
|
||||
expect(
|
||||
paymentOrchestrationStateFromValue('payment_state_settled'),
|
||||
PaymentOrchestrationState.settled,
|
||||
);
|
||||
expect(
|
||||
paymentOrchestrationStateFromValue('payment_state_cancelled'),
|
||||
PaymentOrchestrationState.failed,
|
||||
);
|
||||
});
|
||||
|
||||
test('unknown state maps to unspecified', () {
|
||||
expect(
|
||||
paymentOrchestrationStateFromValue('something_else'),
|
||||
PaymentOrchestrationState.unspecified,
|
||||
);
|
||||
expect(
|
||||
paymentOrchestrationStateFromValue(null),
|
||||
PaymentOrchestrationState.unspecified,
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
group('Payment model state helpers', () {
|
||||
test('isPending and isTerminal are derived from typed state', () {
|
||||
const created = Payment(
|
||||
paymentRef: 'p-1',
|
||||
idempotencyKey: 'idem-1',
|
||||
state: 'orchestration_state_created',
|
||||
orchestrationState: PaymentOrchestrationState.created,
|
||||
failureCode: null,
|
||||
failureReason: null,
|
||||
lastQuote: null,
|
||||
metadata: null,
|
||||
createdAt: null,
|
||||
);
|
||||
const settled = Payment(
|
||||
paymentRef: 'p-2',
|
||||
idempotencyKey: 'idem-2',
|
||||
state: 'orchestration_state_settled',
|
||||
orchestrationState: PaymentOrchestrationState.settled,
|
||||
failureCode: null,
|
||||
failureReason: null,
|
||||
lastQuote: null,
|
||||
metadata: null,
|
||||
createdAt: null,
|
||||
);
|
||||
|
||||
expect(created.isPending, isTrue);
|
||||
expect(created.isTerminal, isFalse);
|
||||
expect(settled.isPending, isFalse);
|
||||
expect(settled.isTerminal, isTrue);
|
||||
});
|
||||
|
||||
test('isFailure handles both explicit code and failed state', () {
|
||||
const withFailureCode = Payment(
|
||||
paymentRef: 'p-3',
|
||||
idempotencyKey: 'idem-3',
|
||||
state: 'orchestration_state_executing',
|
||||
orchestrationState: PaymentOrchestrationState.executing,
|
||||
failureCode: 'failure_ledger',
|
||||
failureReason: 'ledger failed',
|
||||
lastQuote: null,
|
||||
metadata: null,
|
||||
createdAt: null,
|
||||
);
|
||||
const failedState = Payment(
|
||||
paymentRef: 'p-4',
|
||||
idempotencyKey: 'idem-4',
|
||||
state: 'orchestration_state_failed',
|
||||
orchestrationState: PaymentOrchestrationState.failed,
|
||||
failureCode: null,
|
||||
failureReason: null,
|
||||
lastQuote: null,
|
||||
metadata: null,
|
||||
createdAt: null,
|
||||
);
|
||||
|
||||
expect(withFailureCode.isFailure, isTrue);
|
||||
expect(failedState.isFailure, isTrue);
|
||||
});
|
||||
});
|
||||
}
|
||||
113
frontend/pshared/test/payment/request_dto_format_test.dart
Normal file
113
frontend/pshared/test/payment/request_dto_format_test.dart
Normal file
@@ -0,0 +1,113 @@
|
||||
import 'dart:convert';
|
||||
|
||||
import 'package:test/test.dart';
|
||||
|
||||
import 'package:pshared/api/requests/payment/initiate.dart';
|
||||
import 'package:pshared/api/requests/payment/initiate_payments.dart';
|
||||
import 'package:pshared/api/requests/payment/quote.dart';
|
||||
import 'package:pshared/data/dto/money.dart';
|
||||
import 'package:pshared/data/dto/payment/endpoint.dart';
|
||||
import 'package:pshared/data/dto/payment/intent/payment.dart';
|
||||
import 'package:pshared/data/mapper/payment/payment.dart';
|
||||
import 'package:pshared/models/payment/asset.dart';
|
||||
import 'package:pshared/models/payment/chain_network.dart';
|
||||
import 'package:pshared/models/payment/methods/card_token.dart';
|
||||
import 'package:pshared/models/payment/methods/crypto_address.dart';
|
||||
import 'package:pshared/models/payment/methods/managed_wallet.dart';
|
||||
|
||||
void main() {
|
||||
group('Payment request DTO contract', () {
|
||||
test('serializes endpoint types to backend canonical values', () {
|
||||
final managed = ManagedWalletPaymentMethod(
|
||||
managedWalletRef: 'mw-1',
|
||||
).toDTO();
|
||||
final external = CryptoAddressPaymentMethod(
|
||||
asset: const PaymentAsset(
|
||||
chain: ChainNetwork.tronMainnet,
|
||||
tokenSymbol: 'USDT',
|
||||
),
|
||||
address: 'TXYZ',
|
||||
).toDTO();
|
||||
final cardToken = CardTokenPaymentMethod(
|
||||
token: 'tok_1',
|
||||
maskedPan: '4111',
|
||||
).toDTO();
|
||||
|
||||
expect(managed.type, equals('managedWallet'));
|
||||
expect(external.type, equals('cryptoAddress'));
|
||||
expect(cardToken.type, equals('cardToken'));
|
||||
});
|
||||
|
||||
test('quote payment request uses expected backend field names', () {
|
||||
final request = QuotePaymentRequest(
|
||||
idempotencyKey: 'idem-1',
|
||||
previewOnly: true,
|
||||
intent: const PaymentIntentDTO(
|
||||
kind: 'payout',
|
||||
source: PaymentEndpointDTO(
|
||||
type: 'ledger',
|
||||
data: {'ledger_account_ref': 'ledger:src'},
|
||||
),
|
||||
destination: PaymentEndpointDTO(
|
||||
type: 'cardToken',
|
||||
data: {'token': 'tok_1', 'masked_pan': '4111'},
|
||||
),
|
||||
amount: MoneyDTO(amount: '10', currency: 'USD'),
|
||||
settlementMode: 'fix_received',
|
||||
settlementCurrency: 'USD',
|
||||
),
|
||||
);
|
||||
|
||||
final json =
|
||||
jsonDecode(jsonEncode(request.toJson())) as Map<String, dynamic>;
|
||||
|
||||
expect(json['idempotencyKey'], equals('idem-1'));
|
||||
expect(json['previewOnly'], isTrue);
|
||||
expect(json['intent'], isA<Map<String, dynamic>>());
|
||||
|
||||
final intent = json['intent'] as Map<String, dynamic>;
|
||||
expect(intent['kind'], equals('payout'));
|
||||
expect(intent['settlement_mode'], equals('fix_received'));
|
||||
expect(intent['settlement_currency'], equals('USD'));
|
||||
|
||||
final source = intent['source'] as Map<String, dynamic>;
|
||||
final destination = intent['destination'] as Map<String, dynamic>;
|
||||
expect(source['type'], equals('ledger'));
|
||||
expect(destination['type'], equals('cardToken'));
|
||||
});
|
||||
|
||||
test('initiate payment by quote keeps expected fields', () {
|
||||
final request = InitiatePaymentRequest(
|
||||
idempotencyKey: 'idem-2',
|
||||
quoteRef: 'q-1',
|
||||
metadata: const {'intent_ref': 'intent-1'},
|
||||
);
|
||||
|
||||
final json = request.toJson();
|
||||
expect(json['idempotencyKey'], equals('idem-2'));
|
||||
expect(json['quoteRef'], equals('q-1'));
|
||||
expect(
|
||||
(json['metadata'] as Map<String, dynamic>)['intent_ref'],
|
||||
equals('intent-1'),
|
||||
);
|
||||
expect(json.containsKey('intent'), isTrue);
|
||||
expect(json['intent'], isNull);
|
||||
});
|
||||
|
||||
test('initiate multi payments request keeps expected fields', () {
|
||||
final request = InitiatePaymentsRequest(
|
||||
idempotencyKey: 'idem-3',
|
||||
quoteRef: 'q-2',
|
||||
metadata: const {'client_payment_ref': 'cp-1'},
|
||||
);
|
||||
|
||||
final json = request.toJson();
|
||||
expect(json['idempotencyKey'], equals('idem-3'));
|
||||
expect(json['quoteRef'], equals('q-2'));
|
||||
expect(
|
||||
(json['metadata'] as Map<String, dynamic>)['client_payment_ref'],
|
||||
equals('cp-1'),
|
||||
);
|
||||
});
|
||||
});
|
||||
}
|
||||
Reference in New Issue
Block a user