Add AI batch reconciliation for accessibility bills
This commit is contained in:
@@ -138,6 +138,8 @@ class RecognitionCandidate {
|
||||
final String? merchant, orderId, sourceText, note;
|
||||
final String recognitionKind, amountSource;
|
||||
final String? categoryHint, resultFingerprint;
|
||||
final String? batchId, aiAction, aiReason;
|
||||
final int? categoryId;
|
||||
final int occurredAtEpochMs;
|
||||
|
||||
RecognitionCandidate.fromJson(Map<String, dynamic> value)
|
||||
@@ -155,13 +157,68 @@ class RecognitionCandidate {
|
||||
note = value['note'] as String?,
|
||||
recognitionKind = value['recognitionKind']?.toString() ?? 'payment',
|
||||
categoryHint = value['categoryHint']?.toString(),
|
||||
categoryId = (value['categoryId'] as num?)?.toInt(),
|
||||
amountSource = value['amountSource']?.toString() ?? 'result',
|
||||
resultFingerprint = value['resultFingerprint']?.toString(),
|
||||
batchId = value['batchId']?.toString(),
|
||||
aiAction = value['aiAction']?.toString(),
|
||||
aiReason = value['aiReason']?.toString(),
|
||||
occurredAtEpochMs = (value['occurredAtEpochMs'] as num).toInt();
|
||||
|
||||
bool get canAutoImport => state == 'auto_ready' && confidence == 'auto';
|
||||
}
|
||||
|
||||
class RecognitionBatchItem {
|
||||
final String candidateId, action, reason, state, type;
|
||||
final double amount;
|
||||
final String? merchant;
|
||||
final bool canRestore;
|
||||
|
||||
RecognitionBatchItem.fromJson(Map<String, dynamic> value)
|
||||
: candidateId = value['candidateId']?.toString() ?? '',
|
||||
action = value['action']?.toString() ?? 'keep',
|
||||
reason = value['reason']?.toString() ?? '',
|
||||
state = value['state']?.toString() ?? '',
|
||||
type = value['type']?.toString() ?? 'expense',
|
||||
amount = (value['amount'] as num?)?.toDouble() ?? 0,
|
||||
merchant = value['merchant']?.toString(),
|
||||
canRestore = value['canRestore'] as bool? ?? false;
|
||||
}
|
||||
|
||||
class RecognitionBatch {
|
||||
final String id, state;
|
||||
final DateTime openedAt, completedAt;
|
||||
final int kept, updated, created, dropped;
|
||||
final bool fallback;
|
||||
final String? failureReason;
|
||||
final List<RecognitionBatchItem> items;
|
||||
|
||||
RecognitionBatch.fromJson(Map<String, dynamic> value)
|
||||
: id = value['id']?.toString() ?? '',
|
||||
state = value['state']?.toString() ?? '',
|
||||
openedAt = DateTime.fromMillisecondsSinceEpoch(
|
||||
(value['openedAt'] as num?)?.toInt() ?? 0,
|
||||
isUtc: true,
|
||||
),
|
||||
completedAt = DateTime.fromMillisecondsSinceEpoch(
|
||||
(value['completedAt'] as num?)?.toInt() ?? 0,
|
||||
isUtc: true,
|
||||
),
|
||||
kept = ((value['summary'] as Map?)?['kept'] as num?)?.toInt() ?? 0,
|
||||
updated = ((value['summary'] as Map?)?['updated'] as num?)?.toInt() ?? 0,
|
||||
created = ((value['summary'] as Map?)?['created'] as num?)?.toInt() ?? 0,
|
||||
dropped = ((value['summary'] as Map?)?['dropped'] as num?)?.toInt() ?? 0,
|
||||
fallback = ((value['summary'] as Map?)?['fallback'] as bool?) ?? false,
|
||||
failureReason = value['failureReason']?.toString(),
|
||||
items = (value['items'] as List<dynamic>? ?? const [])
|
||||
.map(
|
||||
(item) => RecognitionBatchItem.fromJson(
|
||||
Map<String, dynamic>.from(item as Map),
|
||||
),
|
||||
)
|
||||
.toList(growable: false);
|
||||
}
|
||||
|
||||
class SpeechEvent {
|
||||
final String type;
|
||||
final String? text;
|
||||
@@ -398,6 +455,37 @@ class ScreenshotChannel {
|
||||
}
|
||||
}
|
||||
|
||||
static Future<List<RecognitionBatch>> listRecognitionBatches() async {
|
||||
try {
|
||||
final values =
|
||||
await _channel.invokeMethod<List<Object?>>(
|
||||
'listRecognitionBatches',
|
||||
) ??
|
||||
const [];
|
||||
return values
|
||||
.whereType<String>()
|
||||
.map(
|
||||
(value) => RecognitionBatch.fromJson(
|
||||
jsonDecode(value) as Map<String, dynamic>,
|
||||
),
|
||||
)
|
||||
.toList(growable: false);
|
||||
} on MissingPluginException {
|
||||
return const [];
|
||||
}
|
||||
}
|
||||
|
||||
static Future<bool> restoreDroppedRecognition(String candidateId) async {
|
||||
try {
|
||||
return await _channel.invokeMethod<bool>('restoreDroppedRecognition', {
|
||||
'candidateId': candidateId,
|
||||
}) ??
|
||||
false;
|
||||
} on MissingPluginException {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
static Future<bool> requestNotificationPermission() async {
|
||||
try {
|
||||
return await _channel.invokeMethod<bool>(
|
||||
|
||||
Reference in New Issue
Block a user