QueenFruits/Mobile Operasional/lib/features/stock_in/presentation/widgets/financial_section.dart

535 lines
20 KiB
Dart

import 'package:flutter/material.dart';
import 'package:niogu_app/core/constants/app_color.dart';
import 'package:niogu_app/core/constants/app_font_size.dart';
import 'package:niogu_app/core/utils/currency_format.dart';
import 'package:niogu_app/core/widgets/custom_form_input.dart';
import 'package:niogu_app/features/stock_in/domain/entities/stock_in.dart';
import 'package:sizer/sizer.dart';
class FinancialSection extends StatelessWidget {
final GlobalKey<FormState> formKey;
final double totalPurchase;
final bool isOtherFormVisible;
final List<SelectedItem> items;
final bool validateChange;
final double totalAmount;
final String selectedPaymentStatus;
final VoidCallback onOtherFormTap;
final TextEditingController discountController;
final TextEditingController taxController;
final TextEditingController noteController;
final TextEditingController payController;
final void Function(String)? onCalculateChange;
final double changeAmount;
final void Function(String)? discountOnChanged;
final void Function(String)? taxOnChanged;
final void Function(String?) onChanged;
const FinancialSection({
super.key,
required this.formKey,
required this.totalPurchase,
required this.isOtherFormVisible,
required this.items,
required this.validateChange,
required this.totalAmount,
required this.selectedPaymentStatus,
required this.onOtherFormTap,
required this.discountController,
required this.taxController,
required this.noteController,
required this.payController,
required this.onCalculateChange,
required this.changeAmount,
required this.discountOnChanged,
required this.taxOnChanged,
required this.onChanged,
});
@override
Widget build(BuildContext context) {
final bool isTablet = 100.w >= 600;
String? discountErrorText;
String? taxErrorText;
String? payErrorText;
final double payAmount = double.tryParse(payController.text.trim()) ?? 0.0;
bool isViewChangeAmount = payAmount >= totalAmount && items.isNotEmpty;
if (selectedPaymentStatus == 'Bayar Sebagian') {
isViewChangeAmount = totalAmount > payAmount && items.isNotEmpty;
}
try {
if (discountController.text.isNotEmpty) {
final double discount = double.parse(discountController.text.trim());
if (discount <= 0) {
discountErrorText = "Diskon harus lebih dari 0";
}
}
} catch (e) {
discountErrorText = "Nominal diskon tidak valid";
}
try {
if (taxController.text.isNotEmpty) {
final double tax = double.parse(taxController.text.trim());
if (tax <= 0) {
taxErrorText = "Pajak harus lebih dari 0";
}
}
} catch (e) {
taxErrorText = "Nominal pajak tidak valid";
}
try {
if (payController.text.isNotEmpty && validateChange) {
final double payAmount = double.parse(payController.text.trim());
if (payAmount <= 0) {
payErrorText = "Nominal pembayaran harus lebih dari 0";
}
if (selectedPaymentStatus == 'Lunas' && totalAmount > payAmount) {
payErrorText =
"Kurang ${CurrencyFormat.formatToIdr((totalAmount - payAmount), 0)}";
}
}
} catch (e) {
payErrorText = "Nominal pembayaran tidak valid";
}
return Container(
padding: EdgeInsets.all(4.w),
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.circular(2.5.w),
border: Border.all(color: Colors.grey.shade200),
),
child: Form(
key: formKey,
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text(
"Subtotal",
style: TextStyle(
color: Colors.grey[700],
fontSize: isTablet
? AppFontSize.medium.sp
: AppFontSize.small.sp,
),
),
Text(
CurrencyFormat.formatToIdr(totalPurchase, 0),
style: TextStyle(
fontWeight: FontWeight.bold,
fontSize: isTablet
? AppFontSize.medium.sp
: AppFontSize.small.sp,
),
),
],
),
Divider(height: 3.h),
Container(
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.circular(2.5.w),
border: Border.all(color: Colors.grey.shade300),
),
child: Column(
children: [
InkWell(
onTap: onOtherFormTap,
borderRadius: BorderRadius.vertical(
top: Radius.circular(2.5.w),
bottom: Radius.circular(isOtherFormVisible ? 0 : 2.5.w),
),
child: Padding(
padding: EdgeInsets.symmetric(
horizontal: 4.w,
vertical: 1.5.h,
),
child: Row(
children: [
Container(
padding: EdgeInsets.all(1.5.w),
decoration: BoxDecoration(
color: isOtherFormVisible
? AppColor.primaryColor.withOpacity(0.1)
: Colors.grey[100],
shape: BoxShape.circle,
),
child: Icon(
Icons.info_outlined,
color: isOtherFormVisible
? AppColor.primaryColor
: Colors.grey,
size: 5.w,
),
),
SizedBox(width: 3.w),
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
"Informasi Lain",
style: TextStyle(
fontWeight: FontWeight.bold,
fontSize: isTablet
? AppFontSize.medium.sp
: AppFontSize.small.sp,
color: Colors.black87,
),
),
SizedBox(height: 1.h),
Text(
"Opsional (Diskon, Pajak, Catatan)",
style: TextStyle(
fontSize: isTablet
? AppFontSize.medium.sp
: AppFontSize.small.sp,
color: Colors.grey,
),
),
],
),
),
Icon(
isOtherFormVisible
? Icons.keyboard_arrow_up_rounded
: Icons.keyboard_arrow_down_rounded,
color: Colors.grey,
size: 6.w,
),
],
),
),
),
if (isOtherFormVisible) ...[
Divider(height: 1, color: Colors.grey.shade200),
Padding(
padding: EdgeInsets.all(4.w),
child: Column(
children: [
CustomFormInput(
label: "Diskon (Rp)",
icon: Icons.discount_outlined,
controller: discountController,
onChanged: discountOnChanged,
inputType: TextInputType.number,
validator: (value) {
if (value != null && value.isNotEmpty) {
try {
final double discount = double.parse(value);
if (discount <= 0) {
return "Diskon harus lebih dari 0";
}
} catch (e) {
return "Nominal diskon tidak valid";
}
}
return null;
},
errorText: discountErrorText,
),
SizedBox(height: 1.5.h),
CustomFormInput(
label: "Pajak (Rp)",
icon: Icons.money_outlined,
controller: taxController,
onChanged: taxOnChanged,
inputType: TextInputType.number,
validator: (value) {
if (value != null && value.isNotEmpty) {
try {
final double tax = double.parse(value);
if (tax <= 0) {
return "Pajak harus lebih dari 0";
}
} catch (e) {
return "Nominal pajak tidak valid";
}
}
return null;
},
errorText: taxErrorText,
),
SizedBox(height: 1.5.h),
CustomFormInput(
label: "Catatan",
icon: Icons.note_alt_outlined,
controller: noteController,
),
],
),
),
],
],
),
),
SizedBox(height: 2.h),
Container(
padding: EdgeInsets.all(3.w),
decoration: BoxDecoration(
color: AppColor.primaryColor.withOpacity(0.05),
borderRadius: BorderRadius.circular(2.w),
),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text(
"Total Pembelian",
style: TextStyle(
fontWeight: FontWeight.bold,
fontSize: isTablet
? AppFontSize.medium.sp
: AppFontSize.small.sp,
),
),
Text(
CurrencyFormat.formatToIdr(totalAmount, 0),
style: TextStyle(
fontWeight: FontWeight.bold,
fontSize: isTablet
? AppFontSize.medium.sp
: AppFontSize.small.sp,
color: AppColor.primaryColor,
),
),
],
),
),
SizedBox(height: 2.h),
Text(
"Status Pembelian",
style: TextStyle(
fontSize: isTablet
? AppFontSize.medium.sp
: AppFontSize.small.sp,
fontWeight: FontWeight.bold,
),
),
SizedBox(height: 1.h),
DropdownButtonFormField<String>(
value: selectedPaymentStatus,
isExpanded: true,
items: ["Lunas", "Bayar Sebagian", "Hutang"]
.map(
(value) => DropdownMenuItem(
value: value,
child: Text(
value,
style: isTablet
? null
: TextStyle(fontSize: AppFontSize.small.sp),
),
),
)
.toList(),
onChanged: onChanged,
icon: const Icon(Icons.keyboard_arrow_down_rounded),
decoration: InputDecoration(
filled: true,
fillColor: Colors.white,
contentPadding: EdgeInsets.symmetric(
horizontal: 4.w,
vertical: 1.8.h,
),
enabledBorder: OutlineInputBorder(
borderRadius: BorderRadius.circular(2.5.w),
borderSide: BorderSide(color: Colors.grey.shade300),
),
focusedBorder: OutlineInputBorder(
borderRadius: BorderRadius.circular(2.5.w),
borderSide: const BorderSide(
color: AppColor.primaryColor,
width: 1.5,
),
),
),
),
SizedBox(height: 2.h),
if (selectedPaymentStatus == 'Lunas' ||
selectedPaymentStatus == 'Bayar Sebagian') ...[
Text(
"Pembayaran",
style: TextStyle(
fontWeight: FontWeight.bold,
fontSize: isTablet
? AppFontSize.medium.sp
: AppFontSize.small.sp,
),
),
SizedBox(height: 1.h),
TextFormField(
controller: payController,
keyboardType: TextInputType.number,
style: TextStyle(
fontSize: isTablet
? AppFontSize.medium.sp
: AppFontSize.small.sp,
),
autovalidateMode: AutovalidateMode.onUserInteraction,
onChanged: onCalculateChange,
validator: (value) {
try {
if (value == null || value.isEmpty) {
return "Masukkan nominal pembayaran";
}
final double payAmount = double.parse(value);
if (payAmount <= 0) {
return "Nominal pembayaran harus lebih dari 0";
}
} catch (e) {
return "Nominal pembayaran tidak valid";
}
return null;
},
decoration: InputDecoration(
labelText: "Bayar (Rp)",
labelStyle: TextStyle(
color: Colors.blue,
fontSize: AppFontSize.medium.sp,
),
prefixIcon: Padding(
padding: isTablet
? EdgeInsets.symmetric(horizontal: 3.w)
: EdgeInsets.zero,
child: Icon(
Icons.payments_outlined,
color: Colors.blue,
size: 5.w,
),
),
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(2.5.w),
),
errorText: payErrorText,
errorStyle: TextStyle(
color: Colors.red,
fontSize: isTablet
? AppFontSize.medium.sp
: AppFontSize.small.sp,
),
errorBorder: OutlineInputBorder(
borderRadius: BorderRadius.circular(2.5.w),
borderSide: const BorderSide(color: Colors.redAccent),
),
enabledBorder: OutlineInputBorder(
borderRadius: BorderRadius.circular(2.5.w),
borderSide: const BorderSide(color: Colors.blue),
),
contentPadding: EdgeInsets.symmetric(
vertical: isTablet ? 3.6.h : 1.8.h,
),
),
),
SizedBox(height: 2.h),
TextField(
controller: TextEditingController(
text: isViewChangeAmount
? CurrencyFormat.formatToIdr(changeAmount, 0)
: '',
),
readOnly: true,
decoration: InputDecoration(
labelText: selectedPaymentStatus == 'Lunas'
? "Kembali"
: 'Kurang Bayar',
labelStyle: TextStyle(fontSize: AppFontSize.medium.sp),
prefixIcon: Padding(
padding: isTablet
? EdgeInsets.symmetric(horizontal: 3.w)
: EdgeInsets.zero,
child: Icon(
Icons.change_circle_outlined,
color: selectedPaymentStatus == 'Lunas'
? Colors.green
: Colors.red,
size: 5.w,
),
),
filled: true,
fillColor: Colors.grey[100],
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(2.5.w),
borderSide: BorderSide.none,
),
contentPadding: EdgeInsets.symmetric(
vertical: isTablet ? 3.6.h : 1.8.h,
),
),
style: TextStyle(
fontSize: isTablet
? AppFontSize.medium.sp
: AppFontSize.small.sp,
fontWeight: FontWeight.bold,
color: selectedPaymentStatus == 'Lunas'
? Colors.green
: Colors.red,
),
),
] else ...[
TextField(
controller: TextEditingController(
text: items.isNotEmpty
? CurrencyFormat.formatToIdr(totalAmount, 0)
: '',
),
readOnly: true,
decoration: InputDecoration(
labelText: 'Hutang',
labelStyle: TextStyle(fontSize: AppFontSize.medium.sp),
prefixIcon: Padding(
padding: isTablet
? EdgeInsets.symmetric(horizontal: 3.w)
: EdgeInsets.zero,
child: Icon(
Icons.change_circle_outlined,
color: Colors.red,
size: 5.w,
),
),
filled: true,
fillColor: Colors.grey[100],
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(2.5.w),
borderSide: BorderSide.none,
),
contentPadding: EdgeInsets.symmetric(
vertical: isTablet ? 3.6.h : 1.8.h,
),
),
style: TextStyle(
fontSize: isTablet
? AppFontSize.medium.sp
: AppFontSize.small.sp,
fontWeight: FontWeight.bold,
color: Colors.red,
),
),
],
],
),
),
);
}
}