Add POS service

This commit is contained in:
Urtzi Alfaro
2025-08-16 15:00:36 +02:00
parent 995a51e285
commit 23c5f50111
34 changed files with 6086 additions and 0 deletions

View File

@@ -0,0 +1,392 @@
// frontend/src/api/services/pos.service.ts
/**
* POS Integration API Service
* Handles all communication with the POS service backend
*/
import { apiClient } from '../client';
// ============================================================================
// TYPES & INTERFACES
// ============================================================================
export interface POSConfiguration {
id: string;
tenant_id: string;
pos_system: 'square' | 'toast' | 'lightspeed';
provider_name: string;
is_active: boolean;
is_connected: boolean;
environment: 'sandbox' | 'production';
location_id?: string;
merchant_id?: string;
sync_enabled: boolean;
sync_interval_minutes: string;
auto_sync_products: boolean;
auto_sync_transactions: boolean;
webhook_url?: string;
last_sync_at?: string;
last_successful_sync_at?: string;
last_sync_status?: 'success' | 'failed' | 'partial';
last_sync_message?: string;
provider_settings?: Record<string, any>;
last_health_check_at?: string;
health_status: 'healthy' | 'unhealthy' | 'warning' | 'unknown';
health_message?: string;
created_at: string;
updated_at: string;
created_by?: string;
notes?: string;
}
export interface CreatePOSConfigurationRequest {
pos_system: 'square' | 'toast' | 'lightspeed';
provider_name: string;
environment: 'sandbox' | 'production';
location_id?: string;
merchant_id?: string;
sync_enabled?: boolean;
sync_interval_minutes?: string;
auto_sync_products?: boolean;
auto_sync_transactions?: boolean;
notes?: string;
// Credentials
api_key?: string;
api_secret?: string;
access_token?: string;
application_id?: string;
webhook_secret?: string;
}
export interface UpdatePOSConfigurationRequest {
provider_name?: string;
is_active?: boolean;
environment?: 'sandbox' | 'production';
location_id?: string;
merchant_id?: string;
sync_enabled?: boolean;
sync_interval_minutes?: string;
auto_sync_products?: boolean;
auto_sync_transactions?: boolean;
notes?: string;
// Credentials (only if updating)
api_key?: string;
api_secret?: string;
access_token?: string;
application_id?: string;
webhook_secret?: string;
}
export interface POSTransaction {
id: string;
tenant_id: string;
pos_config_id: string;
pos_system: string;
external_transaction_id: string;
external_order_id?: string;
transaction_type: 'sale' | 'refund' | 'void' | 'exchange';
status: 'completed' | 'pending' | 'failed' | 'refunded' | 'voided';
subtotal: number;
tax_amount: number;
tip_amount: number;
discount_amount: number;
total_amount: number;
currency: string;
payment_method?: string;
payment_status?: string;
transaction_date: string;
pos_created_at: string;
pos_updated_at?: string;
location_id?: string;
location_name?: string;
staff_id?: string;
staff_name?: string;
customer_id?: string;
customer_email?: string;
customer_phone?: string;
order_type?: string;
table_number?: string;
receipt_number?: string;
is_synced_to_sales: boolean;
sales_record_id?: string;
sync_attempted_at?: string;
sync_completed_at?: string;
sync_error?: string;
sync_retry_count: number;
is_processed: boolean;
processing_error?: string;
is_duplicate: boolean;
duplicate_of?: string;
created_at: string;
updated_at: string;
items: POSTransactionItem[];
}
export interface POSTransactionItem {
id: string;
transaction_id: string;
external_item_id?: string;
sku?: string;
product_name: string;
product_category?: string;
product_subcategory?: string;
quantity: number;
unit_price: number;
total_price: number;
discount_amount: number;
tax_amount: number;
modifiers?: Record<string, any>;
inventory_product_id?: string;
is_mapped_to_inventory: boolean;
is_synced_to_sales: boolean;
sync_error?: string;
}
export interface POSSyncLog {
id: string;
tenant_id: string;
pos_config_id: string;
sync_type: 'full' | 'incremental' | 'manual' | 'webhook_triggered';
sync_direction: 'inbound' | 'outbound' | 'bidirectional';
data_type: 'transactions' | 'products' | 'customers' | 'orders';
pos_system: string;
status: 'started' | 'in_progress' | 'completed' | 'failed' | 'cancelled';
started_at: string;
completed_at?: string;
duration_seconds?: number;
sync_from_date?: string;
sync_to_date?: string;
records_requested: number;
records_processed: number;
records_created: number;
records_updated: number;
records_skipped: number;
records_failed: number;
api_calls_made: number;
error_message?: string;
error_code?: string;
retry_attempt: number;
max_retries: number;
progress_percentage?: number;
revenue_synced?: number;
transactions_synced: number;
triggered_by?: string;
triggered_by_user_id?: string;
created_at: string;
updated_at: string;
}
export interface SyncRequest {
sync_type?: 'full' | 'incremental';
data_types?: ('transactions' | 'products' | 'customers')[];
from_date?: string;
to_date?: string;
}
export interface SyncStatus {
current_sync?: POSSyncLog;
last_successful_sync?: POSSyncLog;
recent_syncs: POSSyncLog[];
sync_health: {
status: 'healthy' | 'unhealthy' | 'warning';
success_rate: number;
average_duration_minutes: number;
last_error?: string;
};
}
export interface SupportedPOSSystem {
id: string;
name: string;
description: string;
features: string[];
supported_regions: string[];
}
export interface POSAnalytics {
period_days: number;
total_syncs: number;
successful_syncs: number;
failed_syncs: number;
success_rate: number;
average_duration_minutes: number;
total_transactions_synced: number;
total_revenue_synced: number;
sync_frequency: {
daily_average: number;
peak_day?: string;
peak_count: number;
};
error_analysis: {
common_errors: Array<{ error: string; count: number }>;
error_trends: Array<{ date: string; count: number }>;
};
}
export interface ConnectionTestResult {
status: 'success' | 'error';
message: string;
tested_at: string;
}
// ============================================================================
// API FUNCTIONS
// ============================================================================
export const posService = {
// Configuration Management
async getConfigurations(tenantId: string, params?: {
pos_system?: string;
is_active?: boolean;
limit?: number;
offset?: number;
}): Promise<{ configurations: POSConfiguration[]; total: number }> {
const response = await apiClient.get(`/pos-service/api/v1/tenants/${tenantId}/pos/configurations`, {
params
});
return response.data;
},
async createConfiguration(tenantId: string, data: CreatePOSConfigurationRequest): Promise<POSConfiguration> {
const response = await apiClient.post(`/pos-service/api/v1/tenants/${tenantId}/pos/configurations`, data);
return response.data;
},
async getConfiguration(tenantId: string, configId: string): Promise<POSConfiguration> {
const response = await apiClient.get(`/pos-service/api/v1/tenants/${tenantId}/pos/configurations/${configId}`);
return response.data;
},
async updateConfiguration(tenantId: string, configId: string, data: UpdatePOSConfigurationRequest): Promise<POSConfiguration> {
const response = await apiClient.put(`/pos-service/api/v1/tenants/${tenantId}/pos/configurations/${configId}`, data);
return response.data;
},
async deleteConfiguration(tenantId: string, configId: string): Promise<void> {
await apiClient.delete(`/pos-service/api/v1/tenants/${tenantId}/pos/configurations/${configId}`);
},
async testConnection(tenantId: string, configId: string): Promise<ConnectionTestResult> {
const response = await apiClient.post(`/pos-service/api/v1/tenants/${tenantId}/pos/configurations/${configId}/test-connection`);
return response.data;
},
// Synchronization
async triggerSync(tenantId: string, configId: string, syncRequest: SyncRequest): Promise<{
message: string;
sync_id: string;
status: string;
sync_type: string;
data_types: string[];
estimated_duration: string;
}> {
const response = await apiClient.post(`/pos-service/api/v1/tenants/${tenantId}/pos/configurations/${configId}/sync`, syncRequest);
return response.data;
},
async getSyncStatus(tenantId: string, configId: string, limit?: number): Promise<SyncStatus> {
const response = await apiClient.get(`/pos-service/api/v1/tenants/${tenantId}/pos/configurations/${configId}/sync/status`, {
params: { limit }
});
return response.data;
},
async getSyncLogs(tenantId: string, configId: string, params?: {
limit?: number;
offset?: number;
status?: string;
sync_type?: string;
data_type?: string;
}): Promise<{ logs: POSSyncLog[]; total: number; has_more: boolean }> {
const response = await apiClient.get(`/pos-service/api/v1/tenants/${tenantId}/pos/configurations/${configId}/sync/logs`, {
params
});
return response.data;
},
// Transaction Management
async getTransactions(tenantId: string, params?: {
pos_system?: string;
start_date?: string;
end_date?: string;
status?: string;
is_synced?: boolean;
limit?: number;
offset?: number;
}): Promise<{
transactions: POSTransaction[];
total: number;
has_more: boolean;
summary: {
total_amount: number;
transaction_count: number;
sync_status: {
synced: number;
pending: number;
failed: number;
};
};
}> {
const response = await apiClient.get(`/pos-service/api/v1/tenants/${tenantId}/pos/transactions`, {
params
});
return response.data;
},
async syncSingleTransaction(tenantId: string, transactionId: string, force?: boolean): Promise<{
message: string;
transaction_id: string;
sync_status: string;
sales_record_id?: string;
}> {
const response = await apiClient.post(`/pos-service/api/v1/tenants/${tenantId}/pos/transactions/${transactionId}/sync`,
{}, { params: { force } }
);
return response.data;
},
async resyncFailedTransactions(tenantId: string, daysBack: number): Promise<{
message: string;
job_id: string;
scope: string;
estimated_transactions: number;
}> {
const response = await apiClient.post(`/pos-service/api/v1/tenants/${tenantId}/pos/data/resync`,
{}, { params: { days_back: daysBack } }
);
return response.data;
},
// Analytics
async getSyncAnalytics(tenantId: string, days: number = 30): Promise<POSAnalytics> {
const response = await apiClient.get(`/pos-service/api/v1/tenants/${tenantId}/pos/analytics/sync-performance`, {
params: { days }
});
return response.data;
},
// System Information
async getSupportedSystems(): Promise<{ systems: SupportedPOSSystem[] }> {
const response = await apiClient.get('/pos-service/api/v1/pos/supported-systems');
return response.data;
},
// Webhook Status
async getWebhookStatus(posSystem: string): Promise<{
pos_system: string;
status: string;
endpoint: string;
supported_events: {
events: string[];
format: string;
authentication: string;
};
last_received?: string;
total_received: number;
}> {
const response = await apiClient.get(`/pos-service/api/v1/webhooks/${posSystem}/status`);
return response.data;
}
};
export default posService;