98 lines
2.9 KiB
Dart
98 lines
2.9 KiB
Dart
import '../models/identity.dart';
|
|
import '../models/limits.dart';
|
|
import '../transport/contracts.dart';
|
|
import 'contracts.dart';
|
|
|
|
/// Process-local backend stand-in. It never stores or sends document bytes.
|
|
class DummyIdentityService implements IdentityService {
|
|
DummyIdentityService({this.delay = const Duration(milliseconds: 450)});
|
|
final Duration delay;
|
|
IdentityDTO _record = const IdentityDTO('unverified');
|
|
String? _lastKey;
|
|
KycError? nextError;
|
|
@override
|
|
bool get isSimulated => true;
|
|
Future<void> _wait() async {
|
|
await Future<void>.delayed(delay);
|
|
final error = nextError;
|
|
nextError = null;
|
|
if (error != null) throw KycException(error);
|
|
}
|
|
|
|
@override
|
|
Future<Identity> fetch() async {
|
|
await _wait();
|
|
return IdentityMapper.fromDTO(_record);
|
|
}
|
|
|
|
@override
|
|
Future<Identity> submit({
|
|
required Photo passport,
|
|
required Photo selfie,
|
|
required String idempotencyKey,
|
|
}) async {
|
|
await _wait();
|
|
if (_lastKey == idempotencyKey) return IdentityMapper.fromDTO(_record);
|
|
if (!IdentityMapper.fromDTO(_record).canSubmit)
|
|
throw const KycException(KycError.conflict);
|
|
if (passport.bytes.isEmpty || selfie.bytes.isEmpty)
|
|
throw const KycException(KycError.incomplete);
|
|
_lastKey = idempotencyKey;
|
|
_record = IdentityDTO('pending', id: idempotencyKey);
|
|
return IdentityMapper.fromDTO(_record);
|
|
}
|
|
|
|
/// Explicit demo-only human decision stand-in; unavailable in real adapters.
|
|
void review(IdentityStatus status, {ReviewReason? reason}) {
|
|
if (_record.status != 'pending')
|
|
throw const KycException(KycError.conflict);
|
|
if (![
|
|
IdentityStatus.approved,
|
|
IdentityStatus.changesRequested,
|
|
IdentityStatus.denied,
|
|
].contains(status))
|
|
throw const KycException(KycError.conflict);
|
|
_record = IdentityDTO(status.name, id: _record.id, reason: reason?.name);
|
|
}
|
|
}
|
|
|
|
/// Mimics backend policy evaluation. Widgets/providers never compute active caps.
|
|
/// Values are illustrative fixtures, not the product's real limits policy.
|
|
class DummyLimitsService implements LimitsService {
|
|
DummyLimitsService(this.identity);
|
|
final IdentityService identity;
|
|
@override
|
|
Future<Limits> fetch() async {
|
|
final record = await identity.fetch();
|
|
final approved = record.status == IdentityStatus.approved;
|
|
return LimitsMapper.fromDTO(
|
|
LimitsDTO(
|
|
tier: approved ? 'verified' : 'basic',
|
|
simulated: true,
|
|
rows: [
|
|
LimitDTO(
|
|
'day',
|
|
'EUR',
|
|
10000,
|
|
250000,
|
|
approved ? 250000 : 10000,
|
|
(approved ? 250000 : 10000) - 4000,
|
|
3000,
|
|
1000,
|
|
),
|
|
LimitDTO(
|
|
'month',
|
|
'EUR',
|
|
50000,
|
|
1000000,
|
|
approved ? 1000000 : 50000,
|
|
(approved ? 1000000 : 50000) - 19000,
|
|
18000,
|
|
1000,
|
|
),
|
|
],
|
|
),
|
|
);
|
|
}
|
|
}
|