h-1.flutter.0/lib/services/business_calendar_mapper.dart
2026-03-04 14:55:40 +09:00

116 lines
4.5 KiB
Dart

import 'package:flutter/foundation.dart';
import 'package:intl/intl.dart';
import '../models/receivable_models.dart';
import '../models/shipment_models.dart';
import 'app_settings_repository.dart';
import 'calendar_sync_service.dart';
/// Maps domain entities (shipments, receivables, etc.) to Google Calendar events.
class BusinessCalendarMapper {
BusinessCalendarMapper({
CalendarSyncService? calendarSyncService,
AppSettingsRepository? settingsRepository,
}) : _calendarSyncService = calendarSyncService ?? CalendarSyncService(),
_settingsRepository = settingsRepository ?? AppSettingsRepository();
final CalendarSyncService _calendarSyncService;
final AppSettingsRepository _settingsRepository;
final NumberFormat _currencyFormat = NumberFormat.currency(locale: 'ja_JP', symbol: '¥');
Future<bool> _ensureReady() async {
final enabled = await _settingsRepository.getGoogleCalendarEnabled();
if (!enabled) return false;
final ready = await _calendarSyncService.ensureSignedIn();
return ready;
}
Future<void> syncShipments(List<Shipment> shipments) async {
if (shipments.isEmpty) return;
if (!await _ensureReady()) return;
for (final shipment in shipments) {
await _syncShipment(shipment);
}
}
Future<void> syncShipment(Shipment shipment) async {
if (!await _ensureReady()) return;
await _syncShipment(shipment);
}
Future<void> syncReceivables(List<ReceivableInvoiceSummary> summaries) async {
if (summaries.isEmpty) return;
if (!await _ensureReady()) return;
for (final summary in summaries) {
await _syncReceivable(summary);
}
}
Future<void> syncReceivable(ReceivableInvoiceSummary summary) async {
if (!await _ensureReady()) return;
await _syncReceivable(summary);
}
Future<void> _syncShipment(Shipment shipment) async {
final date = shipment.scheduledShipDate ?? shipment.actualShipDate;
if (date == null) return;
final start = DateTime(date.year, date.month, date.day, 9);
final end = start.add(const Duration(hours: 2));
final summary = '[出荷] ${(shipment.customerNameSnapshot ?? '取引先未設定')}';
final buffer = StringBuffer()
..writeln('受注番号: ${shipment.orderNumberSnapshot ?? '-'}')
..writeln('ステータス: ${shipment.status.displayName}')
..writeln('配送業者: ${shipment.carrierName ?? '-'}')
..writeln('追跡番号: ${shipment.trackingNumber ?? '-'}');
if (shipment.trackingUrl?.isNotEmpty == true) {
buffer.writeln('トラッキングURL: ${shipment.trackingUrl}');
}
try {
await _calendarSyncService.createOrUpdateEvent(
eventId: 'shipment-${shipment.id}',
summary: summary,
description: buffer.toString(),
start: start,
end: end,
extendedProperties: {
'type': 'shipment',
'shipmentId': shipment.id,
if (shipment.orderNumberSnapshot != null) 'orderNumber': shipment.orderNumberSnapshot!,
if (shipment.customerNameSnapshot != null) 'customer': shipment.customerNameSnapshot!,
},
);
} catch (e, stack) {
debugPrint('Failed to sync shipment ${shipment.id} to calendar: $e\n$stack');
}
}
Future<void> _syncReceivable(ReceivableInvoiceSummary summary) async {
final dueDate = summary.dueDate;
final start = DateTime(dueDate.year, dueDate.month, dueDate.day, 10);
final end = start.add(const Duration(hours: 1));
final title = '[入金予定] ${summary.customerName}';
final description = StringBuffer()
..writeln('請求書番号: ${summary.invoiceNumber}')
..writeln('請求日: ${DateFormat('yyyy/MM/dd').format(summary.invoiceDate)}')
..writeln('期日: ${DateFormat('yyyy/MM/dd').format(summary.dueDate)}')
..writeln('請求額: ${_currencyFormat.format(summary.totalAmount)}')
..writeln('入金済み: ${_currencyFormat.format(summary.paidAmount)}')
..writeln('残高: ${_currencyFormat.format(summary.outstandingAmount)}');
try {
await _calendarSyncService.createOrUpdateEvent(
eventId: 'receivable-${summary.invoiceId}',
summary: title,
description: description.toString(),
start: start,
end: end,
extendedProperties: {
'type': 'receivable',
'invoiceId': summary.invoiceId,
'invoiceNumber': summary.invoiceNumber,
},
);
} catch (e, stack) {
debugPrint('Failed to sync receivable ${summary.invoiceId} to calendar: $e\n$stack');
}
}
}