cashumit/lib/services/local_receipt_service.dart

240 lines
7.8 KiB
Dart

import 'package:shared_preferences/shared_preferences.dart';
import 'dart:convert';
import 'package:cashumit/models/local_receipt.dart';
import 'package:cashumit/models/receipt_item.dart';
import 'package:cashumit/services/firefly_api_service.dart';
class LocalReceiptService {
static const String _receiptsKey = 'local_receipts';
/// Save a receipt to local storage
static Future<void> saveReceipt(LocalReceipt receipt) async {
final prefs = await SharedPreferences.getInstance();
final receipts = await getReceipts();
// Check if receipt with the same ID already exists
final existingIndex = receipts.indexWhere((r) => r.id == receipt.id);
if (existingIndex != -1) {
// Replace existing receipt
receipts[existingIndex] = receipt;
} else {
// Add new receipt
receipts.add(receipt);
}
// Convert receipts to JSON strings
final receiptJsonList =
receipts.map((receipt) => json.encode(receipt.toJson())).toList();
await prefs.setStringList(_receiptsKey, receiptJsonList);
}
/// Get all receipts from local storage
static Future<List<LocalReceipt>> getReceipts() async {
final prefs = await SharedPreferences.getInstance();
final receiptJsonList = prefs.getStringList(_receiptsKey) ?? [];
return receiptJsonList
.map((jsonString) => LocalReceipt.fromJson(json.decode(jsonString)))
.toList();
}
/// Get unsubmitted receipts from local storage
static Future<List<LocalReceipt>> getUnsubmittedReceipts() async {
final allReceipts = await getReceipts();
return allReceipts.where((receipt) => !receipt.isSubmitted).toList();
}
/// Get submitted receipts from local storage
static Future<List<LocalReceipt>> getSubmittedReceipts() async {
final allReceipts = await getReceipts();
return allReceipts.where((receipt) => receipt.isSubmitted).toList();
}
/// Update a receipt's submission status
static Future<void> updateReceiptSubmissionStatus(String receiptId,
{bool? isSubmitted, String? submissionError}) async {
final prefs = await SharedPreferences.getInstance();
final receipts = await getReceipts();
final receiptIndex = receipts.indexWhere((r) => r.id == receiptId);
if (receiptIndex != -1) {
final receipt = receipts[receiptIndex];
receipts[receiptIndex] = receipt.copyWith(
isSubmitted: isSubmitted ?? receipt.isSubmitted,
submissionError: submissionError ?? receipt.submissionError,
submittedAt: isSubmitted == true ? DateTime.now() : receipt.submittedAt,
);
// Convert receipts to JSON strings
final receiptJsonList =
receipts.map((receipt) => json.encode(receipt.toJson())).toList();
await prefs.setStringList(_receiptsKey, receiptJsonList);
}
}
/// Remove a receipt from local storage
static Future<void> removeReceipt(String receiptId) async {
final prefs = await SharedPreferences.getInstance();
final receipts = await getReceipts();
final filteredReceipts =
receipts.where((receipt) => receipt.id != receiptId).toList();
// Convert receipts to JSON strings
final receiptJsonList = filteredReceipts
.map((receipt) => json.encode(receipt.toJson()))
.toList();
await prefs.setStringList(_receiptsKey, receiptJsonList);
}
/// Clear all receipts from local storage
static Future<void> clearAllReceipts() async {
final prefs = await SharedPreferences.getInstance();
await prefs.remove(_receiptsKey);
}
/// Submit a single receipt to FireFly III
static Future<bool> submitReceiptToServer(
LocalReceipt receipt,
String baseUrl,
String accessToken,
) async {
try {
// Check if the receipt is already submitted
if (receipt.isSubmitted) {
return true; // Already submitted
}
// Validate required fields
if (receipt.sourceAccountId == null ||
receipt.destinationAccountId == null) {
await updateReceiptSubmissionStatus(receipt.id,
isSubmitted: false, submissionError: 'Missing account information');
return false;
}
// Submit to FireFly III
final transactionId = await _submitToFireFly(
receipt: receipt,
baseUrl: baseUrl,
accessToken: accessToken,
);
if (transactionId != null) {
// Update receipt status to submitted
await updateReceiptSubmissionStatus(receipt.id,
isSubmitted: true, submissionError: null);
return true;
} else {
await updateReceiptSubmissionStatus(receipt.id,
isSubmitted: false, submissionError: 'Failed to submit to server');
return false;
}
} catch (e) {
await updateReceiptSubmissionStatus(receipt.id,
isSubmitted: false, submissionError: e.toString());
return false;
}
}
/// Submit all unsubmitted receipts to FireFly III
static Future<Map<String, dynamic>> submitAllUnsubmittedReceipts(
String baseUrl,
String accessToken,
) async {
final unsubmittedReceipts = await getUnsubmittedReceipts();
final results = <String, bool>{};
int successCount = 0;
int failureCount = 0;
for (final receipt in unsubmittedReceipts) {
try {
final success =
await submitReceiptToServer(receipt, baseUrl, accessToken);
results[receipt.id] = success;
if (success) {
successCount++;
} else {
failureCount++;
}
} catch (e) {
results[receipt.id] = false;
failureCount++;
// Update the receipt with the error
await updateReceiptSubmissionStatus(receipt.id,
isSubmitted: false, submissionError: e.toString());
}
}
return {
'results': results,
'successCount': successCount,
'failureCount': failureCount,
'totalCount': unsubmittedReceipts.length,
};
}
/// Private method to handle actual submission to FireFly III
static Future<String?> _submitToFireFly({
required LocalReceipt receipt,
required String baseUrl,
required String accessToken,
}) async {
try {
final transactionId = await FireflyApiService.submitDummyTransaction(
baseUrl: baseUrl,
accessToken: accessToken,
sourceId: receipt.sourceAccountId!,
destinationId: receipt.destinationAccountId!,
type: 'deposit', // Assuming deposit for receipts
description: receipt.transactionDescription ??
_generateTransactionDescription(receipt.items),
date:
'${receipt.transactionDate.year}-${receipt.transactionDate.month.toString().padLeft(2, '0')}-${receipt.transactionDate.day.toString().padLeft(2, '0')}',
amount: receipt.total.toStringAsFixed(2),
);
// Jika transaksi berhasil dikirim, simpan transactionId dan URL
if (transactionId != null) {
// Update receipt dengan transactionId dan URL
final updatedReceipt = receipt.copyWith(
fireflyTransactionId: transactionId,
fireflyTransactionUrl: '$baseUrl/transactions/show/$transactionId',
);
// Simpan kembali receipt yang diperbarui ke storage
await saveReceipt(updatedReceipt);
}
return transactionId;
} catch (e) {
print('Error submitting receipt to FireFly III: $e');
return null;
}
}
/// Generate transaction description
static String _generateTransactionDescription(List<ReceiptItem> items) {
if (items.isEmpty) {
return 'Transaksi Struk Belanja';
}
// Take the first 5 item descriptions
final itemNames = items.take(5).map((item) => item.description).toList();
// If there are more than 5 items, append ', dll' to the last item
if (items.length > 5) {
itemNames[4] += ', dll';
}
// Join the item names with ', '
return itemNames.join(', ');
}
}