import 'dart:math'; import 'package:flutter/material.dart'; class ProductItem { final String id; final String name; final double price; final int stock; final String code; ProductItem({ required this.id, required this.name, required this.price, required this.stock, required this.code, }); } class BillingItem { final ProductItem product; int quantity; BillingItem({ required this.product, required this.quantity, }); } class BillingDashboardScreen extends StatefulWidget { final String businessName; final String businessType; final String gstin; final bool barcodeScanner; final bool kotManagement; final bool inventoryAlerts; const BillingDashboardScreen({ super.key, required this.businessName, required this.businessType, required this.gstin, required this.barcodeScanner, required this.kotManagement, required this.inventoryAlerts, }); @override State createState() => _BillingDashboardScreenState(); } class _BillingDashboardScreenState extends State { late List _products; final List _billingList = []; bool _printingInvoice = false; String _invoiceNumber = 'POZO-26402'; String _scanMessage = ''; final Map> _inventoryPresets = { 'supermarket': [ ProductItem(id: 'sm1', name: 'Premium Basmati Rice (1kg)', price: 120.0, stock: 45, code: '89012300052'), ProductItem(id: 'sm2', name: 'Fresh Farm Milk (1L)', price: 65.0, stock: 2, code: '89045300010'), ProductItem(id: 'sm3', name: 'Refined Cooking Oil (1L)', price: 165.0, stock: 18, code: '89010320491'), ProductItem(id: 'sm4', name: 'Refined White Sugar (1kg)', price: 48.0, stock: 3, code: '89034200421'), ProductItem(id: 'sm5', name: 'Organic Green T-Tea (250g)', price: 110.0, stock: 24, code: '89512300011'), ProductItem(id: 'sm6', name: 'Whole Wheat Atta (5kg)', price: 230.0, stock: 7, code: '89011210042'), ], 'restaurant': [ ProductItem(id: 'rt1', name: 'Fresh Paneer Butter Masala', price: 240.0, stock: 19, code: '9901230'), ProductItem(id: 'rt2', name: 'Butter Tandoori Naan', price: 45.0, stock: 15, code: '9904530'), ProductItem(id: 'rt3', name: 'Dum Veg Biryani Deluxe', price: 190.0, stock: 2, code: '9901032'), ProductItem(id: 'rt4', name: 'Crispy Butter Masala Dosa', price: 90.0, stock: 22, code: '9903420'), ProductItem(id: 'rt5', name: 'Rich Chocolate Milkshake', price: 120.0, stock: 3, code: '9951230'), ProductItem(id: 'rt6', name: 'Hot Roasted Filter Coffee', price: 50.0, stock: 30, code: '9901121'), ], 'clothing': [ ProductItem(id: 'cl1', name: 'Premium Oxford Cotton Shirt', price: 899.0, stock: 8, code: '77012301'), ProductItem(id: 'cl2', name: 'Slim Fit Dark Jeans', price: 1599.0, stock: 2, code: '77045302'), ProductItem(id: 'cl3', name: 'Designer Summer Slip Dress', price: 1299.0, stock: 5, code: '77010323'), ProductItem(id: 'cl4', name: 'Graphic Printed Tee-Shirt', price: 450.0, stock: 40, code: '77034204'), ProductItem(id: 'cl5', name: 'Breathable Sports Sneakers', price: 1899.0, stock: 3, code: '77512305'), ProductItem(id: 'cl6', name: 'Stitch Leather Belt Brown', price: 349.0, stock: 12, code: '77011216'), ], 'kirana': [ ProductItem(id: 'kr1', name: 'Premium Toor Dal (1kg)', price: 145.0, stock: 15, code: '4401230'), ProductItem(id: 'kr2', name: 'Iodized Powdered Salt (1kg)', price: 22.0, stock: 50, code: '4404530'), ProductItem(id: 'kr3', name: 'Herbal Moisturizer Soap', price: 42.0, stock: 2, code: '4401032'), ProductItem(id: 'kr4', name: 'Anti-Germ Toothpaste (200g)', price: 85.0, stock: 16, code: '4403420'), ProductItem(id: 'kr5', name: 'Dishwash Cleaning Soap', price: 25.0, stock: 3, code: '4451230'), ProductItem(id: 'kr6', name: 'Red Chili Powder (200g)', price: 65.0, stock: 18, code: '4401121'), ], 'others': [ ProductItem(id: 'ot1', name: 'Utility Household Scrubber', price: 35.0, stock: 33, code: '5501230'), ProductItem(id: 'ot2', name: 'AAA Rechargeable Batteries', price: 120.0, stock: 4, code: '5504530'), ProductItem(id: 'ot3', name: 'LED High Bright Focus Bulb', price: 140.0, stock: 2, code: '5501032'), ProductItem(id: 'ot4', name: 'Water Bottle Stainless (1L)', price: 320.0, stock: 11, code: '5503420'), ProductItem(id: 'ot5', name: 'Microfiber Floor Duster', price: 75.0, stock: 24, code: '5551230'), ProductItem(id: 'ot6', name: 'Multi-plug Protection Adapter', price: 240.0, stock: 9, code: '5501121'), ] }; @override void initState() { super.initState(); _products = _inventoryPresets[widget.businessType] ?? _inventoryPresets['supermarket']!; } void _handleAddItem(ProductItem product) { setState(() { final index = _billingList.indexWhere((element) => element.product.id == product.id); if (index != -1) { final existingItem = _billingList[index]; if (existingItem.quantity >= product.stock && widget.inventoryAlerts) { _showErrorSnackBar('Cannot add more. Inventory limit reached for ${product.name}!'); return; } existingItem.quantity += 1; } else { _billingList.add(BillingItem(product: product, quantity: 1)); } }); } void _handleRemoveOne(String productId) { setState(() { final index = _billingList.indexWhere((element) => element.product.id == productId); if (index != -1) { if (_billingList[index].quantity > 1) { _billingList[index].quantity -= 1; } else { _billingList.removeAt(index); } } }); } void _simulateBarcodeScan() { if (!widget.barcodeScanner) return; final random = Random(); final randomProduct = _products[random.nextInt(_products.length)]; _handleAddItem(randomProduct); setState(() { _scanMessage = '🎯 Scanned EAN Barcode [${randomProduct.code}] - Added ${randomProduct.name}!'; }); Future.delayed(const Duration(milliseconds: 3000), () { if (mounted) { setState(() { _scanMessage = ''; }); } }); } void _clearRegister() { setState(() { _billingList.clear(); }); } void _showErrorSnackBar(String message) { ScaffoldMessenger.of(context).showSnackBar( SnackBar( content: Text(message), backgroundColor: Colors.red[800], behavior: SnackBarBehavior.floating, ), ); } double get _subtotal { return _billingList.fold(0.0, (sum, item) => sum + (item.product.price * item.quantity)); } bool get _hasGstin { return widget.gstin.trim().isNotEmpty; } double get _cgst => _hasGstin ? _subtotal * 0.09 : 0.0; double get _sgst => _hasGstin ? _subtotal * 0.09 : 0.0; double get _total => _subtotal + _cgst + _sgst; void _handleReviewAndGenerate() { final random = Random(); final invoiceVal = 'POZO-${random.nextInt(90000) + 10000}'; setState(() { _invoiceNumber = invoiceVal; _printingInvoice = true; }); } void _closeReceiptAndReset() { setState(() { _printingInvoice = false; _billingList.clear(); }); } @override Widget build(BuildContext context) { final theme = Theme.of(context); final isDesktop = MediaQuery.of(context).size.width >= 600; return Stack( children: [ Scaffold( backgroundColor: const Color(0xFF1E293B), // Slate-900 like appBar: AppBar( backgroundColor: const Color(0xFF0F172A), // Slate-950 like elevation: 4, leading: IconButton( icon: const Icon(Icons.arrow_back, color: Colors.white), onPressed: () => Navigator.pop(context), ), title: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text( widget.businessName.isNotEmpty ? widget.businessName : 'Sharma General Store', style: const TextStyle( color: Colors.white, fontWeight: FontWeight.bold, fontSize: 15, ), ), Row( children: [ Container( width: 6, height: 6, decoration: const BoxDecoration( color: Color(0xFF10B981), shape: BoxShape.circle, ), ), const SizedBox(width: 4), const Text( 'Live Register', style: TextStyle( color: Colors.grey, fontSize: 10, fontWeight: FontWeight.bold, ), ), ], ), ], ), actions: [ if (widget.barcodeScanner) Padding( padding: const EdgeInsets.only(right: 8.0), child: Directionality( textDirection: TextDirection.rtl, child: ElevatedButton.icon( onPressed: _simulateBarcodeScan, style: ElevatedButton.styleFrom( minimumSize: const Size(0, 32), backgroundColor: theme.colorScheme.primary, foregroundColor: Colors.white, padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 8), shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(12), ), ), icon: const Icon(Icons.qr_code_scanner, size: 16), label: const Text( 'Scan Item', style: TextStyle(fontSize: 10, fontWeight: FontWeight.bold), ), ), ), ), if (widget.kotManagement) Container( margin: const EdgeInsets.symmetric(horizontal: 4, vertical: 12), padding: const EdgeInsets.symmetric(horizontal: 8, vertical: 4), decoration: BoxDecoration( color: Colors.cyan.withOpacity(0.15), borderRadius: BorderRadius.circular(8), border: Border.all(color: Colors.cyan.withOpacity(0.3)), ), child: const Center( child: Text( 'KOT', style: TextStyle( color: Colors.cyanAccent, fontSize: 10, fontWeight: FontWeight.bold, ), ), ), ), const SizedBox(width: 8), ], ), body: SafeArea( child: Column( children: [ // Scan Banner Message if (_scanMessage.isNotEmpty) Container( width: double.infinity, color: const Color(0xFF10B981), padding: const EdgeInsets.symmetric(vertical: 8, horizontal: 16), child: Row( mainAxisAlignment: MainAxisAlignment.center, children: [ const Icon(Icons.stars, color: Colors.white, size: 16), const SizedBox(width: 8), Expanded( child: Text( _scanMessage, style: const TextStyle( color: Colors.white, fontSize: 12, fontWeight: FontWeight.bold, ), textAlign: TextAlign.center, ), ), ], ), ), // Main Layout Split Expanded( child: isDesktop ? Row( children: [ Expanded(child: _buildCatalogPart(theme)), _buildLedgerTrayPart(theme, isDesktop), ], ) : Column( children: [ Expanded(child: _buildCatalogPart(theme)), const Divider(color: Color(0xFF334155), height: 1), SizedBox( height: 240, child: _buildLedgerTrayPart(theme, isDesktop), ), ], ), ), // Bottom Checkout sum action for Mobile ONLY if (!isDesktop) _buildBottomComputationBar(theme), ], ), ), ), // Custom Overlay for Printable Invoice if (_printingInvoice) _buildThermalReceiptOverlay(theme), ], ); } Widget _buildCatalogPart(ThemeData theme) { return Padding( padding: const EdgeInsets.all(12.0), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ const Text( 'STORE CATALOG', style: TextStyle( color: Colors.grey, fontWeight: FontWeight.bold, fontSize: 11, letterSpacing: 1.0, ), ), Container( padding: const EdgeInsets.symmetric(horizontal: 8, vertical: 2), decoration: BoxDecoration( color: const Color(0xFF334155), borderRadius: BorderRadius.circular(10), ), child: Text( widget.businessType.toUpperCase(), style: const TextStyle( color: Colors.white70, fontSize: 9, fontWeight: FontWeight.bold, ), ), ), ], ), const SizedBox(height: 10), Expanded( child: GridView.builder( physics: const BouncingScrollPhysics(), gridDelegate: const SliverGridDelegateWithFixedCrossAxisCount( crossAxisCount: 2, crossAxisSpacing: 10, mainAxisSpacing: 10, childAspectRatio: 1.4, ), itemCount: _products.length, itemBuilder: (context, index) { final prod = _products[index]; final billingIndex = _billingList.indexWhere((element) => element.product.id == prod.id); final countInCart = billingIndex != -1 ? _billingList[billingIndex].quantity : 0; final remainingStock = prod.stock - countInCart; final isLowStock = widget.inventoryAlerts && remainingStock <= 3; final isOutOfStock = widget.inventoryAlerts && remainingStock <= 0; return InkWell( onTap: isOutOfStock ? null : () => _handleAddItem(prod), borderRadius: BorderRadius.circular(16), child: Container( padding: const EdgeInsets.all(10), decoration: BoxDecoration( color: countInCart > 0 ? const Color(0xFF1E1B4B) // Deep indigo accent : const Color(0xFF1E293B).withOpacity(0.8), borderRadius: BorderRadius.circular(16), border: Border.all( color: countInCart > 0 ? theme.colorScheme.primary : const Color(0xFF334155), width: countInCart > 0 ? 1.5 : 1.0, ), ), child: Column( crossAxisAlignment: CrossAxisAlignment.start, mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ Expanded( child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text( prod.name, maxLines: 2, overflow: TextOverflow.ellipsis, style: const TextStyle( color: Colors.white, fontWeight: FontWeight.bold, fontSize: 11, ), ), const SizedBox(height: 4), Text( '₹${prod.price.toStringAsFixed(0)}', style: TextStyle( color: theme.colorScheme.primary, fontWeight: FontWeight.w800, fontSize: 13, ), ), ], ), ), Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ if (widget.inventoryAlerts) Container( padding: const EdgeInsets.symmetric(horizontal: 6, vertical: 2), decoration: BoxDecoration( color: isLowStock ? Colors.red.withOpacity(0.15) : const Color(0xFF334155), borderRadius: BorderRadius.circular(6), ), child: Text( isOutOfStock ? 'Out of stock' : '$remainingStock Stock', style: TextStyle( color: isLowStock ? Colors.redAccent : Colors.grey, fontSize: 8, fontWeight: FontWeight.bold, ), ), ) else const SizedBox(), if (countInCart > 0) Container( width: 20, height: 20, decoration: BoxDecoration( color: theme.colorScheme.primary, shape: BoxShape.circle, ), alignment: Alignment.center, child: Text( '$countInCart', style: const TextStyle( color: Colors.white, fontWeight: FontWeight.bold, fontSize: 10, ), ), ) ], ) ], ), ), ); }, ), ) ], ), ); } Widget _buildLedgerTrayPart(ThemeData theme, bool isDesktop) { return Container( width: isDesktop ? 300 : double.infinity, color: const Color(0xFF0F172A).withOpacity(0.3), padding: const EdgeInsets.all(12), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ Text( 'BILLING TRAY (${_billingList.length})', style: const TextStyle( color: Colors.grey, fontWeight: FontWeight.bold, fontSize: 11, letterSpacing: 1.0, ), ), if (_billingList.isNotEmpty) GestureDetector( onTap: _clearRegister, child: const Row( children: [ Icon(Icons.refresh, color: Colors.grey, size: 12), SizedBox(width: 4), Text( 'Clear', style: TextStyle( color: Colors.grey, fontWeight: FontWeight.bold, fontSize: 10, ), ) ], ), ) ], ), const SizedBox(height: 10), Expanded( child: _billingList.isEmpty ? Center( child: Column( mainAxisAlignment: MainAxisAlignment.center, children: [ Icon(Icons.shopping_cart_outlined, color: Colors.grey[600], size: 30), const SizedBox(height: 8), const Text( 'No products selected.', style: TextStyle(color: Colors.grey, fontSize: 11), ), const Text( 'Tap items in catalog above.', style: TextStyle(color: Colors.white30, fontSize: 10), ), ], ), ) : ListView.builder( physics: const BouncingScrollPhysics(), itemCount: _billingList.length, itemBuilder: (context, index) { final item = _billingList[index]; return Container( margin: const EdgeInsets.only(bottom: 8), padding: const EdgeInsets.all(8), decoration: BoxDecoration( color: const Color(0xFF1E293B), borderRadius: BorderRadius.circular(12), border: Border.all(color: const Color(0xFF334155), width: 0.5), ), child: Row( children: [ Expanded( child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text( item.product.name, maxLines: 1, overflow: TextOverflow.ellipsis, style: const TextStyle( color: Colors.white, fontWeight: FontWeight.bold, fontSize: 11, ), ), const SizedBox(height: 2), Text( '₹${item.product.price.toStringAsFixed(0)} × ${item.quantity}', style: const TextStyle( color: Colors.grey, fontSize: 10, fontWeight: FontWeight.bold, ), ), ], ), ), Row( children: [ GestureDetector( onTap: () => _handleRemoveOne(item.product.id), child: Container( padding: const EdgeInsets.all(4), decoration: BoxDecoration( color: const Color(0xFF334155), borderRadius: BorderRadius.circular(6), ), child: const Icon(Icons.remove, size: 14, color: Colors.white), ), ), Padding( padding: const EdgeInsets.symmetric(horizontal: 8.0), child: Text( '${item.quantity}', style: const TextStyle( color: Colors.white, fontWeight: FontWeight.bold, fontSize: 12, ), ), ), GestureDetector( onTap: () => _handleAddItem(item.product), child: Container( padding: const EdgeInsets.all(4), decoration: BoxDecoration( color: const Color(0xFF334155), borderRadius: BorderRadius.circular(6), ), child: const Icon(Icons.add, size: 14, color: Colors.white), ), ), ], ), ], ), ); }, ), ), if (isDesktop) ...[ const Divider(color: Color(0xFF334155), height: 16), _buildComputationCalculations(theme), const SizedBox(height: 10), ElevatedButton( onPressed: _billingList.isEmpty ? null : _handleReviewAndGenerate, style: ElevatedButton.styleFrom( backgroundColor: theme.colorScheme.primary, disabledBackgroundColor: const Color(0xFF1E293B), minimumSize: const Size.fromHeight(48), ), child: const Row( mainAxisAlignment: MainAxisAlignment.center, children: [ Icon(Icons.receipt, size: 16), SizedBox(width: 8), Text('Generate Invoice'), ], ), ) ] ], ), ); } Widget _buildComputationCalculations(ThemeData theme) { return Column( children: [ Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ const Text('Subtotal', style: TextStyle(color: Colors.grey, fontSize: 11)), Text('₹${_subtotal.toStringAsFixed(2)}', style: const TextStyle(color: Colors.white, fontSize: 11, fontWeight: FontWeight.bold)), ], ), if (_hasGstin) ...[ const SizedBox(height: 4), Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ const Text('CGST (9%)', style: TextStyle(color: Colors.grey, fontSize: 11)), Text('₹${_cgst.toStringAsFixed(2)}', style: const TextStyle(color: Colors.white70, fontSize: 11)), ], ), const SizedBox(height: 4), Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ const Text('SGST (9%)', style: TextStyle(color: Colors.grey, fontSize: 11)), Text('₹${_sgst.toStringAsFixed(2)}', style: const TextStyle(color: Colors.white70, fontSize: 11)), ], ), ], const Padding( padding: EdgeInsets.symmetric(vertical: 6.0), child: Divider(color: Color(0xFF334155), height: 1), ), Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ const Text('Grand Total', style: TextStyle(color: Colors.white, fontSize: 13, fontWeight: FontWeight.bold)), Text( '₹${_total.toStringAsFixed(2)}', style: TextStyle( color: theme.colorScheme.primary, fontSize: 14, fontWeight: FontWeight.w900, ), ), ], ), ], ); } Widget _buildBottomComputationBar(ThemeData theme) { return Container( color: const Color(0xFF0F172A), padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 12), child: Column( mainAxisSize: MainAxisSize.min, children: [ Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ const Text('GRAND TOTAL', style: TextStyle(color: Colors.grey, fontSize: 9, fontWeight: FontWeight.bold)), Text( '₹${_total.toStringAsFixed(2)}', style: TextStyle( color: theme.colorScheme.primary, fontSize: 18, fontWeight: FontWeight.w900, ), ) ], ), ElevatedButton( onPressed: _billingList.isEmpty ? null : _handleReviewAndGenerate, style: ElevatedButton.styleFrom( padding: const EdgeInsets.symmetric(horizontal: 24, vertical: 12), minimumSize: const Size(180, 44), ), child: const Row( mainAxisSize: MainAxisSize.min, children: [ Icon(Icons.print, size: 16), SizedBox(width: 8), Text('Review & Invoice', style: TextStyle(fontSize: 12)), ], ), ) ], ) ], ), ); } Widget _buildThermalReceiptOverlay(ThemeData theme) { return Scaffold( backgroundColor: Colors.black87, body: Center( child: SingleChildScrollView( padding: const EdgeInsets.symmetric(horizontal: 16.0, vertical: 30), child: Container( width: double.infinity, constraints: const BoxConstraints(maxWidth: 340), padding: const EdgeInsets.all(16), decoration: BoxDecoration( color: Colors.white, borderRadius: BorderRadius.circular(20), ), child: Column( mainAxisSize: MainAxisSize.min, children: [ // Thermal dotted-dash receipt border box Container( padding: const EdgeInsets.all(12), decoration: BoxDecoration( border: Border.all(color: Colors.grey[400]!, width: 2, style: BorderStyle.solid), borderRadius: BorderRadius.circular(4), ), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Center( child: Column( children: [ Text( widget.businessName.isNotEmpty ? widget.businessName.toUpperCase() : 'SHARMA GENERAL STORE', textAlign: TextAlign.center, style: const TextStyle( color: Colors.black, fontWeight: FontWeight.w900, fontSize: 16, fontFamily: 'monospace', ), ), const SizedBox(height: 2), Text( '${widget.businessType.toUpperCase()} COUNTER', style: const TextStyle( color: Colors.grey, fontSize: 9, fontFamily: 'monospace', ), ), if (_hasGstin) ...[ const SizedBox(height: 4), Text( 'GSTIN: ${widget.gstin}', style: const TextStyle( color: Colors.black, fontSize: 8, fontWeight: FontWeight.bold, fontFamily: 'monospace', ), ), ] ], ), ), const SizedBox(height: 12), const Divider(color: Colors.black38, thickness: 1), const SizedBox(height: 4), // Metadata Info _buildReceiptRow('Invoice No', _invoiceNumber), _buildReceiptRow('Date Track', '${DateTime.now().day}/${DateTime.now().month}/${DateTime.now().year}'), _buildReceiptRow('Terminal', 'Pozo Counter'), const SizedBox(height: 4), const Divider(color: Colors.black38, thickness: 1), const SizedBox(height: 4), // Headers const Row( children: [ Expanded( flex: 6, child: Text('Item Description', style: TextStyle(fontWeight: FontWeight.bold, color: Colors.black, fontSize: 8, fontFamily: 'monospace')), ), Expanded( flex: 2, child: Text('Qty', textAlign: TextAlign.right, style: TextStyle(fontWeight: FontWeight.bold, color: Colors.black, fontSize: 8, fontFamily: 'monospace')), ), Expanded( flex: 4, child: Text('Price', textAlign: TextAlign.right, style: TextStyle(fontWeight: FontWeight.bold, color: Colors.black, fontSize: 8, fontFamily: 'monospace')), ), ], ), const SizedBox(height: 6), // Products ..._billingList.map((item) => Padding( padding: const EdgeInsets.only(bottom: 6.0), child: Row( children: [ Expanded( flex: 6, child: Text( item.product.name, maxLines: 1, overflow: TextOverflow.ellipsis, style: const TextStyle(color: Colors.black87, fontSize: 9, fontFamily: 'monospace'), ), ), Expanded( flex: 2, child: Text( 'x${item.quantity}', textAlign: TextAlign.right, style: const TextStyle(color: Colors.black87, fontSize: 9, fontFamily: 'monospace'), ), ), Expanded( flex: 4, child: Text( '₹${(item.product.price * item.quantity).toStringAsFixed(0)}', textAlign: TextAlign.right, style: const TextStyle(color: Colors.black, fontWeight: FontWeight.bold, fontSize: 9, fontFamily: 'monospace'), ), ), ], ), )), const Divider(color: Colors.black38, thickness: 1), const SizedBox(height: 4), // Ledger math sum _buildReceiptRow('Cart Total:', '₹${_subtotal.toStringAsFixed(2)}'), if (_hasGstin) ...[ _buildReceiptRow('CGST (9%):', '₹${_cgst.toStringAsFixed(2)}'), _buildReceiptRow('SGST (9%):', '₹${_sgst.toStringAsFixed(2)}'), ], const SizedBox(height: 4), _buildReceiptRow('NET TOTAL:', '₹${_total.toStringAsFixed(2)}', isBold: true), const SizedBox(height: 8), const Divider(color: Colors.black38, thickness: 1), const SizedBox(height: 8), const Center( child: Column( children: [ Text( 'THANK YOU FOR YOUR PATRONAGE!', style: TextStyle(color: Colors.black54, fontSize: 8, fontWeight: FontWeight.bold, fontFamily: 'monospace'), ), SizedBox(height: 4), Text( 'Powered by PozoApp', style: TextStyle(color: Colors.red, fontSize: 8, fontWeight: FontWeight.bold, fontFamily: 'monospace'), ), ], ), ), ], ), ), const SizedBox(height: 16), ElevatedButton.icon( onPressed: () { ScaffoldMessenger.of(context).showSnackBar( SnackBar( content: Text('🧾 Thermal Printed: $_invoiceNumber successfully!'), backgroundColor: const Color(0xFF10B981), behavior: SnackBarBehavior.floating, ), ); }, icon: const Icon(Icons.print, size: 16), label: const Text('Simulate Print Receipt', style: TextStyle(fontSize: 12)), style: ElevatedButton.styleFrom( backgroundColor: Colors.black, foregroundColor: Colors.white, minimumSize: const Size.fromHeight(42), ), ), const SizedBox(height: 8), ElevatedButton( onPressed: _closeReceiptAndReset, style: ElevatedButton.styleFrom( backgroundColor: theme.colorScheme.primary, minimumSize: const Size.fromHeight(42), ), child: const Text('New Ledger Sale', style: TextStyle(fontSize: 12)), ), ], ), ), ), ), ); } Widget _buildReceiptRow(String label, String val, {bool isBold = false}) { return Padding( padding: const EdgeInsets.symmetric(vertical: 2.0), child: Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ Text( label, style: TextStyle( fontSize: 9, fontFamily: 'monospace', fontWeight: isBold ? FontWeight.bold : FontWeight.normal, color: isBold ? Colors.black : Colors.black87, ), ), Text( val, style: TextStyle( fontSize: 9, fontFamily: 'monospace', fontWeight: isBold ? FontWeight.bold : FontWeight.normal, color: isBold ? Colors.black : Colors.black87, ), ), ], ), ); } }