MEGAINFRA-WEBAPP/scripts/migrations/2026-10-01-add-dn-line-posting.mjs
DEls ed69b517e8 Integrate agent work and add dashboard attention indicators
Remove repeated Plant, Financial and Workforce shortcut cards. Add site-scoped Plant and Financial sidebar attention status with automatic refresh.

Include accumulated delivery processing, purchase order recovery, supplier reconciliation, plant data and user management changes and audit records.
2026-10-04 21:53:32 +02:00

38 lines
3.8 KiB
JavaScript

/** Additive allocation storage. Dry-run by default; --apply backs up and verifies. */
import PocketBase from 'pocketbase';
import {mkdtemp,writeFile} from 'node:fs/promises';
import {tmpdir} from 'node:os';
import {join,resolve} from 'node:path';
import {fileURLToPath} from 'node:url';
import {equalJson} from './2026-09-30-add-supplier-reconciliation-rules.mjs';
const additions={
delivery_notes:[{name:'receiving_identity_key',type:'text',required:false,max:100}],
dn_batch_notes:[{name:'line_posting',type:'json',required:false,maxSize:2000000}],
delivery_note_items:[{name:'allocation_key',type:'text',required:false,max:100},{name:'source_line_keys',type:'json',required:false,maxSize:10000},{name:'booking',type:'json',required:false,maxSize:100000}],
dn_pipeline_locks:[{name:'scope_key',type:'text',required:false,max:100}],
};
export const normalizeIndex=sql=>sql.replace(/`/g,'').replace(/\s+/g,'').toLowerCase();
const indexes={delivery_notes:"CREATE UNIQUE INDEX idx_dn_receiving_identity ON delivery_notes (receiving_identity_key) WHERE receiving_identity_key != ''",delivery_note_items:'CREATE UNIQUE INDEX idx_dn_allocation_key ON delivery_note_items (allocation_key) WHERE allocation_key != \'\'',dn_pipeline_locks:'CREATE UNIQUE INDEX idx_dn_posting_scope ON dn_pipeline_locks (scope_key) WHERE scope_key != \'\''};
const pb=new PocketBase(process.env.NEXT_PUBLIC_POCKETBASE_URL||process.env.PB_URL);
async function main(){
if(process.argv.slice(2).some(a=>a!=='--apply'))throw Error('Only --apply supported');
if(process.env.POCKETBASE_ADMIN_TOKEN)pb.authStore.save(process.env.POCKETBASE_ADMIN_TOKEN);else await pb.collection('_superusers').authWithPassword(process.env.POCKETBASE_ADMIN_EMAIL,process.env.POCKETBASE_ADMIN_PASSWORD);
const schemas=await Promise.all(Object.keys(additions).map(n=>pb.collections.getOne(n)));
const dir=process.argv.includes('--apply')?await mkdtemp(join(tmpdir(),'mega-line-posting-schema-')):null;
for(const schema of schemas){
const key=schema.name.toLowerCase();const fields=additions[key];for(const f of fields){const e=schema.fields.find(v=>v.name===f.name);if(e&&(e.type!==f.type||e.required||(f.maxSize&&e.maxSize<f.maxSize)))throw Error(`Incompatible ${schema.name}.${f.name}`);}
const extra=fields.filter(f=>!schema.fields.some(v=>v.name===f.name));const index=indexes[key];
const updatedIndexes=index&&!schema.indexes.some(i=>normalizeIndex(i)===normalizeIndex(index))?[...schema.indexes,index]:schema.indexes;
console.log(JSON.stringify({collection:schema.name,addFields:extra.map(f=>f.name),addIndex:updatedIndexes.length>schema.indexes.length}));
if(!dir)continue;await writeFile(join(dir,schema.name+'.json'),JSON.stringify(schema,null,2),{mode:0o600});
if(!equalJson(schema,await pb.collections.getOne(schema.id)))throw Error('Schema changed');
await pb.collections.update(schema.id,{fields:[...schema.fields,...extra],indexes:updatedIndexes});
const after=await pb.collections.getOne(schema.id);
if(!equalJson(schema.fields,after.fields.filter(f=>!extra.some(e=>e.name===f.name))))throw Error('Existing fields changed');
for(const k of ['listRule','viewRule','createRule','updateRule','deleteRule'])if(!equalJson(schema[k],after[k]))throw Error('Access rules changed');
if(!equalJson(after.indexes.map(normalizeIndex),updatedIndexes.map(normalizeIndex)))throw Error('Index verification failed');
for(const field of fields){const verified=after.fields.find(f=>f.name===field.name);if(!verified||verified.type!==field.type||verified.required||field.maxSize&&verified.maxSize<field.maxSize||field.max&&verified.max<field.max)throw Error('Added field verification failed: '+field.name);}
}
if(dir)console.log('Schema backups: '+dir);
}
if(process.argv[1]&&resolve(process.argv[1])===fileURLToPath(import.meta.url))main().catch(e=>{console.error(e.status?`PocketBase HTTP ${e.status}`:e.message);process.exitCode=1;});