<?php
|
|
namespace JVBase\rest\routes;
|
|
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;
|
|
if (!defined('ABSPATH')) {
|
exit;
|
}
|
|
/**
|
* JaneApp Import Routes
|
*
|
* REST API endpoints for importing JaneApp data
|
*/
|
class ImporterRoutes extends Rest
|
{
|
/**
|
* Register REST routes
|
*/
|
public function registerRoutes(): void
|
{
|
// Client import endpoint
|
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
|
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
|
Route::for(Route::pattern('jane/import-status/{id}'))
|
->get([$this, 'getImportStatus'])
|
->arg('id', 'string|required')
|
->auth('admin')
|
->rateLimit(30)
|
->register();
|
}
|
|
/**
|
* Check if user has admin permissions
|
*/
|
public function checkAdminPermission(): bool
|
{
|
return current_user_can('manage_options');
|
}
|
|
/**
|
* Import clients from CSV
|
*
|
* @param WP_REST_Request $request
|
* @return WP_REST_Response
|
*/
|
public function importClients(WP_REST_Request $request): WP_REST_Response
|
{
|
// Get uploaded file
|
$files = $request->get_file_params();
|
if (empty($files['file'])) {
|
return $this->error('No file uploaded', 'no_file', 400);
|
}
|
|
$file = $files['file'];
|
|
// Validate file type
|
if (!$this->isValidCSV($file)) {
|
return $this->error('Invalid file type. Please upload a CSV file.', 'invalid_file', 400);
|
}
|
|
// 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,
|
'send_welcome_email' => false
|
];
|
$options = wp_parse_args($options, $default_options);
|
|
// Process import
|
$importer = new JaneAppClientImporter();
|
$results = $importer->importFromCSV($file['tmp_name'], $options);
|
|
if (is_wp_error($results)) {
|
$this->logError('Client import failed', [
|
'error' => $results->get_error_message(),
|
'file' => $file['name']
|
]);
|
|
return $this->error(
|
$results->get_error_message(),
|
'import_failed',
|
500
|
);
|
}
|
|
// Store results in transient for status checking
|
$import_id = wp_generate_password(12, false);
|
set_transient('jane_import_' . $import_id, [
|
'type' => 'clients',
|
'results' => $results,
|
'completed_at' => current_time('mysql')
|
], HOUR_IN_SECONDS);
|
|
return $this->success([
|
'import_id' => $import_id,
|
'results' => $results,
|
'summary' => $this->generateClientImportSummary($results)
|
]);
|
}
|
|
/**
|
* Import sales from CSV
|
*
|
* @param WP_REST_Request $request
|
* @return WP_REST_Response
|
*/
|
public function importSales(WP_REST_Request $request): WP_REST_Response
|
{
|
// Get uploaded file
|
$files = $request->get_file_params();
|
if (empty($files['file'])) {
|
return $this->error('No file uploaded', 'no_file', 400);
|
}
|
|
$file = $files['file'];
|
|
// Validate file type
|
if (!$this->isValidCSV($file)) {
|
return $this->error('Invalid file type. Please upload a CSV file.', 'invalid_file', 400);
|
}
|
|
// 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 JaneAppSalesImporter();
|
$results = $importer->importFromCSV($file['tmp_name'], $options);
|
|
if (is_wp_error($results)) {
|
$this->logError('Sales import failed', [
|
'error' => $results->get_error_message(),
|
'file' => $file['name']
|
]);
|
|
return $this->error(
|
$results->get_error_message(),
|
'import_failed',
|
500
|
);
|
}
|
|
// Store results in transient for status checking
|
$import_id = wp_generate_password(12, false);
|
set_transient('jane_import_' . $import_id, [
|
'type' => 'sales',
|
'results' => $results,
|
'completed_at' => current_time('mysql')
|
], HOUR_IN_SECONDS);
|
|
return $this->success([
|
'import_id' => $import_id,
|
'results' => $results,
|
'summary' => $this->generateSalesImportSummary($results)
|
]);
|
}
|
|
/**
|
* Get import status by ID
|
*
|
* @param WP_REST_Request $request
|
* @return WP_REST_Response
|
*/
|
public function getImportStatus(WP_REST_Request $request): WP_REST_Response
|
{
|
$import_id = sanitize_text_field($request->get_param('id'));
|
$import_data = get_transient('jane_import_' . $import_id);
|
|
if (!$import_data) {
|
return $this->notFound('Import not found or expired');
|
}
|
|
return $this->success($import_data);
|
}
|
|
/**
|
* Validate CSV file
|
*
|
* @param array $file Uploaded file data
|
* @return bool
|
*/
|
protected function isValidCSV(array $file): bool
|
{
|
// Check file extension
|
$ext = strtolower(pathinfo($file['name'], PATHINFO_EXTENSION));
|
if ($ext !== 'csv') {
|
return false;
|
}
|
|
// Check MIME type
|
$allowed_types = ['text/csv', 'text/plain', 'application/csv', 'application/vnd.ms-excel'];
|
if (!in_array($file['type'], $allowed_types)) {
|
return false;
|
}
|
|
// Check if file is actually readable as CSV
|
$handle = fopen($file['tmp_name'], 'r');
|
if (!$handle) {
|
return false;
|
}
|
|
$header = fgetcsv($handle);
|
fclose($handle);
|
|
return !empty($header);
|
}
|
|
/**
|
* Generate human-readable summary of client import
|
*
|
* @param array $results Import results
|
* @return string
|
*/
|
protected function generateClientImportSummary(array $results): string
|
{
|
$summary = [];
|
|
if ($results['created'] > 0) {
|
$summary[] = "{$results['created']} new users created";
|
}
|
|
if ($results['updated'] > 0) {
|
$summary[] = "{$results['updated']} existing users updated";
|
}
|
|
if ($results['skipped'] > 0) {
|
$summary[] = "{$results['skipped']} rows skipped";
|
}
|
|
if (count($results['errors']) > 0) {
|
$summary[] = count($results['errors']) . " errors encountered";
|
}
|
|
if (count($results['unmatched_emails']) > 0) {
|
$summary[] = count($results['unmatched_emails']) . " unmatched emails";
|
}
|
|
return implode('. ', $summary) . '.';
|
}
|
|
/**
|
* Generate human-readable summary of sales import
|
*
|
* @param array $results Import results
|
* @return string
|
*/
|
protected function generateSalesImportSummary(array $results): string
|
{
|
$summary = [];
|
|
if ($results['consultations'] > 0) {
|
$summary[] = "{$results['consultations']} consultations processed";
|
}
|
|
if ($results['treatments'] > 0) {
|
$summary[] = "{$results['treatments']} treatments recorded";
|
}
|
|
if ($results['skipped'] > 0) {
|
$summary[] = "{$results['skipped']} rows skipped";
|
}
|
|
if (count($results['errors']) > 0) {
|
$summary[] = count($results['errors']) . " errors encountered";
|
}
|
|
if (count($results['unmatched_guids']) > 0) {
|
$summary[] = count($results['unmatched_guids']) . " unmatched patient GUIDs";
|
}
|
|
if (count($results['no_referral']) > 0) {
|
$summary[] = count($results['no_referral']) . " users without referral records";
|
}
|
|
return implode('. ', $summary) . '.';
|
}
|
}
|