update order detail

This commit is contained in:
Phuoc Nguyen
2025-11-24 17:00:11 +07:00
parent 75d6507719
commit 1851d60038
9 changed files with 1238 additions and 455 deletions

View File

@@ -0,0 +1,502 @@
/// Order Detail Model
///
/// Data model for order detail API response.
library;
import 'package:worker/features/orders/domain/entities/order_detail.dart';
/// Order Detail Model
class OrderDetailModel {
const OrderDetailModel({
required this.order,
required this.billingAddress,
required this.shippingAddress,
required this.items,
required this.paymentTerms,
required this.timeline,
required this.payments,
required this.invoices,
});
final OrderDetailInfoModel order;
final AddressInfoModel billingAddress;
final AddressInfoModel shippingAddress;
final List<OrderItemDetailModel> items;
final PaymentTermsInfoModel paymentTerms;
final List<TimelineItemModel> timeline;
final List<dynamic> payments;
final List<dynamic> invoices;
/// Create from JSON
factory OrderDetailModel.fromJson(Map<String, dynamic> json) {
return OrderDetailModel(
order: OrderDetailInfoModel.fromJson(
json['order'] as Map<String, dynamic>,
),
billingAddress: AddressInfoModel.fromJson(
json['billing_address'] as Map<String, dynamic>,
),
shippingAddress: AddressInfoModel.fromJson(
json['shipping_address'] as Map<String, dynamic>,
),
items: (json['items'] as List<dynamic>)
.map((item) =>
OrderItemDetailModel.fromJson(item as Map<String, dynamic>))
.toList(),
paymentTerms: PaymentTermsInfoModel.fromJson(
json['payment_terms'] as Map<String, dynamic>,
),
timeline: (json['timeline'] as List<dynamic>)
.map((item) =>
TimelineItemModel.fromJson(item as Map<String, dynamic>))
.toList(),
payments: json['payments'] as List<dynamic>? ?? [],
invoices: json['invoices'] as List<dynamic>? ?? [],
);
}
/// Convert to JSON
Map<String, dynamic> toJson() {
return {
'order': order.toJson(),
'billing_address': billingAddress.toJson(),
'shipping_address': shippingAddress.toJson(),
'items': items.map((item) => item.toJson()).toList(),
'payment_terms': paymentTerms.toJson(),
'timeline': timeline.map((item) => item.toJson()).toList(),
'payments': payments,
'invoices': invoices,
};
}
/// Convert to domain entity
OrderDetail toEntity() {
return OrderDetail(
order: order.toEntity(),
billingAddress: billingAddress.toEntity(),
shippingAddress: shippingAddress.toEntity(),
items: items.map((item) => item.toEntity()).toList(),
paymentTerms: paymentTerms.toEntity(),
timeline: timeline.map((item) => item.toEntity()).toList(),
payments: payments,
invoices: invoices,
);
}
/// Create from domain entity
factory OrderDetailModel.fromEntity(OrderDetail entity) {
return OrderDetailModel(
order: OrderDetailInfoModel.fromEntity(entity.order),
billingAddress: AddressInfoModel.fromEntity(entity.billingAddress),
shippingAddress: AddressInfoModel.fromEntity(entity.shippingAddress),
items: entity.items
.map((item) => OrderItemDetailModel.fromEntity(item))
.toList(),
paymentTerms: PaymentTermsInfoModel.fromEntity(entity.paymentTerms),
timeline: entity.timeline
.map((item) => TimelineItemModel.fromEntity(item))
.toList(),
payments: entity.payments,
invoices: entity.invoices,
);
}
}
/// Order Detail Info Model
class OrderDetailInfoModel {
const OrderDetailInfoModel({
required this.name,
required this.customer,
required this.transactionDate,
required this.deliveryDate,
required this.status,
required this.statusColor,
required this.totalQty,
required this.total,
required this.grandTotal,
required this.totalRemaining,
required this.description,
required this.contractRequest,
required this.ignorePricingRule,
this.rejectionReason,
required this.isAllowCancel,
});
final String name;
final String customer;
final String transactionDate;
final String deliveryDate;
final String status;
final String statusColor;
final double totalQty;
final double total;
final double grandTotal;
final double totalRemaining;
final String description;
final bool contractRequest;
final bool ignorePricingRule;
final String? rejectionReason;
final bool isAllowCancel;
factory OrderDetailInfoModel.fromJson(Map<String, dynamic> json) {
return OrderDetailInfoModel(
name: json['name'] as String,
customer: json['customer'] as String,
transactionDate: json['transaction_date'] as String,
deliveryDate: json['delivery_date'] as String,
status: json['status'] as String,
statusColor: json['status_color'] as String,
totalQty: (json['total_qty'] as num).toDouble(),
total: (json['total'] as num).toDouble(),
grandTotal: (json['grand_total'] as num).toDouble(),
totalRemaining: (json['total_remaining'] as num).toDouble(),
description: json['description'] as String,
contractRequest: json['contract_request'] as bool,
ignorePricingRule: json['ignore_pricing_rule'] as bool,
rejectionReason: json['rejection_reason'] as String?,
isAllowCancel: json['is_allow_cancel'] as bool,
);
}
Map<String, dynamic> toJson() {
return {
'name': name,
'customer': customer,
'transaction_date': transactionDate,
'delivery_date': deliveryDate,
'status': status,
'status_color': statusColor,
'total_qty': totalQty,
'total': total,
'grand_total': grandTotal,
'total_remaining': totalRemaining,
'description': description,
'contract_request': contractRequest,
'ignore_pricing_rule': ignorePricingRule,
'rejection_reason': rejectionReason,
'is_allow_cancel': isAllowCancel,
};
}
OrderDetailInfo toEntity() {
return OrderDetailInfo(
name: name,
customer: customer,
transactionDate: transactionDate,
deliveryDate: deliveryDate,
status: status,
statusColor: statusColor,
totalQty: totalQty,
total: total,
grandTotal: grandTotal,
totalRemaining: totalRemaining,
description: description,
contractRequest: contractRequest,
ignorePricingRule: ignorePricingRule,
rejectionReason: rejectionReason,
isAllowCancel: isAllowCancel,
);
}
factory OrderDetailInfoModel.fromEntity(OrderDetailInfo entity) {
return OrderDetailInfoModel(
name: entity.name,
customer: entity.customer,
transactionDate: entity.transactionDate,
deliveryDate: entity.deliveryDate,
status: entity.status,
statusColor: entity.statusColor,
totalQty: entity.totalQty,
total: entity.total,
grandTotal: entity.grandTotal,
totalRemaining: entity.totalRemaining,
description: entity.description,
contractRequest: entity.contractRequest,
ignorePricingRule: entity.ignorePricingRule,
rejectionReason: entity.rejectionReason,
isAllowCancel: entity.isAllowCancel,
);
}
}
/// Address Info Model
class AddressInfoModel {
const AddressInfoModel({
required this.name,
required this.addressTitle,
required this.addressLine1,
required this.phone,
required this.email,
this.fax,
required this.taxCode,
required this.cityCode,
required this.wardCode,
required this.cityName,
required this.wardName,
required this.isAllowEdit,
});
final String name;
final String addressTitle;
final String addressLine1;
final String phone;
final String email;
final String? fax;
final String taxCode;
final String cityCode;
final String wardCode;
final String cityName;
final String wardName;
final bool isAllowEdit;
factory AddressInfoModel.fromJson(Map<String, dynamic> json) {
return AddressInfoModel(
name: json['name'] as String,
addressTitle: json['address_title'] as String,
addressLine1: json['address_line1'] as String,
phone: json['phone'] as String,
email: json['email'] as String,
fax: json['fax'] as String?,
taxCode: json['tax_code'] as String,
cityCode: json['city_code'] as String,
wardCode: json['ward_code'] as String,
cityName: json['city_name'] as String,
wardName: json['ward_name'] as String,
isAllowEdit: json['is_allow_edit'] as bool,
);
}
Map<String, dynamic> toJson() {
return {
'name': name,
'address_title': addressTitle,
'address_line1': addressLine1,
'phone': phone,
'email': email,
'fax': fax,
'tax_code': taxCode,
'city_code': cityCode,
'ward_code': wardCode,
'city_name': cityName,
'ward_name': wardName,
'is_allow_edit': isAllowEdit,
};
}
AddressInfo toEntity() {
return AddressInfo(
name: name,
addressTitle: addressTitle,
addressLine1: addressLine1,
phone: phone,
email: email,
fax: fax,
taxCode: taxCode,
cityCode: cityCode,
wardCode: wardCode,
cityName: cityName,
wardName: wardName,
isAllowEdit: isAllowEdit,
);
}
factory AddressInfoModel.fromEntity(AddressInfo entity) {
return AddressInfoModel(
name: entity.name,
addressTitle: entity.addressTitle,
addressLine1: entity.addressLine1,
phone: entity.phone,
email: entity.email,
fax: entity.fax,
taxCode: entity.taxCode,
cityCode: entity.cityCode,
wardCode: entity.wardCode,
cityName: entity.cityName,
wardName: entity.wardName,
isAllowEdit: entity.isAllowEdit,
);
}
}
/// Order Item Detail Model
class OrderItemDetailModel {
const OrderItemDetailModel({
required this.name,
required this.itemCode,
required this.itemName,
required this.description,
required this.qtyEntered,
required this.qtyOfSm,
required this.qtyOfNos,
required this.conversionFactor,
required this.price,
required this.totalAmount,
required this.deliveryDate,
this.thumbnail,
});
final String name;
final String itemCode;
final String itemName;
final String description;
final double qtyEntered;
final double qtyOfSm;
final double qtyOfNos;
final double conversionFactor;
final double price;
final double totalAmount;
final String deliveryDate;
final String? thumbnail;
factory OrderItemDetailModel.fromJson(Map<String, dynamic> json) {
return OrderItemDetailModel(
name: json['name'] as String,
itemCode: json['item_code'] as String,
itemName: json['item_name'] as String,
description: json['description'] as String,
qtyEntered: (json['qty_entered'] as num).toDouble(),
qtyOfSm: (json['qty_of_sm'] as num).toDouble(),
qtyOfNos: (json['qty_of_nos'] as num).toDouble(),
conversionFactor: (json['conversion_factor'] as num).toDouble(),
price: (json['price'] as num).toDouble(),
totalAmount: (json['total_amount'] as num).toDouble(),
deliveryDate: json['delivery_date'] as String,
thumbnail: json['thumbnail'] as String?,
);
}
Map<String, dynamic> toJson() {
return {
'name': name,
'item_code': itemCode,
'item_name': itemName,
'description': description,
'qty_entered': qtyEntered,
'qty_of_sm': qtyOfSm,
'qty_of_nos': qtyOfNos,
'conversion_factor': conversionFactor,
'price': price,
'total_amount': totalAmount,
'delivery_date': deliveryDate,
'thumbnail': thumbnail,
};
}
OrderItemDetail toEntity() {
return OrderItemDetail(
name: name,
itemCode: itemCode,
itemName: itemName,
description: description,
qtyEntered: qtyEntered,
qtyOfSm: qtyOfSm,
qtyOfNos: qtyOfNos,
conversionFactor: conversionFactor,
price: price,
totalAmount: totalAmount,
deliveryDate: deliveryDate,
thumbnail: thumbnail,
);
}
factory OrderItemDetailModel.fromEntity(OrderItemDetail entity) {
return OrderItemDetailModel(
name: entity.name,
itemCode: entity.itemCode,
itemName: entity.itemName,
description: entity.description,
qtyEntered: entity.qtyEntered,
qtyOfSm: entity.qtyOfSm,
qtyOfNos: entity.qtyOfNos,
conversionFactor: entity.conversionFactor,
price: entity.price,
totalAmount: entity.totalAmount,
deliveryDate: entity.deliveryDate,
thumbnail: entity.thumbnail,
);
}
}
/// Payment Terms Info Model
class PaymentTermsInfoModel {
const PaymentTermsInfoModel({
required this.name,
required this.description,
});
final String name;
final String description;
factory PaymentTermsInfoModel.fromJson(Map<String, dynamic> json) {
return PaymentTermsInfoModel(
name: json['name'] as String,
description: json['description'] as String,
);
}
Map<String, dynamic> toJson() {
return {
'name': name,
'description': description,
};
}
PaymentTermsInfo toEntity() {
return PaymentTermsInfo(
name: name,
description: description,
);
}
factory PaymentTermsInfoModel.fromEntity(PaymentTermsInfo entity) {
return PaymentTermsInfoModel(
name: entity.name,
description: entity.description,
);
}
}
/// Timeline Item Model
class TimelineItemModel {
const TimelineItemModel({
required this.label,
this.value,
required this.status,
});
final String label;
final String? value;
final String status;
factory TimelineItemModel.fromJson(Map<String, dynamic> json) {
return TimelineItemModel(
label: json['label'] as String,
value: json['value'] as String?,
status: json['status'] as String,
);
}
Map<String, dynamic> toJson() {
return {
'label': label,
'value': value,
'status': status,
};
}
TimelineItem toEntity() {
return TimelineItem(
label: label,
value: value,
status: status,
);
}
factory TimelineItemModel.fromEntity(TimelineItem entity) {
return TimelineItemModel(
label: entity.label,
value: entity.value,
status: entity.status,
);
}
}

View File

@@ -5,8 +5,10 @@ library;
import 'package:worker/features/orders/data/datasources/order_remote_datasource.dart';
import 'package:worker/features/orders/data/datasources/order_status_local_datasource.dart';
import 'package:worker/features/orders/data/models/order_detail_model.dart';
import 'package:worker/features/orders/data/models/order_model.dart';
import 'package:worker/features/orders/domain/entities/order.dart';
import 'package:worker/features/orders/domain/entities/order_detail.dart';
import 'package:worker/features/orders/domain/entities/order_status.dart';
import 'package:worker/features/orders/domain/entities/payment_term.dart';
import 'package:worker/features/orders/domain/repositories/order_repository.dart';
@@ -40,6 +42,17 @@ class OrderRepositoryImpl implements OrderRepository {
}
}
@override
Future<OrderDetail> getOrderDetail(String orderId) async {
try {
final detailData = await _remoteDataSource.getOrderDetail(orderId);
// Convert JSON → Model → Entity
return OrderDetailModel.fromJson(detailData).toEntity();
} catch (e) {
throw Exception('Failed to get order detail: $e');
}
}
@override
Future<List<OrderStatus>> getOrderStatusList() async {
try {