import 'package:flutter/material.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:sysfarma_mobile/src/app/widgets/app_loader.dart'; import 'package:sysfarma_mobile/src/core/network/api_client.dart'; import 'package:sysfarma_mobile/src/core/theme/app_tokens.dart'; import 'package:sysfarma_mobile/src/features/yape_inbox/data/yape_inbox_providers.dart'; /// Sheet para vincular un pago capturado a un comprobante pendiente de cobro. /// Lista las cuentas por cobrar (receivables) cuyo saldo alcanza al monto del /// pago; el destino es la caja abierta del cajero (el backend lo valida). class ClaimPaymentSheet extends ConsumerStatefulWidget { const ClaimPaymentSheet({super.key, required this.payment}); final ReceivedPaymentRow payment; @override ConsumerState createState() => _ClaimPaymentSheetState(); } class _ClaimPaymentSheetState extends ConsumerState { bool _loading = true; bool _submitting = false; List> _receivables = const []; String? _error; @override void initState() { super.initState(); _load(); } Future _load() async { final response = await ref.read(apiClientProvider).receivables(perPage: 50); if (!mounted) return; setState(() { _loading = false; if (response.success) { // Solo los que el pago alcanza a cubrir (sin sobrepago -- el backend // tambien lo valida, esto es para no mostrar opciones que fallarian). _receivables = (response.data ?? []) .where((row) => (double.tryParse('${row['total_to_pay']}') ?? 0) + 0.01 >= widget.payment.amount) .toList(); } else { _error = response.message ?? 'No se pudieron cargar los comprobantes.'; } }); } Future _claim(Map row) async { setState(() => _submitting = true); final response = await ref.read(apiClientProvider).yapeInboxClaim( id: widget.payment.id, payload: { 'matched_type': row['type'] == 'sale_note' ? 'sale_note' : 'document', 'matched_id': (row['id'] as num).toInt(), 'payment_destination_id': 'cash', }, ); if (!mounted) return; setState(() => _submitting = false); if (response.success) { Navigator.pop(context, true); } else { ScaffoldMessenger.of(context).showSnackBar( SnackBar(content: Text(response.message ?? 'No se pudo vincular el pago.')), ); } } @override Widget build(BuildContext context) { return Container( decoration: const BoxDecoration( color: AppTokens.surface, borderRadius: BorderRadius.vertical(top: Radius.circular(AppTokens.radiusLarge)), ), padding: EdgeInsets.only( left: 20, right: 20, top: 16, bottom: MediaQuery.of(context).viewInsets.bottom + 20, ), child: Column( mainAxisSize: MainAxisSize.min, crossAxisAlignment: CrossAxisAlignment.start, children: [ Center( child: Container( width: 40, height: 4, decoration: BoxDecoration( color: AppTokens.border, borderRadius: BorderRadius.circular(AppTokens.radiusPill), ), ), ), const SizedBox(height: 16), Text( 'Vincular pago de S/ ${widget.payment.amount.toStringAsFixed(2)}', style: const TextStyle(fontSize: 18, fontWeight: FontWeight.w700, color: AppTokens.textPrimary), ), const SizedBox(height: 4), const Text( 'Elige el comprobante que este pago cancela. Entra a tu caja abierta.', style: TextStyle(fontSize: 13, color: AppTokens.textSecondary), ), const SizedBox(height: 16), if (_loading) const Padding(padding: EdgeInsets.all(32), child: Center(child: AppLoader())) else if (_error != null) Padding( padding: const EdgeInsets.symmetric(vertical: 24), child: Text(_error!, style: const TextStyle(color: AppTokens.danger)), ) else if (_receivables.isEmpty) const Padding( padding: EdgeInsets.symmetric(vertical: 24), child: Text( 'No hay comprobantes pendientes con saldo suficiente para este pago.', style: TextStyle(color: AppTokens.textSecondary), ), ) else Flexible( child: ListView.separated( shrinkWrap: true, itemCount: _receivables.length, separatorBuilder: (_, __) => const Divider(height: 1, color: AppTokens.border), itemBuilder: (context, index) { final row = _receivables[index]; return ListTile( contentPadding: EdgeInsets.zero, title: Text('${row['number_full'] ?? ''}', style: const TextStyle(fontWeight: FontWeight.w600)), subtitle: Text('${row['customer_name'] ?? ''} ยท Saldo S/ ${row['total_to_pay'] ?? ''}'), trailing: _submitting ? null : const Icon(Icons.chevron_right_rounded, color: AppTokens.textSecondary), onTap: _submitting ? null : () => _claim(row), ); }, ), ), ], ), ); } }