fix(actas): move closure to reusable inspector signing
Android CI / RC / Android · lint, tests, debug APK, release compile (push) Failing after 2m3s
DH V2 CI / API · typecheck, tests, build (push) Successful in 34s
DH V2 CI / WEB · typecheck, build (push) Successful in 20s
Production dependency audit / API · production dependencies (push) Successful in 9s
Production dependency audit / WEB · production dependencies (push) Successful in 8s
DH V2 CI / Docker / scripts contract (push) Successful in 1m18s
Android CI / RC / Android · lint, tests, debug APK, release compile (push) Failing after 2m3s
DH V2 CI / API · typecheck, tests, build (push) Successful in 34s
DH V2 CI / WEB · typecheck, build (push) Successful in 20s
Production dependency audit / API · production dependencies (push) Successful in 9s
Production dependency audit / WEB · production dependencies (push) Successful in 8s
DH V2 CI / Docker / scripts contract (push) Successful in 1m18s
This commit is contained in:
@@ -28,7 +28,8 @@ test('F3.2/F4 exige seleccionar el Acta explícitamente al crear Hallazgos desde
|
||||
test('F4 conserva el cierre documental inmutable de cada Acta como LOCKED y luego SEALED', () => {
|
||||
const closing = read('src/inspection-closing/inspection-closing.service.ts');
|
||||
assert.match(closing, /status='LOCKED'/);
|
||||
assert.match(closing, /INSPECTION_ACT_INSPECTOR_SIGNATURE_REQUIRED/);
|
||||
assert.match(closing, /INSPECTION_INSPECTOR_PROFILE_SIGNATURE_REQUIRED/);
|
||||
assert.match(closing, /createInspectorSignatureFromProfile/);
|
||||
assert.match(closing, /INSPECTION_ACT_COMPANY_OUTCOME_REQUIRED/);
|
||||
assert.match(closing, /finalSha256 = sha256CanonicalJson\(finalSnapshot\)/);
|
||||
assert.match(closing, /status='SEALED'/);
|
||||
|
||||
@@ -4,9 +4,9 @@ import { readFileSync } from 'node:fs';
|
||||
import { resolve } from 'node:path';
|
||||
import { API_PHASE, API_VERSION } from '../../src/version';
|
||||
|
||||
test('health metadata reports the current F6.1 release', () => {
|
||||
assert.equal(API_PHASE, 'F6.2');
|
||||
test('health metadata reports the current F6.7 release', () => {
|
||||
assert.equal(API_PHASE, 'F6.7');
|
||||
const pkg = JSON.parse(readFileSync(resolve(process.cwd(), 'package.json'), 'utf8')) as { version: string };
|
||||
assert.equal(API_VERSION, pkg.version);
|
||||
assert.equal(API_VERSION, '0.29.0-6');
|
||||
assert.equal(API_VERSION, '0.29.0-7');
|
||||
});
|
||||
@@ -80,9 +80,10 @@ test('F4 field finding flow only targets a draft act of the same in-progress ins
|
||||
assert.match(draftGuard, /WHERE visit_id = \$1::uuid[\s\S]*AND status = 'DRAFT'/);
|
||||
});
|
||||
|
||||
test('F4 sealing requires inspector signature and exactly one terminal company outcome', () => {
|
||||
test('F6.7 sealing copies the stored inspector signature and requires exactly one terminal company outcome', () => {
|
||||
const closeBody = closing.slice(closing.indexOf(' async close('), closing.indexOf(' async signatureContent('));
|
||||
assert.match(closeBody, /INSPECTION_ACT_INSPECTOR_SIGNATURE_REQUIRED/);
|
||||
assert.match(closeBody, /createInspectorSignatureFromProfile/);
|
||||
assert.match(closing, /INSPECTION_INSPECTOR_PROFILE_SIGNATURE_REQUIRED/);
|
||||
assert.match(closeBody, /companyOutcomes\.length !== 1/);
|
||||
assert.match(closeBody, /INSPECTION_ACT_COMPANY_OUTCOME_REQUIRED/);
|
||||
assert.match(closeBody, /ausencia documentada/);
|
||||
|
||||
@@ -10,8 +10,8 @@ function mountedRepoFile(path: string): string {
|
||||
test('F6.3 Android test cut targets production API and has a distinct installable debug version', () => {
|
||||
const gradle = mountedRepoFile('android-app/app/build.gradle.kts');
|
||||
|
||||
assert.match(gradle, /versionCode = 36/);
|
||||
assert.match(gradle, /versionName = "0\.19\.8"/);
|
||||
assert.match(gradle, /versionCode = 37/);
|
||||
assert.match(gradle, /versionName = "0\.19\.9"/);
|
||||
assert.match(gradle, /https:\/\/dhv2\.korexlabs\.com\/api\/v3\//);
|
||||
assert.match(gradle, /applicationIdSuffix = "\.debug"/);
|
||||
});
|
||||
|
||||
@@ -13,7 +13,7 @@ test('F6.1 presentation metadata keeps the visible WEB version aligned with pack
|
||||
const visibleVersion = version.match(/APP_VERSION\s*=\s*'([^']+)'/)?.[1];
|
||||
|
||||
assert.equal(visibleVersion, pkg.version);
|
||||
assert.match(version, /APP_PHASE\s*=\s*'F6\.2 · Firma por Acta y correo de usuario'/);
|
||||
assert.match(version, /APP_PHASE\s*=\s*'F6\.7 · Cierre y firma por Acta'/);
|
||||
});
|
||||
|
||||
test('F6.1 presentation keeps Relevamientos retired from WEB navigation and routes', () => {
|
||||
|
||||
@@ -0,0 +1,50 @@
|
||||
import assert from 'node:assert/strict';
|
||||
import { readFileSync } from 'node:fs';
|
||||
import { resolve } from 'node:path';
|
||||
import test from 'node:test';
|
||||
|
||||
function source(path: string): string {
|
||||
return readFileSync(resolve(process.cwd(), path), 'utf8');
|
||||
}
|
||||
|
||||
const closing = source('src/inspection-closing/inspection-closing.service.ts');
|
||||
const users = source('src/administration/users/users.controller.ts');
|
||||
const userService = source('src/administration/users/users.service.ts');
|
||||
const migration = source('src/database/migrations/1790124600000-f6-7-user-reusable-signature.ts');
|
||||
const android = source('../android-app/app/src/main/java/com/korexlabs/dhinspeccion/ui/ModernMobileActsScreen.kt');
|
||||
const labels = source('../android-app/app/src/main/java/com/korexlabs/dhinspeccion/ui/UiSpanishLabels.kt');
|
||||
const profile = source('../web-v2/src/pages/MyProfilePage.tsx');
|
||||
|
||||
test('F6.7 Acta lock and seal use SELECT-shaped version CTEs', () => {
|
||||
assert.doesNotMatch(closing, /RETURNING current_version AS "versionNumber"/);
|
||||
assert.equal((closing.match(/WITH updated AS \(/g) ?? []).length >= 2, true);
|
||||
assert.equal((closing.match(/SELECT current_version AS "versionNumber" FROM updated/g) ?? []).length >= 2, true);
|
||||
});
|
||||
test('F6.7 inspector signature is stored once in profile and copied into each sealed Acta', () => {
|
||||
assert.match(migration, /CREATE TABLE user_signature_profiles/);
|
||||
assert.match(migration, /image_data bytea NOT NULL/);
|
||||
assert.match(migration, /image_sha256 char\(64\) NOT NULL/);
|
||||
assert.match(users, /@Put\('self\/signature'\)/);
|
||||
assert.match(users, /@Get\('self\/signature\/content'\)/);
|
||||
assert.match(userService, /inspectInspectionSignatureFile/);
|
||||
assert.match(closing, /requireReusableInspectorSignature/);
|
||||
assert.match(closing, /createInspectorSignatureFromProfile/);
|
||||
assert.match(closing, /signatureMode: 'PROFILE_REUSABLE'/);
|
||||
});
|
||||
|
||||
test('F6.7 Android goes Draft to Para firmar to company manifestation without inspector drawing', () => {
|
||||
assert.match(labels, /"LOCKED" -> "Para firmar"/);
|
||||
assert.match(android, /Cerrar contenido y pasar a firma/);
|
||||
assert.match(android, /Firma del representante de la empresa \(acompañante\)/);
|
||||
assert.match(android, /Aplicar mi firma y cerrar Acta/);
|
||||
assert.doesNotMatch(android, /Firmá como inspector\/a/);
|
||||
assert.doesNotMatch(android, /inspectorSigned/);
|
||||
assert.doesNotMatch(android, /Text\(selected\.code/);
|
||||
assert.match(android, /companyOutcome\?\.status == "ABSENT"/);
|
||||
});
|
||||
test('F6.7 Dashboard exposes the reusable inspector signature clearly', () => {
|
||||
assert.match(profile, /FIRMA DEL INSPECTOR/);
|
||||
assert.match(profile, /Firma guardada para Actas/);
|
||||
assert.match(profile, /saveSelfSignature/);
|
||||
assert.match(profile, /Cada Acta conserva una copia propia de la firma/);
|
||||
});
|
||||
Reference in New Issue
Block a user