feat(api): make Yacimiento own company and concession
This commit is contained in:
@@ -20,6 +20,7 @@ import type { CreateInventoryStructureDto, InventoryStructureKind } from './dto/
|
|||||||
import { AssetHistoryService } from './asset-history.service';
|
import { AssetHistoryService } from './asset-history.service';
|
||||||
|
|
||||||
type StructureTypeRow = { id: string; code: string; name: string };
|
type StructureTypeRow = { id: string; code: string; name: string };
|
||||||
|
type SimpleOptionRow = { id: string; code: string; name: string };
|
||||||
type FamilyParent = { id: string; code: string; name: string };
|
type FamilyParent = { id: string; code: string; name: string };
|
||||||
type FamilyRow = {
|
type FamilyRow = {
|
||||||
id: string;
|
id: string;
|
||||||
@@ -37,9 +38,17 @@ type ParentRow = {
|
|||||||
name: string;
|
name: string;
|
||||||
typeCode: string;
|
typeCode: string;
|
||||||
inventoryFamilyId: string | null;
|
inventoryFamilyId: string | null;
|
||||||
|
operationalAreaId: string | null;
|
||||||
|
operatorCompanyId: string | null;
|
||||||
};
|
};
|
||||||
type IdRow = { id: string };
|
type IdRow = { id: string };
|
||||||
|
|
||||||
|
type YacimientoContext = {
|
||||||
|
companyId: string;
|
||||||
|
concessionTypeId: string;
|
||||||
|
concessionName: string;
|
||||||
|
};
|
||||||
|
|
||||||
const TYPE_CODE_BY_KIND: Record<Exclude<InventoryStructureKind, 'EMPRESA'>, string> = {
|
const TYPE_CODE_BY_KIND: Record<Exclude<InventoryStructureKind, 'EMPRESA'>, string> = {
|
||||||
DEPARTAMENTO: 'departamento',
|
DEPARTAMENTO: 'departamento',
|
||||||
AREA: 'area',
|
AREA: 'area',
|
||||||
@@ -114,6 +123,21 @@ export class InventoryStructureService {
|
|||||||
ORDER BY family.level,family.name,family.code
|
ORDER BY family.level,family.name,family.code
|
||||||
`)) as FamilyRow[];
|
`)) as FamilyRow[];
|
||||||
|
|
||||||
|
const companies = (await this.dataSource.query(`
|
||||||
|
SELECT asset.id,asset.code,COALESCE(profile.legal_name,asset.name) AS name
|
||||||
|
FROM assets asset
|
||||||
|
JOIN asset_types type ON type.id=asset.asset_type_id AND type.operational_role='COMPANY' AND type.is_active=true
|
||||||
|
LEFT JOIN organization_profiles profile ON profile.asset_id=asset.id
|
||||||
|
WHERE asset.information_status<>'INACTIVE'
|
||||||
|
ORDER BY COALESCE(profile.legal_name,asset.name),asset.code
|
||||||
|
`)) as SimpleOptionRow[];
|
||||||
|
const concessionTypes = (await this.dataSource.query(`
|
||||||
|
SELECT id,code,name
|
||||||
|
FROM concession_types
|
||||||
|
WHERE is_active=true
|
||||||
|
ORDER BY CASE lower(name) WHEN 'explotación' THEN 1 WHEN 'exploración' THEN 2 ELSE 9 END,name,code
|
||||||
|
`)) as SimpleOptionRow[];
|
||||||
|
|
||||||
return {
|
return {
|
||||||
independentMasters: [
|
independentMasters: [
|
||||||
{ kind: 'EMPRESA', label: 'Empresa', type: company, parentKind: null, requiresFamily: false },
|
{ kind: 'EMPRESA', label: 'Empresa', type: company, parentKind: null, requiresFamily: false },
|
||||||
@@ -125,6 +149,8 @@ export class InventoryStructureService {
|
|||||||
{ kind: 'INSTALACION', label: 'Instalación', type: instalacion, parentKind: 'YACIMIENTO', requiresFamily: true },
|
{ kind: 'INSTALACION', label: 'Instalación', type: instalacion, parentKind: 'YACIMIENTO', requiresFamily: true },
|
||||||
{ kind: 'SUBINSTALACION', label: 'Subinstalación', type: subinstalacion, parentKind: 'INSTALACION', requiresFamily: true },
|
{ kind: 'SUBINSTALACION', label: 'Subinstalación', type: subinstalacion, parentKind: 'INSTALACION', requiresFamily: true },
|
||||||
],
|
],
|
||||||
|
companies,
|
||||||
|
concessionTypes,
|
||||||
installationFamilies: families.filter((item) => item.level==='INSTALLATION'),
|
installationFamilies: families.filter((item) => item.level==='INSTALLATION'),
|
||||||
subinstallationFamilies: families.filter((item) => item.level==='SUBINSTALLATION'),
|
subinstallationFamilies: families.filter((item) => item.level==='SUBINSTALLATION'),
|
||||||
};
|
};
|
||||||
@@ -179,25 +205,43 @@ export class InventoryStructureService {
|
|||||||
const type = await this.requireStructureType(manager, dto.kind);
|
const type = await this.requireStructureType(manager, dto.kind);
|
||||||
const parent = await this.requireParent(manager, dto.kind, dto.parentId ?? null);
|
const parent = await this.requireParent(manager, dto.kind, dto.parentId ?? null);
|
||||||
const family = await this.requireFamily(manager, dto.kind, dto.familyId ?? null, parent);
|
const family = await this.requireFamily(manager, dto.kind, dto.familyId ?? null, parent);
|
||||||
|
const yacimientoContext = await this.requireYacimientoContext(manager, dto);
|
||||||
const generatedCode = dto.code?.trim().toUpperCase() || this.generatedCode(dto.kind, dto.name);
|
const generatedCode = dto.code?.trim().toUpperCase() || this.generatedCode(dto.kind, dto.name);
|
||||||
const operationalAreaId = parent && ['YACIMIENTO','INSTALACION','SUBINSTALACION'].includes(dto.kind)
|
const operationalAreaId = parent && ['YACIMIENTO','INSTALACION','SUBINSTALACION'].includes(dto.kind)
|
||||||
? await this.resolveAreaId(manager, parent)
|
? await this.resolveAreaId(manager, parent)
|
||||||
: null;
|
: null;
|
||||||
|
const operatorCompanyId = dto.kind === 'YACIMIENTO'
|
||||||
|
? yacimientoContext?.companyId ?? null
|
||||||
|
: dto.kind === 'INSTALACION' || dto.kind === 'SUBINSTALACION'
|
||||||
|
? parent?.operatorCompanyId ?? null
|
||||||
|
: null;
|
||||||
|
const concessionTypeId = dto.kind === 'YACIMIENTO'
|
||||||
|
? yacimientoContext?.concessionTypeId ?? null
|
||||||
|
: null;
|
||||||
|
|
||||||
|
if ((dto.kind === 'INSTALACION' || dto.kind === 'SUBINSTALACION') && !operatorCompanyId) {
|
||||||
|
throw new ConflictException({
|
||||||
|
code: 'INVENTORY_YACIMIENTO_COMPANY_MISSING',
|
||||||
|
message: 'El Yacimiento de origen no tiene una Empresa relacionada válida',
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
const inserted = (await manager.query(`
|
const inserted = (await manager.query(`
|
||||||
INSERT INTO assets (
|
INSERT INTO assets (
|
||||||
asset_type_id,parent_id,operational_area_id,operator_company_id,inventory_family_id,
|
asset_type_id,parent_id,operational_area_id,operator_company_id,concession_type_id,inventory_family_id,
|
||||||
code,name,common_name,description,information_status,operational_status,
|
code,name,common_name,description,information_status,operational_status,
|
||||||
data_origin,source_name,source_reference,source_notes,created_by,updated_by,provenance_updated_by
|
data_origin,source_name,source_reference,source_notes,created_by,updated_by,provenance_updated_by
|
||||||
) VALUES (
|
) VALUES (
|
||||||
$1::uuid,$2::uuid,$3::uuid,NULL,$4::uuid,
|
$1::uuid,$2::uuid,$3::uuid,$4::uuid,$5::uuid,$6::uuid,
|
||||||
$5::varchar,$6::varchar,$7::varchar,$8::text,$9::asset_information_status,$10::asset_operational_status,
|
$7::varchar,$8::varchar,$9::varchar,$10::text,$11::asset_information_status,$12::asset_operational_status,
|
||||||
$11::varchar,$12::varchar,$13::varchar,$14::text,$15::uuid,$15::uuid,$15::uuid
|
$13::varchar,$14::varchar,$15::varchar,$16::text,$17::uuid,$17::uuid,$17::uuid
|
||||||
) RETURNING id
|
) RETURNING id
|
||||||
`, [
|
`, [
|
||||||
type.id,
|
type.id,
|
||||||
parent?.id ?? null,
|
parent?.id ?? null,
|
||||||
operationalAreaId,
|
operationalAreaId,
|
||||||
|
operatorCompanyId,
|
||||||
|
concessionTypeId,
|
||||||
family?.id ?? null,
|
family?.id ?? null,
|
||||||
generatedCode,
|
generatedCode,
|
||||||
dto.name,
|
dto.name,
|
||||||
@@ -206,9 +250,13 @@ export class InventoryStructureService {
|
|||||||
AssetInformationStatus.DRAFT,
|
AssetInformationStatus.DRAFT,
|
||||||
AssetOperationalStatus.UNKNOWN,
|
AssetOperationalStatus.UNKNOWN,
|
||||||
AssetDataOrigin.MANUAL,
|
AssetDataOrigin.MANUAL,
|
||||||
dto.kind === 'EMPRESA' ? 'Maestro manual de Empresas F6' : 'Estructura manual de Inventario F6',
|
dto.kind === 'EMPRESA' ? 'Maestro manual de Empresas' : 'Estructura manual de Inventario',
|
||||||
dto.kind === 'EMPRESA' ? 'inventory-master:empresa' : `inventory-structure:${dto.kind.toLowerCase()}`,
|
dto.kind === 'EMPRESA' ? 'inventory-master:empresa' : `inventory-structure:${dto.kind.toLowerCase()}`,
|
||||||
family ? `Clasificación técnica: ${family.code} · ${family.name}` : null,
|
family
|
||||||
|
? `Clasificación técnica: ${family.code} · ${family.name}`
|
||||||
|
: yacimientoContext
|
||||||
|
? `Tipo de concesión: ${yacimientoContext.concessionName}`
|
||||||
|
: null,
|
||||||
principal.userId,
|
principal.userId,
|
||||||
])) as Array<{ id: string }>;
|
])) as Array<{ id: string }>;
|
||||||
const id = inserted[0]?.id;
|
const id = inserted[0]?.id;
|
||||||
@@ -221,6 +269,15 @@ export class InventoryStructureService {
|
|||||||
ON CONFLICT (asset_id) DO UPDATE SET legal_name=EXCLUDED.legal_name,updated_by=EXCLUDED.updated_by,updated_at=CURRENT_TIMESTAMP
|
ON CONFLICT (asset_id) DO UPDATE SET legal_name=EXCLUDED.legal_name,updated_by=EXCLUDED.updated_by,updated_at=CURRENT_TIMESTAMP
|
||||||
`,[id,dto.name,principal.userId]);
|
`,[id,dto.name,principal.userId]);
|
||||||
}
|
}
|
||||||
|
if (dto.kind === 'YACIMIENTO' && operationalAreaId && operatorCompanyId && concessionTypeId) {
|
||||||
|
await this.ensureCompatibilityProjection(
|
||||||
|
manager,
|
||||||
|
operationalAreaId,
|
||||||
|
operatorCompanyId,
|
||||||
|
concessionTypeId,
|
||||||
|
yacimientoContext?.concessionName ?? 'Concesión',
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
const versionNumber = await this.history.capture(
|
const versionNumber = await this.history.capture(
|
||||||
manager,id,AssetVersionChangeType.CREATED,principal,request,
|
manager,id,AssetVersionChangeType.CREATED,principal,request,
|
||||||
@@ -229,10 +286,14 @@ export class InventoryStructureService {
|
|||||||
INSERT INTO asset_context_history (
|
INSERT INTO asset_context_history (
|
||||||
asset_id,parent_id,operational_area_id,operator_company_id,valid_from,
|
asset_id,parent_id,operational_area_id,operator_company_id,valid_from,
|
||||||
change_reason,asset_version_number,source,request_id,created_by
|
change_reason,asset_version_number,source,request_id,created_by
|
||||||
) VALUES ($1,$2,$3,NULL,CURRENT_TIMESTAMP,$4,$5,'WEB',$6,$7)
|
) VALUES ($1,$2,$3,$4,CURRENT_TIMESTAMP,$5,$6,'WEB',$7,$8)
|
||||||
`, [
|
`, [
|
||||||
id,parent?.id ?? null,operationalAreaId,
|
id,parent?.id ?? null,operationalAreaId,operatorCompanyId,
|
||||||
dto.kind === 'EMPRESA' ? 'Alta manual de Empresa independiente F6' : 'Alta manual de estructura de Inventario F6',
|
dto.kind === 'YACIMIENTO'
|
||||||
|
? 'Alta manual de Yacimiento con Área, Empresa y Tipo de concesión'
|
||||||
|
: dto.kind === 'EMPRESA'
|
||||||
|
? 'Alta manual de Empresa independiente'
|
||||||
|
: 'Alta manual de estructura de Inventario',
|
||||||
versionNumber,request.requestId,principal.userId,
|
versionNumber,request.requestId,principal.userId,
|
||||||
]);
|
]);
|
||||||
const created = await this.loadView(manager, id);
|
const created = await this.loadView(manager, id);
|
||||||
@@ -244,7 +305,8 @@ export class InventoryStructureService {
|
|||||||
metadata: {
|
metadata: {
|
||||||
versionNumber,inventoryStructureKind: dto.kind,
|
versionNumber,inventoryStructureKind: dto.kind,
|
||||||
inventoryFamilyId: family?.id ?? null,inventoryFamilyCode: family?.code ?? null,
|
inventoryFamilyId: family?.id ?? null,inventoryFamilyCode: family?.code ?? null,
|
||||||
operatorOwnership: false,
|
operatorCompanyId,
|
||||||
|
concessionTypeId,
|
||||||
},
|
},
|
||||||
}, manager);
|
}, manager);
|
||||||
return created;
|
return created;
|
||||||
@@ -290,7 +352,9 @@ export class InventoryStructureService {
|
|||||||
});
|
});
|
||||||
const rows = (await manager.query(`
|
const rows = (await manager.query(`
|
||||||
SELECT asset.id,asset.code,asset.name,type.code AS "typeCode",
|
SELECT asset.id,asset.code,asset.name,type.code AS "typeCode",
|
||||||
asset.inventory_family_id AS "inventoryFamilyId"
|
asset.inventory_family_id AS "inventoryFamilyId",
|
||||||
|
asset.operational_area_id AS "operationalAreaId",
|
||||||
|
asset.operator_company_id AS "operatorCompanyId"
|
||||||
FROM assets asset
|
FROM assets asset
|
||||||
JOIN asset_types type ON type.id=asset.asset_type_id
|
JOIN asset_types type ON type.id=asset.asset_type_id
|
||||||
WHERE asset.id=$1::uuid AND asset.information_status<>'INACTIVE'
|
WHERE asset.id=$1::uuid AND asset.information_status<>'INACTIVE'
|
||||||
@@ -305,8 +369,65 @@ export class InventoryStructureService {
|
|||||||
return parent;
|
return parent;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private async requireYacimientoContext(
|
||||||
|
manager: EntityManager,
|
||||||
|
dto: CreateInventoryStructureDto,
|
||||||
|
): Promise<YacimientoContext | null> {
|
||||||
|
if (dto.kind !== 'YACIMIENTO') {
|
||||||
|
if (dto.operatorCompanyId || dto.concessionTypeId) {
|
||||||
|
throw new BadRequestException({
|
||||||
|
code: 'INVENTORY_YACIMIENTO_CONTEXT_NOT_ALLOWED',
|
||||||
|
message: 'Empresa relacionada y Tipo de concesión sólo corresponden al Yacimiento',
|
||||||
|
});
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
if (!dto.operatorCompanyId) {
|
||||||
|
throw new BadRequestException({
|
||||||
|
code: 'INVENTORY_YACIMIENTO_COMPANY_REQUIRED',
|
||||||
|
message: 'Seleccioná la Empresa relacionada del Yacimiento',
|
||||||
|
});
|
||||||
|
}
|
||||||
|
if (!dto.concessionTypeId) {
|
||||||
|
throw new BadRequestException({
|
||||||
|
code: 'INVENTORY_YACIMIENTO_CONCESSION_REQUIRED',
|
||||||
|
message: 'Seleccioná el Tipo de concesión del Yacimiento',
|
||||||
|
});
|
||||||
|
}
|
||||||
|
const companyRows = (await manager.query(`
|
||||||
|
SELECT asset.id
|
||||||
|
FROM assets asset
|
||||||
|
JOIN asset_types type ON type.id=asset.asset_type_id
|
||||||
|
WHERE asset.id=$1::uuid
|
||||||
|
AND type.operational_role='COMPANY'
|
||||||
|
AND type.is_active=true
|
||||||
|
AND asset.information_status<>'INACTIVE'
|
||||||
|
FOR KEY SHARE
|
||||||
|
`,[dto.operatorCompanyId])) as IdRow[];
|
||||||
|
if (!companyRows[0]) throw new BadRequestException({
|
||||||
|
code: 'INVENTORY_YACIMIENTO_COMPANY_INVALID',
|
||||||
|
message: 'La Empresa relacionada seleccionada no es válida',
|
||||||
|
});
|
||||||
|
const concessionRows = (await manager.query(`
|
||||||
|
SELECT id,name
|
||||||
|
FROM concession_types
|
||||||
|
WHERE id=$1::uuid AND is_active=true
|
||||||
|
FOR KEY SHARE
|
||||||
|
`,[dto.concessionTypeId])) as Array<{id:string;name:string}>;
|
||||||
|
if (!concessionRows[0]) throw new BadRequestException({
|
||||||
|
code: 'INVENTORY_YACIMIENTO_CONCESSION_INVALID',
|
||||||
|
message: 'El Tipo de concesión seleccionado no es válido',
|
||||||
|
});
|
||||||
|
return {
|
||||||
|
companyId: dto.operatorCompanyId,
|
||||||
|
concessionTypeId: dto.concessionTypeId,
|
||||||
|
concessionName: concessionRows[0].name,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
private async resolveAreaId(manager: EntityManager,parent: ParentRow):Promise<string> {
|
private async resolveAreaId(manager: EntityManager,parent: ParentRow):Promise<string> {
|
||||||
if (parent.typeCode.toLowerCase()==='area') return parent.id;
|
if (parent.typeCode.toLowerCase()==='area') return parent.id;
|
||||||
|
if (parent.operationalAreaId) return parent.operationalAreaId;
|
||||||
const rows = (await manager.query(`
|
const rows = (await manager.query(`
|
||||||
WITH RECURSIVE lineage AS (
|
WITH RECURSIVE lineage AS (
|
||||||
SELECT asset.id,asset.parent_id,asset.asset_type_id FROM assets asset WHERE asset.id=$1::uuid
|
SELECT asset.id,asset.parent_id,asset.asset_type_id FROM assets asset WHERE asset.id=$1::uuid
|
||||||
@@ -381,6 +502,40 @@ export class InventoryStructureService {
|
|||||||
return family;
|
return family;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private async ensureCompatibilityProjection(
|
||||||
|
manager: EntityManager,
|
||||||
|
areaId: string,
|
||||||
|
companyId: string,
|
||||||
|
concessionTypeId: string,
|
||||||
|
concessionName: string,
|
||||||
|
): Promise<void> {
|
||||||
|
const companyProjection = await manager.query(`
|
||||||
|
SELECT id FROM area_company_relations
|
||||||
|
WHERE area_id=$1::uuid AND company_id=$2::uuid AND relation_role='OPERATOR' AND valid_to IS NULL
|
||||||
|
LIMIT 1
|
||||||
|
`,[areaId,companyId]);
|
||||||
|
if (!companyProjection[0]) {
|
||||||
|
await manager.query(`
|
||||||
|
INSERT INTO area_company_relations(area_id,company_id,relation_role,valid_from,start_reason)
|
||||||
|
VALUES($1::uuid,$2::uuid,'OPERATOR',CURRENT_TIMESTAMP,'Proyección derivada de Yacimiento')
|
||||||
|
`,[areaId,companyId]);
|
||||||
|
}
|
||||||
|
const rightType = concessionName.toLocaleLowerCase('es-AR').includes('explor')
|
||||||
|
? 'EXPLORATION_PERMIT'
|
||||||
|
: 'EXPLOITATION_CONCESSION';
|
||||||
|
const rightProjection = await manager.query(`
|
||||||
|
SELECT id FROM area_legal_rights
|
||||||
|
WHERE area_id=$1::uuid AND right_type=$2::area_legal_right_type AND status='ACTIVE'
|
||||||
|
LIMIT 1
|
||||||
|
`,[areaId,rightType]);
|
||||||
|
if (!rightProjection[0]) {
|
||||||
|
await manager.query(`
|
||||||
|
INSERT INTO area_legal_rights(area_id,right_type,name,status,notes)
|
||||||
|
VALUES($1::uuid,$2::area_legal_right_type,$3,'ACTIVE',$4)
|
||||||
|
`,[areaId,rightType,`${concessionName} · proyección de Yacimiento`,`Tipo de concesión canónico: ${concessionTypeId}`]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private generatedCode(kind: InventoryStructureKind, name: string): string {
|
private generatedCode(kind: InventoryStructureKind, name: string): string {
|
||||||
const prefix = kind === 'EMPRESA' ? 'EMP'
|
const prefix = kind === 'EMPRESA' ? 'EMP'
|
||||||
: kind === 'DEPARTAMENTO' ? 'DEP'
|
: kind === 'DEPARTAMENTO' ? 'DEP'
|
||||||
@@ -400,6 +555,8 @@ export class InventoryStructureService {
|
|||||||
JSONB_BUILD_OBJECT('id',type.id,'code',type.code,'name',type.name) AS type,
|
JSONB_BUILD_OBJECT('id',type.id,'code',type.code,'name',type.name) AS type,
|
||||||
CASE WHEN parent.id IS NULL THEN NULL ELSE JSONB_BUILD_OBJECT('id',parent.id,'code',parent.code,'name',parent.name) END AS parent,
|
CASE WHEN parent.id IS NULL THEN NULL ELSE JSONB_BUILD_OBJECT('id',parent.id,'code',parent.code,'name',parent.name) END AS parent,
|
||||||
CASE WHEN area.id IS NULL THEN NULL ELSE JSONB_BUILD_OBJECT('id',area.id,'code',area.code,'name',area.name) END AS "operationalArea",
|
CASE WHEN area.id IS NULL THEN NULL ELSE JSONB_BUILD_OBJECT('id',area.id,'code',area.code,'name',area.name) END AS "operationalArea",
|
||||||
|
CASE WHEN company.id IS NULL THEN NULL ELSE JSONB_BUILD_OBJECT('id',company.id,'code',company.code,'name',COALESCE(profile.legal_name,company.name)) END AS "operatorCompany",
|
||||||
|
CASE WHEN concession.id IS NULL THEN NULL ELSE JSONB_BUILD_OBJECT('id',concession.id,'code',concession.code,'name',concession.name) END AS "concessionType",
|
||||||
CASE WHEN family.id IS NULL THEN NULL ELSE JSONB_BUILD_OBJECT(
|
CASE WHEN family.id IS NULL THEN NULL ELSE JSONB_BUILD_OBJECT(
|
||||||
'id',family.id,'code',family.code,'name',family.name,'level',family.level,
|
'id',family.id,'code',family.code,'name',family.name,'level',family.level,
|
||||||
'informationLabels',family.information_labels
|
'informationLabels',family.information_labels
|
||||||
@@ -409,6 +566,9 @@ export class InventoryStructureService {
|
|||||||
JOIN asset_types type ON type.id=asset.asset_type_id
|
JOIN asset_types type ON type.id=asset.asset_type_id
|
||||||
LEFT JOIN assets parent ON parent.id=asset.parent_id
|
LEFT JOIN assets parent ON parent.id=asset.parent_id
|
||||||
LEFT JOIN assets area ON area.id=asset.operational_area_id
|
LEFT JOIN assets area ON area.id=asset.operational_area_id
|
||||||
|
LEFT JOIN assets company ON company.id=asset.operator_company_id
|
||||||
|
LEFT JOIN organization_profiles profile ON profile.asset_id=company.id
|
||||||
|
LEFT JOIN concession_types concession ON concession.id=asset.concession_type_id
|
||||||
LEFT JOIN inventory_families family ON family.id=asset.inventory_family_id
|
LEFT JOIN inventory_families family ON family.id=asset.inventory_family_id
|
||||||
WHERE asset.id=$1::uuid
|
WHERE asset.id=$1::uuid
|
||||||
`, [id]);
|
`, [id]);
|
||||||
|
|||||||
Reference in New Issue
Block a user