546 lines
22 KiB
Dart
546 lines
22 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
|
|
// ============================================================================
|
|
|
|
/// Create new project
|
|
/// POST /projects
|
|
static const String createProject = '/projects';
|
|
|
|
/// Get user's projects
|
|
/// GET /projects?status={status}&page={page}&limit={limit}
|
|
static const String getProjects = '/projects';
|
|
|
|
/// Get project details by ID
|
|
/// GET /projects/{projectId}
|
|
static const String getProjectDetails = '/projects';
|
|
|
|
/// Update project
|
|
/// PUT /projects/{projectId}
|
|
static const String updateProject = '/projects';
|
|
|
|
/// Update project progress
|
|
/// PATCH /projects/{projectId}/progress
|
|
/// Body: { "progress": 75 }
|
|
static const String updateProjectProgress = '/projects';
|
|
|
|
/// Delete project
|
|
/// 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';
|
|
}
|
|
}
|