50 lines
2.8 KiB
TypeScript
50 lines
2.8 KiB
TypeScript
import 'reflect-metadata';
|
|
import assert from 'node:assert/strict';
|
|
import { readFileSync } from 'node:fs';
|
|
import { join, resolve } from 'node:path';
|
|
import test from 'node:test';
|
|
import { REQUIRED_PERMISSIONS_KEY } from '../../src/authorization/decorators/require-permissions.decorator';
|
|
import { AssetImportsController } from '../../src/asset-imports/asset-imports.controller';
|
|
import { analyzeImportWorkbook } from '../../src/asset-imports/asset-import-profiles';
|
|
import type { ParsedWorkbook } from '../../src/asset-imports/asset-import-parser';
|
|
|
|
function source(relative: string): string { return readFileSync(resolve(process.cwd(), relative), 'utf8'); }
|
|
function permissionFor(method: string): string[] {
|
|
const controller = AssetImportsController.prototype;
|
|
return Reflect.getMetadata(REQUIRED_PERMISSIONS_KEY, controller[method as keyof typeof controller]) as string[];
|
|
}
|
|
function workbook(rows: string[][]): ParsedWorkbook { return { kind: 'XLSX', sheets: [{ name: 'Inventario', rows }] }; }
|
|
|
|
test('D5.3.6 protects reconciliation as an import-management operation', () => {
|
|
assert.deepEqual(permissionFor('reconcile'), ['asset_imports.manage']);
|
|
});
|
|
|
|
test('D5.3.6 normalizes technical family and subtype while preserving source classification', () => {
|
|
const analysis = analyzeImportWorkbook(workbook([
|
|
['Item','Area/ Yacimiento','Instalacion','Sub instalacion','Equipo','Denominación del equipo','Ubicación del equipo o instalación','N° ID/ Inventario','Cantidad','Especificaciones técnicas','Estado'],
|
|
['1','REFUGIO TUPUNGATO','TUP-PIAS','ZONA BOMBAS','Bomba Centrífuga','Clase: BBA; Tipo: CEN','N/A','BBA-050','1','Fabricante; GOULD; Modelo: 3196','NO'],
|
|
]));
|
|
assert.equal(analysis.rows[0]?.normalized.sourceClass, 'BBA');
|
|
assert.equal(analysis.rows[0]?.normalized.sourceSubtype, 'CEN');
|
|
assert.equal(analysis.rows[0]?.normalized.normalizedFamily, 'bomba');
|
|
assert.equal(analysis.rows[0]?.normalized.normalizedSubtype, 'centrifuga');
|
|
assert.equal(analysis.rows[0]?.normalized.sourceStatus, 'NO');
|
|
});
|
|
|
|
test('D5.3.6 reconciliation is conservative and does not write Maestro assets', () => {
|
|
const service = source('src/asset-imports/asset-imports.service.ts');
|
|
const reconcile = service.slice(service.indexOf('async reconcile'), service.indexOf('async cancel'));
|
|
assert.match(reconcile, /INVENTORY_ID_OR_CODE_EXACT/);
|
|
assert.match(reconcile, /AREA_FIELD_EXACT/);
|
|
assert.match(reconcile, /MATCH_MULTIPLE_ASSETS/);
|
|
assert.match(reconcile, /masterModified: false/);
|
|
assert.doesNotMatch(reconcile, /INSERT INTO assets\s*\(/);
|
|
assert.doesNotMatch(reconcile, /UPDATE assets\s+SET/);
|
|
});
|
|
|
|
|
|
test('D5.3.6.3 audit summary is exposed as a plain record', () => {
|
|
const source = readFileSync(join(process.cwd(), 'src/asset-imports/asset-imports.service.ts'), 'utf8');
|
|
assert.match(source, /afterData:\s*\{\s*\.\.\.summary\s*\}/);
|
|
});
|