| | |
| | | <?php |
| | | |
| | | namespace JVBase\routes; |
| | | namespace JVBase\rest\routes; |
| | | |
| | | use JVBase\managers\JaneClientImporter; |
| | | use JVBase\managers\JaneSalesImporter; |
| | | use JVBase\importers\JaneAppClientImporter; |
| | | use JVBase\importers\JaneAppSalesImporter; |
| | | use JVBase\rest\Rest; |
| | | use JVBase\rest\Route; |
| | | use WP_REST_Request; |
| | | use WP_REST_Response; |
| | | use WP_Error; |
| | |
| | | * |
| | | * REST API endpoints for importing JaneApp data |
| | | */ |
| | | class JaneImportRoutes |
| | | class ImporterRoutes extends Rest |
| | | { |
| | | protected string $namespace; |
| | | |
| | | public function __construct() |
| | | { |
| | | $this->namespace = BASE . 'v1'; |
| | | } |
| | | |
| | | /** |
| | | * Register REST routes |
| | | */ |
| | | public function registerRoutes(): void |
| | | { |
| | | // Client import endpoint |
| | | register_rest_route($this->namespace, '/jane/import-clients', [ |
| | | 'methods' => 'POST', |
| | | 'callback' => [$this, 'importClients'], |
| | | 'permission_callback' => [$this, 'checkAdminPermission'], |
| | | 'args' => [ |
| | | 'file' => [ |
| | | 'required' => true, |
| | | 'description' => 'CSV file containing client data' |
| | | ], |
| | | 'options' => [ |
| | | 'required' => false, |
| | | 'default' => [], |
| | | 'description' => 'Import options' |
| | | ] |
| | | ] |
| | | ]); |
| | | Route::for('jane/import-clients') |
| | | ->post([$this, 'importClients']) |
| | | ->args([ |
| | | 'options' => 'string', // JSON string of options |
| | | ]) |
| | | ->auth('admin') |
| | | ->rateLimit(3, 300) |
| | | ->register(); // 3 imports per 5 minutes |
| | | |
| | | // Sales import endpoint |
| | | register_rest_route($this->namespace, '/jane/import-sales', [ |
| | | 'methods' => 'POST', |
| | | 'callback' => [$this, 'importSales'], |
| | | 'permission_callback' => [$this, 'checkAdminPermission'], |
| | | 'args' => [ |
| | | 'file' => [ |
| | | 'required' => true, |
| | | 'description' => 'CSV file containing sales data' |
| | | ], |
| | | 'options' => [ |
| | | 'required' => false, |
| | | 'default' => [], |
| | | 'description' => 'Import options' |
| | | ] |
| | | ] |
| | | ]); |
| | | Route::for('jane/import-sales') |
| | | ->post([$this, 'importSales']) |
| | | ->args([ |
| | | 'options' => 'string', // JSON string of options |
| | | ]) |
| | | ->auth('admin') |
| | | ->rateLimit(3, 300) |
| | | ->register(); // 3 imports per 5 minutes |
| | | |
| | | // Get import status |
| | | register_rest_route($this->namespace, '/jane/import-status/(?P<id>[\w-]+)', [ |
| | | 'methods' => 'GET', |
| | | 'callback' => [$this, 'getImportStatus'], |
| | | 'permission_callback' => [$this, 'checkAdminPermission'] |
| | | ]); |
| | | Route::for(Route::pattern('jane/import-status/{id}')) |
| | | ->get([$this, 'getImportStatus']) |
| | | ->arg('id', 'string|required') |
| | | ->auth('admin') |
| | | ->rateLimit(30) |
| | | ->register(); |
| | | } |
| | | |
| | | /** |
| | |
| | | * Import clients from CSV |
| | | * |
| | | * @param WP_REST_Request $request |
| | | * @return WP_REST_Response|WP_Error |
| | | * @return WP_REST_Response |
| | | */ |
| | | public function importClients(WP_REST_Request $request) |
| | | public function importClients(WP_REST_Request $request): WP_REST_Response |
| | | { |
| | | // Get uploaded file |
| | | $files = $request->get_file_params(); |
| | | if (empty($files['file'])) { |
| | | return new WP_Error('no_file', 'No file uploaded', ['status' => 400]); |
| | | return $this->error('No file uploaded', 'no_file', 400); |
| | | } |
| | | |
| | | $file = $files['file']; |
| | | |
| | | // Validate file type |
| | | if (!$this->isValidCSV($file)) { |
| | | return new WP_Error('invalid_file', 'Invalid file type. Please upload a CSV file.', ['status' => 400]); |
| | | return $this->error('Invalid file type. Please upload a CSV file.', 'invalid_file', 400); |
| | | } |
| | | |
| | | // Get options |
| | | $options = $request->get_param('options') ?: []; |
| | | // Get and parse options |
| | | $options_param = $request->get_param('options'); |
| | | $options = !empty($options_param) ? json_decode($options_param, true) : []; |
| | | |
| | | $default_options = [ |
| | | 'update_existing' => true, |
| | | 'create_users' => true, |
| | |
| | | $options = wp_parse_args($options, $default_options); |
| | | |
| | | // Process import |
| | | $importer = new JaneClientImporter(); |
| | | $importer = new JaneAppClientImporter(); |
| | | $results = $importer->importFromCSV($file['tmp_name'], $options); |
| | | |
| | | if (is_wp_error($results)) { |
| | | return new WP_Error( |
| | | 'import_failed', |
| | | $this->logError('Client import failed', [ |
| | | 'error' => $results->get_error_message(), |
| | | 'file' => $file['name'] |
| | | ]); |
| | | |
| | | return $this->error( |
| | | $results->get_error_message(), |
| | | ['status' => 500] |
| | | 'import_failed', |
| | | 500 |
| | | ); |
| | | } |
| | | |
| | |
| | | 'completed_at' => current_time('mysql') |
| | | ], HOUR_IN_SECONDS); |
| | | |
| | | return new WP_REST_Response([ |
| | | 'success' => true, |
| | | return $this->success([ |
| | | 'import_id' => $import_id, |
| | | 'results' => $results, |
| | | 'summary' => $this->generateClientImportSummary($results) |
| | | ], 200); |
| | | ]); |
| | | } |
| | | |
| | | /** |
| | | * Import sales from CSV |
| | | * |
| | | * @param WP_REST_Request $request |
| | | * @return WP_REST_Response|WP_Error |
| | | * @return WP_REST_Response |
| | | */ |
| | | public function importSales(WP_REST_Request $request) |
| | | public function importSales(WP_REST_Request $request): WP_REST_Response |
| | | { |
| | | // Get uploaded file |
| | | $files = $request->get_file_params(); |
| | | if (empty($files['file'])) { |
| | | return new WP_Error('no_file', 'No file uploaded', ['status' => 400]); |
| | | return $this->error('No file uploaded', 'no_file', 400); |
| | | } |
| | | |
| | | $file = $files['file']; |
| | | |
| | | // Validate file type |
| | | if (!$this->isValidCSV($file)) { |
| | | return new WP_Error('invalid_file', 'Invalid file type. Please upload a CSV file.', ['status' => 400]); |
| | | return $this->error('Invalid file type. Please upload a CSV file.', 'invalid_file', 400); |
| | | } |
| | | |
| | | // Get options |
| | | $options = $request->get_param('options') ?: []; |
| | | // Get and parse options |
| | | $options_param = $request->get_param('options'); |
| | | $options = !empty($options_param) ? json_decode($options_param, true) : []; |
| | | |
| | | $default_options = [ |
| | | 'skip_existing' => true |
| | | ]; |
| | | $options = wp_parse_args($options, $default_options); |
| | | |
| | | // Process import |
| | | $importer = new JaneSalesImporter(); |
| | | $importer = new JaneAppSalesImporter(); |
| | | $results = $importer->importFromCSV($file['tmp_name'], $options); |
| | | |
| | | if (is_wp_error($results)) { |
| | | return new WP_Error( |
| | | 'import_failed', |
| | | $this->logError('Sales import failed', [ |
| | | 'error' => $results->get_error_message(), |
| | | 'file' => $file['name'] |
| | | ]); |
| | | |
| | | return $this->error( |
| | | $results->get_error_message(), |
| | | ['status' => 500] |
| | | 'import_failed', |
| | | 500 |
| | | ); |
| | | } |
| | | |
| | |
| | | 'completed_at' => current_time('mysql') |
| | | ], HOUR_IN_SECONDS); |
| | | |
| | | return new WP_REST_Response([ |
| | | 'success' => true, |
| | | return $this->success([ |
| | | 'import_id' => $import_id, |
| | | 'results' => $results, |
| | | 'summary' => $this->generateSalesImportSummary($results) |
| | | ], 200); |
| | | ]); |
| | | } |
| | | |
| | | /** |
| | | * Get import status by ID |
| | | * |
| | | * @param WP_REST_Request $request |
| | | * @return WP_REST_Response|WP_Error |
| | | * @return WP_REST_Response |
| | | */ |
| | | public function getImportStatus(WP_REST_Request $request) |
| | | public function getImportStatus(WP_REST_Request $request): WP_REST_Response |
| | | { |
| | | $import_id = $request->get_param('id'); |
| | | $import_id = sanitize_text_field($request->get_param('id')); |
| | | $import_data = get_transient('jane_import_' . $import_id); |
| | | |
| | | if (!$import_data) { |
| | | return new WP_Error( |
| | | 'import_not_found', |
| | | 'Import not found or expired', |
| | | ['status' => 404] |
| | | ); |
| | | return $this->notFound('Import not found or expired'); |
| | | } |
| | | |
| | | return new WP_REST_Response([ |
| | | 'success' => true, |
| | | 'data' => $import_data |
| | | ], 200); |
| | | return $this->success($import_data); |
| | | } |
| | | |
| | | /** |