Initial project import
This commit is contained in:
@@ -0,0 +1,149 @@
|
||||
import 'package:miaoji_zhang/shared/api/api_client.dart';
|
||||
import 'package:miaoji_zhang/shared/services/current_ledger_store.dart';
|
||||
import 'package:miaoji_zhang/shared/services/shanghai_time.dart';
|
||||
|
||||
class GuestMergeResult {
|
||||
final int ledgerId;
|
||||
final int transactionCount;
|
||||
|
||||
const GuestMergeResult({
|
||||
required this.ledgerId,
|
||||
required this.transactionCount,
|
||||
});
|
||||
}
|
||||
|
||||
class GuestMergeService {
|
||||
GuestMergeService._();
|
||||
|
||||
static final _dio = ApiClient.instance.dio;
|
||||
|
||||
static Future<GuestMergeResult> merge(Map<String, dynamic> snapshot) async {
|
||||
final ledgerResponse = await _dio.post(
|
||||
'/api/ledgers',
|
||||
data: {'name': '游客数据', 'iconKey': 'wallet'},
|
||||
);
|
||||
final ledgerId = (ledgerResponse.data['id'] as num).toInt();
|
||||
final categoryMap = <int, int>{};
|
||||
final available = <Map<String, dynamic>>[];
|
||||
for (final type in ['expense', 'income']) {
|
||||
final response = await _dio.get(
|
||||
'/api/categories',
|
||||
queryParameters: {'type': type},
|
||||
);
|
||||
available.addAll(
|
||||
(response.data as List).map((item) => item as Map<String, dynamic>),
|
||||
);
|
||||
}
|
||||
|
||||
for (final value in snapshot['categories'] as List<dynamic>? ?? const []) {
|
||||
final category = value as Map<String, dynamic>;
|
||||
final existing = available.where(
|
||||
(item) =>
|
||||
item['type'] == category['type'] &&
|
||||
item['name'] == category['name'],
|
||||
);
|
||||
Map<String, dynamic> remote;
|
||||
if (existing.isNotEmpty) {
|
||||
remote = existing.first;
|
||||
} else {
|
||||
final response = await _dio.post(
|
||||
'/api/categories',
|
||||
data: {
|
||||
'name': category['name'],
|
||||
'iconKey': category['iconKey'],
|
||||
'colorKey': category['colorKey'],
|
||||
'type': category['type'],
|
||||
},
|
||||
);
|
||||
remote = response.data as Map<String, dynamic>;
|
||||
available.add(remote);
|
||||
}
|
||||
categoryMap[(category['id'] as num).toInt()] = (remote['id'] as num)
|
||||
.toInt();
|
||||
}
|
||||
|
||||
int mapCategory(Map<String, dynamic> transaction) {
|
||||
final oldId = (transaction['categoryId'] as num).toInt();
|
||||
final custom = categoryMap[oldId];
|
||||
if (custom != null) return custom;
|
||||
final exact = available.where(
|
||||
(item) =>
|
||||
item['type'] == transaction['type'] &&
|
||||
item['name'] == transaction['categoryName'],
|
||||
);
|
||||
if (exact.isNotEmpty) return (exact.first['id'] as num).toInt();
|
||||
final fallback = available.firstWhere(
|
||||
(item) => item['type'] == transaction['type'] && item['name'] == '其他',
|
||||
);
|
||||
return (fallback['id'] as num).toInt();
|
||||
}
|
||||
|
||||
var transactionCount = 0;
|
||||
for (final value
|
||||
in snapshot['transactions'] as List<dynamic>? ?? const []) {
|
||||
final transaction = value as Map<String, dynamic>;
|
||||
await _dio.post(
|
||||
'/api/transactions',
|
||||
data: {
|
||||
'ledgerId': ledgerId,
|
||||
'categoryId': mapCategory(transaction),
|
||||
'type': transaction['type'],
|
||||
'amount': transaction['amount'],
|
||||
'note': transaction['note'],
|
||||
'paymentMethod': transaction['paymentMethod'],
|
||||
'occurredAt': transaction['occurredAt'],
|
||||
'source': 'manual',
|
||||
'sourceText': null,
|
||||
},
|
||||
);
|
||||
transactionCount++;
|
||||
}
|
||||
|
||||
for (final value in snapshot['budgets'] as List<dynamic>? ?? const []) {
|
||||
final budget = value as Map<String, dynamic>;
|
||||
final period = (budget['period'] as num).toInt();
|
||||
final recurring = budget['recurring'] == true || period == 0;
|
||||
final current = ShanghaiTime.now;
|
||||
final year = period == 0 ? current.year : period ~/ 100;
|
||||
final month = period == 0 ? current.month : period % 100;
|
||||
final oldCategoryId = (budget['categoryId'] as num?)?.toInt();
|
||||
await _dio.put(
|
||||
'/api/budgets',
|
||||
queryParameters: {'year': year, 'month': month, 'ledgerId': ledgerId},
|
||||
data: {
|
||||
'categoryId': oldCategoryId == null
|
||||
? null
|
||||
: categoryMap[oldCategoryId] ??
|
||||
_findMappedDefault(available, snapshot, oldCategoryId),
|
||||
'amount': budget['amount'],
|
||||
'recurring': recurring,
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
await CurrentLedgerStore.instance.ensureLoaded(force: true);
|
||||
await CurrentLedgerStore.instance.select(ledgerId);
|
||||
return GuestMergeResult(
|
||||
ledgerId: ledgerId,
|
||||
transactionCount: transactionCount,
|
||||
);
|
||||
}
|
||||
|
||||
static int? _findMappedDefault(
|
||||
List<Map<String, dynamic>> available,
|
||||
Map<String, dynamic> snapshot,
|
||||
int oldCategoryId,
|
||||
) {
|
||||
final transaction = (snapshot['transactions'] as List<dynamic>? ?? const [])
|
||||
.cast<Map<String, dynamic>>()
|
||||
.where((item) => item['categoryId'] == oldCategoryId)
|
||||
.firstOrNull;
|
||||
if (transaction == null) return null;
|
||||
final match = available.where(
|
||||
(item) =>
|
||||
item['type'] == transaction['type'] &&
|
||||
item['name'] == transaction['categoryName'],
|
||||
);
|
||||
return match.isEmpty ? null : (match.first['id'] as num).toInt();
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user