<?php
|
|
namespace JVBase\routes;
|
|
use JVBase\managers\JaneClientImporter;
|
use JVBase\managers\JaneSalesImporter;
|
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 JaneImportRoutes
|
{
|
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'
|
]
|
]
|
]);
|
|
// 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'
|
]
|
]
|
]);
|
|
// Get import status
|
register_rest_route($this->namespace, '/jane/import-status/(?P<id>[\w-]+)', [
|
'methods' => 'GET',
|
'callback' => [$this, 'getImportStatus'],
|
'permission_callback' => [$this, 'checkAdminPermission']
|
]);
|
}
|
|
/**
|
* 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|WP_Error
|
*/
|
public function importClients(WP_REST_Request $request)
|
{
|
// Get uploaded file
|
$files = $request->get_file_params();
|
if (empty($files['file'])) {
|
return new WP_Error('no_file', 'No file uploaded', ['status' => 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]);
|
}
|
|
// Get options
|
$options = $request->get_param('options') ?: [];
|
$default_options = [
|
'update_existing' => true,
|
'create_users' => true,
|
'send_welcome_email' => false
|
];
|
$options = wp_parse_args($options, $default_options);
|
|
// Process import
|
$importer = new JaneClientImporter();
|
$results = $importer->importFromCSV($file['tmp_name'], $options);
|
|
if (is_wp_error($results)) {
|
return new WP_Error(
|
'import_failed',
|
$results->get_error_message(),
|
['status' => 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 new WP_REST_Response([
|
'success' => true,
|
'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
|
*/
|
public function importSales(WP_REST_Request $request)
|
{
|
// Get uploaded file
|
$files = $request->get_file_params();
|
if (empty($files['file'])) {
|
return new WP_Error('no_file', 'No file uploaded', ['status' => 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]);
|
}
|
|
// Get options
|
$options = $request->get_param('options') ?: [];
|
$default_options = [
|
'skip_existing' => true
|
];
|
$options = wp_parse_args($options, $default_options);
|
|
// Process import
|
$importer = new JaneSalesImporter();
|
$results = $importer->importFromCSV($file['tmp_name'], $options);
|
|
if (is_wp_error($results)) {
|
return new WP_Error(
|
'import_failed',
|
$results->get_error_message(),
|
['status' => 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 new WP_REST_Response([
|
'success' => true,
|
'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
|
*/
|
public function getImportStatus(WP_REST_Request $request)
|
{
|
$import_id = $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 new WP_REST_Response([
|
'success' => true,
|
'data' => $import_data
|
], 200);
|
}
|
|
/**
|
* 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) . '.';
|
}
|
}
|