116 lines
4.5 KiB
Dart
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');
|
|
}
|
|
}
|
|
}
|