feat: update split bill

This commit is contained in:
efrilm 2025-08-08 23:04:35 +07:00
parent b7ab9c6939
commit 670a0b6414
5 changed files with 198 additions and 43 deletions

View File

@ -121,17 +121,17 @@ class PaymentSplitBillRequest {
class SplitItem { class SplitItem {
final String orderItemId; final String orderItemId;
final int amount; final int quantity;
SplitItem({ SplitItem({
required this.orderItemId, required this.orderItemId,
required this.amount, required this.quantity,
}); });
Map<String, dynamic> toJson() { Map<String, dynamic> toJson() {
return { return {
'order_item_id': orderItemId, 'order_item_id': orderItemId,
'amount': amount, 'quantity': quantity,
}; };
} }
} }

View File

@ -244,6 +244,7 @@ class OrderItem {
DateTime? createdAt; DateTime? createdAt;
DateTime? updatedAt; DateTime? updatedAt;
String? printerType; String? printerType;
int? paidQuantity;
OrderItem({ OrderItem({
this.id, this.id,
@ -261,6 +262,7 @@ class OrderItem {
this.createdAt, this.createdAt,
this.updatedAt, this.updatedAt,
this.printerType, this.printerType,
this.paidQuantity,
}); });
factory OrderItem.fromMap(Map<String, dynamic> map) { factory OrderItem.fromMap(Map<String, dynamic> map) {
@ -281,6 +283,7 @@ class OrderItem {
createdAt: DateTime.parse(map['created_at']), createdAt: DateTime.parse(map['created_at']),
updatedAt: DateTime.parse(map['updated_at']), updatedAt: DateTime.parse(map['updated_at']),
printerType: map['printer_type'], printerType: map['printer_type'],
paidQuantity: map['paid_quantity'],
); );
} }
@ -301,6 +304,7 @@ class OrderItem {
'created_at': createdAt?.toIso8601String(), 'created_at': createdAt?.toIso8601String(),
'updated_at': updatedAt?.toIso8601String(), 'updated_at': updatedAt?.toIso8601String(),
'printer_type': printerType, 'printer_type': printerType,
'paid_quantity': paidQuantity,
}; };
} }
} }

View File

@ -468,7 +468,7 @@ class _PaymentPageState extends State<PaymentPage> {
items: itemPending items: itemPending
?.map((item) => SplitItem( ?.map((item) => SplitItem(
orderItemId: item.id ?? "", orderItemId: item.id ?? "",
amount: item.unitPrice ?? 0, quantity: item.quantity ?? 0,
)) ))
.toList() ?? .toList() ??
[], [],

View File

@ -271,6 +271,57 @@ class SalesListOrder extends StatelessWidget {
), ),
], ],
), ),
if (order?.splitType == 'ITEM' && order?.status == 'pending') ...[
SpaceHeight(6),
Align(
alignment: Alignment.centerRight,
child: Container(
padding:
const EdgeInsets.symmetric(horizontal: 10, vertical: 4),
decoration: BoxDecoration(
color: AppColors.primary.withOpacity(0.2),
borderRadius: BorderRadius.circular(8),
border: Border.all(color: AppColors.primary),
),
child: RichText(
text: TextSpan(
children: [
TextSpan(
text: '${product.paidQuantity} ',
style: const TextStyle(
fontSize: 12,
fontWeight: FontWeight.w600,
color: AppColors.primary,
),
),
TextSpan(
text: 'dari ',
style: const TextStyle(
fontSize: 12,
color: AppColors.primary,
),
),
TextSpan(
text: '${product.quantity} ',
style: const TextStyle(
fontSize: 12,
fontWeight: FontWeight.w600,
color: AppColors.primary,
),
),
TextSpan(
text: 'kuantiti telah dibayar.',
style: const TextStyle(
fontSize: 12,
color: AppColors.primary,
),
),
],
),
),
),
)
],
], ],
), ),
), ),

View File

@ -1,6 +1,7 @@
import 'dart:developer'; import 'dart:developer';
import 'package:enaklo_pos/core/components/flushbar.dart'; import 'package:enaklo_pos/core/components/flushbar.dart';
import 'package:enaklo_pos/core/components/spaces.dart';
import 'package:enaklo_pos/core/extensions/build_context_ext.dart'; import 'package:enaklo_pos/core/extensions/build_context_ext.dart';
import 'package:enaklo_pos/data/models/response/customer_response_model.dart'; import 'package:enaklo_pos/data/models/response/customer_response_model.dart';
import 'package:enaklo_pos/data/models/response/order_response_model.dart'; import 'package:enaklo_pos/data/models/response/order_response_model.dart';
@ -176,6 +177,50 @@ class _SplitBillPageState extends State<SplitBillPage> {
), ),
SizedBox(height: 8), SizedBox(height: 8),
], ],
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text(
'Total terbayar',
style: TextStyle(
fontSize: 14,
color: AppColorSplitBill.textPrimary,
fontWeight: FontWeight.w600,
),
),
Text(
'Rp ${_formatCurrency(widget.order.totalPaid ?? 0)}',
style: TextStyle(
fontSize: 14,
color: AppColorSplitBill.textPrimary,
fontWeight: FontWeight.w600,
),
),
],
),
SizedBox(height: 2),
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text(
'Sisa Tagihan',
style: TextStyle(
fontSize: 14,
color: Colors.red,
fontWeight: FontWeight.w600,
),
),
Text(
'Rp ${_formatCurrency(widget.order.remainingAmount ?? 0)}',
style: TextStyle(
fontSize: 14,
color: Colors.red,
fontWeight: FontWeight.w600,
),
),
],
),
SizedBox(height: 2),
Row( Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween, mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [ children: [
@ -313,48 +358,103 @@ class _SplitBillPageState extends State<SplitBillPage> {
Widget _buildOrderItem(OrderItem item) { Widget _buildOrderItem(OrderItem item) {
return Container( return Container(
padding: EdgeInsets.symmetric(vertical: 12), padding: EdgeInsets.symmetric(vertical: 12),
child: Row( child: Column(
children: [ children: [
Expanded( Row(
child: Column( children: [
crossAxisAlignment: CrossAxisAlignment.start, Expanded(
children: [ child: Column(
Text( crossAxisAlignment: CrossAxisAlignment.start,
item.productName ?? '', children: [
style: TextStyle( Text(
fontSize: 16, item.productName ?? '',
fontWeight: FontWeight.w600, style: TextStyle(
color: AppColorSplitBill.textPrimary, fontSize: 16,
), fontWeight: FontWeight.w600,
), color: AppColorSplitBill.textPrimary,
if (item.productVariantName != null && ),
item.productVariantName!.isNotEmpty)
Text(
item.productVariantName!,
style: TextStyle(
fontSize: 14,
color: AppColorSplitBill.textSecondary,
fontStyle: FontStyle.italic,
), ),
), if (item.productVariantName != null &&
Text( item.productVariantName!.isNotEmpty)
'Qty: ${item.quantity} x Rp ${_formatCurrency(item.unitPrice ?? 0)}', Text(
style: TextStyle( item.productVariantName!,
fontSize: 14, style: TextStyle(
color: AppColorSplitBill.textSecondary, fontSize: 14,
color: AppColorSplitBill.textSecondary,
fontStyle: FontStyle.italic,
),
),
Text(
'Qty: ${item.quantity} x Rp ${_formatCurrency(item.unitPrice ?? 0)}',
style: TextStyle(
fontSize: 14,
color: AppColorSplitBill.textSecondary,
),
),
],
),
),
Text(
'Rp ${_formatCurrency(item.totalPrice ?? 0)}',
style: TextStyle(
fontSize: 16,
fontWeight: FontWeight.w600,
color: AppColorSplitBill.textPrimary,
),
),
],
),
if ((item.paidQuantity ?? 0) > 1) ...[
SpaceHeight(6),
Align(
alignment: Alignment.centerRight,
child: Container(
padding:
const EdgeInsets.symmetric(horizontal: 10, vertical: 4),
decoration: BoxDecoration(
color: AppColorSplitBill.primary.withOpacity(0.2),
borderRadius: BorderRadius.circular(8),
border: Border.all(color: AppColorSplitBill.primary),
),
child: RichText(
text: TextSpan(
children: [
TextSpan(
text: '${item.paidQuantity} ',
style: const TextStyle(
fontSize: 12,
fontWeight: FontWeight.w600,
color: AppColorSplitBill.primary,
),
),
TextSpan(
text: 'dari ',
style: const TextStyle(
fontSize: 12,
color: AppColorSplitBill.primary,
),
),
TextSpan(
text: '${item.quantity} ',
style: const TextStyle(
fontSize: 12,
fontWeight: FontWeight.w600,
color: AppColorSplitBill.primary,
),
),
TextSpan(
text: 'kuantiti telah dibayar.',
style: const TextStyle(
fontSize: 12,
color: AppColorSplitBill.primary,
),
),
],
), ),
), ),
], ),
), )
), ],
Text(
'Rp ${_formatCurrency(item.totalPrice ?? 0)}',
style: TextStyle(
fontSize: 16,
fontWeight: FontWeight.w600,
color: AppColorSplitBill.textPrimary,
),
),
], ],
), ),
); );
@ -468,7 +568,7 @@ class _SplitBillPageState extends State<SplitBillPage> {
Widget _buildProductSplitItem(OrderItem item) { Widget _buildProductSplitItem(OrderItem item) {
int selectedQty = selectedProducts[item.id] ?? 0; int selectedQty = selectedProducts[item.id] ?? 0;
int maxQty = item.quantity ?? 0; int maxQty = (item.quantity ?? 0) - (item.paidQuantity ?? 0);
return Container( return Container(
margin: EdgeInsets.only(bottom: 12), margin: EdgeInsets.only(bottom: 12),