@ -51,8 +51,9 @@ function stageClients(db: DB, records: Record<string, string>[]): number {
)
)
const seen = new Set < string > ( )
const seen = new Set < string > ( )
const insert = db . prepare (
const insert = db . prepare (
` INSERT INTO stg_client (row_no, code, name, gstin, state_code, address, phone, email, status, problems)
` INSERT INTO stg_client (row_no, code, name, gstin, state_code, address, phone, email, status,
VALUES ( ? , ? , ? , ? , ? , ? , ? , ? , ? , ? ) ` ,
anydesk , os , district , sector , problems )
VALUES ( ? , ? , ? , ? , ? , ? , ? , ? , ? , ? , ? , ? , ? , ? ) ` ,
)
)
records . forEach ( ( r , i ) = > {
records . forEach ( ( r , i ) = > {
const problems : string [ ] = [ ]
const problems : string [ ] = [ ]
@ -68,6 +69,8 @@ function stageClients(db: DB, records: Record<string, string>[]): number {
insert . run (
insert . run (
i + 1 , code , r [ 'name' ] ? ? '' , gstin , r [ 'state_code' ] ? ? '' ,
i + 1 , code , r [ 'name' ] ? ? '' , gstin , r [ 'state_code' ] ? ? '' ,
r [ 'address' ] ? ? '' , r [ 'phone' ] ? ? '' , r [ 'email' ] ? ? '' , status ,
r [ 'address' ] ? ? '' , r [ 'phone' ] ? ? '' , r [ 'email' ] ? ? '' , status ,
// WS-F support-access fields — optional headers; absent columns stage as ''.
r [ 'anydesk' ] ? ? '' , r [ 'os' ] ? ? '' , r [ 'district' ] ? ? '' , r [ 'sector' ] ? ? '' ,
JSON . stringify ( problems ) ,
JSON . stringify ( problems ) ,
)
)
} )
} )
@ -117,9 +120,13 @@ function stageInvoices(db: DB, records: Record<string, string>[]): number {
export function stageCsv ( db : DB , kind : 'clients' | 'invoices' , csvText : string ) : { staged : number } {
export function stageCsv ( db : DB , kind : 'clients' | 'invoices' , csvText : string ) : { staged : number } {
const records = parseCsv ( csvText )
const records = parseCsv ( csvText )
const staged = kind === 'clients' ? stageClients ( db , records ) : stageInvoices ( db , records )
// One transaction: the DELETE + re-insert of the staging area and its audit row
writeAudit ( db , 'system' , 'stage' , ` stg_ ${ kind } ` , kind , undefined , { staged } )
// land (or roll back) together — same-txn audit rule.
return { staged }
return db . transaction ( ( ) = > {
const staged = kind === 'clients' ? stageClients ( db , records ) : stageInvoices ( db , records )
writeAudit ( db , 'system' , 'stage' , ` stg_ ${ kind } ` , kind , undefined , { staged } )
return { staged }
} ) ( )
}
}
// ---------- verification report ----------
// ---------- verification report ----------
@ -159,7 +166,8 @@ export function verificationReport(db: DB): VerificationReport {
interface StgClientRow {
interface StgClientRow {
row_no : number ; code : string ; name : string ; gstin : string ; state_code : string
row_no : number ; code : string ; name : string ; gstin : string ; state_code : string
address : string ; phone : string ; email : string ; status : string ; problems : string
address : string ; phone : string ; email : string ; status : string
anydesk : string ; os : string ; district : string ; sector : string ; problems : string
}
}
interface StgInvoiceRow {
interface StgInvoiceRow {
@ -195,9 +203,11 @@ export function commitImport(db: DB, userId: string): CommitResult {
// Clients — source 'apex' marks the cutover rows.
// Clients — source 'apex' marks the cutover rows.
const stgClients = db . prepare ( ` SELECT * FROM stg_client ORDER BY row_no ` ) . all ( ) as StgClientRow [ ]
const stgClients = db . prepare ( ` SELECT * FROM stg_client ORDER BY row_no ` ) . all ( ) as StgClientRow [ ]
const insertClient = db . prepare (
const insertClient = db . prepare (
` INSERT INTO client (id, code, name, gstin, state_code, address, contacts, status, source, created_at)
` INSERT INTO client (id, code, name, gstin, state_code, address, contacts, status,
VALUES ( ? , ? , ? , ? , ? , ? , ? , ? , 'apex' , ? ) ` ,
anydesk , os , district , sector , source , created_at )
VALUES ( ? , ? , ? , ? , ? , ? , ? , ? , ? , ? , ? , ? , 'apex' , ? ) ` ,
)
)
const orNull = ( v : string ) : string | null = > ( v !== '' ? v : null )
for ( const c of stgClients ) {
for ( const c of stgClients ) {
const id = uuidv7 ( )
const id = uuidv7 ( )
const contacts = c . phone !== '' || c . email !== ''
const contacts = c . phone !== '' || c . email !== ''
@ -210,7 +220,9 @@ export function commitImport(db: DB, userId: string): CommitResult {
insertClient . run (
insertClient . run (
id , c . code , c . name , c . gstin !== '' ? c.gstin : null ,
id , c . code , c . name , c . gstin !== '' ? c.gstin : null ,
c . state_code !== '' ? c.state_code : ourState , c . address ,
c . state_code !== '' ? c.state_code : ourState , c . address ,
JSON . stringify ( contacts ) , c . status !== '' ? c . status : 'active' , now ,
JSON . stringify ( contacts ) , c . status !== '' ? c . status : 'active' ,
// WS-F: the old book's support-access data rides the cutover, not re-keying.
orNull ( c . anydesk ) , orNull ( c . os ) , orNull ( c . district ) , orNull ( c . sector ) , now ,
)
)
writeAudit ( db , userId , 'import' , 'client' , id , undefined , { code : c.code , name : c.name , source : 'apex' } )
writeAudit ( db , userId , 'import' , 'client' , id , undefined , { code : c.code , name : c.name , source : 'apex' } )
}
}