Files
worker/lib/core/constants/api_constants.dart
Phuoc Nguyen 6e7e848ad6 submission
2025-11-27 17:58:13 +07:00

586 lines
24 KiB
Dart

/// API-related constants for the Worker app
///
/// This file contains all API endpoints, timeouts, and network-related configurations.
/// Base URLs should be configured per environment (dev, staging, production).
class ApiConstants {
// Private constructor to prevent instantiation
ApiConstants._();
// ============================================================================
// Base URLs
// ============================================================================
/// Base URL for all APIs (Frappe/ERPNext)
static const String baseUrl = 'https://land.dbiz.com';
/// Full API base URL (no version prefix, using Frappe endpoints)
static String get apiBaseUrl => baseUrl;
// ============================================================================
// Timeout Configurations
// ============================================================================
/// Connection timeout in milliseconds (30 seconds)
static const Duration connectionTimeout = Duration(milliseconds: 30000);
/// Receive timeout in milliseconds (30 seconds)
static const Duration receiveTimeout = Duration(milliseconds: 30000);
/// Send timeout in milliseconds (30 seconds)
static const Duration sendTimeout = Duration(milliseconds: 30000);
// ============================================================================
// Retry Configurations
// ============================================================================
/// Maximum number of retry attempts for failed requests
static const int maxRetryAttempts = 3;
/// Initial retry delay in milliseconds
static const Duration initialRetryDelay = Duration(milliseconds: 1000);
/// Maximum retry delay in milliseconds
static const Duration maxRetryDelay = Duration(milliseconds: 5000);
/// Retry delay multiplier for exponential backoff
static const double retryDelayMultiplier = 2.0;
// ============================================================================
// Cache Configurations
// ============================================================================
/// Default cache duration (1 hour)
static const Duration defaultCacheDuration = Duration(hours: 1);
/// Products cache duration (24 hours)
static const Duration productsCacheDuration = Duration(hours: 24);
/// Profile cache duration (1 hour)
static const Duration profileCacheDuration = Duration(hours: 1);
/// Categories cache duration (48 hours)
static const Duration categoriesCacheDuration = Duration(hours: 48);
/// Maximum cache size in bytes (50 MB)
static const int maxCacheSize = 50 * 1024 * 1024;
// ============================================================================
// Request Headers
// ============================================================================
/// Content-Type header for JSON requests
static const String contentTypeJson = 'application/json';
/// Accept header for JSON responses
static const String acceptJson = 'application/json';
/// Accept-Language header for Vietnamese
static const String acceptLanguageVi = 'vi';
/// Accept-Language header for English
static const String acceptLanguageEn = 'en';
// ============================================================================
// Authentication Endpoints
// ============================================================================
/// Request OTP for phone number login
/// POST /auth/request-otp
/// Body: { "phone": "+84912345678" }
static const String requestOtp = '/auth/request-otp';
/// Verify OTP code
/// POST /auth/verify-otp
/// Body: { "phone": "+84912345678", "otp": "123456" }
static const String verifyOtp = '/auth/verify-otp';
/// Register new user
/// POST /auth/register
/// Body: { "name": "...", "phone": "...", "email": "...", "userType": "..." }
static const String register = '/auth/register';
/// Refresh access token
/// POST /auth/refresh-token
/// Headers: { "Authorization": "Bearer {refreshToken}" }
static const String refreshToken = '/auth/refresh-token';
/// Logout user
/// POST /auth/logout
static const String logout = '/auth/logout';
/// Get current user profile
/// GET /auth/me
static const String getCurrentUser = '/auth/me';
// ============================================================================
// Loyalty Program Endpoints
// ============================================================================
/// Get loyalty points and tier information
/// GET /loyalty/points
static const String getLoyaltyPoints = '/loyalty/points';
/// Get loyalty points transaction history
/// GET /loyalty/transactions?page={page}&limit={limit}
static const String getPointsHistory = '/loyalty/transactions';
/// Get available rewards for redemption
/// GET /loyalty/rewards?category={category}
static const String getRewards = '/loyalty/rewards';
/// Redeem a reward
/// POST /loyalty/rewards/{rewardId}/redeem
static const String redeemReward = '/loyalty/rewards';
/// Get user's redeemed gifts
/// GET /loyalty/gifts?status={active|used|expired}
static const String getGifts = '/loyalty/gifts';
/// Get referral information
/// GET /loyalty/referral
static const String getReferralInfo = '/loyalty/referral';
/// Share referral link
/// POST /loyalty/referral/share
/// Body: { "method": "whatsapp|telegram|sms" }
static const String shareReferral = '/loyalty/referral/share';
// ============================================================================
// Favorites/Wishlist Endpoints (Frappe ERPNext)
// ============================================================================
/// Get favorite/wishlist items for current user
/// POST /api/method/building_material.building_material.api.item_wishlist.get_list
/// Body: { "limit_start": 0, "limit_page_length": 0 }
static const String getFavorites = '/building_material.building_material.api.item_wishlist.get_list';
/// Add item to wishlist
/// POST /api/method/building_material.building_material.api.item_wishlist.add_to_wishlist
/// Body: { "item_id": "GIB20 G04" }
static const String addToFavorites = '/building_material.building_material.api.item_wishlist.add_to_wishlist';
/// Remove item from wishlist
/// POST /api/method/building_material.building_material.api.item_wishlist.remove_from_wishlist
/// Body: { "item_id": "GIB20 G04" }
static const String removeFromFavorites = '/building_material.building_material.api.item_wishlist.remove_from_wishlist';
// ============================================================================
// Product Endpoints
// ============================================================================
/// Get all products with pagination
/// GET /products?page={page}&limit={limit}&category={categoryId}
static const String getProducts = '/products';
/// Get product details by ID
/// GET /products/{productId}
static const String getProductDetails = '/products';
/// Search products
/// GET /products/search?q={query}&page={page}&limit={limit}
static const String searchProducts = '/products/search';
/// Get product categories
/// GET /categories
static const String getCategories = '/categories';
/// Get products by category
/// GET /categories/{categoryId}/products
static const String getProductsByCategory = '/categories';
// ============================================================================
// Cart Endpoints (Frappe ERPNext)
// ============================================================================
/// Add items to cart
/// POST /api/method/building_material.building_material.api.user_cart.add_to_cart
/// Body: { "items": [{ "item_id": "...", "amount": 0, "quantity": 0 }] }
static const String addToCart = '/building_material.building_material.api.user_cart.add_to_cart';
/// Remove items from cart
/// POST /api/method/building_material.building_material.api.user_cart.remove_from_cart
/// Body: { "item_ids": ["item_id1", "item_id2"] }
static const String removeFromCart = '/building_material.building_material.api.user_cart.remove_from_cart';
/// Get user's cart items
/// POST /api/method/building_material.building_material.api.user_cart.get_user_cart
/// Body: { "limit_start": 0, "limit_page_length": 0 }
static const String getUserCart = '/building_material.building_material.api.user_cart.get_user_cart';
// ============================================================================
// Order Endpoints
// ============================================================================
/// Get order status list (requires sid and csrf_token)
/// POST /api/method/building_material.building_material.api.sales_order.get_order_status_list
/// Returns: { "message": [{ "status": "...", "label": "...", "color": "...", "index": 0 }] }
static const String getOrderStatusList = '/building_material.building_material.api.sales_order.get_order_status_list';
/// Create new order (requires sid and csrf_token)
/// POST /api/method/building_material.building_material.api.sales_order.save
/// Body: { "transaction_date": "...", "delivery_date": "...", "items": [...], ... }
static const String createOrder = '/building_material.building_material.api.sales_order.save';
/// Generate QR code for payment (requires sid and csrf_token)
/// POST /api/method/building_material.building_material.api.v1.qrcode.generate
/// Body: { "order_id": "SAL-ORD-2025-00048" }
/// Returns: { "message": { "qr_code": "...", "amount": null, "transaction_id": "...", "bank_info": {...} } }
static const String generateQrCode = '/building_material.building_material.api.v1.qrcode.generate';
/// Upload file (bill/invoice/attachment) (requires sid and csrf_token)
/// POST /api/method/upload_file
/// Form-data: { "file": File, "is_private": "1", "folder": "Home/Attachments", "doctype": "Sales Order", "docname": "SAL-ORD-2025-00058-1", "optimize": "true" }
/// Returns: { "message": { "file_url": "...", "file_name": "...", ... } }
static const String uploadFile = '/upload_file';
/// Get list of orders (requires sid and csrf_token)
/// POST /api/method/building_material.building_material.api.sales_order.get_list
/// Body: { "limit_start": 0, "limit_page_length": 0 }
/// Returns: { "message": [...] }
static const String getOrdersList = '/building_material.building_material.api.sales_order.get_list';
/// Get order details (requires sid and csrf_token)
/// POST /api/method/building_material.building_material.api.sales_order.get_detail
/// Body: { "name": "SAL-ORD-2025-00058-1" }
/// Returns: { "message": {...} }
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 /orders?status={status}&page={page}&limit={limit}
static const String getOrders = '/orders';
/// Get order details by ID
/// GET /orders/{orderId}
static const String getOrderDetails = '/orders';
/// Get payment transactions
/// GET /payments?page={page}&limit={limit}
static const String getPayments = '/payments';
/// Get payment details
/// GET /payments/{paymentId}
static const String getPaymentDetails = '/payments';
// ============================================================================
// Project Endpoints (Frappe ERPNext)
// ============================================================================
/// Get project status list (requires sid and csrf_token)
/// POST /api/method/building_material.building_material.api.project.get_project_status_list
/// Body: { "limit_start": 0, "limit_page_length": 0 }
/// Returns: { "message": [{ "status": "...", "label": "...", "color": "...", "index": 0 }] }
static const String getProjectStatusList =
'/building_material.building_material.api.project.get_project_status_list';
/// Get list of project submissions (requires sid and csrf_token)
/// POST /api/method/building_material.building_material.api.project.get_list
/// Body: { "limit_start": 0, "limit_page_length": 0 }
/// Returns: { "message": [{ "name": "...", "designed_area": "...", "design_area": 0, ... }] }
static const String getProjectList =
'/building_material.building_material.api.project.get_list';
/// Save (create/update) project submission
/// POST /api/method/building_material.building_material.api.project.save
/// Body: {
/// "name": "...", // optional for new, required for update
/// "designed_area": "Project Name",
/// "address_of_project": "...",
/// "project_owner": "...",
/// "design_firm": "...",
/// "contruction_contractor": "...",
/// "design_area": 350.5,
/// "products_included_in_the_design": "...",
/// "project_progress": "progress_id", // from ProjectProgress.id
/// "expected_commencement_date": "2026-01-15",
/// "description": "...",
/// "request_date": "2025-11-26 09:30:00"
/// }
static const String saveProject =
'/building_material.building_material.api.project.save';
/// Get project detail (requires sid and csrf_token)
/// POST /api/method/building_material.building_material.api.project.get_detail
/// Body: { "name": "#DA00011" }
/// Returns: Full project detail with all fields
static const String getProjectDetail =
'/building_material.building_material.api.project.get_detail';
/// Create new project (legacy endpoint - may be deprecated)
/// POST /projects
static const String createProject = '/projects';
/// Get user's projects (legacy endpoint - may be deprecated)
/// GET /projects?status={status}&page={page}&limit={limit}
static const String getProjects = '/projects';
/// Get project details by ID (legacy endpoint - may be deprecated)
/// GET /projects/{projectId}
static const String getProjectDetails = '/projects';
/// Update project (legacy endpoint - may be deprecated)
/// PUT /projects/{projectId}
static const String updateProject = '/projects';
/// Update project progress (legacy endpoint - may be deprecated)
/// PATCH /projects/{projectId}/progress
/// Body: { "progress": 75 }
static const String updateProjectProgress = '/projects';
/// Delete project (legacy endpoint - may be deprecated)
/// DELETE /projects/{projectId}
static const String deleteProject = '/projects';
// ============================================================================
// Quote Endpoints
// ============================================================================
/// Create new quote
/// POST /quotes
static const String createQuote = '/quotes';
/// Get user's quotes
/// GET /quotes?status={status}&page={page}&limit={limit}
static const String getQuotes = '/quotes';
/// Get quote details by ID
/// GET /quotes/{quoteId}
static const String getQuoteDetails = '/quotes';
/// Update quote
/// PUT /quotes/{quoteId}
static const String updateQuote = '/quotes';
/// Send quote to client
/// POST /quotes/{quoteId}/send
/// Body: { "email": "client@example.com" }
static const String sendQuote = '/quotes';
/// Convert quote to order
/// POST /quotes/{quoteId}/convert
static const String convertQuoteToOrder = '/quotes';
// ============================================================================
// Chat Endpoints
// ============================================================================
/// WebSocket endpoint for real-time chat
static const String chatWebSocket = '/ws/chat';
/// Get chat messages
/// GET /chat/messages?roomId={roomId}&before={messageId}&limit={limit}
static const String getChatMessages = '/chat/messages';
/// Send chat message
/// POST /chat/messages
/// Body: { "roomId": "...", "text": "...", "attachments": [...] }
static const String sendChatMessage = '/chat/messages';
/// Mark messages as read
/// POST /chat/messages/read
/// Body: { "messageIds": [...] }
static const String markMessagesAsRead = '/chat/messages/read';
// ============================================================================
// Account & Profile Endpoints
// ============================================================================
/// Get user profile
/// GET /profile
static const String getProfile = '/profile';
/// Update user profile
/// PUT /profile
static const String updateProfile = '/profile';
/// Upload avatar
/// POST /profile/avatar
/// Form-data: { "avatar": File }
static const String uploadAvatar = '/profile/avatar';
/// Change password
/// POST /profile/change-password
/// Body: { "currentPassword": "...", "newPassword": "..." }
static const String changePassword = '/profile/change-password';
/// Get user addresses
/// GET /addresses
static const String getAddresses = '/addresses';
/// Add new address
/// POST /addresses
static const String addAddress = '/addresses';
/// Update address
/// PUT /addresses/{addressId}
static const String updateAddress = '/addresses';
/// Delete address
/// DELETE /addresses/{addressId}
static const String deleteAddress = '/addresses';
/// Set default address
/// POST /addresses/{addressId}/set-default
static const String setDefaultAddress = '/addresses';
// ============================================================================
// Promotion Endpoints
// ============================================================================
/// Get active promotions
/// GET /promotions?category={category}
static const String getPromotions = '/promotions';
/// Get promotion details
/// GET /promotions/{promotionId}
static const String getPromotionDetails = '/promotions';
/// Claim promotion
/// POST /promotions/{promotionId}/claim
static const String claimPromotion = '/promotions';
// ============================================================================
// Frappe/ERPNext API Endpoints
// ============================================================================
/// Frappe API method prefix
static const String frappeApiMethod = '/api/method';
/// Get Frappe session (public API, no auth required)
/// POST /api/method/dbiz_common.dbiz_common.api.auth.get_session
/// Returns: { "message": { "data": { "sid": "...", "csrf_token": "..." } }, "full_name": "..." }
static const String frappeGetSession = '/dbiz_common.dbiz_common.api.auth.get_session';
/// Login with phone (requires session sid and csrf_token)
/// POST /api/method/building_material.building_material.api.auth.login
/// Body: { "username": "phone", "googleid": null, "facebookid": null, "zaloid": null }
/// Returns: { "message": { "data": { "sid": "...", "csrf_token": "..." } }, "full_name": "..." }
static const String frappeLogin = '/building_material.building_material.api.auth.login';
/// Frappe client get_list (requires sid and csrf_token)
/// POST /api/method/frappe.client.get_list
static const String frappeGetList = '/frappe.client.get_list';
/// Frappe client get (requires sid and csrf_token)
/// POST /api/method/frappe.client.get
static const String frappeGet = '/frappe.client.get';
/// Register user (requires session sid and csrf_token)
/// POST /api/method/building_material.building_material.api.user.register
static const String frappeRegister = '/building_material.building_material.api.user.register';
/// Frappe public API user ID
static const String frappePublicUserId = 'public_api@dbiz.com';
// ============================================================================
// Product/Item Endpoints (Frappe ERPNext)
// ============================================================================
/// Get product/item list (requires sid and csrf_token)
/// POST /api/method/building_material.building_material.api.item.get_list
/// Body: { "limit_start": 0, "limit_page_length": 0 }
static const String frappeGetItems = '/building_material.building_material.api.item.get_list';
/// Get product/item detail (requires sid and csrf_token)
/// POST /api/method/building_material.building_material.api.item.get_detail
/// Body: { "name": "item_code" }
static const String frappeGetItemDetail = '/building_material.building_material.api.item.get_detail';
/// Get item attributes list (requires sid and csrf_token)
/// POST /api/method/building_material.building_material.api.item_attribute.get_list
/// Body: { "filters": {"is_group": 0}, "limit_page_length": 0 }
static const String frappeGetItemAttributes = '/building_material.building_material.api.item_attribute.get_list';
// ============================================================================
// Review/Feedback Endpoints (Frappe ERPNext)
// ============================================================================
/// Get list of reviews for a product (requires sid and csrf_token)
/// POST /api/method/building_material.building_material.api.item_feedback.get_list
/// Body: { "limit_page_length": 10, "limit_start": 0, "item_id": "GIB20 G04" }
static const String frappeGetReviews = '/building_material.building_material.api.item_feedback.get_list';
/// Create or update a review (requires sid and csrf_token)
/// POST /api/method/building_material.building_material.api.item_feedback.update
/// Body: { "item_id": "...", "rating": 0.5, "comment": "...", "name": "..." }
/// Note: rating is 0-1 scale (0.5 = 50% or 2.5 stars out of 5)
/// Note: name is optional - if provided, updates existing review
static const String frappeUpdateReview = '/building_material.building_material.api.item_feedback.update';
/// Delete a review (requires sid and csrf_token)
/// POST /api/method/building_material.building_material.api.item_feedback.delete
/// Body: { "name": "ITEM-{item_id}-{user_email}" }
static const String frappeDeleteReview = '/building_material.building_material.api.item_feedback.delete';
// ============================================================================
// Notification Endpoints
// ============================================================================
/// Get notifications
/// GET /notifications?type={type}&page={page}&limit={limit}
static const String getNotifications = '/notifications';
/// Mark notification as read
/// POST /notifications/{notificationId}/read
static const String markNotificationAsRead = '/notifications';
/// Mark all notifications as read
/// POST /notifications/read-all
static const String markAllNotificationsAsRead = '/notifications/read-all';
/// Clear all notifications
/// DELETE /notifications
static const String clearAllNotifications = '/notifications';
/// Register FCM token for push notifications
/// POST /notifications/fcm-token
/// Body: { "token": "..." }
static const String registerFcmToken = '/notifications/fcm-token';
// ============================================================================
// Helper Methods
// ============================================================================
/// Build full URL for endpoint
///
/// Example:
/// ```dart
/// final url = ApiConstants.buildUrl('/api/method/frappe.client.get_list', {'doctype': 'Item'});
/// // Returns: https://land.dbiz.com/api/method/frappe.client.get_list?doctype=Item
/// ```
static String buildUrl(String endpoint, [Map<String, String>? queryParams]) {
final uri = Uri.parse('$apiBaseUrl$endpoint');
if (queryParams != null && queryParams.isNotEmpty) {
return uri.replace(queryParameters: queryParams).toString();
}
return uri.toString();
}
/// Build URL with path parameters
///
/// Example:
/// ```dart
/// final url = ApiConstants.buildUrlWithParams('/api/resource/Item/{id}', {'id': '123'});
/// // Returns: https://land.dbiz.com/api/resource/Item/123
/// ```
static String buildUrlWithParams(
String endpoint,
Map<String, String> params,
) {
String url = endpoint;
params.forEach((key, value) {
url = url.replaceAll('{$key}', value);
});
return '$apiBaseUrl$url';
}
}