perubahan denomuretor on pos sale
This commit is contained in:
@@ -23,7 +23,6 @@ import '../../Const/api_config.dart';
|
||||
import '../../GlobalComponents/glonal_popup.dart';
|
||||
import '../../Repository/API/future_invoice.dart';
|
||||
import '../../constant.dart';
|
||||
import '../../currency.dart';
|
||||
import '../../model/add_to_cart_model.dart';
|
||||
import '../../model/sale_transaction_model.dart';
|
||||
import '../../widgets/multipal payment mathods/multi_payment_widget.dart';
|
||||
@@ -35,6 +34,16 @@ import '../invoice_details/sales_invoice_details_screen.dart';
|
||||
import '../vat_&_tax/model/vat_model.dart';
|
||||
import '../vat_&_tax/provider/text_repo.dart';
|
||||
|
||||
/// Format a number as Indonesian Rupiah for display only.
|
||||
/// Example: 12500.75 → "Rp 12.500"
|
||||
String _formatRupiah(num value) {
|
||||
final intStr = value.round().toString().replaceAllMapped(
|
||||
RegExp(r'(\d)(?=(\d{3})+(?!\d))'),
|
||||
(m) => '${m[1]}.',
|
||||
);
|
||||
return 'Rp $intStr';
|
||||
}
|
||||
|
||||
class AddSalesScreen extends ConsumerStatefulWidget {
|
||||
AddSalesScreen({
|
||||
super.key,
|
||||
@@ -70,6 +79,11 @@ class AddSalesScreenState extends ConsumerState<AddSalesScreen> {
|
||||
void initState() {
|
||||
super.initState();
|
||||
|
||||
// Pre-populate phone from selected customer
|
||||
if (widget.customerModel?.phone != null) {
|
||||
phoneController.text = widget.customerModel!.phone!;
|
||||
}
|
||||
|
||||
// Listener for Received Amount Controller to calculate prices
|
||||
recevedAmountController.addListener(() {
|
||||
final cart = ref.read(cartNotifier);
|
||||
@@ -296,7 +310,9 @@ class AddSalesScreenState extends ConsumerState<AddSalesScreen> {
|
||||
children: [
|
||||
Text(lang.S.of(context).dueAmount),
|
||||
Text(
|
||||
widget.customerModel?.due == null ? '$currency 0' : '$currency${widget.customerModel?.due}',
|
||||
widget.customerModel?.due == null
|
||||
? _formatRupiah(0)
|
||||
: _formatRupiah(widget.customerModel!.due ?? 0),
|
||||
style: const TextStyle(color: Color(0xFFFF8C34)),
|
||||
),
|
||||
],
|
||||
@@ -304,30 +320,34 @@ class AddSalesScreenState extends ConsumerState<AddSalesScreen> {
|
||||
const SizedBox(
|
||||
height: 10,
|
||||
),
|
||||
AppTextField(
|
||||
textFieldType: TextFieldType.NAME,
|
||||
readOnly: true,
|
||||
initialValue: widget.customerModel?.name ?? 'Guest',
|
||||
decoration: InputDecoration(
|
||||
floatingLabelBehavior: FloatingLabelBehavior.always,
|
||||
labelText: lang.S.of(context).customerName,
|
||||
border: const OutlineInputBorder(),
|
||||
),
|
||||
),
|
||||
Visibility(
|
||||
visible: widget.customerModel == null,
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.only(top: 20.0),
|
||||
child: AppTextField(
|
||||
controller: phoneController,
|
||||
textFieldType: TextFieldType.PHONE,
|
||||
decoration: kInputDecoration.copyWith(
|
||||
floatingLabelBehavior: FloatingLabelBehavior.always,
|
||||
labelText: lang.S.of(context).customerPhoneNumber,
|
||||
hintText: lang.S.of(context).enterCustomerPhoneNumber,
|
||||
Row(
|
||||
children: [
|
||||
Expanded(
|
||||
child: AppTextField(
|
||||
textFieldType: TextFieldType.NAME,
|
||||
readOnly: true,
|
||||
initialValue: widget.customerModel?.name ?? 'Guest',
|
||||
decoration: InputDecoration(
|
||||
floatingLabelBehavior: FloatingLabelBehavior.always,
|
||||
labelText: lang.S.of(context).customerName,
|
||||
border: const OutlineInputBorder(),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
const SizedBox(width: 16),
|
||||
Expanded(
|
||||
child: AppTextField(
|
||||
controller: phoneController,
|
||||
textFieldType: TextFieldType.PHONE,
|
||||
readOnly: widget.customerModel != null,
|
||||
decoration: kInputDecoration.copyWith(
|
||||
floatingLabelBehavior: FloatingLabelBehavior.always,
|
||||
labelText: lang.S.of(context).customerPhoneNumber,
|
||||
hintText: lang.S.of(context).enterCustomerPhoneNumber,
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
],
|
||||
),
|
||||
@@ -385,7 +405,7 @@ class AddSalesScreenState extends ConsumerState<AddSalesScreen> {
|
||||
),
|
||||
),
|
||||
Text(
|
||||
'$currency${formatPointNumber(providerData.totalAmount)}',
|
||||
_formatRupiah(providerData.totalAmount),
|
||||
style: _theme.textTheme.titleSmall?.copyWith(
|
||||
fontWeight: FontWeight.w500,
|
||||
),
|
||||
@@ -584,30 +604,17 @@ class AddSalesScreenState extends ConsumerState<AddSalesScreen> {
|
||||
|
||||
const SizedBox(width: 10),*/
|
||||
|
||||
// VAT Amount Input Field
|
||||
// VAT Amount Display (readOnly — show as Rupiah)
|
||||
SizedBox(
|
||||
height: 30,
|
||||
width: 100,
|
||||
child: TextFormField(
|
||||
controller: providerData.vatAmountController,
|
||||
style: _theme.textTheme.titleSmall,
|
||||
readOnly: true,
|
||||
onChanged: (value) => providerData.calculateDiscount(
|
||||
value: value,
|
||||
selectedTaxType: discountType.toString(),
|
||||
child: Align(
|
||||
alignment: Alignment.centerRight,
|
||||
child: Text(
|
||||
_formatRupiah(num.tryParse(providerData.vatAmountController.text) ?? 0),
|
||||
style: _theme.textTheme.titleSmall,
|
||||
textAlign: TextAlign.right,
|
||||
),
|
||||
textAlign: TextAlign.right,
|
||||
decoration: InputDecoration(
|
||||
hintText: '0',
|
||||
hintStyle: _theme.textTheme.titleSmall?.copyWith(
|
||||
color: kPeraColor,
|
||||
),
|
||||
border: const UnderlineInputBorder(borderSide: BorderSide(color: kBorder)),
|
||||
enabledBorder: const UnderlineInputBorder(borderSide: BorderSide(color: kBorder)),
|
||||
focusedBorder: const UnderlineInputBorder(),
|
||||
contentPadding: const EdgeInsets.symmetric(horizontal: 0, vertical: 8),
|
||||
),
|
||||
keyboardType: TextInputType.number,
|
||||
),
|
||||
),
|
||||
],
|
||||
@@ -663,7 +670,7 @@ class AddSalesScreenState extends ConsumerState<AddSalesScreen> {
|
||||
),
|
||||
),
|
||||
Text(
|
||||
formatPointNumber(providerData.actualTotalAmount),
|
||||
_formatRupiah(providerData.actualTotalAmount),
|
||||
style: _theme.textTheme.titleSmall?.copyWith(
|
||||
fontWeight: FontWeight.w600,
|
||||
),
|
||||
@@ -690,7 +697,7 @@ class AddSalesScreenState extends ConsumerState<AddSalesScreen> {
|
||||
),
|
||||
),
|
||||
Text(
|
||||
formatPointNumber(providerData.roundingAmount),
|
||||
_formatRupiah(providerData.roundingAmount),
|
||||
style: _theme.textTheme.titleSmall?.copyWith(
|
||||
color: kPeraColor,
|
||||
),
|
||||
@@ -710,7 +717,7 @@ class AddSalesScreenState extends ConsumerState<AddSalesScreen> {
|
||||
),
|
||||
),
|
||||
Text(
|
||||
formatPointNumber(providerData.totalPayableAmount),
|
||||
_formatRupiah(providerData.totalPayableAmount),
|
||||
style: _theme.textTheme.titleSmall?.copyWith(
|
||||
color: kPeraColor,
|
||||
),
|
||||
@@ -734,27 +741,45 @@ class AddSalesScreenState extends ConsumerState<AddSalesScreen> {
|
||||
color: kPeraColor,
|
||||
),
|
||||
),
|
||||
SizedBox(
|
||||
width: context.width() / 4,
|
||||
height: 30,
|
||||
child: TextFormField(
|
||||
controller: recevedAmountController,
|
||||
readOnly: (paymentWidgetKey.currentState?.getPaymentEntries().length ?? 1) > 1,
|
||||
keyboardType: TextInputType.number,
|
||||
textAlign: TextAlign.right,
|
||||
style: _theme.textTheme.titleSmall,
|
||||
decoration: InputDecoration(
|
||||
hintText: '0',
|
||||
hintStyle: _theme.textTheme.titleSmall?.copyWith(
|
||||
color: kPeraColor,
|
||||
// Received Amount — show Rupiah format when readOnly, numeric input when editable
|
||||
Builder(builder: (ctx) {
|
||||
final isReadOnly = (paymentWidgetKey.currentState?.getPaymentEntries().length ?? 1) > 1;
|
||||
if (isReadOnly) {
|
||||
return SizedBox(
|
||||
width: context.width() / 4,
|
||||
height: 30,
|
||||
child: Align(
|
||||
alignment: Alignment.centerRight,
|
||||
child: Text(
|
||||
_formatRupiah(num.tryParse(recevedAmountController.text) ?? 0),
|
||||
style: _theme.textTheme.titleSmall,
|
||||
textAlign: TextAlign.right,
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
return SizedBox(
|
||||
width: context.width() / 4,
|
||||
height: 30,
|
||||
child: TextFormField(
|
||||
controller: recevedAmountController,
|
||||
readOnly: false,
|
||||
keyboardType: TextInputType.number,
|
||||
textAlign: TextAlign.right,
|
||||
style: _theme.textTheme.titleSmall,
|
||||
decoration: InputDecoration(
|
||||
hintText: '0',
|
||||
hintStyle: _theme.textTheme.titleSmall?.copyWith(
|
||||
color: kPeraColor,
|
||||
),
|
||||
border: UnderlineInputBorder(borderSide: BorderSide(color: kBorder)),
|
||||
enabledBorder: UnderlineInputBorder(borderSide: BorderSide(color: kBorder)),
|
||||
focusedBorder: UnderlineInputBorder(),
|
||||
contentPadding: EdgeInsets.symmetric(horizontal: 0, vertical: 8),
|
||||
),
|
||||
border: UnderlineInputBorder(borderSide: BorderSide(color: kBorder)),
|
||||
enabledBorder: UnderlineInputBorder(borderSide: BorderSide(color: kBorder)),
|
||||
focusedBorder: UnderlineInputBorder(),
|
||||
contentPadding: EdgeInsets.symmetric(horizontal: 0, vertical: 8),
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}),
|
||||
],
|
||||
),
|
||||
),
|
||||
@@ -774,7 +799,7 @@ class AddSalesScreenState extends ConsumerState<AddSalesScreen> {
|
||||
),
|
||||
),
|
||||
Text(
|
||||
formatPointNumber(providerData.changeAmount),
|
||||
_formatRupiah(providerData.changeAmount),
|
||||
style: _theme.textTheme.titleSmall?.copyWith(
|
||||
color: kPeraColor,
|
||||
),
|
||||
@@ -800,7 +825,7 @@ class AddSalesScreenState extends ConsumerState<AddSalesScreen> {
|
||||
),
|
||||
),
|
||||
Text(
|
||||
formatPointNumber(providerData.dueAmount),
|
||||
_formatRupiah(providerData.dueAmount),
|
||||
style: _theme.textTheme.titleSmall?.copyWith(
|
||||
color: kPeraColor,
|
||||
),
|
||||
@@ -820,6 +845,7 @@ class AddSalesScreenState extends ConsumerState<AddSalesScreen> {
|
||||
key: paymentWidgetKey,
|
||||
showWalletOption: true,
|
||||
totalAmountController: recevedAmountController,
|
||||
totalDueAmount: providerData.totalPayableAmount,
|
||||
showChequeOption: true,
|
||||
showCashDenomination: true,
|
||||
initialTransactions: widget.transitionModel?.transactions,
|
||||
|
||||
@@ -4,9 +4,18 @@ import 'package:hugeicons/hugeicons.dart';
|
||||
import 'package:mobile_pos/Screens/Sales/provider/sales_cart_provider.dart';
|
||||
import 'package:mobile_pos/Screens/Sales/sales_add_to_cart_sales_widget.dart';
|
||||
import 'package:mobile_pos/constant.dart';
|
||||
import 'package:mobile_pos/currency.dart';
|
||||
import 'package:mobile_pos/generated/l10n.dart' as lang;
|
||||
|
||||
/// Format a number as Indonesian Rupiah for display only.
|
||||
/// Example: 12500.75 → "Rp 12.500"
|
||||
String _formatRupiah(num value) {
|
||||
final intStr = value.round().toString().replaceAllMapped(
|
||||
RegExp(r'(\d)(?=(\d{3})+(?!\d))'),
|
||||
(m) => '${m[1]}.',
|
||||
);
|
||||
return 'Rp $intStr';
|
||||
}
|
||||
|
||||
class SalesCartListWidget extends ConsumerWidget {
|
||||
const SalesCartListWidget({super.key});
|
||||
|
||||
@@ -137,7 +146,7 @@ class SalesCartListWidget extends ConsumerWidget {
|
||||
|
||||
// 3. Qty Order
|
||||
Text(
|
||||
formatPointNumber(quantity),
|
||||
formatPointNumber(quantity, addComma: true),
|
||||
style: const TextStyle(fontWeight: FontWeight.bold),
|
||||
),
|
||||
const SizedBox(width: 8),
|
||||
@@ -158,7 +167,7 @@ class SalesCartListWidget extends ConsumerWidget {
|
||||
|
||||
// 5. Value Original
|
||||
Text(
|
||||
'$currency${formatPointNumber(originalTotal)}',
|
||||
_formatRupiah(originalTotal),
|
||||
style: TextStyle(
|
||||
color: kPeraColor,
|
||||
fontSize: 12,
|
||||
@@ -169,7 +178,7 @@ class SalesCartListWidget extends ConsumerWidget {
|
||||
// 6. Value VAT/Tax
|
||||
if (itemVAT > 0) ...[
|
||||
Text(
|
||||
'VAT: $currency${formatPointNumber(itemVAT)}',
|
||||
'VAT: ${_formatRupiah(itemVAT)}',
|
||||
style: TextStyle(
|
||||
color: kPeraColor,
|
||||
fontSize: 10,
|
||||
@@ -180,7 +189,7 @@ class SalesCartListWidget extends ConsumerWidget {
|
||||
|
||||
// 7. Sum (Value Original + VAT/Tax)
|
||||
Text(
|
||||
'$currency${formatPointNumber(finalTotal)}',
|
||||
_formatRupiah(finalTotal),
|
||||
style: _theme.textTheme.titleSmall?.copyWith(
|
||||
color: kMainColor,
|
||||
fontWeight: FontWeight.bold,
|
||||
|
||||
@@ -317,7 +317,7 @@ class _ProductCardState extends State<ProductCard> {
|
||||
),
|
||||
// if (permissionService.hasPermission(Permit.salesPriceView.value))
|
||||
Text(
|
||||
'$currency${widget.productPrice}',
|
||||
'$currency ${formatPointNumber(widget.productPrice, addComma: true)}',
|
||||
style: theme.textTheme.titleMedium!.copyWith(fontSize: 18),
|
||||
),
|
||||
],
|
||||
|
||||
Reference in New Issue
Block a user