import 'package:flutter/material.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:hl_lieferservice/domain/entity/delivery.dart'; import 'package:hl_lieferservice/domain/entity/tour_details.dart'; import 'package:hl_lieferservice/feature/car_selection/bloc/bloc.dart'; import 'package:hl_lieferservice/feature/car_selection/bloc/state.dart'; import 'package:hl_lieferservice/feature/delivery/bloc/tour_bloc.dart'; import 'package:hl_lieferservice/feature/delivery/bloc/tour_event.dart'; import 'package:hl_lieferservice/feature/delivery/detail/model/delivery_payment_status.dart'; import 'package:hl_lieferservice/feature/delivery/detail/presentation/widget/delivered_items_card.dart'; import 'package:hl_lieferservice/feature/delivery/detail/presentation/widget/payment_breakdown_card.dart'; import 'package:hl_lieferservice/feature/delivery/detail/presentation/widget/payment_record_card.dart'; import 'package:hl_lieferservice/feature/delivery/detail/presentation/widget/payment_sheet.dart'; /// Step „Zahlung" — Zahlungsabwicklung („Abkassieren") vor der Übersicht. /// /// Zeigt die ausgelieferten Artikel mit Menge und Preis, die Betrags- /// aufstellung und den Zahlungsstatus. Über „Zahlung abwickeln" öffnet sich /// das Zahlungs-Modal; die Bestätigung wird am Server protokolliert. /// /// Ist nichts offen (bereits bezahlt), kann der Fahrer den Step /// überspringen. Sonst gibt die Detail-Page „Weiter" erst frei, wenn eine /// gültige Zahlung protokolliert ist (siehe `DeliveryPaymentStatus`). class StepPayment extends StatelessWidget { const StepPayment({super.key, required this.delivery, required this.details}); final Delivery delivery; final TourDetails details; @override Widget build(BuildContext context) { final status = DeliveryPaymentStatus.of(delivery, details); final canCollect = delivery.state == DeliveryState.active && status.hasOpenAmount; return Column( children: [ Expanded( child: ListView( padding: const EdgeInsets.fromLTRB(16, 16, 16, 24), children: [ const _SectionHeader(text: 'Ausgelieferte Artikel'), const SizedBox(height: 8), DeliveredItemsCard(delivery: delivery, details: details), const SizedBox(height: 24), const _SectionHeader(text: 'Betrag'), const SizedBox(height: 8), PaymentBreakdownCard( status: status, credit: details.creditOf(delivery.id), ), const SizedBox(height: 16), PaymentRecordCard(status: status), ], ), ), if (canCollect) _CollectPanel( status: status, onCollect: () => _openPaymentSheet(context, status), ), ], ); } Future _openPaymentSheet( BuildContext context, DeliveryPaymentStatus status, ) async { final tourBloc = context.read(); final actorCarId = _actorCarId(context); final customer = details.customerOf(delivery); final result = await showPaymentSheet( context, openCents: status.openCents, customerNumber: customer?.erpCustomerId ?? 0, // Vorauswahl: zuletzt abgewickelte Methode, sonst die vom Beleg. preselectedMethodId: status.latestPayment?.paymentMethodId ?? delivery.paymentMethodId, ); switch (result) { case PaymentConfirmed(:final method): tourBloc.add( RecordDeliveryPayment( deliveryId: delivery.id, paymentMethodId: method.id, expectedAmountCents: status.openCents, actorCarId: actorCarId, ), ); case DeliveryCancelRequested(:final reason): tourBloc.add(CancelDelivery(deliveryId: delivery.id, reason: reason)); case null: break; } } String? _actorCarId(BuildContext context) { final state = context.read().state; return state is CarSelectComplete ? state.selectedCar.id : null; } } /// Fester Bereich unten: offener Betrag + großer „Zahlung abwickeln"-Button. /// Bleibt sichtbar, auch wenn die Artikelliste lang ist. class _CollectPanel extends StatelessWidget { const _CollectPanel({required this.status, required this.onCollect}); final DeliveryPaymentStatus status; final VoidCallback onCollect; @override Widget build(BuildContext context) { final theme = Theme.of(context); final settled = status.validPayment != null; return Material( elevation: 6, color: theme.colorScheme.surface, child: Padding( padding: const EdgeInsets.fromLTRB(16, 12, 16, 12), child: Column( crossAxisAlignment: CrossAxisAlignment.stretch, children: [ Row( children: [ Text('Offener Betrag', style: theme.textTheme.titleMedium), const Spacer(), Text( formatEuroCents(status.openCents), style: theme.textTheme.headlineSmall?.copyWith( fontWeight: FontWeight.w800, color: theme.colorScheme.primary, ), ), ], ), const SizedBox(height: 10), if (settled) // Bereits abgewickelt: Korrektur möglich, aber nicht mehr im // Vordergrund — „Weiter" ist jetzt der nächste Schritt. OutlinedButton.icon( style: OutlinedButton.styleFrom( minimumSize: const Size.fromHeight(52), ), onPressed: onCollect, icon: const Icon(Icons.edit_outlined), label: const Text('Zahlung korrigieren'), ) else FilledButton.icon( style: FilledButton.styleFrom( minimumSize: const Size.fromHeight(68), textStyle: const TextStyle( fontSize: 20, fontWeight: FontWeight.w700, ), ), onPressed: onCollect, icon: const Icon(Icons.point_of_sale, size: 28), label: const Text('Zahlung abwickeln'), ), ], ), ), ); } } class _SectionHeader extends StatelessWidget { const _SectionHeader({required this.text}); final String text; @override Widget build(BuildContext context) { return Text( text, style: Theme.of( context, ).textTheme.titleMedium?.copyWith(fontWeight: FontWeight.w700), ); } }