order page

This commit is contained in:
efrilm
2025-10-27 21:55:19 +07:00
parent b8eefcbac0
commit 8bd61eb58e
38 changed files with 8795 additions and 89 deletions
@@ -0,0 +1,61 @@
import 'dart:developer';
import 'package:data_channel/data_channel.dart';
import 'package:injectable/injectable.dart';
import 'package:intl/intl.dart';
import '../../../common/api/api_client.dart';
import '../../../common/api/api_failure.dart';
import '../../../common/function/app_function.dart';
import '../../../common/url/api_path.dart';
import '../../../domain/order/order.dart';
import '../order_dtos.dart';
@injectable
class OrderRemoteDataProvider {
final ApiClient _apiClient;
final _logName = 'OrderRemoteDataProvider';
OrderRemoteDataProvider(this._apiClient);
Future<DC<OrderFailure, ListOrderDto>> fetchOrders({
int page = 1,
int limit = 10,
String status = 'completed',
required DateTime startDate,
required DateTime endDate,
String? search,
}) async {
try {
Map<String, dynamic> params = {
'page': page,
'limit': limit,
'status': status,
'date_from': DateFormat('dd-MM-yyyy').format(startDate),
'date_to': DateFormat('dd-MM-yyyy').format(endDate),
};
if (search != null && search.isNotEmpty) {
params['search'] = search;
}
final response = await _apiClient.get(
ApiPath.orders,
params: params,
headers: getAuthorizationHeader(),
);
if (response.data['success'] == false) {
return DC.error(OrderFailure.unexpectedError());
}
final orders = ListOrderDto.fromJson(
response.data['data'] as Map<String, dynamic>,
);
return DC.data(orders);
} on ApiFailure catch (e, s) {
log('fetchOrderError', name: _logName, error: e, stackTrace: s);
return DC.error(OrderFailure.serverError(e));
}
}
}
@@ -0,0 +1,182 @@
part of '../order_dtos.dart';
@freezed
class ListOrderDto with _$ListOrderDto {
const ListOrderDto._();
const factory ListOrderDto({
@JsonKey(name: "orders") List<OrderDto>? orders,
@JsonKey(name: 'total_count') int? totalCount,
@JsonKey(name: 'page') int? page,
@JsonKey(name: 'limit') int? limit,
@JsonKey(name: 'total_pages') int? totalPages,
}) = _ListOrderDto;
factory ListOrderDto.fromJson(Map<String, dynamic> json) =>
_$ListOrderDtoFromJson(json);
ListOrder toDomain() => ListOrder(
orders: orders?.map((e) => e.toDomain()).toList() ?? [],
totalCount: totalCount ?? 0,
page: page ?? 0,
limit: limit ?? 0,
totalPages: totalPages ?? 0,
);
}
@freezed
class OrderDto with _$OrderDto {
const OrderDto._();
const factory OrderDto({
@JsonKey(name: "id") String? id,
@JsonKey(name: "order_number") String? orderNumber,
@JsonKey(name: "outlet_id") String? outletId,
@JsonKey(name: "user_id") String? userId,
@JsonKey(name: "table_number") String? tableNumber,
@JsonKey(name: "order_type") String? orderType,
@JsonKey(name: "status") String? status,
@JsonKey(name: "subtotal") int? subtotal,
@JsonKey(name: "tax_amount") int? taxAmount,
@JsonKey(name: "discount_amount") int? discountAmount,
@JsonKey(name: "total_amount") int? totalAmount,
@JsonKey(name: "total_cost") num? totalCost,
@JsonKey(name: "remaining_amount") int? remainingAmount,
@JsonKey(name: "payment_status") String? paymentStatus,
@JsonKey(name: "refund_amount") int? refundAmount,
@JsonKey(name: "is_void") bool? isVoid,
@JsonKey(name: "is_refund") bool? isRefund,
@JsonKey(name: "notes") String? notes,
@JsonKey(name: "metadata") Map<String, dynamic>? metadata,
@JsonKey(name: "created_at") String? createdAt,
@JsonKey(name: "updated_at") String? updatedAt,
@JsonKey(name: "order_items") List<OrderItemDto>? orderItems,
@JsonKey(name: "payments") List<PaymentOrderDto>? payments,
@JsonKey(name: "total_paid") int? totalPaid,
@JsonKey(name: "payment_count") int? paymentCount,
@JsonKey(name: "split_type") String? splitType,
}) = _OrderDto;
factory OrderDto.fromJson(Map<String, dynamic> json) =>
_$OrderDtoFromJson(json);
// Optional: mapper ke domain entity
Order toDomain() => Order(
id: id ?? '',
orderNumber: orderNumber ?? '',
outletId: outletId ?? '',
userId: userId ?? '',
tableNumber: tableNumber ?? '',
orderType: orderType ?? '',
status: status ?? '',
subtotal: subtotal ?? 0,
taxAmount: taxAmount ?? 0,
discountAmount: discountAmount ?? 0,
totalAmount: totalAmount ?? 0,
totalCost: totalCost ?? 0,
remainingAmount: remainingAmount ?? 0,
paymentStatus: paymentStatus ?? '',
refundAmount: refundAmount ?? 0,
isVoid: isVoid ?? false,
isRefund: isRefund ?? false,
notes: notes ?? '',
metadata: metadata ?? const {},
createdAt: createdAt != null ? DateTime.parse(createdAt!) : DateTime(1970),
updatedAt: updatedAt != null ? DateTime.parse(updatedAt!) : DateTime(1970),
orderItems: orderItems?.map((e) => e.toDomain()).toList() ?? const [],
payments: payments?.map((e) => e.toDomain()).toList() ?? const [],
totalPaid: totalPaid ?? 0,
paymentCount: paymentCount ?? 0,
splitType: splitType ?? '',
);
}
@freezed
class OrderItemDto with _$OrderItemDto {
const OrderItemDto._();
const factory OrderItemDto({
@JsonKey(name: "id") String? id,
@JsonKey(name: "order_id") String? orderId,
@JsonKey(name: "product_id") String? productId,
@JsonKey(name: "product_name") String? productName,
@JsonKey(name: "product_variant_id") String? productVariantId,
@JsonKey(name: "product_variant_name") String? productVariantName,
@JsonKey(name: "quantity") int? quantity,
@JsonKey(name: "unit_price") int? unitPrice,
@JsonKey(name: "total_price") int? totalPrice,
@JsonKey(name: "modifiers") List<dynamic>? modifiers,
@JsonKey(name: "notes") String? notes,
@JsonKey(name: "status") String? status,
@JsonKey(name: "created_at") String? createdAt,
@JsonKey(name: "updated_at") String? updatedAt,
@JsonKey(name: "printer_type") String? printerType,
@JsonKey(name: "paid_quantity") int? paidQuantity,
}) = _OrderItemDto;
factory OrderItemDto.fromJson(Map<String, dynamic> json) =>
_$OrderItemDtoFromJson(json);
// Optional mapper to domain entity
OrderItem toDomain() => OrderItem(
id: id ?? '',
orderId: orderId ?? '',
productId: productId ?? '',
productName: productName ?? '',
productVariantId: productVariantId ?? '',
productVariantName: productVariantName ?? '',
quantity: quantity ?? 0,
unitPrice: unitPrice ?? 0,
totalPrice: totalPrice ?? 0,
modifiers: modifiers ?? [],
notes: notes ?? '',
status: status ?? '',
createdAt: createdAt != null ? DateTime.parse(createdAt!) : DateTime(1970),
updatedAt: updatedAt != null ? DateTime.parse(updatedAt!) : DateTime(1970),
printerType: printerType ?? '',
paidQuantity: paidQuantity ?? 0,
);
}
@freezed
class PaymentOrderDto with _$PaymentOrderDto {
const PaymentOrderDto._();
const factory PaymentOrderDto({
@JsonKey(name: "id") String? id,
@JsonKey(name: "order_id") String? orderId,
@JsonKey(name: "payment_method_id") String? paymentMethodId,
@JsonKey(name: "payment_method_name") String? paymentMethodName,
@JsonKey(name: "payment_method_type") String? paymentMethodType,
@JsonKey(name: "amount") int? amount,
@JsonKey(name: "status") String? status,
@JsonKey(name: "split_number") int? splitNumber,
@JsonKey(name: "split_total") int? splitTotal,
@JsonKey(name: "split_description") String? splitDescription,
@JsonKey(name: "refund_amount") int? refundAmount,
@JsonKey(name: "metadata") Map<String, dynamic>? metadata,
@JsonKey(name: "created_at") String? createdAt,
@JsonKey(name: "updated_at") String? updatedAt,
}) = _PaymentOrderDto;
factory PaymentOrderDto.fromJson(Map<String, dynamic> json) =>
_$PaymentOrderDtoFromJson(json);
// Optional mapper ke domain entity
PaymentOrder toDomain() => PaymentOrder(
id: id ?? '',
orderId: orderId ?? '',
paymentMethodId: paymentMethodId ?? '',
paymentMethodName: paymentMethodName ?? '',
paymentMethodType: paymentMethodType ?? '',
amount: amount ?? 0,
status: status ?? '',
splitNumber: splitNumber ?? 0,
splitTotal: splitTotal ?? 0,
splitDescription: splitDescription ?? '',
refundAmount: refundAmount ?? 0,
metadata: metadata ?? const {},
createdAt: createdAt != null ? DateTime.parse(createdAt!) : DateTime(1970),
updatedAt: updatedAt != null ? DateTime.parse(updatedAt!) : DateTime(1970),
);
}
+8
View File
@@ -0,0 +1,8 @@
import 'package:freezed_annotation/freezed_annotation.dart';
import '../../domain/order/order.dart';
part 'order_dtos.freezed.dart';
part 'order_dtos.g.dart';
part 'dtos/order_dto.dart';
File diff suppressed because it is too large Load Diff
+169
View File
@@ -0,0 +1,169 @@
// GENERATED CODE - DO NOT MODIFY BY HAND
part of 'order_dtos.dart';
// **************************************************************************
// JsonSerializableGenerator
// **************************************************************************
_$ListOrderDtoImpl _$$ListOrderDtoImplFromJson(Map<String, dynamic> json) =>
_$ListOrderDtoImpl(
orders: (json['orders'] as List<dynamic>?)
?.map((e) => OrderDto.fromJson(e as Map<String, dynamic>))
.toList(),
totalCount: (json['total_count'] as num?)?.toInt(),
page: (json['page'] as num?)?.toInt(),
limit: (json['limit'] as num?)?.toInt(),
totalPages: (json['total_pages'] as num?)?.toInt(),
);
Map<String, dynamic> _$$ListOrderDtoImplToJson(_$ListOrderDtoImpl instance) =>
<String, dynamic>{
'orders': instance.orders,
'total_count': instance.totalCount,
'page': instance.page,
'limit': instance.limit,
'total_pages': instance.totalPages,
};
_$OrderDtoImpl _$$OrderDtoImplFromJson(Map<String, dynamic> json) =>
_$OrderDtoImpl(
id: json['id'] as String?,
orderNumber: json['order_number'] as String?,
outletId: json['outlet_id'] as String?,
userId: json['user_id'] as String?,
tableNumber: json['table_number'] as String?,
orderType: json['order_type'] as String?,
status: json['status'] as String?,
subtotal: (json['subtotal'] as num?)?.toInt(),
taxAmount: (json['tax_amount'] as num?)?.toInt(),
discountAmount: (json['discount_amount'] as num?)?.toInt(),
totalAmount: (json['total_amount'] as num?)?.toInt(),
totalCost: json['total_cost'] as num?,
remainingAmount: (json['remaining_amount'] as num?)?.toInt(),
paymentStatus: json['payment_status'] as String?,
refundAmount: (json['refund_amount'] as num?)?.toInt(),
isVoid: json['is_void'] as bool?,
isRefund: json['is_refund'] as bool?,
notes: json['notes'] as String?,
metadata: json['metadata'] as Map<String, dynamic>?,
createdAt: json['created_at'] as String?,
updatedAt: json['updated_at'] as String?,
orderItems: (json['order_items'] as List<dynamic>?)
?.map((e) => OrderItemDto.fromJson(e as Map<String, dynamic>))
.toList(),
payments: (json['payments'] as List<dynamic>?)
?.map((e) => PaymentOrderDto.fromJson(e as Map<String, dynamic>))
.toList(),
totalPaid: (json['total_paid'] as num?)?.toInt(),
paymentCount: (json['payment_count'] as num?)?.toInt(),
splitType: json['split_type'] as String?,
);
Map<String, dynamic> _$$OrderDtoImplToJson(_$OrderDtoImpl instance) =>
<String, dynamic>{
'id': instance.id,
'order_number': instance.orderNumber,
'outlet_id': instance.outletId,
'user_id': instance.userId,
'table_number': instance.tableNumber,
'order_type': instance.orderType,
'status': instance.status,
'subtotal': instance.subtotal,
'tax_amount': instance.taxAmount,
'discount_amount': instance.discountAmount,
'total_amount': instance.totalAmount,
'total_cost': instance.totalCost,
'remaining_amount': instance.remainingAmount,
'payment_status': instance.paymentStatus,
'refund_amount': instance.refundAmount,
'is_void': instance.isVoid,
'is_refund': instance.isRefund,
'notes': instance.notes,
'metadata': instance.metadata,
'created_at': instance.createdAt,
'updated_at': instance.updatedAt,
'order_items': instance.orderItems,
'payments': instance.payments,
'total_paid': instance.totalPaid,
'payment_count': instance.paymentCount,
'split_type': instance.splitType,
};
_$OrderItemDtoImpl _$$OrderItemDtoImplFromJson(Map<String, dynamic> json) =>
_$OrderItemDtoImpl(
id: json['id'] as String?,
orderId: json['order_id'] as String?,
productId: json['product_id'] as String?,
productName: json['product_name'] as String?,
productVariantId: json['product_variant_id'] as String?,
productVariantName: json['product_variant_name'] as String?,
quantity: (json['quantity'] as num?)?.toInt(),
unitPrice: (json['unit_price'] as num?)?.toInt(),
totalPrice: (json['total_price'] as num?)?.toInt(),
modifiers: json['modifiers'] as List<dynamic>?,
notes: json['notes'] as String?,
status: json['status'] as String?,
createdAt: json['created_at'] as String?,
updatedAt: json['updated_at'] as String?,
printerType: json['printer_type'] as String?,
paidQuantity: (json['paid_quantity'] as num?)?.toInt(),
);
Map<String, dynamic> _$$OrderItemDtoImplToJson(_$OrderItemDtoImpl instance) =>
<String, dynamic>{
'id': instance.id,
'order_id': instance.orderId,
'product_id': instance.productId,
'product_name': instance.productName,
'product_variant_id': instance.productVariantId,
'product_variant_name': instance.productVariantName,
'quantity': instance.quantity,
'unit_price': instance.unitPrice,
'total_price': instance.totalPrice,
'modifiers': instance.modifiers,
'notes': instance.notes,
'status': instance.status,
'created_at': instance.createdAt,
'updated_at': instance.updatedAt,
'printer_type': instance.printerType,
'paid_quantity': instance.paidQuantity,
};
_$PaymentOrderDtoImpl _$$PaymentOrderDtoImplFromJson(
Map<String, dynamic> json,
) => _$PaymentOrderDtoImpl(
id: json['id'] as String?,
orderId: json['order_id'] as String?,
paymentMethodId: json['payment_method_id'] as String?,
paymentMethodName: json['payment_method_name'] as String?,
paymentMethodType: json['payment_method_type'] as String?,
amount: (json['amount'] as num?)?.toInt(),
status: json['status'] as String?,
splitNumber: (json['split_number'] as num?)?.toInt(),
splitTotal: (json['split_total'] as num?)?.toInt(),
splitDescription: json['split_description'] as String?,
refundAmount: (json['refund_amount'] as num?)?.toInt(),
metadata: json['metadata'] as Map<String, dynamic>?,
createdAt: json['created_at'] as String?,
updatedAt: json['updated_at'] as String?,
);
Map<String, dynamic> _$$PaymentOrderDtoImplToJson(
_$PaymentOrderDtoImpl instance,
) => <String, dynamic>{
'id': instance.id,
'order_id': instance.orderId,
'payment_method_id': instance.paymentMethodId,
'payment_method_name': instance.paymentMethodName,
'payment_method_type': instance.paymentMethodType,
'amount': instance.amount,
'status': instance.status,
'split_number': instance.splitNumber,
'split_total': instance.splitTotal,
'split_description': instance.splitDescription,
'refund_amount': instance.refundAmount,
'metadata': instance.metadata,
'created_at': instance.createdAt,
'updated_at': instance.updatedAt,
};
@@ -0,0 +1,46 @@
import 'dart:developer';
import 'package:dartz/dartz.dart';
import 'package:injectable/injectable.dart';
import '../../../domain/order/order.dart';
import '../datasources/remote_data_provider.dart';
@Injectable(as: IOrderRepository)
class OrderRepository implements IOrderRepository {
final OrderRemoteDataProvider _dataProvider;
final _logName = 'OrderRepository';
OrderRepository(this._dataProvider);
@override
Future<Either<OrderFailure, ListOrder>> getOrders({
int page = 1,
int limit = 10,
String status = 'completed',
required DateTime startDate,
required DateTime endDate,
String? search,
}) async {
try {
final result = await _dataProvider.fetchOrders(
page: page,
limit: limit,
status: status,
startDate: startDate,
endDate: endDate,
search: search,
);
if (result.hasError) {
return left(result.error!);
}
final orders = result.data!.toDomain();
return right(orders);
} catch (e) {
log('getOrdersError', name: _logName, error: e);
return left(const OrderFailure.unexpectedError());
}
}
}