Get orders import started, get all needed products imported
This commit is contained in:
@@ -122,7 +122,6 @@ CREATE TABLE orders (
|
|||||||
billing_address TEXT,
|
billing_address TEXT,
|
||||||
canceled BOOLEAN DEFAULT false,
|
canceled BOOLEAN DEFAULT false,
|
||||||
FOREIGN KEY (pid) REFERENCES products(pid),
|
FOREIGN KEY (pid) REFERENCES products(pid),
|
||||||
FOREIGN KEY (SKU) REFERENCES products(SKU),
|
|
||||||
INDEX idx_order_number (order_number),
|
INDEX idx_order_number (order_number),
|
||||||
INDEX idx_customer (customer),
|
INDEX idx_customer (customer),
|
||||||
INDEX idx_date (date),
|
INDEX idx_date (date),
|
||||||
|
|||||||
@@ -238,7 +238,7 @@ async function importCategories(prodConnection, localConnection) {
|
|||||||
|
|
||||||
async function importProducts(prodConnection, localConnection) {
|
async function importProducts(prodConnection, localConnection) {
|
||||||
outputProgress({
|
outputProgress({
|
||||||
operation: 'Starting products import',
|
operation: 'Starting products import - Getting schema',
|
||||||
status: 'running'
|
status: 'running'
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -255,6 +255,27 @@ async function importProducts(prodConnection, localConnection) {
|
|||||||
|
|
||||||
const columnNames = columns.map(col => col.COLUMN_NAME);
|
const columnNames = columns.map(col => col.COLUMN_NAME);
|
||||||
|
|
||||||
|
// Get total count first for progress indication
|
||||||
|
outputProgress({
|
||||||
|
operation: 'Starting products import - Getting total count',
|
||||||
|
status: 'running'
|
||||||
|
});
|
||||||
|
|
||||||
|
const [countResult] = await prodConnection.query(`
|
||||||
|
SELECT COUNT(*) as total
|
||||||
|
FROM products p
|
||||||
|
LEFT JOIN product_last_sold pls ON p.pid = pls.pid
|
||||||
|
WHERE pls.date_sold >= DATE_SUB(CURRENT_DATE, INTERVAL 2 YEAR)
|
||||||
|
OR p.date_created >= DATE_SUB(CURRENT_DATE, INTERVAL 2 YEAR)
|
||||||
|
OR p.itemnumber LIKE 'chbx%'
|
||||||
|
`);
|
||||||
|
const totalProducts = countResult[0].total;
|
||||||
|
|
||||||
|
outputProgress({
|
||||||
|
operation: `Starting products import - Fetching ${totalProducts} products from production`,
|
||||||
|
status: 'running'
|
||||||
|
});
|
||||||
|
|
||||||
// Get products from production with optimized query
|
// Get products from production with optimized query
|
||||||
const [rows] = await prodConnection.query(`
|
const [rows] = await prodConnection.query(`
|
||||||
SELECT
|
SELECT
|
||||||
@@ -353,14 +374,16 @@ async function importProducts(prodConnection, localConnection) {
|
|||||||
WHERE active = 1
|
WHERE active = 1
|
||||||
GROUP BY pid
|
GROUP BY pid
|
||||||
) pcp ON p.pid = pcp.pid
|
) pcp ON p.pid = pcp.pid
|
||||||
WHERE p.date_created >= DATE_SUB(CURRENT_DATE, INTERVAL 2 YEAR)
|
WHERE (pls.date_sold >= DATE_SUB(CURRENT_DATE, INTERVAL 2 YEAR)
|
||||||
|
OR p.date_created >= DATE_SUB(CURRENT_DATE, INTERVAL 2 YEAR)
|
||||||
|
OR p.itemnumber LIKE 'chbx%')
|
||||||
GROUP BY p.pid
|
GROUP BY p.pid
|
||||||
`);
|
`);
|
||||||
|
|
||||||
let current = 0;
|
let current = 0;
|
||||||
const total = rows.length;
|
const total = rows.length;
|
||||||
|
|
||||||
// Process products in larger batches
|
// Process products in batches
|
||||||
const BATCH_SIZE = 100;
|
const BATCH_SIZE = 100;
|
||||||
for (let i = 0; i < rows.length; i += BATCH_SIZE) {
|
for (let i = 0; i < rows.length; i += BATCH_SIZE) {
|
||||||
const batch = rows.slice(i, i + BATCH_SIZE);
|
const batch = rows.slice(i, i + BATCH_SIZE);
|
||||||
@@ -478,20 +501,61 @@ async function importProducts(prodConnection, localConnection) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Helper function to get date ranges for chunked queries
|
||||||
|
async function getDateRanges(prodConnection, table, dateField, startYearsAgo = 2, chunkMonths = 3) {
|
||||||
|
const ranges = [];
|
||||||
|
const [result] = await prodConnection.query(`
|
||||||
|
SELECT
|
||||||
|
DATE_SUB(CURRENT_DATE, INTERVAL ? YEAR) as start_date,
|
||||||
|
CURRENT_DATE as end_date
|
||||||
|
`, [startYearsAgo]);
|
||||||
|
|
||||||
|
let currentDate = new Date(result[0].end_date);
|
||||||
|
const startDate = new Date(result[0].start_date);
|
||||||
|
|
||||||
|
while (currentDate > startDate) {
|
||||||
|
const rangeEnd = new Date(currentDate);
|
||||||
|
currentDate.setMonth(currentDate.getMonth() - chunkMonths);
|
||||||
|
const rangeStart = new Date(Math.max(currentDate, startDate));
|
||||||
|
|
||||||
|
ranges.push({
|
||||||
|
start: rangeStart.toISOString().split('T')[0],
|
||||||
|
end: rangeEnd.toISOString().split('T')[0]
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
return ranges;
|
||||||
|
}
|
||||||
|
|
||||||
async function importOrders(prodConnection, localConnection) {
|
async function importOrders(prodConnection, localConnection) {
|
||||||
outputProgress({
|
outputProgress({
|
||||||
operation: 'Starting orders import',
|
operation: 'Starting orders import - Getting total count',
|
||||||
status: 'running'
|
status: 'running'
|
||||||
});
|
});
|
||||||
|
|
||||||
const startTime = Date.now();
|
const startTime = Date.now();
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
// Get total count first for progress indication
|
||||||
|
const [countResult] = await prodConnection.query(`
|
||||||
|
SELECT COUNT(*) as total
|
||||||
|
FROM _order o
|
||||||
|
JOIN order_items oi ON o.order_id = oi.order_id
|
||||||
|
WHERE o.order_status >= 15
|
||||||
|
AND o.date_placed_onlydate >= DATE_SUB(CURRENT_DATE, INTERVAL 2 YEAR)
|
||||||
|
`);
|
||||||
|
const totalOrders = countResult[0].total;
|
||||||
|
|
||||||
|
outputProgress({
|
||||||
|
operation: `Starting orders import - Fetching ${totalOrders} orders from production`,
|
||||||
|
status: 'running'
|
||||||
|
});
|
||||||
|
|
||||||
// Get orders from production
|
// Get orders from production
|
||||||
const [rows] = await prodConnection.query(`
|
const [rows] = await prodConnection.query(`
|
||||||
SELECT
|
SELECT
|
||||||
oi.order_id AS order_number,
|
oi.order_id AS order_number,
|
||||||
oi.prod_pid AS product_id,
|
oi.prod_pid AS pid,
|
||||||
oi.prod_itemnumber AS SKU,
|
oi.prod_itemnumber AS SKU,
|
||||||
o.date_placed_onlydate AS date,
|
o.date_placed_onlydate AS date,
|
||||||
oi.prod_price_reg AS price,
|
oi.prod_price_reg AS price,
|
||||||
@@ -535,11 +599,31 @@ async function importOrders(prodConnection, localConnection) {
|
|||||||
let current = 0;
|
let current = 0;
|
||||||
const total = rows.length;
|
const total = rows.length;
|
||||||
|
|
||||||
|
// Start transaction
|
||||||
|
await localConnection.query('START TRANSACTION');
|
||||||
|
|
||||||
// Process in batches
|
// Process in batches
|
||||||
const BATCH_SIZE = 500;
|
const BATCH_SIZE = 500;
|
||||||
for (let i = 0; i < rows.length; i += BATCH_SIZE) {
|
for (let i = 0; i < rows.length; i += BATCH_SIZE) {
|
||||||
const batch = rows.slice(i, i + BATCH_SIZE);
|
const batch = rows.slice(i, i + BATCH_SIZE);
|
||||||
|
|
||||||
|
// Get unique product IDs from this batch
|
||||||
|
const productIds = [...new Set(batch.map(row => row.pid))];
|
||||||
|
|
||||||
|
// Verify all products exist
|
||||||
|
const [existingProducts] = await localConnection.query(
|
||||||
|
'SELECT pid FROM products WHERE pid IN (?)',
|
||||||
|
[productIds]
|
||||||
|
);
|
||||||
|
|
||||||
|
const existingProductIds = new Set(existingProducts.map(p => p.pid));
|
||||||
|
const missingProducts = productIds.filter(pid => !existingProductIds.has(pid));
|
||||||
|
|
||||||
|
if (missingProducts.length > 0) {
|
||||||
|
console.error('Missing products:', missingProducts);
|
||||||
|
throw new Error(`Products missing from database: ${missingProducts.join(', ')}`);
|
||||||
|
}
|
||||||
|
|
||||||
// Create placeholders for batch insert
|
// Create placeholders for batch insert
|
||||||
const placeholders = batch.map(() =>
|
const placeholders = batch.map(() =>
|
||||||
'(?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)'
|
'(?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)'
|
||||||
@@ -548,7 +632,7 @@ async function importOrders(prodConnection, localConnection) {
|
|||||||
// Flatten values for batch insert
|
// Flatten values for batch insert
|
||||||
const values = batch.flatMap(row => [
|
const values = batch.flatMap(row => [
|
||||||
row.order_number,
|
row.order_number,
|
||||||
row.product_id,
|
row.pid,
|
||||||
row.SKU,
|
row.SKU,
|
||||||
row.date,
|
row.date,
|
||||||
row.price,
|
row.price,
|
||||||
@@ -562,27 +646,35 @@ async function importOrders(prodConnection, localConnection) {
|
|||||||
row.canceled
|
row.canceled
|
||||||
]);
|
]);
|
||||||
|
|
||||||
await localConnection.query(`
|
try {
|
||||||
INSERT INTO orders (
|
await localConnection.query(`
|
||||||
order_number, product_id, SKU, date, price, quantity, discount,
|
INSERT INTO orders (
|
||||||
tax, tax_included, shipping, customer, customer_name, canceled
|
order_number, pid, SKU, date, price, quantity, discount,
|
||||||
)
|
tax, tax_included, shipping, customer, customer_name, canceled
|
||||||
VALUES ${placeholders}
|
)
|
||||||
ON DUPLICATE KEY UPDATE
|
VALUES ${placeholders}
|
||||||
price = VALUES(price),
|
ON DUPLICATE KEY UPDATE
|
||||||
quantity = VALUES(quantity),
|
price = VALUES(price),
|
||||||
discount = VALUES(discount),
|
quantity = VALUES(quantity),
|
||||||
tax = VALUES(tax),
|
discount = VALUES(discount),
|
||||||
tax_included = VALUES(tax_included),
|
tax = VALUES(tax),
|
||||||
shipping = VALUES(shipping),
|
tax_included = VALUES(tax_included),
|
||||||
customer_name = VALUES(customer_name),
|
shipping = VALUES(shipping),
|
||||||
canceled = VALUES(canceled)
|
customer_name = VALUES(customer_name),
|
||||||
`, values);
|
canceled = VALUES(canceled)
|
||||||
|
`, values);
|
||||||
|
} catch (insertError) {
|
||||||
|
console.error('Error inserting batch:', insertError);
|
||||||
|
throw insertError;
|
||||||
|
}
|
||||||
|
|
||||||
current += batch.length;
|
current += batch.length;
|
||||||
updateProgress(current, total, 'Orders import', startTime);
|
updateProgress(current, total, 'Orders import', startTime);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// If we get here, commit the transaction
|
||||||
|
await localConnection.query('COMMIT');
|
||||||
|
|
||||||
outputProgress({
|
outputProgress({
|
||||||
status: 'complete',
|
status: 'complete',
|
||||||
operation: 'Orders import completed',
|
operation: 'Orders import completed',
|
||||||
@@ -591,6 +683,8 @@ async function importOrders(prodConnection, localConnection) {
|
|||||||
duration: formatDuration((Date.now() - startTime) / 1000)
|
duration: formatDuration((Date.now() - startTime) / 1000)
|
||||||
});
|
});
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
|
// Rollback on error
|
||||||
|
await localConnection.query('ROLLBACK');
|
||||||
console.error('Error importing orders:', error);
|
console.error('Error importing orders:', error);
|
||||||
throw error;
|
throw error;
|
||||||
}
|
}
|
||||||
@@ -598,13 +692,18 @@ async function importOrders(prodConnection, localConnection) {
|
|||||||
|
|
||||||
async function importPurchaseOrders(prodConnection, localConnection) {
|
async function importPurchaseOrders(prodConnection, localConnection) {
|
||||||
outputProgress({
|
outputProgress({
|
||||||
operation: 'Starting purchase orders import',
|
operation: 'Starting purchase orders import - Initializing',
|
||||||
status: 'running'
|
status: 'running'
|
||||||
});
|
});
|
||||||
|
|
||||||
const startTime = Date.now();
|
const startTime = Date.now();
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
outputProgress({
|
||||||
|
operation: 'Starting purchase orders import - Fetching POs from production',
|
||||||
|
status: 'running'
|
||||||
|
});
|
||||||
|
|
||||||
// Get purchase orders from production
|
// Get purchase orders from production
|
||||||
const [rows] = await prodConnection.query(`
|
const [rows] = await prodConnection.query(`
|
||||||
SELECT
|
SELECT
|
||||||
@@ -710,6 +809,12 @@ async function importPurchaseOrders(prodConnection, localConnection) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Modify main function to handle cancellation and avoid process.exit
|
// Modify main function to handle cancellation and avoid process.exit
|
||||||
|
// Constants to control which imports run
|
||||||
|
const IMPORT_CATEGORIES = true;
|
||||||
|
const IMPORT_PRODUCTS = true;
|
||||||
|
const IMPORT_ORDERS = true;
|
||||||
|
const IMPORT_PURCHASE_ORDERS = true;
|
||||||
|
|
||||||
async function main() {
|
async function main() {
|
||||||
let ssh;
|
let ssh;
|
||||||
let prodConnection;
|
let prodConnection;
|
||||||
@@ -718,7 +823,7 @@ async function main() {
|
|||||||
try {
|
try {
|
||||||
outputProgress({
|
outputProgress({
|
||||||
status: 'running',
|
status: 'running',
|
||||||
operation: 'Starting import process',
|
operation: 'Starting import process',
|
||||||
message: 'Setting up connections...'
|
message: 'Setting up connections...'
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -735,19 +840,26 @@ async function main() {
|
|||||||
|
|
||||||
if (isImportCancelled) throw new Error('Import cancelled');
|
if (isImportCancelled) throw new Error('Import cancelled');
|
||||||
|
|
||||||
// First import all categories
|
// Run each import based on constants
|
||||||
await importCategories(prodConnection, localConnection);
|
if (IMPORT_CATEGORIES) {
|
||||||
if (isImportCancelled) throw new Error('Import cancelled');
|
await importCategories(prodConnection, localConnection);
|
||||||
|
if (isImportCancelled) throw new Error('Import cancelled');
|
||||||
|
}
|
||||||
|
|
||||||
// Then import products
|
if (IMPORT_PRODUCTS) {
|
||||||
await importProducts(prodConnection, localConnection);
|
await importProducts(prodConnection, localConnection);
|
||||||
if (isImportCancelled) throw new Error('Import cancelled');
|
if (isImportCancelled) throw new Error('Import cancelled');
|
||||||
|
}
|
||||||
|
|
||||||
await importOrders(prodConnection, localConnection);
|
if (IMPORT_ORDERS) {
|
||||||
if (isImportCancelled) throw new Error('Import cancelled');
|
await importOrders(prodConnection, localConnection);
|
||||||
|
if (isImportCancelled) throw new Error('Import cancelled');
|
||||||
|
}
|
||||||
|
|
||||||
await importPurchaseOrders(prodConnection, localConnection);
|
if (IMPORT_PURCHASE_ORDERS) {
|
||||||
if (isImportCancelled) throw new Error('Import cancelled');
|
await importPurchaseOrders(prodConnection, localConnection);
|
||||||
|
if (isImportCancelled) throw new Error('Import cancelled');
|
||||||
|
}
|
||||||
|
|
||||||
outputProgress({
|
outputProgress({
|
||||||
status: 'complete',
|
status: 'complete',
|
||||||
|
|||||||
Reference in New Issue
Block a user