Dự án này sử dụng một base path là /api cho tất cả các routes.
Base URL: http://localhost:8080/api
Đăng ký tài khoản người dùng mới.
-
Tham số (Body):
name(String, Bắt buộc): Tên người dùng.email(String, Tùy chọn): Email người dùng.phone(String, Tùy chọn): Số điện thoại người dùng (định dạng+84...).password(String, Bắt buộc): Mật khẩu (tối thiểu 8 ký tự).passwordConfirm(String, Bắt buộc): Xác nhận mật khẩu.
Lưu ý: Phải cung cấp
emailhoặcphone. User mới sẽ có role mặc định là "user". -
Kết quả thành công (201):
- Nếu đăng ký bằng email, trả về thông tin người dùng và token JWT.
- Nếu đăng ký bằng SĐT, trả về thông báo yêu cầu xác thực OTP.
{ "status": "success", "token": "your_jwt_token", "data": { "user": { "_id": "userId", "name": "Test User", "email": "test@example.com", "phone": "+84123456789", "role": "user", "isPhoneVerified": false } } }
Đăng nhập vào hệ thống.
-
Tham số (Body):
identifier(String, Bắt buộc): Email hoặc số điện thoại của người dùng.password(String, Bắt buộc): Mật khẩu.
-
Kết quả thành công (200):
{ "status": "success", "token": "your_jwt_token", "data": { "user": { "_id": "userId", "name": "Test User", "email": "test@example.com", "role": "user" } } }
Xác thực số điện thoại bằng mã OTP.
-
Tham số (Body):
phone(String, Bắt buộc): Số điện thoại đã đăng ký.code(String, Bắt buộc): Mã OTP nhận được.
-
Kết quả thành công (200):
- Trả về thông tin người dùng và token JWT sau khi xác thực thành công.
Yêu cầu reset mật khẩu qua email.
-
Tham số (Body):
email(String, Bắt buộc): Email đã đăng ký.
-
Kết quả thành công (200):
{ "status": "success", "message": "Token reset mật khẩu đã được gửi tới email!" }
Đặt lại mật khẩu mới bằng token đã nhận.
-
Tham số (URL):
token(String, Bắt buộc): Token reset nhận được từ email.
-
Tham số (Body):
password(String, Bắt buộc): Mật khẩu mới.passwordConfirm(String, Bắt buộc): Xác nhận mật khẩu mới.
-
Kết quả thành công (200):
- Trả về thông tin người dùng và token JWT mới.
Lấy danh sách sản phẩm với search, filter, sort và pagination.
-
Tham số (Query):
page(Number, Mặc định: 1): Số trang.limit(Number, Mặc định: 10): Số lượng sản phẩm mỗi trang.search(String): Tìm kiếm theo tên, mô tả, hoặc ISBN.categoryId(ObjectId): Lọc theo danh mục.authorId(ObjectId): Lọc theo tác giả.minPrice(Number): Giá tối thiểu.maxPrice(Number): Giá tối đa.minRating(Number): Rating tối thiểu (1-5).inStock(Boolean):trueđể chỉ hiển thị sản phẩm còn hàng.sort(String): Sắp xếp theo:price_asc: Giá tăng dầnprice_desc: Giá giảm dầnrating: Rating cao nhấtbestseller: Bán chạy nhấtname: Tên A-Z- Mặc định: Mới nhất
-
Ví dụ:
GET /api/product?search=harry&minPrice=50000&maxPrice=200000&sort=price_asc&page=1&limit=10&inStock=true -
Kết quả thành công (200):
{ "status": "success", "results": 10, "data": { "products": [ { "_id": "productId", "name": "Tên sản phẩm", "slug": "ten-san-pham", "price": 150000, "discount": 10, "description": "Mô tả sản phẩm", "categoryId": { "_id": "categoryId", "name": "Tiểu thuyết", "slug": "tieu-thuyet" }, "authors": [ { "_id": "authorId", "name": "J.K. Rowling", "slug": "jk-rowling" } ], "publisher": "Bloomsbury", "isbn": "978-0439708180", "coverImageUrl": "https://example.com/image.jpg", "rating": 4.5, "inStock": 100, "sold": 250, "createdAt": "2025-12-01T00:00:00.000Z" } ], "pagination": { "page": 1, "limit": 10, "total": 45, "totalPages": 5 } } }
Lấy thông tin chi tiết một sản phẩm.
-
Tham số (URL):
id(ObjectId, Bắt buộc): ID của sản phẩm.
-
Kết quả thành công (200):
{ "status": "success", "data": { "product": { "_id": "productId", "name": "Harry Potter và Hòn đá phù thủy", "slug": "harry-potter-va-hon-da-phu-thuy", "price": 150000, "discount": 10, "description": "Cuốn sách đầu tiên...", "categoryId": { ... }, "authors": [ ... ], "publisher": "Bloomsbury", "publicationDate": "1997-06-26", "isbn": "978-0439708180", "coverImageUrl": "https://...", "gallery": ["url1", "url2"], "rating": 4.8, "inStock": 50, "sold": 1200 } } } -
Lỗi (404):
{ "status": "error", "message": "Sản phẩm không tồn tại" }
Tạo một sản phẩm mới.
-
Headers:
Authorization:Bearer your_jwt_token(Admin role required)
-
Tham số (Body):
name(String, Bắt buộc): Tên sản phẩm.price(Number, Bắt buộc): Giá sản phẩm.discount(Number, 0-100): Phần trăm giảm giá.description(String): Mô tả sản phẩm.categoryId(ObjectId, Bắt buộc): ID danh mục.authors(Array): Mảng object[{ name: "Tên tác giả" }]. Hệ thống sẽ tự tạo author mới nếu chưa tồn tại.publisher(String): Nhà xuất bản.publicationDate(Date): Ngày xuất bản.isbn(String): Mã ISBN.coverImageUrl(String): URL ảnh bìa.gallery(Array of String): Mảng URL ảnh.inStock(Number): Số lượng trong kho.slug(String, Tùy chọn): Tự động tạo từ name nếu không cung cấp.
-
Kết quả thành công (201):
{ "status": "success", "data": { "product": { ... } } }
Cập nhật thông tin sản phẩm.
-
Headers:
Authorization:Bearer your_jwt_token(Admin role required)
-
Tham số (URL):
id(ObjectId, Bắt buộc): ID của sản phẩm.
-
Tham số (Body):
- Các trường cần cập nhật (giống POST).
-
Kết quả thành công (200):
{ "status": "success", "data": { "product": { ... } } }
Xóa một sản phẩm.
-
Headers:
Authorization:Bearer your_jwt_token(Admin role required)
-
Tham số (URL):
id(ObjectId, Bắt buộc): ID của sản phẩm.
-
Kết quả thành công (200):
{ "status": "success", "message": "Đã xóa sản phẩm thành công", "data": { "product": { ... } } }
Lấy danh sách tác giả với pagination.
-
Tham số (Query):
page(Number, Mặc định: 1)limit(Number, Mặc định: 10)
-
Kết quả thành công (200):
{ "status": "success", "results": 10, "data": { "authors": [ { "_id": "authorId", "name": "J.K. Rowling", "slug": "jk-rowling", "biography": "Tiểu sử...", "nationality": "British", "dateOfBirth": "1965-07-31", "totalBooks": 15, "followers": 1000000 } ], "pagination": { "page": 1, "limit": 10, "total": 50, "totalPages": 5 } } }
Lấy chi tiết tác giả.
- Kết quả thành công (200):
{ "status": "success", "data": { "author": { "_id": "authorId", "name": "J.K. Rowling", "slug": "jk-rowling", "biography": "...", "books": [ { "_id": "productId", "name": "Harry Potter", "slug": "harry-potter", "coverImageUrl": "..." } ] } } }
Tạo tác giả mới.
- Headers:
Authorization: Bearer your_jwt_token - Body:
name(required),biography,nationality,dateOfBirth,avatar
Cập nhật tác giả.
Xóa tác giả.
Lấy danh sách danh mục.
- Kết quả thành công (200):
{ "status": "success", "results": 15, "data": { "categories": [ { "_id": "categoryId", "name": "Tiểu thuyết", "slug": "tieu-thuyet", "description": "...", "parentCategory": null, "imageUrl": "..." } ] } }
Lấy chi tiết danh mục.
Tạo danh mục mới.
- Headers:
Authorization: Bearer your_jwt_token - Body:
name(required),description,parentCategory,imageUrl
Cập nhật danh mục.
Xóa danh mục.
Lấy tất cả đánh giá của một sản phẩm.
-
Tham số (URL):
productId(ObjectId, Bắt buộc)
-
Tham số (Query):
page(Number, Mặc định: 1)limit(Number, Mặc định: 10)
-
Kết quả thành công (200):
{ "status": "success", "results": 10, "data": { "reviews": [ { "_id": "reviewId", "rating": 5, "comment": "Sản phẩm rất tốt!", "userId": { "_id": "userId", "name": "Nguyen Van A" }, "productId": "productId", "createdAt": "2025-12-01T00:00:00.000Z" } ], "pagination": { "page": 1, "limit": 10, "total": 45, "totalPages": 5 } } }
Tạo đánh giá mới cho sản phẩm.
-
Headers:
Authorization:Bearer your_jwt_token
-
Tham số (Body):
productId(ObjectId, Bắt buộc): ID sản phẩm.rating(Number, Bắt buộc): Điểm đánh giá (1-5).comment(String): Bình luận.
-
Kết quả thành công (201):
{ "status": "success", "data": { "review": { "_id": "reviewId", "rating": 5, "comment": "Rất hay!", "userId": "userId", "productId": "productId" } } }
Xóa một đánh giá (phải là chủ sở hữu hoặc admin).
-
Headers:
Authorization:Bearer your_jwt_token
-
Kết quả thành công (200):
{ "status": "success", "message": "Đã xóa review thành công", "data": { "review": { ... } } }
Tất cả các API trong mục này yêu cầu đăng nhập.
Lấy giỏ hàng của người dùng hiện tại.
-
Headers:
Authorization:Bearer your_jwt_token
-
Kết quả thành công (200):
{ "status": "success", "data": { "cart": [ { "product": { "_id": "productId", "name": "Harry Potter", "price": 150000, "coverImageUrl": "...", "inStock": 50 }, "quantity": 2, "_id": "cartItemId" } ] } }
Thêm sản phẩm vào giỏ hàng.
-
Headers:
Authorization:Bearer your_jwt_token
-
Tham số (Body):
productId(ObjectId, Bắt buộc): ID sản phẩm.quantity(Number, Mặc định: 1): Số lượng.
-
Kết quả thành công (200):
{ "status": "success", "message": "Sản phẩm đã được thêm vào giỏ hàng.", "data": { "cart": [ ... ] } } -
Lỗi (400):
{ "status": "error", "message": "Sản phẩm không đủ số lượng trong kho." }
Cập nhật số lượng sản phẩm trong giỏ hàng.
-
Headers:
Authorization:Bearer your_jwt_token
-
Tham số (URL):
productId(ObjectId, Bắt buộc)
-
Tham số (Body):
quantity(Number, Bắt buộc): Số lượng mới (>= 1).
-
Kết quả thành công (200):
{ "status": "success", "message": "Giỏ hàng đã được cập nhật.", "data": { "cart": [ ... ] } }
Xóa sản phẩm khỏi giỏ hàng.
-
Headers:
Authorization:Bearer your_jwt_token
-
Kết quả thành công (200):
{ "status": "success", "message": "Sản phẩm đã được xóa khỏi giỏ hàng.", "data": { "cart": [ ... ] } }
Tất cả các API trong mục này yêu cầu đăng nhập.
Tạo đơn hàng từ giỏ hàng hiện tại.
-
Headers:
Authorization:Bearer your_jwt_token
-
Tham số (Body):
shippingAddress(Object, Bắt buộc):fullName(String, Bắt buộc)address(String, Bắt buộc)city(String, Bắt buộc)postalCode(String, Bắt buộc)country(String, Bắt buộc)phone(String, Bắt buộc)
paymentMethod(String, Bắt buộc):"COD"hoặc"Card"
-
Kết quả thành công (201):
{ "status": "success", "data": { "order": { "_id": "orderId", "user": "userId", "items": [ { "product": "productId", "name": "Harry Potter", "quantity": 2, "price": 150000 } ], "totalAmount": 300000, "shippingAddress": { ... }, "paymentMethod": "COD", "paymentStatus": "pending", "status": "pending", "createdAt": "2025-12-07T00:00:00.000Z" } } } -
Lỗi (400):
{ "status": "error", "message": "Giỏ hàng của bạn đang trống." }hoặc
{ "status": "error", "message": "Sản phẩm \"Harry Potter\" không đủ hàng." }
- **Headers:**
- `Authorization`: `Bearer your_jwt_token`
- **Tham số (Body):**
- `shippingAddress` (Object, Bắt buộc):
- `paymentMethod` (String, Bắt buộc): `"COD"` hoặc `"Card"`
- `item` (Object, bắt buộc):
VD: {
"shippingAddress": "Số 1 Đại Cồ Việt, Hà Nội",
"paymentMethod": "COD",
"items": [
{ "product": "69394302990b2958fe87145a", "quantity": 4 }
]
}
- **Kết Quả:**
```json
{
"status": "success",
"data": {
"order": {
"user": "692c552f5946a5d346011abe",
"items": [
{
"product": "69394302990b2958fe87145a",
"name": "Cà Phê Cùng Tony",
"quantity": 4,
"price": 89000,
"_id": "69442faef69e6c554fcdca33"
}
],
"totalAmount": 356000,
"shippingAddress": "Số 1 Đại Cồ Việt, Hà Nội",
"paymentMethod": "COD",
"paymentStatus": "pending",
"transactionCode": null,
"status": "pending",
"_id": "69442faef69e6c554fcdca32",
"createdAt": "2025-12-18T16:45:34.542Z",
"updatedAt": "2025-12-18T16:45:34.542Z",
"__v": 0
}
}
}
Lấy danh sách đơn hàng của người dùng hiện tại.
-
Headers:
Authorization:Bearer your_jwt_token
-
Kết quả thành công (200):
{ "status": "success", "results": 5, "data": { "orders": [ { "_id": "orderId", "items": [ ... ], "totalAmount": 300000, "status": "delivered", "paymentStatus": "paid", "createdAt": "2025-12-01T00:00:00.000Z" } ] } }
Lấy chi tiết một đơn hàng (phải là chủ đơn hàng hoặc admin).
-
Headers:
Authorization:Bearer your_jwt_token
-
Kết quả thành công (200):
{ "status": "success", "data": { "order": { "_id": "orderId", "user": { "_id": "userId", "name": "Nguyen Van A", "email": "user@example.com" }, "items": [ ... ], "totalAmount": 300000, "shippingAddress": { ... }, "paymentMethod": "COD", "paymentStatus": "pending", "status": "processing", "createdAt": "2025-12-07T00:00:00.000Z", "updatedAt": "2025-12-07T01:00:00.000Z" } } }
Lấy tất cả đơn hàng (admin only).
-
Headers:
Authorization:Bearer your_admin_jwt_token
-
Kết quả thành công (200):
{ "status": "success", "results": 100, "data": { "orders": [ ... ] } }
Cập nhật trạng thái đơn hàng (admin only).
-
Headers:
Authorization:Bearer your_admin_jwt_token
-
Tham số (Body):
status(String, Bắt buộc):"pending","processing","shipped","delivered", hoặc"cancelled"
-
Kết quả thành công (200):
{ "status": "success", "data": { "order": { ... } } }
Lấy danh sách sản phẩm.
-
Tham số (Query):
page(Number, Tùy chọn, Mặc định: 1): Số trang.limit(Number, Tùy chọn, Mặc định: 10): Số lượng sản phẩm mỗi trang.
-
Kết quả thành công (200):
- Trả về một mảng các sản phẩm.
[ { "_id": "productId", "name": "Tên sản phẩm", "price": 100000, "discount": 10, "description": "Mô tả sản phẩm", "categoryId": "categoryId", "authors": ["authorId1", "authorId2"], "rating": 4.5, "inStock": 100 } ]
Tạo một sản phẩm mới (Yêu cầu quyền admin).
-
Tham số (Body):
name(String, Bắt buộc)price(Number, Bắt buộc)description(String)categoryId(ObjectId, Bắt buộc)authors(Array of ObjectId)inStock(Number)- ... (và các trường khác trong
product.model.js)
-
Kết quả thành công (201):
- Trả về đối tượng sản phẩm vừa tạo.
Lấy thông tin chi tiết một sản phẩm.
-
Tham số (URL):
id(ObjectId, Bắt buộc): ID của sản phẩm.
-
Kết quả thành công (200):
- Trả về đối tượng sản phẩm.
Cập nhật thông tin sản phẩm (Yêu cầu quyền admin).
-
Tham số (URL):
id(ObjectId, Bắt buộc): ID của sản phẩm.
-
Tham số (Body):
- Các trường thông tin sản phẩm cần cập nhật.
-
Kết quả thành công (200):
- Trả về đối tượng sản phẩm đã được cập nhật.
Xóa một sản phẩm (Yêu cầu quyền admin).
-
Tham số (URL):
id(ObjectId, Bắt buộc): ID của sản phẩm.
-
Kết quả thành công (200):
- Trả về đối tượng sản phẩm đã bị xóa.
Lưu ý: Tất cả các routes admin yêu cầu đăng nhập và có role admin.
-
GET /api/author: Lấy danh sách tác giả. -
POST /api/author: Tạo tác giả mới. -
GET /api/author/:id: Lấy chi tiết tác giả. -
PUT /api/author/:id: Cập nhật tác giả. -
DELETE /api/author/:id: Xóa tác giả. -
Đối tượng Author:
{ "_id": "authorId", "name": "Tên tác giả", "biography": "Tiểu sử", "nationality": "Quốc tịch", "books": ["productId1", "productId2"] }
Tương tự như Products, bao gồm các API:
-
GET /api/category: Lấy danh sách danh mục. -
POST /api/category: Tạo danh mục mới. -
GET /api/category/:id: Lấy chi tiết danh mục. -
PUT /api/category/:id: Cập nhật danh mục. -
DELETE /api/category/:id: Xóa danh mục. -
Đối tượng Category:
{ "_id": "categoryId", "name": "Tên danh mục", "slug": "ten-danh-muc", "description": "Mô tả danh mục", "parentCategory": "parentCategoryId" }
Tạo một đánh giá mới cho sản phẩm (Yêu cầu đăng nhập).
-
Header:
Authorization:Bearer your_jwt_token
-
Tham số (Body):
productId(ObjectId, Bắt buộc): ID sản phẩm được đánh giá.rating(Number, Bắt buộc): Điểm đánh giá (1-5).comment(String): Bình luận.
-
Kết quả thành công (201):
- Trả về đối tượng review vừa tạo.
{ "_id": "reviewId", "rating": 5, "comment": "Sản phẩm rất tốt!", "userId": "userId", "productId": "productId" }
Lấy tất cả đánh giá của một sản phẩm.
-
Tham số (URL):
productId(ObjectId, Bắt buộc): ID của sản phẩm.
-
Tham số (Query):
page,limit
-
Kết quả thành công (200):
- Trả về một mảng các đánh giá.
Xóa một đánh giá (Yêu cầu đăng nhập và là chủ sở hữu review hoặc admin).
-
Header:
Authorization:Bearer your_jwt_token
-
Tham số (URL):
id(ObjectId, Bắt buộc): ID của review.
-
Kết quả thành công (200):
- Trả về đối tượng review đã bị xóa.
Tất cả các API trong mục này đều yêu cầu đăng nhập (Authorization: Bearer your_jwt_token).
Lấy thông tin giỏ hàng của người dùng hiện tại.
- Kết quả thành công (200):
{ "status": "success", "data": { "cart": [ { "product": { "_id": "productId", "name": "Tên sản phẩm", "price": 100000, "images": ["url1", "url2"], "stock": 50 }, "quantity": 2, "_id": "cartItemId" } ] } }
Thêm sản phẩm vào giỏ hàng.
-
Tham số (Body):
productId(ObjectId, Bắt buộc): ID sản phẩm.quantity(Number, Tùy chọn, Mặc định: 1): Số lượng.
-
Kết quả thành công (200):
- Trả về giỏ hàng đã được cập nhật.
Cập nhật số lượng của một sản phẩm trong giỏ hàng.
-
Tham số (URL):
productId(ObjectId, Bắt buộc): ID sản phẩm trong giỏ hàng.
-
Tham số (Body):
quantity(Number, Bắt buộc): Số lượng mới (phải >= 1).
-
Kết quả thành công (200):
- Trả về giỏ hàng đã được cập nhật.
Xóa một sản phẩm khỏi giỏ hàng.
-
Tham số (URL):
productId(ObjectId, Bắt buộc): ID sản phẩm cần xóa.
-
Kết quả thành công (200):
- Trả về giỏ hàng đã được cập nhật.
Xóa toàn bộ giỏ hàng.
-
Yêu cầu: Đăng nhập (protect middleware)
-
Kết quả thành công (200):
{ "status": "success", "message": "Giỏ hàng đã được xóa.", "data": { "cart": { "_id": "cartId", "user": "userId", "items": [], "totalItems": 0, "totalPrice": 0 } } }
Tất cả các API trong mục này yêu cầu đăng nhập.
Tính năng thanh toán hỗ trợ ba phương thức:
- COD (Cash on Delivery - Thanh toán khi nhận hàng)
- VietQR (Chuyển khoản ngân hàng qua mã QR)
- ETH (Thanh toán bằng Ethereum blockchain)
- Khách hàng tạo đơn hàng (
POST /api/orders) với một trong ba phương thức thanh toán - Hệ thống tự động khởi tạo bản ghi thanh toán với trạng thái
Pending - Tuỳ theo phương thức thanh toán:
- COD: Khách hàng xác nhận đã sẵn sàng khi nhận hàng
- VietQR: Khách hàng quét mã QR và chuyển khoản, gửi mã giao dịch
- ETH: Khách hàng kết nối ví crypto và gửi transaction hash
- Khách hàng gọi API
POST /api/payment/confirmđể xác nhận thanh toán - Hệ thống cập nhật trạng thái thanh toán thành
Completedvà đơn hàng thànhProcessing
Xác nhận thanh toán cho đơn hàng.
-
Headers:
Authorization:Bearer your_jwt_token
-
Tham số (Body):
orderId(String, Bắt buộc): ID của đơn hàng cần thanh toántransactionCode(String, Bắt buộc): Mã xác nhận thanh toán tùy theo phương thức:- COD: Mã xác nhận hoặc để trống (VD: "COD_001" hoặc "confirmed")
- VietQR: Mã giao dịch ngân hàng (VD: "123456789ABC")
- ETH: Transaction hash từ blockchain (VD: "0x1234567890abcdef...")
-
Ví dụ request:
COD:
{ "orderId": "69442faef69e6c554fcdca32", "transactionCode": "confirmed" }VietQR:
{ "orderId": "69442faef69e6c554fcdca32", "transactionCode": "VIET_QR_20251219_12345" }ETH:
{ "orderId": "69442faef69e6c554fcdca32", "transactionCode": "0x1f3c4d5e6f7a8b9c0d1e2f3a4b5c6d7e8f9a0b1c2d3e4f5a6b7c8d9e0f1a2b" } -
Kết quả thành công (200):
{ "status": "success", "data": { "payment": { "_id": "paymentId", "order": "69442faef69e6c554fcdca32", "user": "692c552f5946a5d346011abe", "amount": 356000, "method": "COD", "status": "Completed", "transactionCode": "confirmed", "paymentDate": "2025-12-19T10:30:45.000Z", "createdAt": "2025-12-18T16:45:34.542Z", "updatedAt": "2025-12-19T10:30:45.123Z" } } }Sau khi xác nhận thanh toán:
- Trạng thái thanh toán:
Completed - Trạng thái đơn hàng:
Processing(Đang xử lý) paymentDateđược cập nhật thời gian xác nhận
- Trạng thái thanh toán:
-
Lỗi (404):
{ "status": "error", "message": "Không tìm thấy thông tin thanh toán cho đơn hàng này." }
Lấy thông tin chi tiết thanh toán của một đơn hàng.
-
Headers:
Authorization:Bearer your_jwt_token
-
Tham số (URL):
orderId(String, Bắt buộc): ID của đơn hàng
-
Kết quả thành công (200):
{ "status": "success", "data": { "payment": { "_id": "paymentId", "order": "69442faef69e6c554fcdca32", "user": "692c552f5946a5d346011abe", "amount": 356000, "method": "COD", "status": "Pending", "transactionCode": null, "paymentDate": "2025-12-18T16:45:34.542Z", "createdAt": "2025-12-18T16:45:34.542Z", "updatedAt": "2025-12-18T16:45:34.542Z" } } } -
Lỗi (404):
{ "status": "error", "message": "Không tìm thấy thông tin thanh toán cho đơn hàng này." }
| Trạng thái | Mô tả |
|---|---|
Pending |
Đơn hàng vừa được tạo, chờ khách hàng thanh toán |
Completed |
Thanh toán đã hoàn tất thành công |
Failed |
Thanh toán thất bại |
Refunded |
Đã hoàn tiền cho khách hàng |
Quy trình:
- Khách hàng chọn phương thức thanh toán là "COD" khi tạo đơn hàng
- Đơn hàng được tạo với trạng thái
paymentStatus: 'pending' - Khách hàng gọi API
POST /api/payment/confirmvớitransactionCodebất kỳ (VD: "confirmed") - Thanh toán được đánh dấu là
Completed - Nhân viên giao hàng sẽ thu tiền trực tiếp từ khách hàng
Ví dụ:
# Tạo đơn hàng với COD
POST /api/orders
{
"shippingAddress": "Số 1 Đại Cồ Việt, Hà Nội",
"paymentMethod": "COD",
"items": [
{ "product": "productId", "quantity": 2 }
]
}
# Xác nhận thanh toán COD
POST /api/payment/confirm
{
"orderId": "orderId_từ_bước_trên",
"transactionCode": "confirmed"
}Quy trình:
- Khách hàng chọn phương thức thanh toán là "ETH" khi tạo đơn hàng
- Frontend kết nối với ví Ethereum của khách hàng (MetaMask, v.v.)
- Smart contract thanh toán được gọi để thực hiện giao dịch
- Khách hàng ký xác nhận giao dịch trong ví
- Sau khi giao dịch được đưa lên blockchain, nhận được transaction hash
- Khách hàng gọi API
POST /api/payment/confirmvà gửi transaction hash - Hệ thống cập nhật trạng thái thanh toán thành
Completed
Ví dụ:
# Tạo đơn hàng với ETH
POST /api/orders
{
"shippingAddress": "Số 1 Đại Cồ Việt, Hà Nội",
"paymentMethod": "ETH",
"items": [
{ "product": "productId", "quantity": 3 }
]
}
# Xác nhận thanh toán ETH (sau khi giao dịch thành công trên blockchain)
POST /api/payment/confirm
{
"orderId": "orderId_từ_bước_trên",
"transactionCode": "0x1f3c4d5e6f7a8b9c0d1e2f3a4b5c6d7e8f9a0b1c2d3e4f5a6b7c8d9e0f1a2b"
}Lưu ý:
- Transaction hash bắt đầu với
0xvà có độ dài 66 ký tự (66 = 2 + 64) - Khách hàng có thể kiểm tra giao dịch tại: https://etherscan.io/tx/[transaction_hash] (cho Mainnet) hoặc explorer blockchain tương ứng
- Smart contract được triển khai tại địa chỉ blockchain được cấu hình trong hệ thống
- Phí gas sẽ được trừ từ ví của khách hàng
Kiểm tra trạng thái giao dịch:
- Truy cập vào blockchain explorer
- Tìm kiếm transaction hash
- Xem trạng thái:
Pending,Success, hoặcFailed
Lưu ý: Tất cả các routes admin yêu cầu đăng nhập và có role admin.
Lấy thống kê tổng quan cho dashboard admin.
-
Yêu cầu: Admin role
-
Kết quả thành công (200):
{ "status": "success", "data": { "stats": { "revenue": { "total": 50000000, "today": 2500000, "thisMonth": 15000000, "thisYear": 45000000 }, "orders": { "total": 150, "today": 5, "thisMonth": 45, "byStatus": { "pending": 10, "processing": 15, "shipped": 20, "delivered": 100, "cancelled": 5 } }, "customers": { "total": 250, "newToday": 3, "newThisMonth": 25 }, "products": { "total": 100, "lowStock": 8, "outOfStock": 2 } } } }
Lấy thống kê doanh thu theo khoảng thời gian.
-
Yêu cầu: Admin role
-
Query Parameters:
period(String, Mặc định: 'month'): Khoảng thời gian - 'week', 'month', 'year'year(Number, Tùy chọn): Năm cụ thể (mặc định: năm hiện tại)month(Number, Tùy chọn): Tháng cụ thể (1-12, chỉ dùng khi period='month')
-
Ví dụ:
GET /api/admin/revenue?period=month&year=2024&month=12GET /api/admin/revenue?period=year&year=2024GET /api/admin/revenue?period=week
-
Kết quả thành công (200):
{ "status": "success", "data": { "stats": { "period": "month", "year": 2024, "month": 12, "data": [ { "period": 1, "revenue": 1200000, "orders": 5 }, { "period": 2, "revenue": 1500000, "orders": 7 } ] } } }
Lấy báo cáo tồn kho chi tiết.
-
Yêu cầu: Admin role
-
Kết quả thành công (200):
{ "status": "success", "data": { "report": { "totalInventoryValue": 125000000, "stockLevels": [ { "_id": 0, "count": 2, "products": [] }, { "_id": 1, "count": 5, "products": [] } ], "lowStockProducts": [ { "_id": "productId", "name": "Sản phẩm A", "inStock": 5, "price": 100000, "categoryId": { "_id": "categoryId", "name": "Category Name" } } ], "outOfStockProducts": [ { "_id": "productId", "name": "Sản phẩm B", "sold": 150, "price": 200000, "categoryId": { "_id": "categoryId", "name": "Category Name" } } ], "productsByCategory": [ { "_id": "categoryId", "categoryName": "Tiểu thuyết", "count": 25, "totalStock": 500 } ] } } }
Lấy danh sách sản phẩm bán chạy nhất.
-
Yêu cầu: Admin role
-
Query Parameters:
limit(Number, Mặc định: 10): Số lượng sản phẩm trả vềperiod(String, Mặc định: 'all'): Khoảng thời gian - 'all', 'month', 'year'
-
Ví dụ:
GET /api/admin/best-selling?limit=20&period=monthGET /api/admin/best-selling?period=year
-
Kết quả thành công (200):
{ "status": "success", "results": 10, "data": { "products": [ { "_id": "productId", "productId": "productId", "name": "Đắc Nhân Tâm", "coverImageUrl": "url", "price": 120000, "inStock": 300, "totalSold": 8900, "totalRevenue": 1068000000, "orderCount": 3500 } ] } }
Lấy thống kê doanh thu theo danh mục sản phẩm.
-
Yêu cầu: Admin role
-
Query Parameters:
period(String, Mặc định: 'all'): Khoảng thời gian - 'all', 'month', 'year'
-
Ví dụ:
GET /api/admin/sales-by-category?period=month
-
Kết quả thành công (200):
{ "status": "success", "results": 5, "data": { "sales": [ { "_id": "categoryId", "categoryId": "categoryId", "categoryName": "Kỹ năng sống", "totalRevenue": 25000000, "totalSold": 350, "orderCount": 180 } ] } }
Lấy thống kê khách hàng.
-
Yêu cầu: Admin role
-
Kết quả thành công (200):
{ "status": "success", "data": { "stats": { "topCustomers": [ { "_id": "userId", "userId": "userId", "name": "Nguyễn Văn A", "email": "user@example.com", "totalSpent": 5000000, "orderCount": 15 } ], "customerGrowth": [ { "_id": 1, "count": 25 }, { "_id": 2, "count": 30 } ] } } }