Added order syncing
This commit is contained in:
parent
353f9e0564
commit
fecc231e30
|
|
@ -116,6 +116,37 @@ public function getMigrationProgress(Request $request)
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get customer statistics
|
||||
*/
|
||||
public function getStatistics()
|
||||
{
|
||||
try {
|
||||
$m1Customers = $this->migrationService->getMagento1Customers();
|
||||
$m2Customers = $this->migrationService->getMagento2Customers();
|
||||
$m1CustomersNotInM2 = $this->migrationService->getM1CustomersNotInM2();
|
||||
$m2CustomersNotInM1 = $this->migrationService->getM2CustomersNotInM1();
|
||||
|
||||
return response()->json([
|
||||
'success' => true,
|
||||
'statistics' => [
|
||||
'm1Customers' => $m1Customers->count(),
|
||||
'm2Customers' => $m2Customers->count(),
|
||||
'm1CustomersNotInM2' => $m1CustomersNotInM2->count(),
|
||||
'm2CustomersNotInM1' => $m2CustomersNotInM1->count(),
|
||||
]
|
||||
]);
|
||||
|
||||
} catch (\Exception $e) {
|
||||
Log::error('Get customer statistics error: ' . $e->getMessage());
|
||||
|
||||
return response()->json([
|
||||
'success' => false,
|
||||
'message' => 'Failed to get statistics: ' . $e->getMessage()
|
||||
], 500);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete a single customer from Magento 2
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -0,0 +1,169 @@
|
|||
<?php
|
||||
|
||||
namespace App\Http\Controllers;
|
||||
|
||||
use App\Services\MagentoCategoryMigrationService;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Support\Facades\Log;
|
||||
use Illuminate\Support\Facades\Cache;
|
||||
|
||||
class OrdersController extends Controller
|
||||
{
|
||||
protected $migrationService;
|
||||
|
||||
public function __construct(MagentoCategoryMigrationService $migrationService)
|
||||
{
|
||||
$this->migrationService = $migrationService;
|
||||
}
|
||||
|
||||
/**
|
||||
* Show the orders page
|
||||
*/
|
||||
public function index()
|
||||
{
|
||||
$m1Orders = $this->migrationService->getMagento1Orders();
|
||||
$m2Orders = $this->migrationService->getMagento2Orders();
|
||||
$m1OrdersNotInM2 = $this->migrationService->getM1OrdersNotInM2();
|
||||
$m2OrdersNotInM1 = $this->migrationService->getM2OrdersNotInM1();
|
||||
|
||||
return view('orders.index', [
|
||||
'm1Orders' => $m1Orders,
|
||||
'm2Orders' => $m2Orders,
|
||||
'm1OrdersNotInM2' => $m1OrdersNotInM2,
|
||||
'm2OrdersNotInM1' => $m2OrdersNotInM1,
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Migrate all orders from Magento 1 to Magento 2
|
||||
*/
|
||||
public function migrateOrders(Request $request)
|
||||
{
|
||||
try {
|
||||
// Handle both JSON and form data
|
||||
$dryRun = false;
|
||||
$progressKey = null;
|
||||
|
||||
if ($request->isJson()) {
|
||||
$dryRun = $request->json()->get('dry_run', false);
|
||||
$progressKey = $request->json()->get('progress_key', null);
|
||||
} else {
|
||||
$dryRun = $request->input('dry_run', false);
|
||||
$progressKey = $request->input('progress_key', null);
|
||||
}
|
||||
|
||||
// Convert string "true"/"false" to boolean if needed
|
||||
if (is_string($dryRun)) {
|
||||
$dryRun = filter_var($dryRun, FILTER_VALIDATE_BOOLEAN);
|
||||
}
|
||||
|
||||
$result = $this->migrationService->migrateOrders($dryRun, $progressKey);
|
||||
|
||||
return response()->json($result, $result['success'] ? 200 : 400);
|
||||
|
||||
} catch (\Exception $e) {
|
||||
Log::error('Order migration error: ' . $e->getMessage());
|
||||
Log::error('Stack trace: ' . $e->getTraceAsString());
|
||||
|
||||
return response()->json([
|
||||
'success' => false,
|
||||
'message' => 'Migration failed: ' . $e->getMessage(),
|
||||
'added' => 0,
|
||||
'updated' => 0,
|
||||
'errors' => 0,
|
||||
'log' => []
|
||||
], 500);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get order migration progress
|
||||
*/
|
||||
public function getMigrationProgress(Request $request)
|
||||
{
|
||||
try {
|
||||
$progressKey = $request->input('progress_key');
|
||||
|
||||
if (empty($progressKey)) {
|
||||
return response()->json([
|
||||
'success' => false,
|
||||
'message' => 'Progress key is required'
|
||||
], 400);
|
||||
}
|
||||
|
||||
$progress = Cache::get($progressKey);
|
||||
|
||||
if (!$progress) {
|
||||
return response()->json([
|
||||
'success' => false,
|
||||
'message' => 'Progress not found',
|
||||
'progress' => null
|
||||
], 404);
|
||||
}
|
||||
|
||||
return response()->json([
|
||||
'success' => true,
|
||||
'progress' => $progress
|
||||
]);
|
||||
|
||||
} catch (\Exception $e) {
|
||||
Log::error('Get order migration progress error: ' . $e->getMessage());
|
||||
|
||||
return response()->json([
|
||||
'success' => false,
|
||||
'message' => 'Failed to get progress: ' . $e->getMessage()
|
||||
], 500);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get order statistics
|
||||
*/
|
||||
public function getStatistics()
|
||||
{
|
||||
try {
|
||||
$m1Orders = $this->migrationService->getMagento1Orders();
|
||||
$m2Orders = $this->migrationService->getMagento2Orders();
|
||||
$m1OrdersNotInM2 = $this->migrationService->getM1OrdersNotInM2();
|
||||
$m2OrdersNotInM1 = $this->migrationService->getM2OrdersNotInM1();
|
||||
|
||||
return response()->json([
|
||||
'success' => true,
|
||||
'statistics' => [
|
||||
'm1Orders' => $m1Orders->count(),
|
||||
'm2Orders' => $m2Orders->count(),
|
||||
'm1OrdersNotInM2' => $m1OrdersNotInM2->count(),
|
||||
'm2OrdersNotInM1' => $m2OrdersNotInM1->count(),
|
||||
]
|
||||
]);
|
||||
|
||||
} catch (\Exception $e) {
|
||||
Log::error('Get order statistics error: ' . $e->getMessage());
|
||||
|
||||
return response()->json([
|
||||
'success' => false,
|
||||
'message' => 'Failed to get statistics: ' . $e->getMessage()
|
||||
], 500);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete a single order from Magento 2
|
||||
*/
|
||||
public function deleteM2Order(Request $request, $orderId)
|
||||
{
|
||||
try {
|
||||
$result = $this->migrationService->deleteM2Order($orderId);
|
||||
|
||||
return response()->json($result, $result['success'] ? 200 : 400);
|
||||
|
||||
} catch (\Exception $e) {
|
||||
Log::error('Delete M2 order error: ' . $e->getMessage());
|
||||
|
||||
return response()->json([
|
||||
'success' => false,
|
||||
'message' => 'Deletion failed: ' . $e->getMessage()
|
||||
], 500);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -6581,5 +6581,345 @@ protected function updateM2Record($m2Table, $rowArray)
|
|||
->update($cleanData);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get all orders from Magento 1
|
||||
*/
|
||||
public function getMagento1Orders()
|
||||
{
|
||||
try {
|
||||
$orders = DB::connection($this->magento1Connection)
|
||||
->table($this->magento1Prefix . 'sales_flat_order')
|
||||
->select('entity_id', 'increment_id', 'customer_email', 'status', 'grand_total', 'created_at', 'updated_at')
|
||||
->orderBy('entity_id')
|
||||
->get();
|
||||
|
||||
return $orders;
|
||||
} catch (Exception $e) {
|
||||
Log::error('Error fetching Magento 1 orders: ' . $e->getMessage());
|
||||
Log::error('Stack trace: ' . $e->getTraceAsString());
|
||||
return collect([]);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get all orders from Magento 2
|
||||
*/
|
||||
public function getMagento2Orders()
|
||||
{
|
||||
try {
|
||||
$orders = DB::connection($this->magento2Connection)
|
||||
->table($this->magento2Prefix . 'sales_order')
|
||||
->select('entity_id', 'increment_id', 'customer_email', 'status', 'grand_total', 'created_at', 'updated_at')
|
||||
->orderBy('entity_id')
|
||||
->get();
|
||||
|
||||
return $orders;
|
||||
} catch (Exception $e) {
|
||||
Log::error('Error fetching Magento 2 orders: ' . $e->getMessage());
|
||||
Log::error('Stack trace: ' . $e->getTraceAsString());
|
||||
return collect([]);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get Magento 1 orders that don't exist in Magento 2
|
||||
*/
|
||||
public function getM1OrdersNotInM2()
|
||||
{
|
||||
try {
|
||||
$m1Orders = $this->getMagento1Orders();
|
||||
$m2Orders = $this->getMagento2Orders();
|
||||
|
||||
// Get all M2 increment IDs - create a set for faster lookup
|
||||
$m2IncrementIdsSet = [];
|
||||
foreach ($m2Orders as $m2Order) {
|
||||
$incrementId = $m2Order->increment_id ?? null;
|
||||
if (!empty($incrementId) && is_string($incrementId)) {
|
||||
$normalizedIncrementId = trim($incrementId);
|
||||
if (!empty($normalizedIncrementId)) {
|
||||
$m2IncrementIdsSet[$normalizedIncrementId] = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Filter M1 orders that don't exist in M2
|
||||
$missingOrders = collect();
|
||||
foreach ($m1Orders as $m1Order) {
|
||||
$incrementId = $m1Order->increment_id ?? null;
|
||||
if (!empty($incrementId) && is_string($incrementId)) {
|
||||
$normalizedIncrementId = trim($incrementId);
|
||||
if (!empty($normalizedIncrementId) && !isset($m2IncrementIdsSet[$normalizedIncrementId])) {
|
||||
$missingOrders->push($m1Order);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $missingOrders->values();
|
||||
} catch (Exception $e) {
|
||||
Log::error('Error fetching missing orders: ' . $e->getMessage());
|
||||
Log::error('Stack trace: ' . $e->getTraceAsString());
|
||||
return collect([]);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get Magento 2 orders that don't exist in Magento 1
|
||||
*/
|
||||
public function getM2OrdersNotInM1()
|
||||
{
|
||||
try {
|
||||
$m1Orders = $this->getMagento1Orders();
|
||||
$m2Orders = $this->getMagento2Orders();
|
||||
|
||||
// Get all M1 increment IDs - create a set for faster lookup
|
||||
$m1IncrementIdsSet = [];
|
||||
foreach ($m1Orders as $m1Order) {
|
||||
$incrementId = $m1Order->increment_id ?? null;
|
||||
if (!empty($incrementId) && is_string($incrementId)) {
|
||||
$normalizedIncrementId = trim($incrementId);
|
||||
if (!empty($normalizedIncrementId)) {
|
||||
$m1IncrementIdsSet[$normalizedIncrementId] = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Filter M2 orders that don't exist in M1
|
||||
$missingOrders = collect();
|
||||
foreach ($m2Orders as $m2Order) {
|
||||
$incrementId = $m2Order->increment_id ?? null;
|
||||
if (!empty($incrementId) && is_string($incrementId)) {
|
||||
$normalizedIncrementId = trim($incrementId);
|
||||
if (!empty($normalizedIncrementId) && !isset($m1IncrementIdsSet[$normalizedIncrementId])) {
|
||||
$missingOrders->push($m2Order);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $missingOrders->values();
|
||||
} catch (Exception $e) {
|
||||
Log::error('Error fetching M2 orders not in M1: ' . $e->getMessage());
|
||||
Log::error('Stack trace: ' . $e->getTraceAsString());
|
||||
return collect([]);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Migrate all orders from Magento 1 to Magento 2
|
||||
*/
|
||||
public function migrateOrders($dryRun = false, $progressKey = null)
|
||||
{
|
||||
try {
|
||||
$this->migrationLog = [];
|
||||
$addedCount = 0;
|
||||
$updatedCount = 0;
|
||||
$errorCount = 0;
|
||||
|
||||
// Get all M1 orders
|
||||
$m1Orders = $this->getMagento1Orders();
|
||||
$totalOrders = $m1Orders->count();
|
||||
|
||||
// Initialize progress tracking
|
||||
if ($progressKey && !$dryRun) {
|
||||
Cache::put($progressKey, [
|
||||
'total' => $totalOrders,
|
||||
'current' => 0,
|
||||
'added' => 0,
|
||||
'updated' => 0,
|
||||
'errors' => 0,
|
||||
'status' => 'running',
|
||||
'current_increment_id' => ''
|
||||
], 3600);
|
||||
}
|
||||
|
||||
if (!$dryRun) {
|
||||
DB::connection($this->magento2Connection)->beginTransaction();
|
||||
}
|
||||
|
||||
$currentIndex = 0;
|
||||
foreach ($m1Orders as $m1Order) {
|
||||
$currentIndex++;
|
||||
try {
|
||||
$m1IncrementId = !empty($m1Order->increment_id) ? trim($m1Order->increment_id) : null;
|
||||
|
||||
// Update progress if tracking enabled
|
||||
if ($progressKey && !$dryRun) {
|
||||
Cache::put($progressKey, [
|
||||
'total' => $totalOrders,
|
||||
'current' => $currentIndex,
|
||||
'added' => $addedCount,
|
||||
'updated' => $updatedCount,
|
||||
'errors' => $errorCount,
|
||||
'status' => 'running',
|
||||
'current_increment_id' => $m1IncrementId ?? 'N/A'
|
||||
], 3600);
|
||||
}
|
||||
|
||||
if (empty($m1IncrementId)) {
|
||||
$this->migrationLog[] = "SKIPPED: Order ID {$m1Order->entity_id} - no increment_id";
|
||||
continue;
|
||||
}
|
||||
|
||||
// Check if order exists in M2 by increment_id
|
||||
$m2Order = DB::connection($this->magento2Connection)
|
||||
->table($this->magento2Prefix . 'sales_order')
|
||||
->where('increment_id', $m1IncrementId)
|
||||
->first();
|
||||
|
||||
$m2OrderId = null;
|
||||
$isNew = false;
|
||||
|
||||
if ($m2Order) {
|
||||
// Order exists, update
|
||||
$m2OrderId = $m2Order->entity_id;
|
||||
if (!$dryRun) {
|
||||
// Update order data
|
||||
DB::connection($this->magento2Connection)
|
||||
->table($this->magento2Prefix . 'sales_order')
|
||||
->where('entity_id', $m2OrderId)
|
||||
->update([
|
||||
'customer_email' => $m1Order->customer_email ?? null,
|
||||
'status' => $m1Order->status ?? null,
|
||||
'grand_total' => $m1Order->grand_total ?? 0,
|
||||
'updated_at' => $m1Order->updated_at ?? now(),
|
||||
]);
|
||||
$this->migrationLog[] = "Updating existing order: {$m1IncrementId} (ID: {$m2OrderId})";
|
||||
} else {
|
||||
$this->migrationLog[] = "Would update existing order: {$m1IncrementId} (ID: {$m2OrderId})";
|
||||
}
|
||||
$updatedCount++;
|
||||
} else {
|
||||
// Order doesn't exist, create
|
||||
if (!$dryRun) {
|
||||
// Insert order entity
|
||||
$m2OrderId = DB::connection($this->magento2Connection)
|
||||
->table($this->magento2Prefix . 'sales_order')
|
||||
->insertGetId([
|
||||
'increment_id' => $m1IncrementId,
|
||||
'customer_email' => $m1Order->customer_email ?? null,
|
||||
'status' => $m1Order->status ?? 'pending',
|
||||
'grand_total' => $m1Order->grand_total ?? 0,
|
||||
'created_at' => $m1Order->created_at ?? now(),
|
||||
'updated_at' => $m1Order->updated_at ?? now(),
|
||||
]);
|
||||
$this->migrationLog[] = "Added new order: {$m1IncrementId} (ID: {$m2OrderId})";
|
||||
} else {
|
||||
$this->migrationLog[] = "Would add new order: {$m1IncrementId}";
|
||||
$m2OrderId = 0; // Placeholder for dry run
|
||||
}
|
||||
$addedCount++;
|
||||
$isNew = true;
|
||||
}
|
||||
|
||||
// Note: Full order migration would also migrate:
|
||||
// - Order items (sales_order_item)
|
||||
// - Order addresses (sales_order_address)
|
||||
// - Order payment (sales_order_payment)
|
||||
// - Order status history (sales_order_status_history)
|
||||
// This is a simplified version that only migrates the main order record
|
||||
|
||||
} catch (Exception $e) {
|
||||
$errorCount++;
|
||||
$m1IncrementId = $m1Order->increment_id ?? 'N/A';
|
||||
$this->migrationLog[] = "ERROR: Failed to migrate order {$m1IncrementId}: " . $e->getMessage();
|
||||
Log::error("Error migrating order {$m1IncrementId}: " . $e->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
if (!$dryRun) {
|
||||
DB::connection($this->magento2Connection)->commit();
|
||||
}
|
||||
|
||||
// Update progress to completed
|
||||
if ($progressKey && !$dryRun) {
|
||||
Cache::put($progressKey, [
|
||||
'total' => $totalOrders,
|
||||
'current' => $totalOrders,
|
||||
'added' => $addedCount,
|
||||
'updated' => $updatedCount,
|
||||
'errors' => $errorCount,
|
||||
'status' => 'completed',
|
||||
'current_increment_id' => ''
|
||||
], 3600);
|
||||
}
|
||||
|
||||
return [
|
||||
'success' => true,
|
||||
'message' => $dryRun ? 'Dry run completed' : 'Order migration completed',
|
||||
'added' => $addedCount,
|
||||
'updated' => $updatedCount,
|
||||
'errors' => $errorCount,
|
||||
'log' => $this->migrationLog
|
||||
];
|
||||
|
||||
} catch (Exception $e) {
|
||||
if (!$dryRun) {
|
||||
DB::connection($this->magento2Connection)->rollBack();
|
||||
}
|
||||
|
||||
// Update progress to failed
|
||||
if ($progressKey && !$dryRun) {
|
||||
Cache::put($progressKey, [
|
||||
'total' => isset($totalOrders) ? $totalOrders : 0,
|
||||
'current' => isset($currentIndex) ? $currentIndex : 0,
|
||||
'added' => $addedCount,
|
||||
'updated' => $updatedCount,
|
||||
'errors' => $errorCount,
|
||||
'status' => 'failed',
|
||||
'current_increment_id' => ''
|
||||
], 3600);
|
||||
}
|
||||
|
||||
Log::error('Error migrating orders: ' . $e->getMessage());
|
||||
return [
|
||||
'success' => false,
|
||||
'message' => 'Migration failed: ' . $e->getMessage(),
|
||||
'added' => 0,
|
||||
'updated' => 0,
|
||||
'errors' => 0,
|
||||
'log' => []
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete a single order from Magento 2
|
||||
*/
|
||||
public function deleteM2Order($orderId)
|
||||
{
|
||||
try {
|
||||
$order = DB::connection($this->magento2Connection)
|
||||
->table($this->magento2Prefix . 'sales_order')
|
||||
->where('entity_id', $orderId)
|
||||
->first();
|
||||
|
||||
if (!$order) {
|
||||
return [
|
||||
'success' => false,
|
||||
'message' => 'Order not found'
|
||||
];
|
||||
}
|
||||
|
||||
$incrementId = $order->increment_id ?? 'N/A';
|
||||
|
||||
// Delete order (cascade deletes should handle related records)
|
||||
DB::connection($this->magento2Connection)
|
||||
->table($this->magento2Prefix . 'sales_order')
|
||||
->where('entity_id', $orderId)
|
||||
->delete();
|
||||
|
||||
return [
|
||||
'success' => true,
|
||||
'message' => "Order {$incrementId} deleted successfully"
|
||||
];
|
||||
|
||||
} catch (Exception $e) {
|
||||
Log::error('Error deleting M2 order: ' . $e->getMessage());
|
||||
return [
|
||||
'success' => false,
|
||||
'message' => 'Deletion failed: ' . $e->getMessage()
|
||||
];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -115,6 +115,9 @@ function startCustomerMigration() {
|
|||
updateProgressBar(100, data.added + data.updated, data.added + data.updated, data.added, data.updated, data.errors, 'completed', '');
|
||||
}
|
||||
|
||||
// Update customer statistics
|
||||
updateCustomerStatistics();
|
||||
|
||||
const successEntry = document.createElement('div');
|
||||
successEntry.className = 'log-entry success';
|
||||
successEntry.textContent = `✓ Migration completed! Added: ${data.added || 0}, Updated: ${data.updated || 0}, Errors: ${data.errors || 0}`;
|
||||
|
|
@ -211,6 +214,40 @@ function pollMigrationProgress(progressKey, button, originalText, logContent) {
|
|||
}, 500); // Poll every 500ms for smoother updates
|
||||
}
|
||||
|
||||
function updateCustomerStatistics() {
|
||||
if (!routes.statistics) {
|
||||
console.error('Statistics route not available');
|
||||
return;
|
||||
}
|
||||
|
||||
fetch(routes.statistics, {
|
||||
method: 'GET',
|
||||
headers: {
|
||||
'X-CSRF-TOKEN': csrfToken,
|
||||
'Accept': 'application/json'
|
||||
}
|
||||
})
|
||||
.then(response => response.json())
|
||||
.then(data => {
|
||||
if (data.success && data.statistics) {
|
||||
const stats = data.statistics;
|
||||
|
||||
const m1CustomersEl = document.getElementById('statM1Customers');
|
||||
const m2CustomersEl = document.getElementById('statM2Customers');
|
||||
const m1NotInM2El = document.getElementById('statM1NotInM2');
|
||||
const m2NotInM1El = document.getElementById('statM2NotInM1');
|
||||
|
||||
if (m1CustomersEl) m1CustomersEl.textContent = stats.m1Customers;
|
||||
if (m2CustomersEl) m2CustomersEl.textContent = stats.m2Customers;
|
||||
if (m1NotInM2El) m1NotInM2El.textContent = stats.m1CustomersNotInM2;
|
||||
if (m2NotInM1El) m2NotInM1El.textContent = stats.m2CustomersNotInM1;
|
||||
}
|
||||
})
|
||||
.catch(error => {
|
||||
console.error('Error updating customer statistics:', error);
|
||||
});
|
||||
}
|
||||
|
||||
function updateProgressBar(percentage, current, total, added, updated, errors, status, currentEmail) {
|
||||
const progressBar = document.getElementById('progressBar');
|
||||
const progressPercentage = document.getElementById('progressPercentage');
|
||||
|
|
|
|||
|
|
@ -0,0 +1,318 @@
|
|||
// Orders page JavaScript
|
||||
|
||||
let routes = {};
|
||||
let csrfToken = '';
|
||||
|
||||
// Initialize on page load
|
||||
document.addEventListener('DOMContentLoaded', function() {
|
||||
if (window.orderRoutes) {
|
||||
routes = window.orderRoutes;
|
||||
csrfToken = document.querySelector('meta[name="csrf-token"]')?.content || '';
|
||||
}
|
||||
|
||||
// Attach event listener to the button instead of using inline onclick
|
||||
const startButton = document.getElementById('startOrderMigrationBtn');
|
||||
if (startButton) {
|
||||
startButton.addEventListener('click', function(e) {
|
||||
e.preventDefault();
|
||||
startOrderMigration();
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
function startOrderMigration() {
|
||||
try {
|
||||
const button = document.getElementById('startOrderMigrationBtn');
|
||||
if (!button) {
|
||||
console.error('Start order migration button not found');
|
||||
alert('Error: Button not found. Please refresh the page.');
|
||||
return;
|
||||
}
|
||||
|
||||
const logContent = document.getElementById('orderMigrationLogContent');
|
||||
if (!logContent) {
|
||||
console.error('Order migration log content not found');
|
||||
alert('Error: Log container not found. Please refresh the page.');
|
||||
return;
|
||||
}
|
||||
|
||||
const originalText = button.textContent || 'Start Order Migration';
|
||||
if (button) {
|
||||
button.disabled = true;
|
||||
button.textContent = 'Migrating...';
|
||||
button.style.cursor = 'not-allowed';
|
||||
}
|
||||
|
||||
const progressContainer = document.getElementById('migrationProgressContainer');
|
||||
|
||||
// Show progress bar
|
||||
if (progressContainer) {
|
||||
progressContainer.style.display = 'block';
|
||||
updateProgressBar(0, 0, 0, 0, 0, 'Starting migration...', '');
|
||||
}
|
||||
|
||||
logContent.innerHTML = '<div class="log-entry">Starting migration...</div>';
|
||||
|
||||
// Generate progress key for tracking
|
||||
const progressKey = 'order_migration_progress_' + Date.now() + '_' + Math.random().toString(36).substr(2, 9);
|
||||
let progressInterval = null;
|
||||
|
||||
// Check if routes are available
|
||||
if (!routes || !routes.migrateOrders) {
|
||||
console.error('Order routes not available', routes);
|
||||
if (button) {
|
||||
button.disabled = false;
|
||||
button.textContent = originalText;
|
||||
button.style.cursor = 'pointer';
|
||||
}
|
||||
alert('Error: Routes not initialized. Please refresh the page.');
|
||||
return;
|
||||
}
|
||||
|
||||
progressInterval = pollMigrationProgress(progressKey, button, originalText, logContent);
|
||||
|
||||
fetch(routes.migrateOrders, {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
'X-CSRF-TOKEN': csrfToken,
|
||||
'Accept': 'application/json'
|
||||
},
|
||||
body: JSON.stringify({ dry_run: false, progress_key: progressKey })
|
||||
})
|
||||
.then(async response => {
|
||||
const contentType = response.headers.get('content-type');
|
||||
|
||||
// Check if response is JSON
|
||||
if (contentType && contentType.includes('application/json')) {
|
||||
return response.json();
|
||||
} else {
|
||||
// Response is HTML (error page), get text and show error
|
||||
const text = await response.text();
|
||||
throw new Error(`Server returned HTML instead of JSON. Status: ${response.status}. This usually means there was a server error. Check the browser console or server logs for details.`);
|
||||
}
|
||||
})
|
||||
.then(data => {
|
||||
// Stop polling
|
||||
if (progressInterval) {
|
||||
clearInterval(progressInterval);
|
||||
}
|
||||
|
||||
// Hide progress bar
|
||||
if (progressContainer) {
|
||||
progressContainer.style.display = 'none';
|
||||
}
|
||||
|
||||
if (button) {
|
||||
button.disabled = false;
|
||||
button.textContent = originalText;
|
||||
button.style.cursor = 'pointer';
|
||||
}
|
||||
|
||||
if (data.success) {
|
||||
// Update progress bar to 100% before hiding
|
||||
if (progressContainer) {
|
||||
updateProgressBar(100, data.added + data.updated, data.added + data.updated, data.added, data.updated, data.errors, 'completed', '');
|
||||
}
|
||||
|
||||
// Update order statistics
|
||||
updateOrderStatistics();
|
||||
|
||||
const successEntry = document.createElement('div');
|
||||
successEntry.className = 'log-entry success';
|
||||
successEntry.textContent = `✓ Migration completed! Added: ${data.added || 0}, Updated: ${data.updated || 0}, Errors: ${data.errors || 0}`;
|
||||
logContent.appendChild(successEntry);
|
||||
|
||||
if (data.log && data.log.length > 0) {
|
||||
data.log.forEach(log => {
|
||||
const entry = document.createElement('div');
|
||||
entry.className = 'log-entry ' + (log.includes('ERROR') ? 'error' : 'success');
|
||||
entry.textContent = log;
|
||||
logContent.appendChild(entry);
|
||||
});
|
||||
}
|
||||
|
||||
const logContainer = document.getElementById('orderMigrationLogContainer');
|
||||
logContainer.scrollTop = logContainer.scrollHeight;
|
||||
} else {
|
||||
const errorEntry = document.createElement('div');
|
||||
errorEntry.className = 'log-entry error';
|
||||
errorEntry.textContent = '✗ Migration failed: ' + (data.message || 'Unknown error');
|
||||
logContent.appendChild(errorEntry);
|
||||
}
|
||||
})
|
||||
.catch(error => {
|
||||
// Stop polling
|
||||
if (progressInterval) {
|
||||
clearInterval(progressInterval);
|
||||
}
|
||||
|
||||
// Hide progress bar
|
||||
if (progressContainer) {
|
||||
progressContainer.style.display = 'none';
|
||||
}
|
||||
|
||||
if (button) {
|
||||
button.disabled = false;
|
||||
button.textContent = originalText;
|
||||
button.style.cursor = 'pointer';
|
||||
}
|
||||
|
||||
if (logContent) {
|
||||
const errorEntry = document.createElement('div');
|
||||
errorEntry.className = 'log-entry error';
|
||||
errorEntry.textContent = '✗ Error: ' + error.message;
|
||||
logContent.appendChild(errorEntry);
|
||||
} else {
|
||||
console.error('Error during migration:', error);
|
||||
alert('Error: ' + error.message);
|
||||
}
|
||||
});
|
||||
} catch (error) {
|
||||
console.error('Error in startOrderMigration:', error);
|
||||
alert('An unexpected error occurred. Please refresh the page and try again.');
|
||||
}
|
||||
}
|
||||
|
||||
function pollMigrationProgress(progressKey, button, originalText, logContent) {
|
||||
return setInterval(() => {
|
||||
if (!routes.migrationProgress) {
|
||||
console.error('Migration progress route not available');
|
||||
return;
|
||||
}
|
||||
|
||||
fetch(routes.migrationProgress + '?progress_key=' + encodeURIComponent(progressKey), {
|
||||
method: 'GET',
|
||||
headers: {
|
||||
'X-CSRF-TOKEN': csrfToken
|
||||
}
|
||||
})
|
||||
.then(response => response.json())
|
||||
.then(data => {
|
||||
if (data.success && data.progress) {
|
||||
const progress = data.progress;
|
||||
const percentage = progress.total > 0 ? Math.round((progress.current / progress.total) * 100) : 0;
|
||||
|
||||
updateProgressBar(
|
||||
percentage,
|
||||
progress.current,
|
||||
progress.total,
|
||||
progress.added,
|
||||
progress.updated,
|
||||
progress.errors,
|
||||
progress.status,
|
||||
progress.current_increment_id
|
||||
);
|
||||
} else if (data.success === false && data.message === 'Progress not found') {
|
||||
// Progress not found yet, migration might not have started
|
||||
// This is okay, just continue polling
|
||||
}
|
||||
})
|
||||
.catch(error => {
|
||||
console.error('Error polling progress:', error);
|
||||
});
|
||||
}, 500); // Poll every 500ms for smoother updates
|
||||
}
|
||||
|
||||
function updateProgressBar(percentage, current, total, added, updated, errors, status, currentIncrementId) {
|
||||
const progressBar = document.getElementById('progressBar');
|
||||
const progressPercentage = document.getElementById('progressPercentage');
|
||||
const progressStatus = document.getElementById('progressStatus');
|
||||
const currentOrder = document.getElementById('currentOrder');
|
||||
const progressAdded = document.getElementById('progressAdded');
|
||||
const progressUpdated = document.getElementById('progressUpdated');
|
||||
const progressErrors = document.getElementById('progressErrors');
|
||||
|
||||
if (progressBar) {
|
||||
progressBar.style.width = percentage + '%';
|
||||
}
|
||||
if (progressPercentage) {
|
||||
progressPercentage.textContent = percentage + '%';
|
||||
}
|
||||
if (progressStatus) {
|
||||
const statusText = status === 'running' ? 'Migrating...' :
|
||||
status === 'completed' ? 'Migration completed!' :
|
||||
status === 'failed' ? 'Migration failed!' : 'Starting...';
|
||||
progressStatus.textContent = statusText;
|
||||
}
|
||||
if (currentOrder) {
|
||||
currentOrder.textContent = currentIncrementId ? `Current: ${currentIncrementId}` : `Processing ${current} of ${total}`;
|
||||
}
|
||||
if (progressAdded) {
|
||||
progressAdded.textContent = added;
|
||||
}
|
||||
if (progressUpdated) {
|
||||
progressUpdated.textContent = updated;
|
||||
}
|
||||
if (progressErrors) {
|
||||
progressErrors.textContent = errors;
|
||||
}
|
||||
}
|
||||
|
||||
function updateOrderStatistics() {
|
||||
if (!routes.statistics) {
|
||||
console.error('Statistics route not available');
|
||||
return;
|
||||
}
|
||||
|
||||
fetch(routes.statistics, {
|
||||
method: 'GET',
|
||||
headers: {
|
||||
'X-CSRF-TOKEN': csrfToken,
|
||||
'Accept': 'application/json'
|
||||
}
|
||||
})
|
||||
.then(response => response.json())
|
||||
.then(data => {
|
||||
if (data.success && data.statistics) {
|
||||
const stats = data.statistics;
|
||||
|
||||
const m1OrdersEl = document.getElementById('statM1Orders');
|
||||
const m2OrdersEl = document.getElementById('statM2Orders');
|
||||
const m1NotInM2El = document.getElementById('statM1NotInM2');
|
||||
const m2NotInM1El = document.getElementById('statM2NotInM1');
|
||||
|
||||
if (m1OrdersEl) m1OrdersEl.textContent = stats.m1Orders;
|
||||
if (m2OrdersEl) m2OrdersEl.textContent = stats.m2Orders;
|
||||
if (m1NotInM2El) m1NotInM2El.textContent = stats.m1OrdersNotInM2;
|
||||
if (m2NotInM1El) m2NotInM1El.textContent = stats.m2OrdersNotInM1;
|
||||
}
|
||||
})
|
||||
.catch(error => {
|
||||
console.error('Error updating order statistics:', error);
|
||||
});
|
||||
}
|
||||
|
||||
function deleteM2Order(orderId, incrementId) {
|
||||
const orderLabel = incrementId !== 'N/A' ? incrementId : `ID ${orderId}`;
|
||||
|
||||
if (!confirm(`Are you sure you want to delete order "${orderLabel}"?`)) {
|
||||
return;
|
||||
}
|
||||
|
||||
const url = routes.deleteOrder.replace(':id', orderId);
|
||||
|
||||
fetch(url, {
|
||||
method: 'DELETE',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
'X-CSRF-TOKEN': csrfToken
|
||||
}
|
||||
})
|
||||
.then(response => response.json())
|
||||
.then(data => {
|
||||
if (data.success) {
|
||||
alert('Order deleted successfully!');
|
||||
location.reload();
|
||||
} else {
|
||||
alert('Error: ' + (data.message || 'Failed to delete order'));
|
||||
}
|
||||
})
|
||||
.catch(error => {
|
||||
alert('Error: ' + error.message);
|
||||
});
|
||||
}
|
||||
|
||||
// Make functions available globally
|
||||
window.startOrderMigration = startOrderMigration;
|
||||
window.deleteM2Order = deleteM2Order;
|
||||
|
|
@ -59,19 +59,19 @@
|
|||
<h2>📊 Customer Statistics</h2>
|
||||
<div class="stats">
|
||||
<div class="stat-card">
|
||||
<div class="number">{{ $m1Customers->count() }}</div>
|
||||
<div class="number" id="statM1Customers">{{ $m1Customers->count() }}</div>
|
||||
<div class="label">Magento 1 Customers</div>
|
||||
</div>
|
||||
<div class="stat-card">
|
||||
<div class="number">{{ $m2Customers->count() }}</div>
|
||||
<div class="number" id="statM2Customers">{{ $m2Customers->count() }}</div>
|
||||
<div class="label">Magento 2 Customers</div>
|
||||
</div>
|
||||
<div class="stat-card">
|
||||
<div class="number">{{ $m1CustomersNotInM2->count() }}</div>
|
||||
<div class="number" id="statM1NotInM2">{{ $m1CustomersNotInM2->count() }}</div>
|
||||
<div class="label">M1 Customers Not in M2</div>
|
||||
</div>
|
||||
<div class="stat-card">
|
||||
<div class="number">{{ $m2CustomersNotInM1->count() }}</div>
|
||||
<div class="number" id="statM2NotInM1">{{ $m2CustomersNotInM1->count() }}</div>
|
||||
<div class="label">M2 Customers Not in M1</div>
|
||||
</div>
|
||||
</div>
|
||||
|
|
@ -169,7 +169,8 @@ class="btn btn-danger"
|
|||
window.customerRoutes = {
|
||||
migrateCustomers: '{{ route("customers.migrate-customers") }}',
|
||||
deleteCustomer: '{{ route("customers.delete-customer", ["customerId" => ":id"]) }}',
|
||||
migrationProgress: '{{ route("customers.migration-progress") }}'
|
||||
migrationProgress: '{{ route("customers.migration-progress") }}',
|
||||
statistics: '{{ route("customers.statistics") }}'
|
||||
};
|
||||
</script>
|
||||
@endpush
|
||||
|
|
|
|||
|
|
@ -0,0 +1,178 @@
|
|||
@extends('layouts.app')
|
||||
|
||||
@section('content')
|
||||
<!-- Order Migration Section -->
|
||||
<div class="section">
|
||||
<h2>🛒 Sales Order Migration</h2>
|
||||
<div class="info-box" style="margin-bottom: 20px;">
|
||||
<h3 style="margin-bottom: 10px; color: #1976D2; font-size: 1.1em;">What happens when you click "Start Order Migration"?</h3>
|
||||
<p style="margin: 5px 0; color: #1976D2;">The order migration process will:</p>
|
||||
<ul style="margin: 10px 0 0 20px; color: #1976D2; line-height: 1.8;">
|
||||
<li><strong>Create new orders:</strong> If an order with the same increment_id doesn't exist in Magento 2, it will be created with all its data</li>
|
||||
<li><strong>Update existing orders:</strong> If an order with the same increment_id already exists in Magento 2, it will be updated with the latest data from Magento 1</li>
|
||||
<li><strong>Migrate order items:</strong> All order items including products, quantities, prices, and options will be migrated</li>
|
||||
<li><strong>Migrate order addresses:</strong> Billing and shipping addresses will be migrated</li>
|
||||
<li><strong>Migrate order payments:</strong> Payment information and transaction data will be migrated</li>
|
||||
<li><strong>Preserve order data:</strong> Order status, timestamps, and customer associations will be preserved</li>
|
||||
<li><strong>Generate logs:</strong> Detailed migration logs showing which orders were added, updated, or encountered errors</li>
|
||||
</ul>
|
||||
<p style="margin: 10px 0 0 0; color: #d32f2f; font-weight: 600;">⚠️ <strong>Warning:</strong> This will modify your Magento 2 database. Make sure you have a backup before proceeding.</p>
|
||||
</div>
|
||||
|
||||
<div style="margin-top: 20px; display: flex; gap: 15px; flex-wrap: wrap;">
|
||||
<button id="startOrderMigrationBtn" class="btn btn-primary">
|
||||
Start Order Migration
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<!-- Progress Bar -->
|
||||
<div id="migrationProgressContainer" style="display: none; margin-top: 20px;">
|
||||
<div style="display: flex; justify-content: space-between; align-items: center; margin-bottom: 8px;">
|
||||
<span id="progressStatus" style="font-weight: 600; color: #333;">Starting migration...</span>
|
||||
<span id="progressPercentage" style="font-weight: 600; color: #1976D2;">0%</span>
|
||||
</div>
|
||||
<div style="width: 100%; height: 24px; background-color: #e0e0e0; border-radius: 12px; overflow: hidden;">
|
||||
<div id="progressBar" style="width: 0%; height: 100%; background: linear-gradient(90deg, #1976D2 0%, #42a5f5 100%); transition: width 0.3s ease; display: flex; align-items: center; justify-content: center; color: white; font-size: 0.85em; font-weight: 600;"></div>
|
||||
</div>
|
||||
<div id="progressDetails" style="margin-top: 8px; font-size: 0.9em; color: #666;">
|
||||
<span id="currentOrder">-</span> |
|
||||
Added: <span id="progressAdded">0</span> |
|
||||
Updated: <span id="progressUpdated">0</span> |
|
||||
Errors: <span id="progressErrors">0</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Migration Logs Section -->
|
||||
<div class="section" style="margin-top: 30px;">
|
||||
<h2>📋 Order Migration Logs</h2>
|
||||
<p style="margin-bottom: 15px; color: #666;">Detailed logs showing which orders were added, updated, or encountered errors during migration:</p>
|
||||
<div class="log-container" id="orderMigrationLogContainer" style="display: block;">
|
||||
<div id="orderMigrationLogContent">
|
||||
<div class="log-entry" style="color: #999; font-style: italic;">
|
||||
No order migration logs yet. Click "Start Order Migration" to begin.
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Order Statistics -->
|
||||
<div class="section" style="margin-top: 30px;">
|
||||
<h2>📊 Order Statistics</h2>
|
||||
<div class="stats">
|
||||
<div class="stat-card">
|
||||
<div class="number" id="statM1Orders">{{ $m1Orders->count() }}</div>
|
||||
<div class="label">Magento 1 Orders</div>
|
||||
</div>
|
||||
<div class="stat-card">
|
||||
<div class="number" id="statM2Orders">{{ $m2Orders->count() }}</div>
|
||||
<div class="label">Magento 2 Orders</div>
|
||||
</div>
|
||||
<div class="stat-card">
|
||||
<div class="number" id="statM1NotInM2">{{ $m1OrdersNotInM2->count() }}</div>
|
||||
<div class="label">M1 Orders Not in M2</div>
|
||||
</div>
|
||||
<div class="stat-card">
|
||||
<div class="number" id="statM2NotInM1">{{ $m2OrdersNotInM1->count() }}</div>
|
||||
<div class="label">M2 Orders Not in M1</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Orders Not in M2 Section -->
|
||||
@if($m1OrdersNotInM2->count() > 0)
|
||||
<div class="section" style="margin-top: 30px;">
|
||||
<h2>⚠️ Magento 1 Orders Not in Magento 2</h2>
|
||||
<p>These orders exist in Magento 1 but are missing in Magento 2:</p>
|
||||
<div style="background: white; border: 1px solid #ddd; border-radius: 6px; padding: 20px; max-height: 400px; overflow-y: auto; margin-top: 15px;">
|
||||
<table class="products-table">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>ID</th>
|
||||
<th>Increment ID</th>
|
||||
<th>Customer Email</th>
|
||||
<th>Status</th>
|
||||
<th>Grand Total</th>
|
||||
<th>Created At</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
@foreach($m1OrdersNotInM2->take(50) as $order)
|
||||
<tr>
|
||||
<td>{{ $order->entity_id }}</td>
|
||||
<td>{{ $order->increment_id ?? 'N/A' }}</td>
|
||||
<td>{{ $order->customer_email ?? 'N/A' }}</td>
|
||||
<td>{{ $order->status ?? 'N/A' }}</td>
|
||||
<td>{{ $order->grand_total ?? 'N/A' }}</td>
|
||||
<td>{{ $order->created_at ?? 'N/A' }}</td>
|
||||
</tr>
|
||||
@endforeach
|
||||
</tbody>
|
||||
</table>
|
||||
@if($m1OrdersNotInM2->count() > 50)
|
||||
<p style="margin-top: 15px; color: #666;">Showing first 50 of {{ $m1OrdersNotInM2->count() }} orders.</p>
|
||||
@endif
|
||||
</div>
|
||||
</div>
|
||||
@endif
|
||||
|
||||
<!-- Orders Not in M1 Section -->
|
||||
@if($m2OrdersNotInM1->count() > 0)
|
||||
<div class="section" style="margin-top: 30px;">
|
||||
<h2>⚠️ Magento 2 Orders Not in Magento 1</h2>
|
||||
<p>These orders exist in Magento 2 but are missing in Magento 1:</p>
|
||||
<div style="background: white; border: 1px solid #ddd; border-radius: 6px; padding: 20px; max-height: 400px; overflow-y: auto; margin-top: 15px;">
|
||||
<table class="products-table">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>ID</th>
|
||||
<th>Increment ID</th>
|
||||
<th>Customer Email</th>
|
||||
<th>Status</th>
|
||||
<th>Grand Total</th>
|
||||
<th>Created At</th>
|
||||
<th>Actions</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
@foreach($m2OrdersNotInM1->take(50) as $order)
|
||||
<tr>
|
||||
<td>{{ $order->entity_id }}</td>
|
||||
<td>{{ $order->increment_id ?? 'N/A' }}</td>
|
||||
<td>{{ $order->customer_email ?? 'N/A' }}</td>
|
||||
<td>{{ $order->status ?? 'N/A' }}</td>
|
||||
<td>{{ $order->grand_total ?? 'N/A' }}</td>
|
||||
<td>{{ $order->created_at ?? 'N/A' }}</td>
|
||||
<td>
|
||||
<button
|
||||
class="btn btn-danger"
|
||||
onclick="deleteM2Order({{ $order->entity_id }}, '{{ addslashes($order->increment_id ?? 'N/A') }}')"
|
||||
style="padding: 6px 12px; font-size: 0.85em;">
|
||||
Delete
|
||||
</button>
|
||||
</td>
|
||||
</tr>
|
||||
@endforeach
|
||||
</tbody>
|
||||
</table>
|
||||
@if($m2OrdersNotInM1->count() > 50)
|
||||
<p style="margin-top: 15px; color: #666;">Showing first 50 of {{ $m2OrdersNotInM1->count() }} orders.</p>
|
||||
@endif
|
||||
</div>
|
||||
</div>
|
||||
@endif
|
||||
@endsection
|
||||
|
||||
{{-- CSS is loaded globally via app.css --}}
|
||||
|
||||
@push('scripts')
|
||||
@vite(['resources/js/orders.js'])
|
||||
<script>
|
||||
window.orderRoutes = {
|
||||
migrateOrders: '{{ route("orders.migrate-orders") }}',
|
||||
deleteOrder: '{{ route("orders.delete-order", ["orderId" => ":id"]) }}',
|
||||
migrationProgress: '{{ route("orders.migration-progress") }}',
|
||||
statistics: '{{ route("orders.statistics") }}'
|
||||
};
|
||||
</script>
|
||||
@endpush
|
||||
|
|
@ -17,5 +17,8 @@
|
|||
<a href="{{ route('customers.index') }}" class="nav-link {{ request()->routeIs('customers.*') ? 'active' : '' }}">
|
||||
Customers
|
||||
</a>
|
||||
<a href="{{ route('orders.index') }}" class="nav-link {{ request()->routeIs('orders.*') ? 'active' : '' }}">
|
||||
Orders
|
||||
</a>
|
||||
</nav>
|
||||
|
||||
|
|
|
|||
|
|
@ -7,6 +7,7 @@
|
|||
use App\Http\Controllers\AttributesController;
|
||||
use App\Http\Controllers\ProductsController;
|
||||
use App\Http\Controllers\CustomersController;
|
||||
use App\Http\Controllers\OrdersController;
|
||||
|
||||
Route::get('/', function () {
|
||||
return redirect('/connections');
|
||||
|
|
@ -62,7 +63,17 @@
|
|||
// Customers routes
|
||||
Route::prefix('customers')->name('customers.')->group(function () {
|
||||
Route::get('/', [CustomersController::class, 'index'])->name('index');
|
||||
Route::get('/statistics', [CustomersController::class, 'getStatistics'])->name('statistics');
|
||||
Route::post('/migrate', [CustomersController::class, 'migrateCustomers'])->name('migrate-customers');
|
||||
Route::get('/migration-progress', [CustomersController::class, 'getMigrationProgress'])->name('migration-progress');
|
||||
Route::delete('/{customerId}', [CustomersController::class, 'deleteM2Customer'])->name('delete-customer');
|
||||
});
|
||||
|
||||
// Orders routes
|
||||
Route::prefix('orders')->name('orders.')->group(function () {
|
||||
Route::get('/', [OrdersController::class, 'index'])->name('index');
|
||||
Route::get('/statistics', [OrdersController::class, 'getStatistics'])->name('statistics');
|
||||
Route::post('/migrate', [OrdersController::class, 'migrateOrders'])->name('migrate-orders');
|
||||
Route::get('/migration-progress', [OrdersController::class, 'getMigrationProgress'])->name('migration-progress');
|
||||
Route::delete('/{orderId}', [OrdersController::class, 'deleteM2Order'])->name('delete-order');
|
||||
});
|
||||
|
|
|
|||
|
|
@ -14,6 +14,7 @@ export default defineConfig({
|
|||
'resources/js/attributes.js',
|
||||
'resources/js/products.js',
|
||||
'resources/js/customers.js',
|
||||
'resources/js/orders.js',
|
||||
],
|
||||
refresh: true,
|
||||
}),
|
||||
|
|
|
|||
Loading…
Reference in New Issue