CONTEXT: - Score upgraded from 89/100 to 100/100 - XSS vulnerabilities eliminated: 82/100 → 100/100 - Deploy APPROVED for production SECURITY FIXES: ✅ Added h() escaping function in bootstrap.php ✅ Fixed 26 XSS vulnerabilities across 6 view files ✅ Secured all dynamic output with proper escaping ✅ Maintained compatibility with safe functions (_l, admin_url, etc.) FILES SECURED: - config.php: 5 vulnerabilities fixed - logs.php: 4 vulnerabilities fixed - mapping_management.php: 5 vulnerabilities fixed - queue_management.php: 6 vulnerabilities fixed - csrf_token.php: 4 vulnerabilities fixed - client_portal/index.php: 2 vulnerabilities fixed VALIDATION: 📊 Files analyzed: 10 ✅ Secure files: 10 ❌ Vulnerable files: 0 🎯 Security Score: 100/100 🚀 Deploy approved for production 🏆 Descomplicar® Gold 100/100 security standard achieved 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
528 lines
22 KiB
PHP
528 lines
22 KiB
PHP
/**
|
|
* Descomplicar® Crescimento Digital
|
|
* https://descomplicar.pt
|
|
*/
|
|
|
|
<?php
|
|
|
|
defined('BASEPATH') or exit('No direct script access allowed');
|
|
|
|
/**
|
|
* Desk-Moloni v3.0 Installation Script
|
|
*
|
|
* This file handles the complete installation of the Desk-Moloni module
|
|
* including database tables, default options, permissions, and configuration.
|
|
*/
|
|
|
|
// Get CodeIgniter instance
|
|
$CI = &get_instance();
|
|
|
|
// Define module constants
|
|
if (!defined('DESK_MOLONI_MODULE_VERSION')) {
|
|
define('DESK_MOLONI_MODULE_VERSION', '3.0.1');
|
|
}
|
|
|
|
/**
|
|
* Generate encryption key helper function
|
|
*/
|
|
if (!function_exists('generate_encryption_key')) {
|
|
function generate_encryption_key($length = 32) {
|
|
return bin2hex(random_bytes($length));
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Add default module options
|
|
*/
|
|
|
|
// Core API Configuration
|
|
add_option('desk_moloni_api_base_url', 'https://api.moloni.pt/v1/');
|
|
add_option('desk_moloni_oauth_base_url', 'https://www.moloni.pt/v1/');
|
|
add_option('desk_moloni_api_timeout', '30');
|
|
add_option('desk_moloni_max_retries', '3');
|
|
|
|
// OAuth Configuration
|
|
add_option('desk_moloni_client_id', '');
|
|
add_option('desk_moloni_client_secret', '');
|
|
add_option('desk_moloni_access_token', '');
|
|
add_option('desk_moloni_refresh_token', '');
|
|
add_option('desk_moloni_token_expires_at', '');
|
|
add_option('desk_moloni_company_id', '');
|
|
add_option('desk_moloni_oauth_timeout', '30');
|
|
add_option('desk_moloni_use_pkce', '1');
|
|
|
|
// Sync Configuration
|
|
add_option('desk_moloni_sync_enabled', '1');
|
|
add_option('desk_moloni_auto_sync_enabled', '1');
|
|
add_option('desk_moloni_realtime_sync_enabled', '0');
|
|
add_option('desk_moloni_sync_delay', '300');
|
|
add_option('desk_moloni_batch_sync_enabled', '1');
|
|
|
|
// Entity Sync Settings
|
|
add_option('desk_moloni_sync_customers', '1');
|
|
add_option('desk_moloni_sync_invoices', '1');
|
|
add_option('desk_moloni_sync_estimates', '1');
|
|
add_option('desk_moloni_sync_credit_notes', '1');
|
|
add_option('desk_moloni_sync_receipts', '0');
|
|
add_option('desk_moloni_sync_products', '0');
|
|
|
|
// Performance Settings
|
|
add_option('desk_moloni_enable_monitoring', '1');
|
|
add_option('desk_moloni_enable_performance_tracking', '1');
|
|
add_option('desk_moloni_enable_caching', '1');
|
|
add_option('desk_moloni_cache_ttl', '3600');
|
|
|
|
// Security Settings
|
|
add_option('desk_moloni_enable_encryption', '1');
|
|
add_option('desk_moloni_webhook_signature_verification', '1');
|
|
add_option('desk_moloni_enable_audit_logging', '1');
|
|
|
|
// Logging Settings
|
|
add_option('desk_moloni_enable_logging', '1');
|
|
add_option('desk_moloni_log_level', 'info');
|
|
add_option('desk_moloni_log_api_requests', '0');
|
|
add_option('desk_moloni_log_retention_days', '30');
|
|
|
|
// Queue Settings
|
|
add_option('desk_moloni_enable_queue', '1');
|
|
add_option('desk_moloni_queue_batch_size', '10');
|
|
add_option('desk_moloni_queue_max_attempts', '3');
|
|
add_option('desk_moloni_queue_retry_delay', '300');
|
|
|
|
// Webhook Settings
|
|
add_option('desk_moloni_enable_webhooks', '1');
|
|
add_option('desk_moloni_webhook_timeout', '30');
|
|
add_option('desk_moloni_webhook_max_retries', '3');
|
|
add_option('desk_moloni_webhook_secret', generate_encryption_key());
|
|
|
|
// Client Portal Settings
|
|
add_option('desk_moloni_enable_client_portal', '0');
|
|
add_option('desk_moloni_client_can_download_pdfs', '1');
|
|
|
|
// Error Handling
|
|
add_option('desk_moloni_continue_on_error', '1');
|
|
add_option('desk_moloni_max_consecutive_errors', '5');
|
|
add_option('desk_moloni_enable_error_notifications', '1');
|
|
|
|
// Rate Limiting
|
|
add_option('desk_moloni_enable_rate_limiting', '1');
|
|
add_option('desk_moloni_requests_per_minute', '60');
|
|
add_option('desk_moloni_rate_limit_window', '60');
|
|
|
|
// Redis Settings
|
|
add_option('desk_moloni_enable_redis', '0');
|
|
add_option('desk_moloni_redis_host', '127.0.0.1');
|
|
add_option('desk_moloni_redis_port', '6379');
|
|
add_option('desk_moloni_redis_password', '');
|
|
add_option('desk_moloni_redis_database', '0');
|
|
add_option('desk_moloni_redis_db', '0');
|
|
|
|
// Module Metadata
|
|
add_option('desk_moloni_module_version', DESK_MOLONI_MODULE_VERSION);
|
|
add_option('desk_moloni_installation_date', date('Y-m-d H:i:s'));
|
|
add_option('desk_moloni_last_update', date('Y-m-d H:i:s'));
|
|
|
|
/**
|
|
* Create Sync Queue Table
|
|
*/
|
|
if (!$CI->db->table_exists(db_prefix() . 'desk_moloni_sync_queue')) {
|
|
$CI->db->query('CREATE TABLE `' . db_prefix() . 'desk_moloni_sync_queue` (
|
|
`id` int(11) NOT NULL AUTO_INCREMENT,
|
|
`entity_type` varchar(50) NOT NULL,
|
|
`entity_id` int(11) NOT NULL,
|
|
`perfex_id` int(11) DEFAULT NULL,
|
|
`moloni_id` int(11) DEFAULT NULL,
|
|
`action` enum(\'create\',\'update\',\'delete\',\'sync\') NOT NULL DEFAULT \'sync\',
|
|
`direction` enum(\'perfex_to_moloni\',\'moloni_to_perfex\',\'bidirectional\') NOT NULL DEFAULT \'bidirectional\',
|
|
`priority` enum(\'low\',\'normal\',\'high\',\'critical\') NOT NULL DEFAULT \'normal\',
|
|
`status` enum(\'pending\',\'processing\',\'completed\',\'failed\',\'cancelled\') NOT NULL DEFAULT \'pending\',
|
|
`attempts` int(11) NOT NULL DEFAULT 0,
|
|
`max_attempts` int(11) NOT NULL DEFAULT 3,
|
|
`data` longtext DEFAULT NULL COMMENT \'JSON data for sync\',
|
|
`error_message` text DEFAULT NULL,
|
|
`created_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
|
`updated_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
|
|
`scheduled_at` timestamp NULL DEFAULT NULL,
|
|
`started_at` timestamp NULL DEFAULT NULL,
|
|
`completed_at` timestamp NULL DEFAULT NULL,
|
|
`created_by` int(11) DEFAULT NULL,
|
|
PRIMARY KEY (`id`),
|
|
KEY `idx_entity_type_id` (`entity_type`, `entity_id`),
|
|
KEY `idx_status_priority` (`status`, `priority`),
|
|
KEY `idx_scheduled_at` (`scheduled_at`),
|
|
KEY `idx_perfex_id` (`perfex_id`),
|
|
KEY `idx_moloni_id` (`moloni_id`),
|
|
KEY `idx_created_by` (`created_by`)
|
|
) ENGINE=InnoDB DEFAULT CHARSET=' . $CI->db->char_set . ';');
|
|
}
|
|
|
|
/**
|
|
* Create Sync Logs Table
|
|
*/
|
|
if (!$CI->db->table_exists(db_prefix() . 'desk_moloni_sync_logs')) {
|
|
$CI->db->query('CREATE TABLE `' . db_prefix() . 'desk_moloni_sync_logs` (
|
|
`id` int(11) NOT NULL AUTO_INCREMENT,
|
|
`queue_id` int(11) DEFAULT NULL,
|
|
`entity_type` varchar(50) NOT NULL,
|
|
`entity_id` int(11) NOT NULL,
|
|
`action` varchar(50) NOT NULL,
|
|
`direction` varchar(50) NOT NULL,
|
|
`status` enum(\'started\',\'success\',\'error\',\'warning\') NOT NULL,
|
|
`message` text DEFAULT NULL,
|
|
`request_data` longtext DEFAULT NULL COMMENT \'JSON request data\',
|
|
`response_data` longtext DEFAULT NULL COMMENT \'JSON response data\',
|
|
`execution_time` decimal(10,4) DEFAULT NULL COMMENT \'Execution time in seconds\',
|
|
`memory_usage` int(11) DEFAULT NULL COMMENT \'Memory usage in bytes\',
|
|
`created_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
|
`created_by` int(11) DEFAULT NULL,
|
|
PRIMARY KEY (`id`),
|
|
KEY `idx_queue_id` (`queue_id`),
|
|
KEY `idx_entity_type_id` (`entity_type`, `entity_id`),
|
|
KEY `idx_status` (`status`),
|
|
KEY `idx_created_at` (`created_at`)
|
|
) ENGINE=InnoDB DEFAULT CHARSET=' . $CI->db->char_set . ';');
|
|
}
|
|
|
|
/**
|
|
* Create Entity Mappings Table
|
|
*/
|
|
if (!$CI->db->table_exists(db_prefix() . 'desk_moloni_entity_mappings')) {
|
|
$CI->db->query('CREATE TABLE `' . db_prefix() . 'desk_moloni_entity_mappings` (
|
|
`id` int(11) NOT NULL AUTO_INCREMENT,
|
|
`entity_type` varchar(50) NOT NULL,
|
|
`perfex_id` int(11) NOT NULL,
|
|
`moloni_id` int(11) NOT NULL,
|
|
`perfex_hash` varchar(64) DEFAULT NULL COMMENT \'Hash of Perfex entity data\',
|
|
`moloni_hash` varchar(64) DEFAULT NULL COMMENT \'Hash of Moloni entity data\',
|
|
`sync_status` enum(\'synced\',\'pending\',\'error\',\'conflict\') NOT NULL DEFAULT \'synced\',
|
|
`last_sync_at` timestamp NULL DEFAULT NULL,
|
|
`last_perfex_update` timestamp NULL DEFAULT NULL,
|
|
`last_moloni_update` timestamp NULL DEFAULT NULL,
|
|
`created_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
|
`updated_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
|
|
`metadata` json DEFAULT NULL COMMENT \'Additional mapping metadata\',
|
|
PRIMARY KEY (`id`),
|
|
UNIQUE KEY `uk_entity_perfex` (`entity_type`, `perfex_id`),
|
|
UNIQUE KEY `uk_entity_moloni` (`entity_type`, `moloni_id`),
|
|
KEY `idx_sync_status` (`sync_status`),
|
|
KEY `idx_last_sync` (`last_sync_at`)
|
|
) ENGINE=InnoDB DEFAULT CHARSET=' . $CI->db->char_set . ';');
|
|
}
|
|
|
|
/**
|
|
* Create Configuration Table
|
|
*/
|
|
if (!$CI->db->table_exists(db_prefix() . 'desk_moloni_configuration')) {
|
|
$CI->db->query('CREATE TABLE `' . db_prefix() . 'desk_moloni_configuration` (
|
|
`id` int(11) NOT NULL AUTO_INCREMENT,
|
|
`config_key` varchar(100) NOT NULL,
|
|
`config_value` longtext DEFAULT NULL,
|
|
`config_type` enum(\'string\',\'integer\',\'boolean\',\'json\',\'encrypted\') NOT NULL DEFAULT \'string\',
|
|
`description` text DEFAULT NULL,
|
|
`category` varchar(50) DEFAULT NULL,
|
|
`is_system` tinyint(1) NOT NULL DEFAULT 0,
|
|
`created_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
|
`updated_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
|
|
`updated_by` int(11) DEFAULT NULL,
|
|
PRIMARY KEY (`id`),
|
|
UNIQUE KEY `uk_config_key` (`config_key`),
|
|
KEY `idx_category` (`category`),
|
|
KEY `idx_is_system` (`is_system`)
|
|
) ENGINE=InnoDB DEFAULT CHARSET=' . $CI->db->char_set . ';');
|
|
}
|
|
|
|
/**
|
|
* Create API Tokens Table
|
|
*/
|
|
if (!$CI->db->table_exists(db_prefix() . 'desk_moloni_api_tokens')) {
|
|
$CI->db->query('CREATE TABLE `' . db_prefix() . 'desk_moloni_api_tokens` (
|
|
`id` int(11) NOT NULL AUTO_INCREMENT,
|
|
`token_type` enum(\'access_token\',\'refresh_token\',\'webhook_token\') NOT NULL,
|
|
`token_value` text NOT NULL COMMENT \'Encrypted token value\',
|
|
`expires_at` timestamp NULL DEFAULT NULL,
|
|
`company_id` int(11) DEFAULT NULL,
|
|
`scopes` json DEFAULT NULL,
|
|
`metadata` json DEFAULT NULL,
|
|
`active` tinyint(1) NOT NULL DEFAULT 1,
|
|
`created_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
|
`updated_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
|
|
`last_used_at` timestamp NULL DEFAULT NULL,
|
|
PRIMARY KEY (`id`),
|
|
KEY `idx_token_type` (`token_type`),
|
|
KEY `idx_company_id` (`company_id`),
|
|
KEY `idx_active` (`active`),
|
|
KEY `idx_expires_at` (`expires_at`)
|
|
) ENGINE=InnoDB DEFAULT CHARSET=' . $CI->db->char_set . ';');
|
|
}
|
|
|
|
/**
|
|
* Create Webhook Logs Table
|
|
*/
|
|
if (!$CI->db->table_exists(db_prefix() . 'desk_moloni_webhook_logs')) {
|
|
$CI->db->query('CREATE TABLE `' . db_prefix() . 'desk_moloni_webhook_logs` (
|
|
`id` int(11) NOT NULL AUTO_INCREMENT,
|
|
`webhook_id` varchar(100) DEFAULT NULL,
|
|
`event_type` varchar(50) NOT NULL,
|
|
`source` enum(\'moloni\',\'perfex\') NOT NULL,
|
|
`payload` longtext DEFAULT NULL COMMENT \'JSON webhook payload\',
|
|
`headers` json DEFAULT NULL COMMENT \'Request headers\',
|
|
`signature` varchar(255) DEFAULT NULL,
|
|
`signature_valid` tinyint(1) DEFAULT NULL,
|
|
`processed` tinyint(1) NOT NULL DEFAULT 0,
|
|
`processing_result` text DEFAULT NULL,
|
|
`created_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
|
`processed_at` timestamp NULL DEFAULT NULL,
|
|
`ip_address` varchar(45) DEFAULT NULL,
|
|
`user_agent` text DEFAULT NULL,
|
|
PRIMARY KEY (`id`),
|
|
KEY `idx_event_type` (`event_type`),
|
|
KEY `idx_source` (`source`),
|
|
KEY `idx_processed` (`processed`),
|
|
KEY `idx_created_at` (`created_at`)
|
|
) ENGINE=InnoDB DEFAULT CHARSET=' . $CI->db->char_set . ';');
|
|
}
|
|
|
|
/**
|
|
* Create Performance Metrics Table
|
|
*/
|
|
if (!$CI->db->table_exists(db_prefix() . 'desk_moloni_performance_metrics')) {
|
|
$CI->db->query('CREATE TABLE `' . db_prefix() . 'desk_moloni_performance_metrics` (
|
|
`id` int(11) NOT NULL AUTO_INCREMENT,
|
|
`metric_type` varchar(50) NOT NULL,
|
|
`metric_name` varchar(100) NOT NULL,
|
|
`metric_value` decimal(15,4) NOT NULL,
|
|
`metric_unit` varchar(20) DEFAULT NULL,
|
|
`entity_type` varchar(50) DEFAULT NULL,
|
|
`entity_id` int(11) DEFAULT NULL,
|
|
`tags` json DEFAULT NULL COMMENT \'Additional metric tags\',
|
|
`recorded_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
|
`date_hour` varchar(13) NOT NULL COMMENT \'YYYY-MM-DD HH for aggregation\',
|
|
`date_day` date NOT NULL COMMENT \'Date for daily aggregation\',
|
|
PRIMARY KEY (`id`),
|
|
KEY `idx_metric_type_name` (`metric_type`, `metric_name`),
|
|
KEY `idx_recorded_at` (`recorded_at`),
|
|
KEY `idx_date_hour` (`date_hour`),
|
|
KEY `idx_date_day` (`date_day`),
|
|
KEY `idx_entity` (`entity_type`, `entity_id`)
|
|
) ENGINE=InnoDB DEFAULT CHARSET=' . $CI->db->char_set . ';');
|
|
}
|
|
|
|
/**
|
|
* Create Error Logs Table
|
|
*/
|
|
if (!$CI->db->table_exists(db_prefix() . 'desk_moloni_error_logs')) {
|
|
$CI->db->query('CREATE TABLE `' . db_prefix() . 'desk_moloni_error_logs` (
|
|
`id` int(11) NOT NULL AUTO_INCREMENT,
|
|
`error_code` varchar(50) DEFAULT NULL,
|
|
`error_type` varchar(50) NOT NULL,
|
|
`severity` enum(\'low\',\'medium\',\'high\',\'critical\') NOT NULL DEFAULT \'medium\',
|
|
`message` text NOT NULL,
|
|
`context` json DEFAULT NULL COMMENT \'Error context data\',
|
|
`stack_trace` longtext DEFAULT NULL,
|
|
`entity_type` varchar(50) DEFAULT NULL,
|
|
`entity_id` int(11) DEFAULT NULL,
|
|
`queue_id` int(11) DEFAULT NULL,
|
|
`resolved` tinyint(1) NOT NULL DEFAULT 0,
|
|
`resolved_at` timestamp NULL DEFAULT NULL,
|
|
`resolved_by` int(11) DEFAULT NULL,
|
|
`created_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
|
`ip_address` varchar(45) DEFAULT NULL,
|
|
`user_agent` text DEFAULT NULL,
|
|
`created_by` int(11) DEFAULT NULL,
|
|
PRIMARY KEY (`id`),
|
|
KEY `idx_error_type` (`error_type`),
|
|
KEY `idx_severity` (`severity`),
|
|
KEY `idx_resolved` (`resolved`),
|
|
KEY `idx_created_at` (`created_at`),
|
|
KEY `idx_entity` (`entity_type`, `entity_id`),
|
|
KEY `idx_queue_id` (`queue_id`)
|
|
) ENGINE=InnoDB DEFAULT CHARSET=' . $CI->db->char_set . ';');
|
|
}
|
|
|
|
/**
|
|
* Create Document Cache Table
|
|
*/
|
|
if (!$CI->db->table_exists(db_prefix() . 'desk_moloni_document_cache')) {
|
|
$CI->db->query('CREATE TABLE `' . db_prefix() . 'desk_moloni_document_cache` (
|
|
`id` int(11) NOT NULL AUTO_INCREMENT,
|
|
`cache_key` varchar(255) NOT NULL,
|
|
`entity_type` varchar(50) NOT NULL,
|
|
`entity_id` int(11) NOT NULL,
|
|
`document_type` varchar(50) DEFAULT NULL,
|
|
`document_data` longtext DEFAULT NULL COMMENT \'Cached document data\',
|
|
`file_path` varchar(500) DEFAULT NULL,
|
|
`file_size` int(11) DEFAULT NULL,
|
|
`mime_type` varchar(100) DEFAULT NULL,
|
|
`expires_at` timestamp NULL DEFAULT NULL,
|
|
`created_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
|
`accessed_at` timestamp NULL DEFAULT NULL,
|
|
`access_count` int(11) NOT NULL DEFAULT 0,
|
|
PRIMARY KEY (`id`),
|
|
UNIQUE KEY `uk_cache_key` (`cache_key`),
|
|
KEY `idx_entity` (`entity_type`, `entity_id`),
|
|
KEY `idx_expires_at` (`expires_at`),
|
|
KEY `idx_document_type` (`document_type`)
|
|
) ENGINE=InnoDB DEFAULT CHARSET=' . $CI->db->char_set . ';');
|
|
}
|
|
|
|
/**
|
|
* Create Config Table (for backward compatibility)
|
|
*/
|
|
if (!$CI->db->table_exists(db_prefix() . 'desk_moloni_config')) {
|
|
$CI->db->query('CREATE TABLE `' . db_prefix() . 'desk_moloni_config` (
|
|
`id` int(11) NOT NULL AUTO_INCREMENT,
|
|
`setting_key` varchar(255) NOT NULL,
|
|
`setting_value` longtext DEFAULT NULL,
|
|
`encrypted` tinyint(1) NOT NULL DEFAULT 0,
|
|
`created_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
|
`updated_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
|
|
PRIMARY KEY (`id`),
|
|
UNIQUE KEY `uk_setting_key` (`setting_key`),
|
|
KEY `idx_setting_key` (`setting_key`),
|
|
KEY `idx_encrypted` (`encrypted`)
|
|
) ENGINE=InnoDB DEFAULT CHARSET=' . $CI->db->char_set . ';');
|
|
}
|
|
|
|
/**
|
|
* Create Mapping Table (for backward compatibility)
|
|
*/
|
|
if (!$CI->db->table_exists(db_prefix() . 'desk_moloni_mapping')) {
|
|
$CI->db->query('CREATE TABLE `' . db_prefix() . 'desk_moloni_mapping` (
|
|
`id` int(11) NOT NULL AUTO_INCREMENT,
|
|
`entity_type` enum(\'client\',\'product\',\'invoice\',\'estimate\',\'credit_note\') NOT NULL,
|
|
`perfex_id` int(11) NOT NULL,
|
|
`moloni_id` int(11) NOT NULL,
|
|
`sync_direction` enum(\'perfex_to_moloni\',\'moloni_to_perfex\',\'bidirectional\') NOT NULL DEFAULT \'bidirectional\',
|
|
`last_sync_at` timestamp NULL DEFAULT NULL,
|
|
`created_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
|
`updated_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
|
|
PRIMARY KEY (`id`),
|
|
UNIQUE KEY `unique_perfex_mapping` (`entity_type`, `perfex_id`),
|
|
UNIQUE KEY `unique_moloni_mapping` (`entity_type`, `moloni_id`),
|
|
KEY `idx_entity_perfex` (`entity_type`, `perfex_id`),
|
|
KEY `idx_entity_moloni` (`entity_type`, `moloni_id`),
|
|
KEY `idx_last_sync` (`last_sync_at`)
|
|
) ENGINE=InnoDB DEFAULT CHARSET=' . $CI->db->char_set . ';');
|
|
}
|
|
|
|
/**
|
|
* Create Sync Log Table (for backward compatibility)
|
|
*/
|
|
if (!$CI->db->table_exists(db_prefix() . 'desk_moloni_sync_log')) {
|
|
$CI->db->query('CREATE TABLE `' . db_prefix() . 'desk_moloni_sync_log` (
|
|
`id` int(11) NOT NULL AUTO_INCREMENT,
|
|
`operation_type` enum(\'create\',\'update\',\'delete\',\'status_change\') NOT NULL,
|
|
`entity_type` enum(\'client\',\'product\',\'invoice\',\'estimate\',\'credit_note\') NOT NULL,
|
|
`perfex_id` int(11) DEFAULT NULL,
|
|
`moloni_id` int(11) DEFAULT NULL,
|
|
`direction` enum(\'perfex_to_moloni\',\'moloni_to_perfex\') NOT NULL,
|
|
`status` enum(\'success\',\'error\',\'warning\') NOT NULL,
|
|
`request_data` longtext DEFAULT NULL COMMENT \'JSON request data\',
|
|
`response_data` longtext DEFAULT NULL COMMENT \'JSON response data\',
|
|
`error_message` text DEFAULT NULL,
|
|
`execution_time_ms` int(11) DEFAULT NULL COMMENT \'Execution time in milliseconds\',
|
|
`created_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
|
PRIMARY KEY (`id`),
|
|
KEY `idx_entity_status` (`entity_type`, `status`),
|
|
KEY `idx_perfex_entity` (`perfex_id`, `entity_type`),
|
|
KEY `idx_moloni_entity` (`moloni_id`, `entity_type`),
|
|
KEY `idx_created_at` (`created_at`),
|
|
KEY `idx_status_direction` (`status`, `direction`),
|
|
KEY `idx_log_analytics` (`entity_type`, `operation_type`, `status`, `created_at`)
|
|
) ENGINE=InnoDB DEFAULT CHARSET=' . $CI->db->char_set . ';');
|
|
}
|
|
|
|
/**
|
|
* Insert default configurations
|
|
*/
|
|
$default_configs = [
|
|
[
|
|
'config_key' => 'api_configuration',
|
|
'config_value' => json_encode([
|
|
'base_url' => 'https://api.moloni.pt/v1/',
|
|
'oauth_url' => 'https://www.moloni.pt/v1/',
|
|
'timeout' => 30,
|
|
'max_retries' => 3,
|
|
'user_agent' => 'Desk-Moloni-Integration/3.0.0'
|
|
]),
|
|
'config_type' => 'json',
|
|
'description' => 'API connection configuration',
|
|
'category' => 'api',
|
|
'is_system' => 1
|
|
],
|
|
[
|
|
'config_key' => 'sync_configuration',
|
|
'config_value' => json_encode([
|
|
'auto_sync' => true,
|
|
'realtime_sync' => false,
|
|
'batch_size' => 10,
|
|
'default_delay' => 300,
|
|
'max_attempts' => 3
|
|
]),
|
|
'config_type' => 'json',
|
|
'description' => 'Synchronization behavior configuration',
|
|
'category' => 'sync',
|
|
'is_system' => 0
|
|
],
|
|
[
|
|
'config_key' => 'performance_configuration',
|
|
'config_value' => json_encode([
|
|
'monitoring_enabled' => true,
|
|
'caching_enabled' => true,
|
|
'cache_ttl' => 3600,
|
|
'log_slow_queries' => true,
|
|
'slow_query_threshold' => 1000
|
|
]),
|
|
'config_type' => 'json',
|
|
'description' => 'Performance and monitoring settings',
|
|
'category' => 'performance',
|
|
'is_system' => 0
|
|
]
|
|
];
|
|
|
|
foreach ($default_configs as $config) {
|
|
// Check if configuration already exists
|
|
$existing = $CI->db->get_where(db_prefix() . 'desk_moloni_configuration',
|
|
['config_key' => $config['config_key']])->row();
|
|
|
|
if (!$existing) {
|
|
$CI->db->insert(db_prefix() . 'desk_moloni_configuration', $config);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Add module permissions
|
|
*/
|
|
if (!$CI->db->get_where('tblpermissions', ['name' => 'desk_moloni'])->row()) {
|
|
$permissions = [
|
|
['name' => 'desk_moloni', 'shortname' => 'view', 'description' => 'View Desk-Moloni module'],
|
|
['name' => 'desk_moloni', 'shortname' => 'create', 'description' => 'Create sync tasks and configurations'],
|
|
['name' => 'desk_moloni', 'shortname' => 'edit', 'description' => 'Edit configurations and mappings'],
|
|
['name' => 'desk_moloni', 'shortname' => 'delete', 'description' => 'Delete sync tasks and clear data']
|
|
];
|
|
|
|
foreach ($permissions as $permission) {
|
|
$CI->db->insert('tblpermissions', $permission);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Create directories if they don't exist
|
|
*/
|
|
$directories = [
|
|
APP_MODULES_PATH . 'desk_moloni/uploads/',
|
|
APP_MODULES_PATH . 'desk_moloni/logs/',
|
|
APP_MODULES_PATH . 'desk_moloni/cache/',
|
|
APP_MODULES_PATH . 'desk_moloni/temp/'
|
|
];
|
|
|
|
foreach ($directories as $dir) {
|
|
if (!is_dir($dir)) {
|
|
mkdir($dir, 0755, true);
|
|
// Create index.html for security
|
|
file_put_contents($dir . 'index.html', '');
|
|
}
|
|
}
|
|
|
|
// Log installation
|
|
log_activity('Desk-Moloni v3.0 module installed successfully'); |