update address, cancel order
This commit is contained in:
@@ -268,3 +268,23 @@ curl --location 'https://land.dbiz.com//api/method/building_material.building_ma
|
|||||||
"invoices": []
|
"invoices": []
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#update address order
|
||||||
|
curl --location 'https://land.dbiz.com//api/method/building_material.building_material.api.sales_order.update' \
|
||||||
|
--header 'Cookie: sid=a0cbe3ea6f9a7e9cf083bbe3139eada68d2357eac0167bcc66cda17d; full_name=Ha%20Duy%20Lam; sid=a0cbe3ea6f9a7e9cf083bbe3139eada68d2357eac0167bcc66cda17d; system_user=yes; user_id=lamhd%40gmail.com; user_image=/files/avatar_0986788766_1763627962.jpg' \
|
||||||
|
--header 'X-Frappe-Csrf-Token: 6ff3be4d1f887dbebf86ba4502b05d94b30c0b0569de49b74a7171a9' \
|
||||||
|
--header 'Content-Type: application/json' \
|
||||||
|
--data '{
|
||||||
|
"name" : "SAL-ORD-2025-00053",
|
||||||
|
"shipping_address_name": "Công ty Tiến Nguyễn 2-thanh toán",
|
||||||
|
"customer_address": "Nguyễn Lê Duy Ti-Billing"
|
||||||
|
}'
|
||||||
|
|
||||||
|
#cancel order
|
||||||
|
curl --location 'https://land.dbiz.com//api/method/building_material.building_material.api.sales_order.cancel' \
|
||||||
|
--header 'Cookie: sid=a0cbe3ea6f9a7e9cf083bbe3139eada68d2357eac0167bcc66cda17d; full_name=Ha%20Duy%20Lam; sid=a0cbe3ea6f9a7e9cf083bbe3139eada68d2357eac0167bcc66cda17d; system_user=yes; user_id=lamhd%40gmail.com; user_image=/files/avatar_0986788766_1763627962.jpg' \
|
||||||
|
--header 'X-Frappe-Csrf-Token: 6ff3be4d1f887dbebf86ba4502b05d94b30c0b0569de49b74a7171a9' \
|
||||||
|
--header 'Content-Type: application/json' \
|
||||||
|
--data '{
|
||||||
|
"name" : "SAL-ORD-2025-00054"
|
||||||
|
}'
|
||||||
@@ -245,6 +245,16 @@ class ApiConstants {
|
|||||||
/// Returns: { "message": {...} }
|
/// Returns: { "message": {...} }
|
||||||
static const String getOrderDetail = '/building_material.building_material.api.sales_order.get_detail';
|
static const String getOrderDetail = '/building_material.building_material.api.sales_order.get_detail';
|
||||||
|
|
||||||
|
/// Update order address (requires sid and csrf_token)
|
||||||
|
/// POST /api/method/building_material.building_material.api.sales_order.update
|
||||||
|
/// Body: { "name": "SAL-ORD-2025-00053", "shipping_address_name": "...", "customer_address": "..." }
|
||||||
|
static const String updateOrder = '/building_material.building_material.api.sales_order.update';
|
||||||
|
|
||||||
|
/// Cancel order (requires sid and csrf_token)
|
||||||
|
/// POST /api/method/building_material.building_material.api.sales_order.cancel
|
||||||
|
/// Body: { "name": "SAL-ORD-2025-00054" }
|
||||||
|
static const String cancelOrder = '/building_material.building_material.api.sales_order.cancel';
|
||||||
|
|
||||||
/// Get user's orders (legacy endpoint - may be deprecated)
|
/// Get user's orders (legacy endpoint - may be deprecated)
|
||||||
/// GET /orders?status={status}&page={page}&limit={limit}
|
/// GET /orders?status={status}&page={page}&limit={limit}
|
||||||
static const String getOrders = '/orders';
|
static const String getOrders = '/orders';
|
||||||
@@ -253,10 +263,6 @@ class ApiConstants {
|
|||||||
/// GET /orders/{orderId}
|
/// GET /orders/{orderId}
|
||||||
static const String getOrderDetails = '/orders';
|
static const String getOrderDetails = '/orders';
|
||||||
|
|
||||||
/// Cancel order
|
|
||||||
/// POST /orders/{orderId}/cancel
|
|
||||||
static const String cancelOrder = '/orders';
|
|
||||||
|
|
||||||
/// Get payment transactions
|
/// Get payment transactions
|
||||||
/// GET /payments?page={page}&limit={limit}
|
/// GET /payments?page={page}&limit={limit}
|
||||||
static const String getPayments = '/payments';
|
static const String getPayments = '/payments';
|
||||||
|
|||||||
@@ -58,7 +58,7 @@ class AccountMenuItem extends StatelessWidget {
|
|||||||
horizontal: AppSpacing.md,
|
horizontal: AppSpacing.md,
|
||||||
vertical: AppSpacing.md,
|
vertical: AppSpacing.md,
|
||||||
),
|
),
|
||||||
decoration: BoxDecoration(
|
decoration: const BoxDecoration(
|
||||||
border: Border(
|
border: Border(
|
||||||
bottom: BorderSide(color: AppColors.grey100, width: 1.0),
|
bottom: BorderSide(color: AppColors.grey100, width: 1.0),
|
||||||
),
|
),
|
||||||
@@ -75,10 +75,12 @@ class AccountMenuItem extends StatelessWidget {
|
|||||||
AppColors.lightBlue.withValues(alpha: 0.1),
|
AppColors.lightBlue.withValues(alpha: 0.1),
|
||||||
shape: BoxShape.circle,
|
shape: BoxShape.circle,
|
||||||
),
|
),
|
||||||
child: FaIcon(
|
child: Center(
|
||||||
icon,
|
child: FaIcon(
|
||||||
size: 18,
|
icon,
|
||||||
color: iconColor ?? AppColors.primaryBlue,
|
size: 18,
|
||||||
|
color: iconColor ?? AppColors.primaryBlue,
|
||||||
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
const SizedBox(width: AppSpacing.md),
|
const SizedBox(width: AppSpacing.md),
|
||||||
|
|||||||
@@ -324,4 +324,48 @@ class OrderRemoteDataSource {
|
|||||||
throw Exception('Failed to get order detail: $e');
|
throw Exception('Failed to get order detail: $e');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Update order address
|
||||||
|
///
|
||||||
|
/// Calls: POST /api/method/building_material.building_material.api.sales_order.update
|
||||||
|
/// Body: {
|
||||||
|
/// "name": "SAL-ORD-2025-00053",
|
||||||
|
/// "shipping_address_name": "Công ty Tiến Nguyễn 2-thanh toán",
|
||||||
|
/// "customer_address": "Nguyễn Lê Duy Ti-Billing"
|
||||||
|
/// }
|
||||||
|
/// Updates shipping and billing addresses for an existing order
|
||||||
|
Future<void> updateOrderAddress({
|
||||||
|
required String orderId,
|
||||||
|
required String shippingAddressName,
|
||||||
|
required String customerAddress,
|
||||||
|
}) async {
|
||||||
|
try {
|
||||||
|
await _dioClient.post(
|
||||||
|
'${ApiConstants.frappeApiMethod}${ApiConstants.updateOrder}',
|
||||||
|
data: {
|
||||||
|
'name': orderId,
|
||||||
|
'shipping_address_name': shippingAddressName,
|
||||||
|
'customer_address': customerAddress,
|
||||||
|
},
|
||||||
|
);
|
||||||
|
} catch (e) {
|
||||||
|
throw Exception('Failed to update order address: $e');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Cancel order
|
||||||
|
///
|
||||||
|
/// Calls: POST /api/method/building_material.building_material.api.sales_order.cancel
|
||||||
|
/// Body: { "name": "SAL-ORD-2025-00054" }
|
||||||
|
/// Cancels an existing order (only allowed for "Chờ phê duyệt" status)
|
||||||
|
Future<void> cancelOrder(String orderId) async {
|
||||||
|
try {
|
||||||
|
await _dioClient.post(
|
||||||
|
'${ApiConstants.frappeApiMethod}${ApiConstants.cancelOrder}',
|
||||||
|
data: {'name': orderId},
|
||||||
|
);
|
||||||
|
} catch (e) {
|
||||||
|
throw Exception('Failed to cancel order: $e');
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,6 +3,7 @@
|
|||||||
/// Data model for order detail API response.
|
/// Data model for order detail API response.
|
||||||
library;
|
library;
|
||||||
|
|
||||||
|
import 'package:worker/features/account/data/models/address_model.dart';
|
||||||
import 'package:worker/features/orders/domain/entities/order_detail.dart';
|
import 'package:worker/features/orders/domain/entities/order_detail.dart';
|
||||||
|
|
||||||
/// Order Detail Model
|
/// Order Detail Model
|
||||||
@@ -19,8 +20,8 @@ class OrderDetailModel {
|
|||||||
});
|
});
|
||||||
|
|
||||||
final OrderDetailInfoModel order;
|
final OrderDetailInfoModel order;
|
||||||
final AddressInfoModel billingAddress;
|
final AddressModel billingAddress;
|
||||||
final AddressInfoModel shippingAddress;
|
final AddressModel shippingAddress;
|
||||||
final List<OrderItemDetailModel> items;
|
final List<OrderItemDetailModel> items;
|
||||||
final PaymentTermsInfoModel paymentTerms;
|
final PaymentTermsInfoModel paymentTerms;
|
||||||
final List<TimelineItemModel> timeline;
|
final List<TimelineItemModel> timeline;
|
||||||
@@ -33,10 +34,10 @@ class OrderDetailModel {
|
|||||||
order: OrderDetailInfoModel.fromJson(
|
order: OrderDetailInfoModel.fromJson(
|
||||||
json['order'] as Map<String, dynamic>,
|
json['order'] as Map<String, dynamic>,
|
||||||
),
|
),
|
||||||
billingAddress: AddressInfoModel.fromJson(
|
billingAddress: AddressModel.fromJson(
|
||||||
json['billing_address'] as Map<String, dynamic>,
|
json['billing_address'] as Map<String, dynamic>,
|
||||||
),
|
),
|
||||||
shippingAddress: AddressInfoModel.fromJson(
|
shippingAddress: AddressModel.fromJson(
|
||||||
json['shipping_address'] as Map<String, dynamic>,
|
json['shipping_address'] as Map<String, dynamic>,
|
||||||
),
|
),
|
||||||
items: (json['items'] as List<dynamic>)
|
items: (json['items'] as List<dynamic>)
|
||||||
@@ -93,8 +94,8 @@ class OrderDetailModel {
|
|||||||
factory OrderDetailModel.fromEntity(OrderDetail entity) {
|
factory OrderDetailModel.fromEntity(OrderDetail entity) {
|
||||||
return OrderDetailModel(
|
return OrderDetailModel(
|
||||||
order: OrderDetailInfoModel.fromEntity(entity.order),
|
order: OrderDetailInfoModel.fromEntity(entity.order),
|
||||||
billingAddress: AddressInfoModel.fromEntity(entity.billingAddress),
|
billingAddress: AddressModel.fromEntity(entity.billingAddress),
|
||||||
shippingAddress: AddressInfoModel.fromEntity(entity.shippingAddress),
|
shippingAddress: AddressModel.fromEntity(entity.shippingAddress),
|
||||||
items: entity.items
|
items: entity.items
|
||||||
.map((item) => OrderItemDetailModel.fromEntity(item))
|
.map((item) => OrderItemDetailModel.fromEntity(item))
|
||||||
.toList(),
|
.toList(),
|
||||||
@@ -229,105 +230,6 @@ class OrderDetailInfoModel {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// 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
|
/// Order Item Detail Model
|
||||||
class OrderItemDetailModel {
|
class OrderItemDetailModel {
|
||||||
const OrderItemDetailModel({
|
const OrderItemDetailModel({
|
||||||
|
|||||||
@@ -140,4 +140,30 @@ class OrderRepositoryImpl implements OrderRepository {
|
|||||||
throw Exception('Failed to upload bill: $e');
|
throw Exception('Failed to upload bill: $e');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Future<void> updateOrderAddress({
|
||||||
|
required String orderId,
|
||||||
|
required String shippingAddressName,
|
||||||
|
required String customerAddress,
|
||||||
|
}) async {
|
||||||
|
try {
|
||||||
|
await _remoteDataSource.updateOrderAddress(
|
||||||
|
orderId: orderId,
|
||||||
|
shippingAddressName: shippingAddressName,
|
||||||
|
customerAddress: customerAddress,
|
||||||
|
);
|
||||||
|
} catch (e) {
|
||||||
|
throw Exception('Failed to update order address: $e');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Future<void> cancelOrder(String orderId) async {
|
||||||
|
try {
|
||||||
|
await _remoteDataSource.cancelOrder(orderId);
|
||||||
|
} catch (e) {
|
||||||
|
throw Exception('Failed to cancel order: $e');
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,6 +4,7 @@
|
|||||||
library;
|
library;
|
||||||
|
|
||||||
import 'package:equatable/equatable.dart';
|
import 'package:equatable/equatable.dart';
|
||||||
|
import 'package:worker/features/account/domain/entities/address.dart';
|
||||||
|
|
||||||
/// Order Detail Entity
|
/// Order Detail Entity
|
||||||
class OrderDetail extends Equatable {
|
class OrderDetail extends Equatable {
|
||||||
@@ -19,8 +20,8 @@ class OrderDetail extends Equatable {
|
|||||||
});
|
});
|
||||||
|
|
||||||
final OrderDetailInfo order;
|
final OrderDetailInfo order;
|
||||||
final AddressInfo billingAddress;
|
final Address billingAddress;
|
||||||
final AddressInfo shippingAddress;
|
final Address shippingAddress;
|
||||||
final List<OrderItemDetail> items;
|
final List<OrderItemDetail> items;
|
||||||
final PaymentTermsInfo paymentTerms;
|
final PaymentTermsInfo paymentTerms;
|
||||||
final List<TimelineItem> timeline;
|
final List<TimelineItem> timeline;
|
||||||
@@ -96,53 +97,6 @@ class OrderDetailInfo extends Equatable {
|
|||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Address Info
|
|
||||||
class AddressInfo extends Equatable {
|
|
||||||
const AddressInfo({
|
|
||||||
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;
|
|
||||||
|
|
||||||
@override
|
|
||||||
List<Object?> get props => [
|
|
||||||
name,
|
|
||||||
addressTitle,
|
|
||||||
addressLine1,
|
|
||||||
phone,
|
|
||||||
email,
|
|
||||||
fax,
|
|
||||||
taxCode,
|
|
||||||
cityCode,
|
|
||||||
wardCode,
|
|
||||||
cityName,
|
|
||||||
wardName,
|
|
||||||
isAllowEdit,
|
|
||||||
];
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Order Item Detail
|
/// Order Item Detail
|
||||||
class OrderItemDetail extends Equatable {
|
class OrderItemDetail extends Equatable {
|
||||||
const OrderItemDetail({
|
const OrderItemDetail({
|
||||||
|
|||||||
@@ -44,4 +44,14 @@ abstract class OrderRepository {
|
|||||||
required String filePath,
|
required String filePath,
|
||||||
required String orderId,
|
required String orderId,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
/// Update order address
|
||||||
|
Future<void> updateOrderAddress({
|
||||||
|
required String orderId,
|
||||||
|
required String shippingAddressName,
|
||||||
|
required String customerAddress,
|
||||||
|
});
|
||||||
|
|
||||||
|
/// Cancel order
|
||||||
|
Future<void> cancelOrder(String orderId);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -13,6 +13,7 @@ import 'package:worker/core/constants/ui_constants.dart';
|
|||||||
import 'package:worker/core/enums/status_color.dart';
|
import 'package:worker/core/enums/status_color.dart';
|
||||||
import 'package:worker/core/theme/colors.dart';
|
import 'package:worker/core/theme/colors.dart';
|
||||||
import 'package:worker/core/utils/extensions.dart';
|
import 'package:worker/core/utils/extensions.dart';
|
||||||
|
import 'package:worker/features/account/domain/entities/address.dart';
|
||||||
import 'package:worker/features/orders/domain/entities/order_detail.dart';
|
import 'package:worker/features/orders/domain/entities/order_detail.dart';
|
||||||
import 'package:worker/features/orders/presentation/providers/orders_provider.dart';
|
import 'package:worker/features/orders/presentation/providers/orders_provider.dart';
|
||||||
|
|
||||||
@@ -33,13 +34,21 @@ class OrderDetailPage extends ConsumerWidget {
|
|||||||
Widget build(BuildContext context, WidgetRef ref) {
|
Widget build(BuildContext context, WidgetRef ref) {
|
||||||
final orderDetailAsync = ref.watch(orderDetailProvider(orderId));
|
final orderDetailAsync = ref.watch(orderDetailProvider(orderId));
|
||||||
|
|
||||||
return Scaffold(
|
return PopScope(
|
||||||
backgroundColor: const Color(0xFFF4F6F8),
|
onPopInvoked: (didPop) {
|
||||||
appBar: AppBar(
|
if (didPop) {
|
||||||
leading: IconButton(
|
// Dispose providers when leaving the page
|
||||||
icon: const FaIcon(FontAwesomeIcons.arrowLeft, color: Colors.black, size: 20),
|
ref.invalidate(updateOrderAddressProvider);
|
||||||
onPressed: () => context.pop(),
|
ref.invalidate(cancelOrderProvider);
|
||||||
),
|
}
|
||||||
|
},
|
||||||
|
child: Scaffold(
|
||||||
|
backgroundColor: const Color(0xFFF4F6F8),
|
||||||
|
appBar: AppBar(
|
||||||
|
leading: IconButton(
|
||||||
|
icon: const FaIcon(FontAwesomeIcons.arrowLeft, color: Colors.black, size: 20),
|
||||||
|
onPressed: () => context.pop(),
|
||||||
|
),
|
||||||
title: const Text(
|
title: const Text(
|
||||||
'Chi tiết đơn hàng',
|
'Chi tiết đơn hàng',
|
||||||
style: TextStyle(color: Colors.black),
|
style: TextStyle(color: Colors.black),
|
||||||
@@ -83,10 +92,10 @@ class OrderDetailPage extends ConsumerWidget {
|
|||||||
_buildStatusTimelineCard(orderDetail),
|
_buildStatusTimelineCard(orderDetail),
|
||||||
|
|
||||||
// Delivery/Address Information Card
|
// Delivery/Address Information Card
|
||||||
_buildAddressInfoCard(context, orderDetail),
|
_buildAddressInfoCard(context, ref, orderDetail),
|
||||||
|
|
||||||
// Invoice Information Card
|
// Invoice Information Card
|
||||||
_buildInvoiceInfoCard(context, orderDetail),
|
_buildInvoiceInfoCard(context, ref, orderDetail),
|
||||||
|
|
||||||
// Invoices List Card
|
// Invoices List Card
|
||||||
_buildInvoicesListCard(context, orderDetail),
|
_buildInvoicesListCard(context, orderDetail),
|
||||||
@@ -98,7 +107,15 @@ class OrderDetailPage extends ConsumerWidget {
|
|||||||
_buildOrderSummaryCard(orderDetail),
|
_buildOrderSummaryCard(orderDetail),
|
||||||
|
|
||||||
// Payment History Card
|
// Payment History Card
|
||||||
_buildPaymentHistoryCard(context, orderDetail),
|
if (orderDetail.order.totalRemaining > 0) ...[
|
||||||
|
_buildPaymentHistoryCard(context, orderDetail),
|
||||||
|
],
|
||||||
|
|
||||||
|
// Cancel Order Button (only show for "Chờ phê duyệt" status)
|
||||||
|
if (orderDetail.order.status == 'Chờ phê duyệt') ...[
|
||||||
|
const SizedBox(height: 16),
|
||||||
|
_buildCancelOrderButton(context, ref, orderDetail),
|
||||||
|
],
|
||||||
|
|
||||||
const SizedBox(height: 16),
|
const SizedBox(height: 16),
|
||||||
],
|
],
|
||||||
@@ -163,6 +180,7 @@ class OrderDetailPage extends ConsumerWidget {
|
|||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -336,7 +354,11 @@ class OrderDetailPage extends ConsumerWidget {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Build Address Info Card
|
/// Build Address Info Card
|
||||||
Widget _buildAddressInfoCard(BuildContext context, OrderDetail orderDetail) {
|
Widget _buildAddressInfoCard(
|
||||||
|
BuildContext context,
|
||||||
|
WidgetRef ref,
|
||||||
|
OrderDetail orderDetail,
|
||||||
|
) {
|
||||||
final order = orderDetail.order;
|
final order = orderDetail.order;
|
||||||
final shippingAddress = orderDetail.shippingAddress;
|
final shippingAddress = orderDetail.shippingAddress;
|
||||||
final dateFormatter = DateFormat('dd/MM/yyyy');
|
final dateFormatter = DateFormat('dd/MM/yyyy');
|
||||||
@@ -384,11 +406,71 @@ class OrderDetailPage extends ConsumerWidget {
|
|||||||
),
|
),
|
||||||
),
|
),
|
||||||
TextButton(
|
TextButton(
|
||||||
onPressed: () {
|
onPressed: () async {
|
||||||
// TODO: Navigate to address update
|
// Navigate to address selection and wait for result
|
||||||
ScaffoldMessenger.of(context).showSnackBar(
|
final result = await context.push<Address>(
|
||||||
const SnackBar(content: Text('Chức năng đang phát triển')),
|
'/account/addresses',
|
||||||
|
extra: {
|
||||||
|
'selectMode': true,
|
||||||
|
'currentAddress': shippingAddress,
|
||||||
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
|
// If user selected an address, update the order
|
||||||
|
if (result != null && context.mounted) {
|
||||||
|
// Show loading indicator
|
||||||
|
ScaffoldMessenger.of(context).showSnackBar(
|
||||||
|
const SnackBar(
|
||||||
|
content: Text('Đang cập nhật địa chỉ...'),
|
||||||
|
duration: Duration(seconds: 1),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
|
||||||
|
// Update shipping address (keep billing address the same)
|
||||||
|
await ref
|
||||||
|
.read(updateOrderAddressProvider.notifier)
|
||||||
|
.updateAddress(
|
||||||
|
orderId: orderId,
|
||||||
|
shippingAddressName: result.name,
|
||||||
|
customerAddress: orderDetail.billingAddress.name,
|
||||||
|
);
|
||||||
|
|
||||||
|
// Check if update was successful
|
||||||
|
final updateState =
|
||||||
|
ref.read(updateOrderAddressProvider)
|
||||||
|
..when(
|
||||||
|
data: (_) {
|
||||||
|
// Refresh order detail to show updated address
|
||||||
|
ref.invalidate(orderDetailProvider(orderId));
|
||||||
|
|
||||||
|
// Show success message
|
||||||
|
if (context.mounted) {
|
||||||
|
ScaffoldMessenger.of(context).showSnackBar(
|
||||||
|
const SnackBar(
|
||||||
|
content: Text(
|
||||||
|
'Cập nhật địa chỉ giao hàng thành công',
|
||||||
|
),
|
||||||
|
backgroundColor: AppColors.success,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
error: (error, _) {
|
||||||
|
// Show error message
|
||||||
|
if (context.mounted) {
|
||||||
|
ScaffoldMessenger.of(context).showSnackBar(
|
||||||
|
SnackBar(
|
||||||
|
content: Text(
|
||||||
|
'Lỗi: ${error.toString()}',
|
||||||
|
),
|
||||||
|
backgroundColor: AppColors.danger,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
loading: () {},
|
||||||
|
);
|
||||||
|
}
|
||||||
},
|
},
|
||||||
style: TextButton.styleFrom(
|
style: TextButton.styleFrom(
|
||||||
padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 8),
|
padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 8),
|
||||||
@@ -501,7 +583,11 @@ class OrderDetailPage extends ConsumerWidget {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Build Invoice Info Card
|
/// Build Invoice Info Card
|
||||||
Widget _buildInvoiceInfoCard(BuildContext context, OrderDetail orderDetail) {
|
Widget _buildInvoiceInfoCard(
|
||||||
|
BuildContext context,
|
||||||
|
WidgetRef ref,
|
||||||
|
OrderDetail orderDetail,
|
||||||
|
) {
|
||||||
final billingAddress = orderDetail.billingAddress;
|
final billingAddress = orderDetail.billingAddress;
|
||||||
|
|
||||||
return Card(
|
return Card(
|
||||||
@@ -536,17 +622,77 @@ class OrderDetailPage extends ConsumerWidget {
|
|||||||
],
|
],
|
||||||
),
|
),
|
||||||
TextButton(
|
TextButton(
|
||||||
onPressed: () {
|
onPressed: () async {
|
||||||
// TODO: Navigate to invoice update
|
// Navigate to address selection and wait for result
|
||||||
ScaffoldMessenger.of(context).showSnackBar(
|
final result = await context.push<Address>(
|
||||||
const SnackBar(content: Text('Chức năng đang phát triển')),
|
'/account/addresses',
|
||||||
|
extra: {
|
||||||
|
'selectMode': true,
|
||||||
|
'currentAddress': billingAddress,
|
||||||
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
|
// If user selected an address, update the order
|
||||||
|
if (result != null && context.mounted) {
|
||||||
|
// Show loading indicator
|
||||||
|
ScaffoldMessenger.of(context).showSnackBar(
|
||||||
|
const SnackBar(
|
||||||
|
content: Text('Đang cập nhật địa chỉ...'),
|
||||||
|
duration: Duration(seconds: 1),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
|
||||||
|
// Update billing address (keep shipping address the same)
|
||||||
|
await ref
|
||||||
|
.read(updateOrderAddressProvider.notifier)
|
||||||
|
.updateAddress(
|
||||||
|
orderId: orderId,
|
||||||
|
shippingAddressName: orderDetail.shippingAddress.name,
|
||||||
|
customerAddress: result.name,
|
||||||
|
);
|
||||||
|
|
||||||
|
// Check if update was successful
|
||||||
|
final updateState =
|
||||||
|
ref.read(updateOrderAddressProvider)
|
||||||
|
..when(
|
||||||
|
data: (_) {
|
||||||
|
// Refresh order detail to show updated address
|
||||||
|
ref.invalidate(orderDetailProvider(orderId));
|
||||||
|
|
||||||
|
// Show success message
|
||||||
|
if (context.mounted) {
|
||||||
|
ScaffoldMessenger.of(context).showSnackBar(
|
||||||
|
const SnackBar(
|
||||||
|
content: Text(
|
||||||
|
'Cập nhật địa chỉ hóa đơn thành công',
|
||||||
|
),
|
||||||
|
backgroundColor: AppColors.success,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
error: (error, _) {
|
||||||
|
// Show error message
|
||||||
|
if (context.mounted) {
|
||||||
|
ScaffoldMessenger.of(context).showSnackBar(
|
||||||
|
SnackBar(
|
||||||
|
content: Text(
|
||||||
|
'Lỗi: ${error.toString()}',
|
||||||
|
),
|
||||||
|
backgroundColor: AppColors.danger,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
loading: () {},
|
||||||
|
);
|
||||||
|
}
|
||||||
},
|
},
|
||||||
style: TextButton.styleFrom(
|
style: TextButton.styleFrom(
|
||||||
padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 8),
|
padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 8),
|
||||||
minimumSize: Size.zero,
|
minimumSize: Size.zero,
|
||||||
tapTargetSize: MaterialTapTargetSize.shrinkWrap,
|
tapTargetSize: MaterialTapTargetSize.shrinkWrap,
|
||||||
side: BorderSide(color: AppColors.grey100),
|
side: const BorderSide(color: AppColors.grey100),
|
||||||
shape: RoundedRectangleBorder(
|
shape: RoundedRectangleBorder(
|
||||||
borderRadius: BorderRadius.circular(8),
|
borderRadius: BorderRadius.circular(8),
|
||||||
),
|
),
|
||||||
@@ -583,7 +729,8 @@ class OrderDetailPage extends ConsumerWidget {
|
|||||||
color: AppColors.grey900,
|
color: AppColors.grey900,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
if (billingAddress.taxCode.isNotEmpty) ...[
|
if (billingAddress.taxCode != null &&
|
||||||
|
billingAddress.taxCode!.isNotEmpty) ...[
|
||||||
const SizedBox(height: 2),
|
const SizedBox(height: 2),
|
||||||
Text(
|
Text(
|
||||||
'Mã số thuế: ${billingAddress.taxCode}',
|
'Mã số thuế: ${billingAddress.taxCode}',
|
||||||
@@ -949,15 +1096,15 @@ class OrderDetailPage extends ConsumerWidget {
|
|||||||
child: Column(
|
child: Column(
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
children: [
|
children: [
|
||||||
Row(
|
const Row(
|
||||||
children: [
|
children: [
|
||||||
const FaIcon(
|
FaIcon(
|
||||||
FontAwesomeIcons.receipt,
|
FontAwesomeIcons.receipt,
|
||||||
color: AppColors.primaryBlue,
|
color: AppColors.primaryBlue,
|
||||||
size: 18,
|
size: 18,
|
||||||
),
|
),
|
||||||
const SizedBox(width: 8),
|
SizedBox(width: 8),
|
||||||
const Text(
|
Text(
|
||||||
'Tổng kết đơn hàng',
|
'Tổng kết đơn hàng',
|
||||||
style: TextStyle(
|
style: TextStyle(
|
||||||
fontSize: 16,
|
fontSize: 16,
|
||||||
@@ -993,15 +1140,15 @@ class OrderDetailPage extends ConsumerWidget {
|
|||||||
const Divider(height: 24),
|
const Divider(height: 24),
|
||||||
|
|
||||||
// Payment Terms
|
// Payment Terms
|
||||||
Row(
|
const Row(
|
||||||
children: [
|
children: [
|
||||||
const FaIcon(
|
FaIcon(
|
||||||
FontAwesomeIcons.creditCard,
|
FontAwesomeIcons.creditCard,
|
||||||
size: 14,
|
size: 14,
|
||||||
color: AppColors.grey500,
|
color: AppColors.grey500,
|
||||||
),
|
),
|
||||||
const SizedBox(width: 6),
|
SizedBox(width: 6),
|
||||||
const Text(
|
Text(
|
||||||
'Điều khoản thanh toán:',
|
'Điều khoản thanh toán:',
|
||||||
style: TextStyle(fontSize: 14, color: AppColors.grey500),
|
style: TextStyle(fontSize: 14, color: AppColors.grey500),
|
||||||
),
|
),
|
||||||
@@ -1295,4 +1442,116 @@ class OrderDetailPage extends ConsumerWidget {
|
|||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Build Cancel Order Button
|
||||||
|
Widget _buildCancelOrderButton(
|
||||||
|
BuildContext context,
|
||||||
|
WidgetRef ref,
|
||||||
|
OrderDetail orderDetail,
|
||||||
|
) {
|
||||||
|
return Padding(
|
||||||
|
padding: const EdgeInsets.symmetric(horizontal: 16),
|
||||||
|
child: OutlinedButton.icon(
|
||||||
|
onPressed: () async {
|
||||||
|
// Show confirmation dialog
|
||||||
|
final confirmed = await showDialog<bool>(
|
||||||
|
context: context,
|
||||||
|
builder: (context) => AlertDialog(
|
||||||
|
title: const Text('Xác nhận hủy đơn'),
|
||||||
|
content: Text(
|
||||||
|
'Bạn có chắc chắn muốn hủy đơn hàng ${orderDetail.order.name}?\n\nHành động này không thể hoàn tác.',
|
||||||
|
),
|
||||||
|
actions: [
|
||||||
|
TextButton(
|
||||||
|
onPressed: () => Navigator.of(context).pop(false),
|
||||||
|
child: const Text('Không'),
|
||||||
|
),
|
||||||
|
ElevatedButton(
|
||||||
|
onPressed: () => Navigator.of(context).pop(true),
|
||||||
|
style: ElevatedButton.styleFrom(
|
||||||
|
backgroundColor: AppColors.danger,
|
||||||
|
foregroundColor: Colors.white,
|
||||||
|
),
|
||||||
|
child: const Text('Hủy đơn'),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
);
|
||||||
|
|
||||||
|
// If user confirmed, proceed with cancellation
|
||||||
|
if (confirmed == true && context.mounted) {
|
||||||
|
// Show loading indicator
|
||||||
|
ScaffoldMessenger.of(context).showSnackBar(
|
||||||
|
const SnackBar(
|
||||||
|
content: Row(
|
||||||
|
children: [
|
||||||
|
SizedBox(
|
||||||
|
width: 20,
|
||||||
|
height: 20,
|
||||||
|
child: CircularProgressIndicator(
|
||||||
|
strokeWidth: 2,
|
||||||
|
valueColor: AlwaysStoppedAnimation<Color>(Colors.white),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
SizedBox(width: 12),
|
||||||
|
Text('Đang hủy đơn hàng...'),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
duration: Duration(seconds: 2),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
|
||||||
|
// Call cancel order API
|
||||||
|
await ref.read(cancelOrderProvider.notifier).cancel(orderId);
|
||||||
|
|
||||||
|
// Check result
|
||||||
|
final cancelState = ref.read(cancelOrderProvider);
|
||||||
|
if (context.mounted) {
|
||||||
|
cancelState.when(
|
||||||
|
data: (_) {
|
||||||
|
// Success: Invalidate order providers and show success message
|
||||||
|
ref.invalidate(ordersProvider);
|
||||||
|
ref.invalidate(orderDetailProvider(orderId));
|
||||||
|
|
||||||
|
ScaffoldMessenger.of(context).showSnackBar(
|
||||||
|
const SnackBar(
|
||||||
|
content: Text('Đã hủy đơn hàng thành công'),
|
||||||
|
backgroundColor: AppColors.success,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
|
||||||
|
// Pop back to orders list
|
||||||
|
context.pop();
|
||||||
|
},
|
||||||
|
error: (error, _) {
|
||||||
|
// Error: Show error message
|
||||||
|
ScaffoldMessenger.of(context).showSnackBar(
|
||||||
|
SnackBar(
|
||||||
|
content: Text('Lỗi: ${error.toString()}'),
|
||||||
|
backgroundColor: AppColors.danger,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
},
|
||||||
|
loading: () {},
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
icon: const FaIcon(FontAwesomeIcons.xmark, size: 18),
|
||||||
|
label: const Text('Hủy đơn hàng'),
|
||||||
|
style: OutlinedButton.styleFrom(
|
||||||
|
padding: const EdgeInsets.symmetric(vertical: 14),
|
||||||
|
side: const BorderSide(
|
||||||
|
color: AppColors.danger,
|
||||||
|
width: 2,
|
||||||
|
),
|
||||||
|
foregroundColor: AppColors.danger,
|
||||||
|
shape: RoundedRectangleBorder(
|
||||||
|
borderRadius: BorderRadius.circular(8),
|
||||||
|
),
|
||||||
|
minimumSize: const Size(double.infinity, 48),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -189,3 +189,51 @@ Future<OrderDetail> orderDetail(Ref ref, String orderId) async {
|
|||||||
final repository = await ref.watch(orderRepositoryProvider.future);
|
final repository = await ref.watch(orderRepositoryProvider.future);
|
||||||
return await repository.getOrderDetail(orderId);
|
return await repository.getOrderDetail(orderId);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Update Order Address Action
|
||||||
|
///
|
||||||
|
/// Updates the shipping and billing addresses for an order.
|
||||||
|
@Riverpod(keepAlive: true)
|
||||||
|
class UpdateOrderAddress extends _$UpdateOrderAddress {
|
||||||
|
@override
|
||||||
|
FutureOr<void> build() {
|
||||||
|
// No initial state needed
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Update order address
|
||||||
|
Future<void> updateAddress({
|
||||||
|
required String orderId,
|
||||||
|
required String shippingAddressName,
|
||||||
|
required String customerAddress,
|
||||||
|
}) async {
|
||||||
|
state = const AsyncValue.loading();
|
||||||
|
state = await AsyncValue.guard(() async {
|
||||||
|
final repository = await ref.read(orderRepositoryProvider.future);
|
||||||
|
await repository.updateOrderAddress(
|
||||||
|
orderId: orderId,
|
||||||
|
shippingAddressName: shippingAddressName,
|
||||||
|
customerAddress: customerAddress,
|
||||||
|
);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Cancel Order Action
|
||||||
|
///
|
||||||
|
/// Cancels an order (only allowed for "Chờ phê duyệt" status).
|
||||||
|
@Riverpod(keepAlive: true)
|
||||||
|
class CancelOrder extends _$CancelOrder {
|
||||||
|
@override
|
||||||
|
FutureOr<void> build() {
|
||||||
|
// No initial state needed
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Cancel order
|
||||||
|
Future<void> cancel(String orderId) async {
|
||||||
|
state = const AsyncValue.loading();
|
||||||
|
state = await AsyncValue.guard(() async {
|
||||||
|
final repository = await ref.read(orderRepositoryProvider.future);
|
||||||
|
await repository.cancelOrder(orderId);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -492,3 +492,122 @@ final class OrderDetailFamily extends $Family
|
|||||||
@override
|
@override
|
||||||
String toString() => r'orderDetailProvider';
|
String toString() => r'orderDetailProvider';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Update Order Address Action
|
||||||
|
///
|
||||||
|
/// Updates the shipping and billing addresses for an order.
|
||||||
|
|
||||||
|
@ProviderFor(UpdateOrderAddress)
|
||||||
|
const updateOrderAddressProvider = UpdateOrderAddressProvider._();
|
||||||
|
|
||||||
|
/// Update Order Address Action
|
||||||
|
///
|
||||||
|
/// Updates the shipping and billing addresses for an order.
|
||||||
|
final class UpdateOrderAddressProvider
|
||||||
|
extends $AsyncNotifierProvider<UpdateOrderAddress, void> {
|
||||||
|
/// Update Order Address Action
|
||||||
|
///
|
||||||
|
/// Updates the shipping and billing addresses for an order.
|
||||||
|
const UpdateOrderAddressProvider._()
|
||||||
|
: super(
|
||||||
|
from: null,
|
||||||
|
argument: null,
|
||||||
|
retry: null,
|
||||||
|
name: r'updateOrderAddressProvider',
|
||||||
|
isAutoDispose: false,
|
||||||
|
dependencies: null,
|
||||||
|
$allTransitiveDependencies: null,
|
||||||
|
);
|
||||||
|
|
||||||
|
@override
|
||||||
|
String debugGetCreateSourceHash() => _$updateOrderAddressHash();
|
||||||
|
|
||||||
|
@$internal
|
||||||
|
@override
|
||||||
|
UpdateOrderAddress create() => UpdateOrderAddress();
|
||||||
|
}
|
||||||
|
|
||||||
|
String _$updateOrderAddressHash() =>
|
||||||
|
r'1913c2ccc2ba232debb4368f350f64c3d08cccec';
|
||||||
|
|
||||||
|
/// Update Order Address Action
|
||||||
|
///
|
||||||
|
/// Updates the shipping and billing addresses for an order.
|
||||||
|
|
||||||
|
abstract class _$UpdateOrderAddress extends $AsyncNotifier<void> {
|
||||||
|
FutureOr<void> build();
|
||||||
|
@$mustCallSuper
|
||||||
|
@override
|
||||||
|
void runBuild() {
|
||||||
|
build();
|
||||||
|
final ref = this.ref as $Ref<AsyncValue<void>, void>;
|
||||||
|
final element =
|
||||||
|
ref.element
|
||||||
|
as $ClassProviderElement<
|
||||||
|
AnyNotifier<AsyncValue<void>, void>,
|
||||||
|
AsyncValue<void>,
|
||||||
|
Object?,
|
||||||
|
Object?
|
||||||
|
>;
|
||||||
|
element.handleValue(ref, null);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Cancel Order Action
|
||||||
|
///
|
||||||
|
/// Cancels an order (only allowed for "Chờ phê duyệt" status).
|
||||||
|
|
||||||
|
@ProviderFor(CancelOrder)
|
||||||
|
const cancelOrderProvider = CancelOrderProvider._();
|
||||||
|
|
||||||
|
/// Cancel Order Action
|
||||||
|
///
|
||||||
|
/// Cancels an order (only allowed for "Chờ phê duyệt" status).
|
||||||
|
final class CancelOrderProvider
|
||||||
|
extends $AsyncNotifierProvider<CancelOrder, void> {
|
||||||
|
/// Cancel Order Action
|
||||||
|
///
|
||||||
|
/// Cancels an order (only allowed for "Chờ phê duyệt" status).
|
||||||
|
const CancelOrderProvider._()
|
||||||
|
: super(
|
||||||
|
from: null,
|
||||||
|
argument: null,
|
||||||
|
retry: null,
|
||||||
|
name: r'cancelOrderProvider',
|
||||||
|
isAutoDispose: false,
|
||||||
|
dependencies: null,
|
||||||
|
$allTransitiveDependencies: null,
|
||||||
|
);
|
||||||
|
|
||||||
|
@override
|
||||||
|
String debugGetCreateSourceHash() => _$cancelOrderHash();
|
||||||
|
|
||||||
|
@$internal
|
||||||
|
@override
|
||||||
|
CancelOrder create() => CancelOrder();
|
||||||
|
}
|
||||||
|
|
||||||
|
String _$cancelOrderHash() => r'201624156f3ae3c05fe438ea7e266cb8fa2a5bd6';
|
||||||
|
|
||||||
|
/// Cancel Order Action
|
||||||
|
///
|
||||||
|
/// Cancels an order (only allowed for "Chờ phê duyệt" status).
|
||||||
|
|
||||||
|
abstract class _$CancelOrder extends $AsyncNotifier<void> {
|
||||||
|
FutureOr<void> build();
|
||||||
|
@$mustCallSuper
|
||||||
|
@override
|
||||||
|
void runBuild() {
|
||||||
|
build();
|
||||||
|
final ref = this.ref as $Ref<AsyncValue<void>, void>;
|
||||||
|
final element =
|
||||||
|
ref.element
|
||||||
|
as $ClassProviderElement<
|
||||||
|
AnyNotifier<AsyncValue<void>, void>,
|
||||||
|
AsyncValue<void>,
|
||||||
|
Object?,
|
||||||
|
Object?
|
||||||
|
>;
|
||||||
|
element.handleValue(ref, null);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user