2026-04-23 15:43:40 +02:00
|
|
|
import { createClient } from '@supabase/supabase-js';
|
|
|
|
|
|
|
|
|
|
const SUPABASE_URL = process.env.SUPABASE_URL || 'https://hwithddwaapyhnfwcesj.supabase.co';
|
2026-04-23 15:46:10 +02:00
|
|
|
const SUPABASE_KEY = process.env.SUPABASE_SERVICE_KEY || 'sb_publishable_fGXkh0bSrAOqSk2jWKAzSg_NJD9YPCv';
|
2026-04-23 15:43:40 +02:00
|
|
|
|
|
|
|
|
const supabase = createClient(SUPABASE_URL, SUPABASE_KEY);
|
|
|
|
|
|
|
|
|
|
export default async function handler(req, res) {
|
|
|
|
|
try {
|
2026-04-23 15:46:10 +02:00
|
|
|
console.log('Starting migration v2...');
|
2026-04-23 15:43:40 +02:00
|
|
|
|
2026-04-23 15:46:10 +02:00
|
|
|
// 1. Fetch products
|
|
|
|
|
const { data: products, error: pErr } = await supabase
|
2026-04-23 15:43:40 +02:00
|
|
|
.from('products')
|
|
|
|
|
.select('product_id, data')
|
2026-04-23 15:46:10 +02:00
|
|
|
.in('status', ['edited', 'synced', 'pending']); // Broaden to catch everything shifted
|
2026-04-23 15:43:40 +02:00
|
|
|
|
2026-04-23 15:46:10 +02:00
|
|
|
if (pErr) throw new pErr;
|
|
|
|
|
|
2026-04-23 15:43:40 +02:00
|
|
|
let pCount = 0;
|
2026-04-23 15:46:10 +02:00
|
|
|
if (products && products.length > 0) {
|
|
|
|
|
const updates = products.map(p => {
|
|
|
|
|
const oldData = p.data;
|
|
|
|
|
// Logic: if index 12 is a date/number, it's the old structure.
|
|
|
|
|
// In the new structure, index 12 is "PM Classification" (string/empty).
|
|
|
|
|
const valAt12 = oldData[12];
|
|
|
|
|
const isOld = typeof valAt12 === 'number' || (typeof valAt12 === 'string' && /^[0-9.]+$/.test(valAt12));
|
|
|
|
|
|
|
|
|
|
if (isOld && oldData.length < 110) { // Don't shift if already shifted
|
|
|
|
|
const newData = [...oldData];
|
|
|
|
|
newData.splice(12, 0, ''); // Shift
|
2026-04-23 15:43:40 +02:00
|
|
|
pCount++;
|
2026-04-23 15:46:10 +02:00
|
|
|
return supabase.from('products').update({ data: newData }).eq('product_id', p.product_id);
|
2026-04-23 15:43:40 +02:00
|
|
|
}
|
2026-04-23 15:46:10 +02:00
|
|
|
return null;
|
|
|
|
|
}).filter(Boolean);
|
|
|
|
|
|
|
|
|
|
// Run updates in parallel (limited) or batches if needed, but for 130 rows it's fine
|
|
|
|
|
await Promise.all(updates);
|
2026-04-23 15:43:40 +02:00
|
|
|
}
|
|
|
|
|
|
2026-04-23 15:46:10 +02:00
|
|
|
// 2. History
|
|
|
|
|
const { data: history, error: hErr } = await supabase.from('products_history').select('*');
|
|
|
|
|
if (hErr) throw hErr;
|
2026-04-23 15:43:40 +02:00
|
|
|
|
|
|
|
|
let hCount = 0;
|
2026-04-23 15:46:10 +02:00
|
|
|
if (history && history.length > 0) {
|
|
|
|
|
const hUpdates = history.map(h => {
|
2026-04-23 15:43:40 +02:00
|
|
|
let changed = false;
|
|
|
|
|
let nOld = h.old_data;
|
|
|
|
|
let nNew = h.new_data;
|
|
|
|
|
|
|
|
|
|
if (nOld && nOld.length >= 13 && (typeof nOld[12] === 'number' || (typeof nOld[12] === 'string' && /^[0-9.]+$/.test(nOld[12])))) {
|
|
|
|
|
nOld = [...nOld];
|
|
|
|
|
nOld.splice(12, 0, '');
|
|
|
|
|
changed = true;
|
|
|
|
|
}
|
|
|
|
|
if (nNew && nNew.length >= 13 && (typeof nNew[12] === 'number' || (typeof nNew[12] === 'string' && /^[0-9.]+$/.test(nNew[12])))) {
|
|
|
|
|
nNew = [...nNew];
|
|
|
|
|
nNew.splice(12, 0, '');
|
|
|
|
|
changed = true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (changed) {
|
|
|
|
|
hCount++;
|
2026-04-23 15:46:10 +02:00
|
|
|
return supabase.from('products_history').update({ old_data: nOld, new_data: nNew }).eq('id', h.id);
|
2026-04-23 15:43:40 +02:00
|
|
|
}
|
2026-04-23 15:46:10 +02:00
|
|
|
return null;
|
|
|
|
|
}).filter(Boolean);
|
|
|
|
|
await Promise.all(hUpdates);
|
2026-04-23 15:43:40 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return res.json({
|
|
|
|
|
success: true,
|
|
|
|
|
productsMigrated: pCount,
|
|
|
|
|
historyMigrated: hCount,
|
2026-04-23 15:46:10 +02:00
|
|
|
message: 'Migration v2 finished.'
|
2026-04-23 15:43:40 +02:00
|
|
|
});
|
|
|
|
|
} catch (err) {
|
2026-04-23 15:46:10 +02:00
|
|
|
console.error('Migration error:', err);
|
|
|
|
|
return res.status(500).json({ error: err.message, stack: err.stack });
|
2026-04-23 15:43:40 +02:00
|
|
|
}
|
|
|
|
|
}
|