Chuyển tới nội dung chính

2. Admin Hooks: Đơn Hàng (Orders)

Các hooks đơn hàng được đăng ký trong bootstrap/order.php. Đây là tập hooks quan trọng nhất để tích hợp Shipping, Affiliate, Webhook, hay bất kỳ hành động nào liên quan đến vòng đời đơn hàng.


2.1 Trang Danh Sách Đơn Hàng (Table)

Hook TypeHook NameTham SốMô Tả
Actionadmin_order_action_bar_headingThêm nút vào thanh công cụ đầu trang (VD: nút "In hàng loạt")
Filteradmin_order_table_column_action($actions, $item)Thêm/sửa nút icon action trong mỗi dòng đơn hàng
Actionadmin_after_order_table_viewThêm Modal/Popup ẩn phục vụ in ấn, export...
// Thêm nút "Xuất Excel" vào thanh công cụ
add_action('admin_order_action_bar_heading', function() {
echo '<a href="/admin/orders/export" class="btn btn-success">📊 Xuất Excel</a>';
});

// Thêm nút "Đẩy sang GHTK" vào mỗi dòng đơn
add_filter('admin_order_table_column_action', function($actions, $order) {
if($order->status == 'confirm') {
$actions['ghtk'] = '<a href="#" data-id="'.$order->id.'" class="btn-ghtk-push">
<i class="fa fa-truck"></i>
</a>';
}
return $actions;
}, 10, 2);

2.2 Trang Chi Tiết Đơn Hàng (View/Edit)

Layout trang chi tiết chia thành 2 cột: Primary (trái/chính) và Secondary (phải/sidebar).

Cột Chính (order_detail_sections_primary)

Hook NamePriorityClass::MethodMô Tả
order_detail_sections_primary10OrderDetail::renderContentDanh sách sản phẩm trong đơn
order_detail_sections_primary20OrderDetail::renderNoteGhi chú đơn hàng
order_detail_sections_primary25OrderDetail::renderPaymentThông tin cổng thanh toán
order_detail_sections_primary30OrderDetail::renderShippingThông tin vận chuyển
order_detail_sections_primary40OrderDetail::renderHistoryLịch sử thao tác
// Chèn block thông tin tích hợp GHTK vào giữa Payment và Shipping
add_action('order_detail_sections_primary', function() {
$orderId = request()->input('id') ?? request()->segment(4);
$ghtkCode = Order::getMeta($orderId, 'ghtk_tracking_code', true);
if($ghtkCode) {
echo '<div class="box-ghtk-info">';
echo '<b>Mã vận đơn GHTK:</b> '.$ghtkCode;
echo '</div>';
}
}, 28); // Giữa Payment(25) và Shipping(30)

Cột Sidebar (order_detail_sections_secondary)

Hook NamePriorityClass::MethodMô Tả
order_detail_sections_secondary10OrderDetail::renderActionBox thay đổi trạng thái
order_detail_sections_secondary20OrderDetail::renderCustomerInfoThông tin khách / địa chỉ giao
// Thêm box thông tin điểm tích lũy vào sidebar
add_action('order_detail_sections_secondary', function() {
$orderId = request()->segment(4);
$order = Order::find($orderId);
$points = User::getMeta($order->customer_id, 'loyalty_points', true);
echo '<div class="box-loyalty"><b>Điểm tích lũy:</b> '.$points.'</div>';
}, 30);

Thanh Tiêu Đề Trang Chi Tiết (order_detail_header_action)

Hook NameClass::MethodMô Tả
order_detail_header_actionOrderPrint::addButtonOrderDetailNút In đơn hàng
order_detail_header_actionOrderDetail::addButtonActionNút Quay về danh sách
add_action('order_detail_header_action', function() {
$orderId = request()->segment(4);
echo '<a href="/admin/ghtk/push/'.$orderId.'" class="btn btn-warning">🚛 Đẩy GHTK</a>';
});

2.3 Trang Tạo Đơn POS (OrderAdd)

Dùng cho Admin tạo đơn trực tiếp từ backend (không qua giỏ hàng Frontend).

Hook NamePriorityClass::MethodMô Tả
admin_order_action_bar_headingOrderAdd::addButtonAddOrderNút "Thêm đơn hàng" trong thanh toolbar
form_order_action_buttonOrderAdd::formButtonNút Submit form đơn hàng POS
order_save_sections_primary10OrderAdd::renderProductItemBox chọn sản phẩm, nhập giá
order_save_sections_primary10OrderAdd::renderShippingForm giao hàng
order_save_sections_primary10OrderAdd::renderDiscountForm mã giảm giá
order_save_sections_primary10OrderAdd::renderPaymentsChọn phương thức thanh toán
order_save_sections_primary100OrderAdd::renderReviewTổng hóa đơn trước submit
order_save_sections_secondary10OrderAdd::renderCustomerInfoBox chọn khách hàng
// Thêm block ghi chú nội bộ vào form POS
add_action('order_save_sections_primary', function() {
echo '<div class="box-internal-note">';
echo '<label>Ghi chú nội bộ (Không gửi cho khách):</label>';
echo '<textarea name="internal_note"></textarea>';
echo '</div>';
}, 50);

2.4 Hooks Thay Đổi Trạng Thái Đơn Hàng

Đây là nhóm hooks quan trọng nhất khi viết plugin tích hợp bên ngoài.

Lifecycle Hooks

Hook TypeHook NameTham SốMô Tả
Filteradmin_order_status_{status}_save($orderUpdate, $status, $order)Mảng dữ liệu sắp ghi vào đơn. Trả về mảng rỗng để chặn việc cập nhật
Actionadmin_order_status_before_update($order, $status)Trước khi lưu trạng thái mới. Có thể response()->error() để chặn
Actionadmin_order_status_update($order, $status)Sau khi trạng thái đã được cập nhật
Actionadmin_order_status_cancelled_after($order)Riêng cho luồng hủy đơn, chạy trước khi xử lý hủy
Filteradmin_order_status_cancelled_errors($messages, $order)Trả SKD_Error để chặn việc hủy đơn

Quan trọng: $orderđối tượng Order, $statustrạng thái mới (chuỗi). Không phải cặp ($statusNew, $statusOld).

Pattern Hook Riêng Cho Từng Trạng Thái

admin_order_status_{status}_save là hook động — tên ghép từ OrderStatus->value:

admin_order_status_wait_save
admin_order_status_confirm_save
admin_order_status_wait-pickup_save
admin_order_status_pickup_save
admin_order_status_pickup-fail_save
admin_order_status_processing_save
admin_order_status_ship_save
admin_order_status_ship-fail_save
admin_order_status_completed_save
admin_order_status_cancelled_save
use Ecommerce\Status\OrderStatus;

// Bổ sung dữ liệu ghi kèm khi đơn chuyển sang "hoàn thành"
add_filter('admin_order_status_'.OrderStatus::COMPLETED->value.'_save', function($orderUpdate, $status, $order) {
$orderUpdate['completed_at'] = time();
return $orderUpdate;
}, 10, 3);

// Chạy trước khi đổi trạng thái (để validate / chặn)
add_action('admin_order_status_before_update', function($order, $status) {
if($order->status == OrderStatus::COMPLETED->value && $status == OrderStatus::WAIT->value) {
response()->error('Không thể reset đơn đã hoàn thành!');
}
}, 1, 2);

// Chạy sau khi đổi trạng thái
add_action('admin_order_status_update', function($order, $status) {
if($status == OrderStatus::COMPLETED->value) {
Http::post('https://affiliate.api/webhook', [
'event' => 'order_completed',
'order_id' => $order->id,
'total' => $order->total,
]);
}
}, 10, 2);

Hooks Trạng Thái Thanh Toán

Hook TypeHook NameTham SốMô Tả
Filteradmin_order_status_pay_{status}_save($orderUpdate, $status, $order)Mảng dữ liệu sắp ghi. Trả mảng rỗng để chặn
Actionadmin_order_status_pay_{status}_action($order, $status)Ngay sau filter _save, trước khi ghi
Actionadmin_order_status_pay_before_update($order, $status)Trước khi lưu trạng thái thanh toán
Actionadmin_order_status_pay_{status}_success($order, $status)Sau khi lưu thành công, riêng theo từng trạng thái
Actionadmin_order_status_pay_update($order, $status)Sau khi lưu thành công, cho mọi trạng thái

Giá trị {status} lấy từ enum OrderPay: unpaid, paid, refunded.

use Ecommerce\Status\OrderPay;

// Hook khi đơn được đánh dấu đã thanh toán
add_action('admin_order_status_pay_'.OrderPay::COMPLETED->value.'_success', function($order, $status) {
// Kích hoạt license key
// Gửi email xác nhận thanh toán
}, 10, 2);

2.5 Hook Sau Khi Admin Tạo Đơn POS

// Chạy sau khi Admin tạo đơn thành công từ trang POS
add_action('admin_order_save_after_success', function($order) {
EmailService::orderCreated($order);
});