This page was exported from Eduardo Spotorno [ http://eduardo.spotorno.com.ar ]
Export date: Sun Sep 19 17:46:26 2021 / +0000 GMT

Interoperabilidad CMCABA/MPF: JusCABA2 vs Kiwi


Detalle de la Implementación de las aplicaciones


A continuación se detalla la estrategia de desarrollo para la implementación de las aplicaciones desarrolladas.

kiwi.juscaba.jusbaires gov.ar (Interoperabilidad CMCABA/MPF)

La interoperabilidad está desarrollada en una aplicación autónoma denominada "juscaba2" que implementa por sí nuevamente las reglas de negocio requeridas para la interoperabilidad utilizando código original de la aplicación JusCABA. Esto significa que los cambios que deban realizarse para el funcionamiento de JusCABA deben trasladarse al código de JusCABA2 también, para así mantener la integridad de la información en la base de datos.

La interoperabilidad de documentos XML se realiza para las entidades de:

  • caso/expediente

  • denuncia

  • cédula

  • audiencia


Para todos los objetos intercambiados anteriormente, la interoperabilidad incluye las siguientes entidades XML:

  • persona

  • domicilio

  • artículo

  • infracción


El intercambio de documentos se realiza a través de una interfaz REST que debe ser iniciada por el cliente, en este caso el sistema Kiwi. Este deberá producir un documento UTF-8 compatible y dirigirlo a la URL kiwi.juscaba.jusbaires.gov.ar con los siguientes parámetros:
        POST( "http://kiwi.juscaba.jusbaires.gov.ar",

array(
"documento" => $xml
,"usuario" => 'kiwi'
,"clave" => "xxxx"
,"m"=>"if_kiwi"
,"a"=>"process"
,"p"=>"if_kiwi" )
);

El documento que ingresa a la interfaz deberá tener una estructura similar a la siguiente para los casos judiciales llevados por el MPF que se convierten en expedientes en JusCABA:

 
<?xml version="1.0" encoding="UTF-8"?>
<caso>
<usuario>
<!--datos del usuario que carga la denuncia -->
<nombre>ALEJANDRO JAVIER CONDE POYO</nombre>
<cargo>Secretario de 1º Inst Min. Pub.</cargo>
<email>aconde@fiscalias.gob.ar</email>
<dependencia PMJ="ufse-uit" />
<firma />
</usuario>
<!-- clasificacion MPF -->
<clasificacion>
<codigo_caso>MPF00264530</codigo_caso>
<fecha_creacion>2014-10-20T15:51:58-03:00</fecha_creacion>
</clasificacion>
<!-- denuncia -->
<denuncia PMJ="DEN01354075">
<!-- identifiacion -->
<codigo_denuncia>DEN00134075</codigo_denuncia>
<tipo>CONTRAVENCION OCI</tipo>
<contravencion>8547</contravencion>
<!-- lugar -->
<zona_fiscalia>Sudeste</zona_fiscalia>
<localizacion lat="-34.608163" lon="-58.384895" />
<flagrante>SI</flagrante>
<!-- tiempo -->
<fecha_alta>2014-11-19T10:28:07-03:00</fecha_alta>
<fecha_inicio_comisaria>2014-11-19 00:00:00</fecha_inicio_comisaria>
<fecha_hecho_inicial>2014-11-17T18:30:00-03:00</fecha_hecho_inicial>
<fecha_hecho_final />
<!-- actores -->
<policia_toma_denuncia />
<comisaria_toma_denuncia PMJ="3.pfa" />
<!-- hecho -->
<descripcion_hecho>Siendo el día 17/11/14 el Cabo Moreno procede a labrar actuaciones por inf. alrt. 85 del CC en
las inmediaciones de la calle Talcahuano catastral 45 aproximadamente, a quien dice ser Osvaldo Perez que se encontraba indocumentado. Se procede al labrado del acta contravencional y al traslado del masculino a la OCI en el marco del art. 36 bis de la LPC.</descripcion_hecho>
<!-- datos persona -->
<persona>
<rol PMJ="denunciado">DENUNCIADO</rol>
<estado>IDENTIFICADO</estado>
<exhibe_documento>NO</exhibe_documento>
<datos_persona PMJ="b9986b3376de5fe11fc7974995f41d7f">
<domicilio PMJ="a95c530a7af5f492a74499e70578d150">
<tipo PMJ="denunciado">OCI</tipo>
<latitud>-34.617871</latitud>
<longitud>-58.386109</longitud>
</domicilio>
<documento>
<tipo PMJ="dni">DNI</tipo>
<numero>2010201001</numero>
<estado>ACTIVO</estado>
<exhibe />
</documento>
</datos_persona>
<!-- infracciones -->
<!-- codificacion del articulado: CABA, ley 1472, art. 85 -->
<articulo PMJ="caba.ar/1472:85" />
</persona>
</denuncia>
</caso>

 

el documento XML en respuesta será similar al siguiente:
<?xml version="1.0" encoding="utf-8"?>
<respuesta xmlns="http://juscaba.jusbaires.gov.ar/namespace/v1/">
<mensajes>
<mensaje tipo="INFO">HOST: xps2; modo ejecucion: desarrollo; tama#o del documento recibido: 5231; Hay menores en el expediente como imputado, seteando exped::tiene_menor = 'si'; denuncia existente con PMJ: DEN00125277, registrando cambios; Se ha afectado a la Asesoria Tutelar PCyF a la causa; Usando tabla de turnos turno_juzgado_juvenil; Se afecta a Secretaría General de Cámara PCyF; Se ha afectado al actor Secretaria Juvenil Juzgado PCyF 3</mensaje>
</mensajes>
<estatus valor="OK"/>
<data>
<exped>
<caratula>MONTANA, JUAN s/art. 11179:149bisparr1 Amenazas - CP (p/ L 2303)</caratula>
<fec_ingreso>16/11/2014</fec_ingreso>
<flagrante>si</flagrante>
<comisaria>13</comisaria>
<numero_kiwi>MPF00060169</numero_kiwi>
<usuario>kiwi@fiscaliapcyf29</usuario>
<timestamp>30/09/2014 14:18:22</timestamp>
<violencia_domestica>no</violencia_domestica>
<tiene_menor>si</tiene_menor>
<puntaje>0.00</puntaje>
<pasos>2</pasos>
</exped>
<forma ID="343433">
<num>13944</num>
<num_policial>DEN00125277</num_policial>
<usuario>kiwi@fiscaliapcyf29</usuario>
<timestamp>30/09/2014 14:18:22</timestamp>
<fec_ingreso>16/11/2014</fec_ingreso>
<flagrante>no</flagrante>
<violencia_domestica>no</violencia_domestica>
<PMJ>DEN00125277</PMJ>
<denunciados>[:/M] MONTANA, JUAN (denunciado)</denunciados>
</forma>
<actor_rol>
<id>2442899</id>
<fec_ingreso>30/09/2014</fec_ingreso>
<exped_ID>376144</exped_ID>
<actor_ID>1807</actor_ID>
<t_actor_ID>1</t_actor_ID>
<actor_nombre>Secretaria Juvenil Juzgado PCyF 3</actor_nombre>
<afecta>si</afecta>
<timestamp>30/09/2014 14:18:22</timestamp>
</actor_rol>
</data>
</respuesta>

Ambos documentos son a modo de ejemplo y no tienen correlación entre sí.

A través del módulo de auditoría se puede inspeccionar el díalogo en línea entre la aplicación Kiwi y JusCABA, ver los accesos que se producen y de dónde como así también los mensajes de error que se puedan presentar. Para acceder al módulo mencionado se deberá acceder a la URL:

http://kiwi.juscaba.jusbaires.gov.ar/?m=audit

 

Captura de pantalla de 2014-11-20 18:18:34

Módulo de Auditoría en la interoperabilidad Kiwi/JusCABA



Módulo if_kiwi para la interoperabilidad de casos, denuncias, cédulas y audiencias

La estrategia general de la implementación de la interoperabilidad es recorrer un XML y asignar los valores a los objetos impactados en el proceso de la base de datos de JusCABA. En particular, para cargar un nuevo caso que se converte en expediente, al recorrer la entidad "caso" provista por el MPF, este generará un nuevo expediente. El módulo if_kiwi (interfaz kiwi) reemplaza al módulo  cr_forma original del diseño inicial de JusCABA, cuando el MPF realizaba las denuncias vía esa herramienta.

Validaciones de datos aplican para todas las instancias. En primer lugar la interoperabilidad realizar una validación a nivel de XML de los datos recibidos, como ser, que exista un artículo en la denuncia, que existan denunciados, etc. Esto puede modificarse en la instancia del objeto if_kiwi en el proceso if_kiwi_exped:
function if_kiwi_exped( $caso ) {/*{{{*/

if ( ! $this->get_flag( 'exped' ) ) {

M()->info( 'proceso de exped deshabilitado por configuracion' );
return false;
}

...

if ( ! ( $codigo_caso = (string) $caso->clasificacion->codigo_caso ) ) {

M()->error( "/caso/clasificacion/codigo_caso vacio: no puedo continuar" );
return;
}

$denunciados = $caso->xpath( "//persona[rol/@PMJ='denunciado' or rol/@PMJ='imputado']" );

if ( ! count( $denunciados ) ) {

M()->error( "caso sin reportar denunciados/imputados" );
return;

} else M()->info( 'encontre ' . count( $denunciados ). ' denunciados' );

$articulos = $caso->xpath( "//persona/articulo" );

if ( ! count( $articulos ) ) {

M()->error( "denuncia sin infracciones a articulos" );
return;

} else M()->info( 'encontre ' . count( $articulos ). ' articulos' );

$denuncias = $caso->xpath( "denuncia" );

if ( ! count( $denuncias ) ) {

M()->error( "caso sin reportar denuncias" );
return;

} else M()->info( 'encontre ' . count( $denuncias ). ' denuncias' );

$exped = $xpdoc->get_instance( 'exped' );

if ( $exped->load( array ( 'numero_kiwi' => $codigo_caso ) ) ) {

M()->user( "Ya existe un expediente con el codigo de caso Nro. $codigo_caso. Registrando cambios" );
}

M()->info( "tomando la primera denuncia del documento" );

$denuncia = array_shift( $denuncias );

/* PMJ en actor_comsiaria: juscaba no tiene comisaria por forma/denuncia, va la primera solamente */

if ( ( $PMJ = (string) $denuncia->comisaria_toma_denuncia['PMJ'] ) ) {

M()->info( "comisaria PMJ: $PMJ" );

$ac = $xpdoc->get_instance( 'actor_comisaria' );

if ( $ac->load( array( 'PMJ' => $PMJ ) ) )

M()->info( "comsiaria: ". $exped->comisaria = $ac->comisaria );
else
M()->warn( "no encuentro el actor_comisaria $PMJ en la base de datos" );

} else M()->info( "caso/denuncia sin comisaria" );

/* $xpdoc->feat->load_full_query = false; DEBUG: no encuentra sector.sector en actor_legal */


/* zona_cardinal */

if ( $t = $this->zona_cardinal( (string) $denuncia->zona_fiscalia ) )
M()->info( "zona_cardinal de la denuncia: ". $exped->zona_cardinal = $t );
else if ( $t = $xpdoc->user->zona )
M()->info( "zona_cardinal: ". $exped->zona_cardinal = $t );
else {

M()->error( "no se pudo establecer la zona ni por la denuncia ni por el actor legal" );
return;
}

/* flagrancia, comisaria */

M()->info( "flagrante: ". $exped->flagrante = strtolower( (string) $denuncia->flagrante ) );

$exped->violencia_domestica = 'no'; // default, luego override en forma

/* deshabilito validates */

$exped->get_attr( 't_causa_ID' )->validate = null;


/* por ahora para que se vea desde el expediente */

M()->info( "Expediente MPF: ". $exped->numero_kiwi = $codigo_caso );

M()->info( "fec_ingreso: ". $exped->fec_ingreso = substr( $denuncia->fecha_alta, 0, 10 ) );
M()->info( "fecha_hecho: ". $exped->fecha_hecho = substr( $denuncia->fecha_hecho_inicial, 0, 10 ) );


/* chequea fechas y flagrancia

if ( ( $this->flagrante == 'si' and ! $this->fecha_hecho ) or ( $this->flagrante != 'si' and ! $this->fec_ingreso ) ) {

M()->error( "Debe especificarse habiendo flagrancia una fecha del hecho, caso contrario una fecha de ingreso, no se puede continuar" );
return;
}

*/

M()->info( "obs: ". $exped->obs = (string) $denuncia->observaciones );
M()->info( 'usuario: '. $exped->usuario = $this->usuario );

/* menor */

if ( count( $caso->xpath( "//datos_persona[menor='SI' and (../rol[@PMJ='denunciado'] or ../rol[@PMJ='imputado'])]" ) ) ) {

M()->user( "Hay menores en el expediente como imputado, seteando exped::tiene_menor = 'si'" );
$exped->tiene_menor = 'si';

} else
$exped->tiene_menor = 'no';


/* caratula */

$exped->caratula = $this->genera_caratula( $denunciados, $articulos );

$exped->push_privileges( array( 'edit' => true, 'add' => true ) );
$exped->store_xml_response();


if ( ! $exped->ID ) {

M()->error( "no se pudo crear el expediente. Proceso canceladoo" );
return;
}

M()->info( "exped_ID: $exped->ID" );

foreach( $caso->xpath( "//denuncia" ) as $denuncia )
$this->if_kiwi_denuncia( $denuncia, $exped );


/* Denuncia del Caso */
/* en /caso/persona/articulo */

if ( count( $persona_articulo = $caso->xpath( 'persona/articulo' ) ) ) {

M()->user( 'agregando Denuncia del Caso' );

/* tomo la primera denuncia */
$adc = array_shift( $caso->xpath( '//denuncia' ) );

/* copio la primera denuncia con las personas del caso y un override de valores */
$this->if_kiwi_denuncia( $denuncia, $exped, $persona_articulo, array( 't_forma_ID' => t_forma_DENUNCIA_CASO ) );

}

foreach( $caso->xpath( "//persona" ) as $persona )
$this->if_kiwi_persona_exped( $persona, $exped );

$this->if_kiwi_actores( $caso, $exped );

foreach( $caso->xpath( "//paso" ) as $paso )
$this->if_kiwi_paso( $paso, $exped );

$xpdoc->feat->load_full_query = true;

// $exped->desnormalizar();
$exped->update();

/*

$this->reset();

$this->xpid = $xpdoc->xpid();
$this->ID = $exped->ID;
$this->clase = $exped->class_name;
$this->estatus = (string) M()->status();

$this->push_privileges( array( 'add' => 1 ) );
$this->store();

*/

}/*}}}*/

Como se verá en el código anterior, hay tres métodos significativos para la validación de las variables recibidas en el documento XML:

  1. por simple evaluación de valores en las variables;

  2. por lookups en base de datos con la función load() para evaluar el valor de una clave foránea en una tabla accesoria;

  3. por queries vía la función XSL xpath() para evaluar la existencia o no de elementos XML necesarios para la interoperabilidad.


Para la remisión de un documento XML con un caso, la sucesión de llamados de variables entonces sería la siguiente:

callgraph

Llamados de funciones para la ejecución de la interoperabilidad cuando se envía un caso que se convierte en expediente


Campos PMJ


Para la resolución de claves foráneas no contempladas intrínsecamente dentro del documento recibido, se ha implementado una serie de valores comunes entre ambos sistemas para su referencia. Esta combinación de valores constantes en formato de cadena de caracteres ha sido combinado entre ambos organismos y así brindar una lingua-franca entre ambos sistemas, que pudieran hablar de lo mismo. Los campos PMJ aparecen en los siguientes objetos/tablas de los sistemas:

  • Tipo Causas

  • Tipo Pasos Procesales

  • Artículos

  • Materias

  • Tipos de Documentos

  • Tipos de Actores

  • Comisarías

  • Actores Legales

  • Nacionalidades (implementa el código alfa-2 de la estandarización ISO-3166-1)

  • Calles (realiza un macheo entre Google Maps y el callejero de la CABA)

  • Zonas

  • Localidades

  • Tipos de Domicilios


Para la identificación de las personas involucradas los sistemas intercambian un hash único de 32 caracteres para poder identificar múltiples NN de los cuales no se tengan aún datos y así poder identificar unívocamente a las personas involucradas. Una vez resuelta su identidad definida, se solapa la información con el registro de la persona identificada.

Identificación de infracciones y sus artículos


Para la identificación de los artículos de las leyes que indican las infracciones denunciadas, se ha elaborado un código único de identificación de artículos con la siguiente nomenclatura:
caba.ar/<ley>:<articulo>[:inciso]

identificando así la jurisdicción, la ley y el artículo, incisos y capítulos, por ejemplo:
caba.ar/11179:135:1

Diferencias entre Kiwi y JusCABA

Si bien partieron de un mismo desarrollo ambas aplicaciones no comparten el modelo de base de datos por lo que hubo que realizar una correspondencia completa entre ambas aplicaciones en lo que respecta al espacio de nombres de ambos sets de datos: estas diferencias requieren modificaciones en ambas aplicaciones son fundamentales para la identificación de los actores particulares:
/ * contemplados en JusCABA */

/*
$ap->t_n_estudio_ID = $datos_persona->;
$ap->t_s_laboral_PSH_ID = $datos_persona->;
$ap->t_s_vivienda_PSH_ID = $datos_persona->;
$ap->t_estado_civil_ID = $datos_persona->;
$ap->t_c_hijos_ID = $datos_persona->;

$ap->ocupacion_ID = $datos_persona->;

// provistos por el KIWI

$ap->madre_nombre = $datos_persona->;
$ap->madre_apellido = $datos_persona->;
$ap->padre_nombre = $datos_persona->;
$ap->padre_apellido = $datos_persona->;

*/

En particular, JusCABA no tiene la habilidad de identificar las infracciones por cada uno de los actores, mientras que Kiwi lo hace. Esto sucede por ejemplo cuando hay delitos colectivos y los participantes tienen distintos roles. La interoperabilidad resuelve estas diferencias y pone los datos como los acepta JusCABA.

Georreferencia de las infracciones

Kiwi incorpora entre sus funciones un mapa del delito, para ello incorporó herramientas de Google Maps y así proveer valores para latitud y longitud. Es por esto el motivo principal del por qué de la utilización de callejeros diferentes. Como beneficio de esa decisión, Kiwi envía latitud y longitud de la georreferencia de la infracción, datos que no podían faltar en JusCABA. Para ello se modificó la base de datos en particular de la tabla denuncia agregado los valores correspondientes. JusCABA debe aprovechar valiosa información e incorporar su propia georreferencia.

Otros datos personales

Kiwi registra también información sobre email y redes sociales del involucrado, esta información no está implementada aún en la interoperabilidad.


Roles y usuarios judiciales entre las aplicaciones


Si bien todas las transacciones se hacen a través de un solo usuario "kiwi" la interoperabilidad debe recrear el perfil del usuario tal como si lo estuviera escribiendo sobre la interfaz de JusCABA: el método de la clase if_kiwi usuario_efectivo() realiza la operación de transposición de identidad y la asigna al usuario actuante que está en la variable global $xpdoc:
function usuario_efectivo( $xml_proc ) {/*{{{*/

global $xpdoc;

/* rol efectivo de la transaccion (t_actor_rol, actor_rol) desde usuario/dependencia/@PMJ */

if ( ! ( $PMJ = (string) $xml_proc->usuario->dependencia['PMJ'] ) ) {

M()->error( 'debe especificar un codigo PMJ para el usuario del caso (en /caso/usuario/dependencia/@PMJ)' );
return;

} else M()->info( "dependencia PMJ: $PMJ" );

$al = $xpdoc->get_instance( 'actor_legal' );

if ( $al->load( array( 'PMJ' => $PMJ ) ) ) {

M()->info( "actor legal: $al->actor_legal" );

} else {

M()->error( "no encuentro el actor $PMJ en la tabla de actor_legal en Juscaba" );
return;
}

/* carga en el user el valor que viene en el PMJ para que la transaccion tenga un usuario con rol */

$xpdoc->user->actor_ID = $al->ID;
$xpdoc->user->t_actor_ID = $al->t_actor_ID;
$xpdoc->user->sector_ID = $al->sector_ID;
$xpdoc->user->fuero_ID = $xpdoc->get_instance( 'sector' )->load( $al->sector_ID )->fuero_ID;
$xpdoc->user->fuero_cod = $xpdoc->get_instance( 'fuero' )->load( $xpdoc->user->fuero_ID )->cod;
$xpdoc->user->zona = $al->zona;

M()->debug( "t_actor_ID = {$xpdoc->user->t_actor_ID}, actor_ID: {$xpdoc->user->actor_ID}" );

/* determina el usuario */

M()->info( 'usuario: '. $this->usuario = $xpdoc->user->user_username . '@'. $xml_proc->usuario->dependencia['PMJ'] );

return $this->usuario;

}/*}}}*/

Macheo entre Google Maps y el callejero de la CABA

Ciclópea tarea hubiera sido a mano realizar el macheo uno por uno de las calles de un callejero y otro, principalmente por que está alterado el orden de los nombres, tal como se comentó anteriormente. Para ello se desarrolló la función busca_calle() que trata de machear entre ambos callejeros:
	function busca_calle( $calle = null ) {/*{{{*/

if ( !$calle )
return;

global $xpdoc;

M()->debug( "calle: $calle" );

$c = $xpdoc->get_instance( 'calle' );

$c->get_attr('PMJ')->match_type = 'like'; // puede estar en el ui.xml tambien

if ( $c->load( array( 'PMJ' => $calle ) ) ) {

M()->debug( "calle encontrada con PMJ $calle" );
return $c->ID;

} else {

M()->user( "no se encontro la calle [$calle]" );
}


$parts = preg_split( "/[s,]+/", $calle );

M()->debug( "partes: ". serialize( $parts ) );


$where = array();

foreach( $parts as $part )
$clause[] = "calle LIKE '%$part%'";

if ( ! count( $parts ) ) {
M()->warn('buscando una calle nula');
return;
}

M()->debug( 'clause: '. implode( ' AND ', $clause ) );

$cs = $c->load_set( null, implode( ' AND ', $clause ), array( 'largo_n' => 'ASC' ) );

$cs_count = $cs->count();

if ( $cs_count < 0 )
M()->warn( "hubo un error al consultar la calle [$calle]" );
else if ( $cs_count == 0 )
M()->warn( "no se encontro la calle [$calle]" );
else if ( $cs_count > 1 ) {

M()->user( "hay mas de un resultado para la calle [$calle]: NO actualizando PMJ!!" );

$c = $cs->current();
$c->PMJ = $calle;
$c->revisar = 1;
$c->push_privileges( array( 'edit' => 1 ) );
// $c->store();

M()->debug( 'primer calle_ID disponible: '. $c->ID );
return $c->ID;

}
else {

M()->user( "un resultado unico para la calle [$calle]: NO actualizando PMJ!!" );

$c = $cs->current();
$c->PMJ = $calle;
$c->push_privileges( array( 'edit' => 1 ) );
// $c->store();

M()->debug( 'calle_ID unico: '. $c->ID );
return $c->ID;
}

return null;

}/*}}}*/

Si la calle es encontrada por su PMJ y hay un solo resultado, la función devuelve el ID de la calle tal como lo necesita JusCABA. En caso de no encontrarse, la función hace un split entre los componentes del nombre, es decir, separa las palabras entre ellas, por ejemplo, para la calle "MARIA ANTONIA DE LA PAZ Y FIGUEROA" (para el callejero de la ciudad la mencionada calle se llama "DE LA PAZ Y FIGUEROA, MARIA ANTONIA") dividirá la consulta en un array de LIKE en combinación con operadores AND:
SELECT 
`calle`.`ID`,
`calle`.`calle`,
`calle`.`timestamp`,
`calle`.`juscaba_calle_ID`,
`calle`.`PMJ`,
`calle`.`revisar`,
length(calle) AS `largo_n`
FROM `calle`
WHERE
calle LIKE '%MARIA%' AND
calle LIKE '%ANTONIA%' AND
calle LIKE '%DE%' AND
calle LIKE '%LA%' AND
calle LIKE '%PAZ%' AND
calle LIKE '%Y%' AND
calle LIKE '%FIGUEROA%'
ORDER BY `largo_n` ASC

Nótese que los resultados están ordenados por el más largo primero, esto indica que la primera calle es la mejor candidata. Configurado de tal forma, la aplicación puede asignar automáticamente este primer resultado al PMJ e señalar en el campo "revisar" que la asignación ha sido automática y debe ser cotejada por un operador para resolver las referencias. Cabe señalar que por algún motivo en particular, los strings de las calles de Google Maps enviados por el Kiwi alternan entre mayúsculas y minúsculas, aunque esto no altera la operación del algoritmo, sin embargo en los listados de calles por su PMJ se nota esta diferencia.

La función busca_localidad(), también implementada, contiene un algoritmo similar.

Fechas de ingreso vs. flagrancia

Junto con la identificación de los involucrados y la privacidad de este dato,  las fechas de ingresos de causas resulta crítico para la conversión de casos en causas en expedientes. La ley indica que
si el hecho es flagrante, la fecha fecha del hecho será tomada para el sorteo del juez
caso contrario se tomará la fecha de la denuncia del caso en la comisaría interviniente

Esa distinción entonces se opera a través de la siguiente línea de código:
/* Distincion flagrante si/no */

$campo_fecha = ( $exped->flagrante == 'si' ) ? 'fecha_hecho' : 'fec_ingreso';
$fecha_inicio = $exped->$campo_fecha;

Sorteo de causas en el fuero CyF


 

El algoritmo realiza los siguientes pasos:

  • Habiendo flagrancia, se toma la fecha del hecho

  • Caso contrario se toma la fecha de ingreso

  • Se identifica la zona asociada a la fiscalía interviniente

  • Si es menor, sortea sobre la tabla "turno_juzgado_juvenil"

  • Si no lo es, sortea sobre la tabla "turno_juzg"

  • Se realiza la búsqueda y se obtiene el juzgado con los parámetros zona, fecha_inicio


 
	function sorteo_juez( $actor_fiscalia_ID = null ) {/*{{{*/

global $xpdoc;

M()->info( "flagrante: $exped->flagrante" );

/* fecha_inicio en base a flagrancia */

if ( $exped->flagrante == 'si' )
$fecha_inicio = $this->fecha_hecho;
else
$fecha_inicio = $this->fec_ingreso;

M()->info( "fecha inicio: $fecha_inicio" );

/* actor_fiscalia */

if ( $actor_fiscalia ) {

$zona_fiscalia = $xpdoc->get_instance( 'actor_legal' )->load( $actor_fiscalia_ID )->zona;
}

/* distincion zona:
o viene ya en el expediente
o es del usuario
o es 'X' (no tiene)
*/

$zona = $exped->zona_cardinal or $zona = $zona_fiscalia or $zona = 'X';

M()->info( "turno juzgado:: flagrante: $exped->flagrante, fecha_inicio: $fecha_inicio, zona: $exped->zona_cardinal" );

/* distincion menor */

if ( $exped->tiene_menor == 'si' ) {

$tabla_turnos = 'turno_juzgado_juvenil';
$a_zona = null;

} else {

$tabla_turnos = 'turno_juzg';
$a_zona = array( 'zona' => $exped->zona_cardinal );
}

M()->user( "Usando tabla de turnos $tabla_turnos" );

/* lookup en la tabla de turnos */

$turno_juzg = $xpdoc->get_instance( $tabla_turnos )
->load( $a_zona, "fecha_desde <= '{$fecha_inicio}' and '{$fecha_inicio}' <= fecha_hasta" );

if ( $turno_juzg ) {

M()->info( "juzgado_ID: $turno_juzg->actor_juzgado_ID" );
return $turno_juzg->actor_juzgado_ID;

} else {

M()->error( "no se encontro turno para el expediente con ID {$exped->ID} y el caso MPF {$exped->numero_kiwi} con fecha $fecha_inicio" );
return ERROR;
}

}/*}}}*/

 

Identificación de menor sobre el documento XML de la transacción


La identificación del menor se realiza a través del descubrimiento de valores vía XPATH sobre el documento XML:
/* menor */

if ( count( $caso->xpath( "//datos_persona[menor='SI' and (../rol[@PMJ='denunciado'] or ../rol[@PMJ='imputado'])]" ) ) ) {

M()->user( "Hay menores en el expediente como imputado, seteando exped::tiene_menor = 'si'" );
$exped->tiene_menor = 'si';

} else
$exped->tiene_menor = 'no';

Estos fragmentos de código se encuentran repartidos entre la funcion if_kiwi_exped() y los métodos del objeto "exped"



Incorporación de Actores Judiciales al Expediente


Una vez recibido un caso dentro del proceso de la interoperabilidad y habiendo una o más denuncias asociadas al caso, el primer actor a incorporar con el rol manifiesto resulta ser la comisaría, luego la fiscalía interviniente, las UIT y UTE, la Fiscalía General y por último se sortea el juzgado. Toda esa regla de cómputo es seleccionar adecuadamente a los actores del MPF que intervienen en la causa, JusCABA asigna todos los actores judiciales, inclusive lo que están fuera de su órbita funcional. Si bien esto resulta razonable, el algoritmo en realidad debería recibir los actores que remite el Kiwi y validar si son los correctos. Paradójicamente resulta más dificil realizar lo segundo que lo primero ya que se requiere de un mapeo completo de la regla computacional detrás de todos los actores y el mapa judicial en la seleección de su competencia.

La implementación actual se realiza entonces a través de una cadena recursiva de guardar (store) actor_rol que se encadenan de la siguiente forma:







AGREGANDO ROL AGREGA NUEVO ROL
COMISARIA FISCALIA / UIT
FISCALIA / UIT JUZGADO
JUZGADO SGCAMCYF
VICTIMA / TESTIGO / DAMNIFICADO OAVyT
MENOR / INCAPAZ ASESORIA TUTELAR PCyF

Recursividad en la selección de los actores judiciales


Esta tarea la realiza el método actor_rol.post_check(): una vez que haya sido cargado el primer actor, en este caso la comisaría, la función que se ejecuta luego de grabar el actual actor_rol. Ahí comienza entonces la recursión a través de un "switch" que puede generar nuevos actores y así sucesivamente, hasta que no se agreguen nuevos integrantes. En el caso de victimas, damnificados, denunciantes la determinación se realiza fuera del "switch" consultando si la persona es menor o incapaz. Para todos los casos se incorpora al coordinador fiscal. Por último, si el actor judicial es ingresado en forma manual e interactiva dentro de JusCABA, se agrega un paso adicional denominado "AFECTAR_ACTOR_LEGAL" anunciando a las partes intervinientes que se a agregado un nuevo actor, con fecha y hora de su incorporación:
	function post_check() {/*{{{*/

// debug_print_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS);

M()->info();

global $xpdoc;

/* exped: espera que haya un exped cargado en la transaccion */

$exped = $xpdoc->get_instance( 'exped' );

if ( $exped->ID == NULL ) {

M()->error( "No se pueda cargar un nuevo actor_rol si no hay un cargado en el proceso" );
return;
}


/* actor_rol: post_check() carga un nuevo actor a la causa asociado al que se esta cargando */
/* ACTUAL >> NUEVO */

$actor_rol = $xpdoc->instance( 'actor_rol' );
$actor_rol->push_privileges( array( 'edit' => true, 'add' => true ) );

/* defaults */

$actor_rol->exped_ID = $exped->ID;
$actor_rol->get_attr( 'fec_ingreso' )->now();

/* actor_legal */

$actor_legal = $xpdoc->get_instance( 'actor_legal' );

/* switch del t_actor_ID ACTUAL */

switch( $this->t_actor_ID ) {

/* COMISARIA >> FISCALIA, UIT */

case COMISARIA:

M()->info( 't_actor_ID: COMISARIA' );

$actor_comisaria = $xpdoc->instance( 'actor_comisaria' )->load( $this->actor_ID );

/* solo las comisarias del "nuevo" modelo deberian tener el valor zona */

if ( $actor_comisaria->zona_nudo != NULL ) {

/* DEBUG: solo deberia haber una por zona en la tabla actor_legal, poner un indice UNIQUE */

if ( $actor_legal->load( array( 't_actor_ID' => UIT, 'zona' => $actor_comisaria->zona_nudo ) ) ) {

$actor_rol->actor_ID = $actor_legal->ID;
$actor_rol->t_actor_ID = UIT;
$actor_rol->actor_nombre = $actor_legal->actor_legal;

// $actor_rol->store();
M()->user( "Se ha afectado a $actor_rol->actor_nombre" );
}

} else if ( $actor_comisaria->zona == "X" ) {

if ( $xpdoc->user->t_actor_ID == FISCAL ) {

$actor_rol->actor_ID = $xpdoc->user->actor_ID;
$actor_rol->t_actor_ID = $xpdoc->user->t_actor_ID;
$actor_rol->actor_nombre = $actor_legal->load( $actor_rol->actor_ID )->actor_legal;

// $actor_rol->store_xml_response();
$actor_rol->store();
M()->user( "Se ha afectado al usuario $actor_legal->actor_legal" );
}

} else {

$mes = date( "m", strtotime( $exped->fecha_hecho ) );

$turno_fiscalia = $xpdoc->instance( 'turno_fiscalia' )->load( array( 'mes'=> $mes, 'actor_comisaria_ID' => $this->actor_ID ));

if ( $fiscalia_ID = $turno_fiscalia->actor_fiscalia_ID ) {

$actor_rol->actor_ID = $fiscalia_ID;
$actor_rol->t_actor_ID = FISCAL;
$actor_rol->actor_nombre = $actor_legal->load( $actor_rol->actor_ID )->actor_legal;

// $actor_rol->store_xml_response();
$actor_rol->store();
M()->user( "Se ha afectado a la fiscalia_ID $fiscalia_ID a la causa" );
}
}

break;

case FISCAL:
case UIT:

/* FISCAL, UIT >> JUEZ */

$actor_rol2 = $xpdoc->instance( 'actor_rol' );

if ( $actor_rol2->load( array( 'exped_ID' => $this->exped_ID, 't_actor_ID' => JUEZ, 'afecta' => 'si' ) ) ) {

M()->user( "Ya hay un juez afectado a la causa: $actor_rol2->actor_nombre" );

unset( $actor_rol2 );
break;

} else unset( $actor_rol2 );

$actor_rol->actor_ID = $exped->sorteo_juez( $this->actor_ID );
$actor_rol->t_actor_ID = JUEZ;
$actor_rol->actor_nombre = $actor_legal->load( $actor_rol->actor_ID )->actor_legal;

// para que devuelva el juzgado_ID
$actor_rol->store_xml_response();

// $actor_rol->store();
M()->user( "Se ha afectado al actor $actor_rol->actor_nombre" );

break;


/* JUEZ >> SGCAMCYF */

case JUEZ:

M()->info( 't_actor_ID: JUEZ' );

$params = array( 'exped_ID' => $exped->ID, 'actor_ID' => SGCAMCYF, 't_actor_ID' => SEC_GRAL, 'afecta' => 'si' );

if ( ! $actor_rol->load( $params ) ) {

$actor_rol->bind( $params, true );
$actor_rol->actor_nombre = $actor_legal->load( SGCAMCYF )->actor_legal;

$actor_rol->get_attr( 'fec_ingreso' )->now();

$actor_rol->store_xml_response();

M()->user( "Se afecta a $actor_legal->actor_legal" );
}


break;


/* VICTIMA, TESTIGO, DAMNIFICADO >> OAVyT */

case VICTIMA:
case TESTIGO:
case DAMNIFICADO:

M()->info( "Afectada a la OAVyT" );

/* Busco a la OAVyT */
$oavyt = $actor_legal->load( array( 'convenio' => 'oavyt' ) );

/* verificar que no este en el expediente */

$actor_rol->load( array( 'exped_ID' => $this->exped_ID, 't_actor_ID' => $oavyt->t_actor_ID, 'actor_ID' => $oavyt->ID ) );

if ( ! $actor_rol ) {

$actor_rol->fec_ingreso = $this->fec_ingreso;
$actor_rol->exped_ID = $this->exped_ID;

$actor_rol->t_actor_ID = $oavyt->t_actor_ID;
$actor_rol->actor_ID = $oavyt->ID;
$actor_rol->actor_nombre = $oavyt->actor_legal;

// $actor_rol->store_xml_response();
$actor_rol->store();
M()->user( "Se agrego a la OAVyT como actor legal del expediente" );
}

break;

default:

M()->debug( "case actor: $this->t_actor_ID no implementado" );

} /* end switch t_actor */

/* menor o incapaz: incorporacion de la ASESORIA_TUTELAR_PCYF */

$t_actor = $xpdoc->get_instance( 't_actor' )->load( $this->t_actor_ID );

if ( $t_actor->t_actor == 'actor_procesal' ) {

M()->info( "actor_procesal, con ID $this->actor_ID" );

$act_procesal = $xpdoc->get_instance( 'actor_procesal' )->load( $this->actor_ID );

if ( $act_procesal->menor == 'si' or $act_procesal->incapaz == 'si' ) {

/* DEBUG: no hay criterio de seleccion para la Asesoria Tutelar */

$params = array(
'exped_ID' => $this->exped_ID,
't_actor_ID' => ASESORIA_TUTELAR_PCYF,
'actor_ID' => ASTUTCYF1
);

if ( ! $actor_rol->load( $params ) ) {

$actor_rol->fec_ingreso = $this->fec_ingreso;
$actor_rol->bind( $params, true );
$actor_rol->actor_nombre = $actor_legal->load( ASTUTCYF1 )->actor_legal;

// $actor_rol->store_xml_response();
$actor_rol->store();
M()->user( "Se ha afectado a la Asesoria Tutelar PCyF a la causa" );

}
}
}

/* registro nuevo */

if ( $this->last_op() == INSERT_OP ) {

/* siempre se tiene que agregar el coordinador cuando se agregue alguien de la uit o utc o equipo fiscal */
/* recursion evitada porque get_fiscal_coordinador va a ser cero */

$fiscal_coordinador = $this->get_fiscal_coordinador();

if ( in_array( $this->t_actor_ID, array( FISCAL, UTC, UIT ) ) and $this->afecta == 'si' and $fiscal_coordinador ) {

if ( ! $actor_rol->load( $this->exped_ID, FISCAL, $fiscal_coordinador ) ) {

$actor_rol->exped_ID = $exped->ID;
$actor_rol->get_attr( 'fec_ingreso' )->now();

$actor_rol->t_actor_ID = FISCAL;
$actor_rol->actor_ID = $fiscal_coordinador;
$actor_rol->actor_nombre = $actor_legal->load( $fiscal_coordinador )->actor_legal;
$actor_rol->afecta = 'si';

// $actor_rol->store_xml_response();
$actor_rol->store();
M()->user( "Afectado el Fiscal Coordinador" );
}
}

/* cuando se agregue un actor legal en forma interactiva, creo un paso [afectacion actor legal] automatico */

if ( $xpdoc->http->m == 'actor_rol' and $xpdoc->http->p == 'store' ) {

if ( $xpdoc->get_instance( 't_actor' )->load( $this->t_actor_ID )->t_actor == 'actor_judicial' ) {

$actor_rol->load( array ( 'exped_ID' => $this->exped_ID,
't_actor_ID' => $xpdoc->user->t_actor_ID,
'actor_ID' => $xpdoc->user->actor_ID ) );

/* si no lo encuentra ya en el expediente, lo agrega */

if ( ! ( $actor_rol and $actor_rol_orig = $actor_rol->ID ) ) {

$data = array(
'exped_ID' => $this->exped_ID,
't_paso_ID' => AFECTAR_ACTOR_LEGAL,
'fec_creado' => date( 'Ymd' ),
'fec_firmado' => date( 'Ymd' ),
'observa' => 'paso procesal creado automaticamente',
'usuario' => $exped->usuario,
'actor_rol_ID_orig' => $actor_rol_orig,
'actor_rol_ID_dest' => $this->ID,
'firma' => 'si',
'proceso' => 1,
't_acceso_ID' => ACCESO_PROTEGIDO

);

$paso = $xpdoc->get_instance( 'paso' )->reset();
$paso->feat->load_full_query = true;
$paso->push_privileges( array( 'edit' => true, 'add' => true ) );

$paso->bind( $data, true );
// $paso->store_xml_response();
$paso->store();
}
}
}
}

unset( $actor_rol );

}/*}}}*/

Mantenimiento de tablas de sorteos de juzgados


Se deben mantener en buena salud las tablas de sorteo de juzgados, no pueden faltar datos en el vértigo del código ejecutándose. En caso de no haber un turno, la "pelota" quedará del lado del CMCABA hasta tanto intervenga un administrador de la aplicación a resolver el inconveniente, ya que no puede rechazar la transacción en tanto y en cuanto el Kiwi haya remitido correctamente toda la información. Para mantener la tabla de juzgados entonces se debe incorporar:

  • un índice único para los juzgados, turnos y zonas

  • incorporar los datos a través de un producto cartesiano en SQL para que atomáticamente repita todos los turnos para todos los juzgados

  • verificar a través de consultas de rangos de tiempos posibles "gaps" en blanco que no haya cobertura temporal


 

Exped Fix


Juscaba2 incorpora el método "exped_fix()" para reasignar el turno del juzgado a través de la interfaz interactiva, en donde se vuelve a repetir el algoritmo de sorteo con los mismos datos originales. Este algoritmo llama a sorteo_juez() y asigna correctamente la zona y la fiscalía:

 
	function exped_fix( $xml = null ) {/*{{{*/

global $xpdoc;

if ( $xml && ! $this->load( $xml['ID'] ) ) {

M()->user('no encuentro el expediente con ID: '. $xml['ID'] );
return;
}

M()->info( "revisando expediente $this->codigo: "$this->caratula" [$this->ID]" );

if ( ! ( $this->zona_cardinal = $this->obtiene_zona_forma() ) ) {

M()->user( "No se pudo verificar la zona cardinal, verifique que haya una forma asociada al expediente. No se pueden avanzar con exped_fix/sorteo_juez" );
return;

} else
M()->info( "zona_cardinal: $this->zona_cardinal" );

if ( ! ( $actor_juzgado_ID = $this->sorteo_juez() ) ) {

M()->user( "ID de juzgado nulo, no se pudo sortear el expediente, verifique si existe un turno para este expediente. No se pueden avanzar con exped_fix/sorteo_juez" );
return;
} else
M()->info( "ID juzgado: $actor_juzgado_ID" );

/* arregla el tipo de causa */

$this->t_causa_ID or ( $this->t_causa_ID = $this->obtiene_t_causa() );

$actor_legal = $xpdoc->get_instance( 'actor_legal' ) ;

$actor_rol = $xpdoc->get_instance( 'actor_rol' );
$actor_rol->push_privileges( array( 'add' => 1, 'edit' => 1 ) );

if ( $actor_rol->load( array( 'exped_ID' => $this->ID, 't_actor_ID' => JUEZ, 'afecta' => 'si' ) ) ) {

M()->info( "juzgado existente con actor_ID $actor_rol->actor_ID" );

if ( $actor_rol->actor_ID != $actor_juzgado_ID ) {

M()->user( "actor_ID distintos: $actor_rol->actor_ID != $actor_juzgado_ID, reparando ..." );

$actor_rol->actor_ID = $actor_juzgado_ID;
$actor_rol->actor_nombre = $actor_legal->load( $actor_rol->actor_ID )->actor_legal;

// $actor_rol->store_xml_response();
$actor_rol->update();

} else {

M()->user( "asignacion de juzgado correcta, sin cambios" );

}
} else {

M()->user( "este expediente no tiene un juzgado asignado, sorteando uno" );

$actor_rol->exped_ID = $this->ID;

/* la fecha es la fecha de ingreso del expediente, no del fix */
$actor_rol->fec_ingreso = $this->obtiene_fecha_inicio();

$actor_rol->t_actor_ID = JUEZ;
$actor_rol->actor_ID = $actor_juzgado_ID;
$actor_rol->actor_nombre = $actor_legal->load( $actor_rol->actor_ID )->actor_legal;

$actor_rol->insert();
}

M()->user( "juzgado_ID: $actor_juzgado_ID" );
M()->user( "zona cardinal: $this->zona_cardinal" );
M()->user( "Se ha afectado al actor $actor_rol->actor_nombre" );

}/*}}}*/

 

Generación de la Carátula del Expediente


Esta función ha sido redefinida, hubo planteos por parte de los usuarios judiciales sin embargo no hubo un planteo definitivo al respecto durante las reuniones de la Comisión de JusCABA. El motivo del reclamo principalmente se debe a que la interfaz debe generar automáticamente la carátula y ha sido redefinida incluyendo los artículos infringidos. La aparición del artículo en forma normalizada tal como se describió anteriormente pudo haber sido la incomodidad planteada por el área usuaria. Una vez siendo de uso corriente no se tuvo novedades sobre el reclamo. El algoritmo de generación de carátula es el siguiente:
	function genera_caratula( $denunciados, $articulos ) {/*{{{*/

$datos = $denunciados[0]->datos_persona;

$tmp = array();

( $t = trim( $datos->razon_social ) and $tmp[0] = $t )
or (

( $t = trim( $datos->apellido ) and $tmp[0] = $t ) and
( $t = trim( $datos->nombre ) and $tmp[0] .= ", $t" )

) or $tmp[0] = 'NN';

( count( $denunciados ) > 1 ) and $tmp[] = 'y otros';

$aa = array();

if ( $ca = count( $articulos ) ) {

$tmp[] = ( $ca > 1 ) ? 's/art(s).' : 's/art.';

foreach( $articulos as $articulo )
$aa[] = str_replace( 'caba.ar/', '', $articulo['PMJ'] );
}

$artuculo = array_shift( $articulos );

global $xpdoc;

$caratula = implode( ' ', array_merge( $tmp, array_unique( $aa ) ) );

if ( $a = $xpdoc->get_instance('articulo')->load( array( 'PMJ' => (string) $articulo['PMJ'] ) ) )
$caratula .= ' '. $a->descripcion;

return $caratula;


}/*}}}*/

Cierre y conclusión


Se han descripto los aspectos más relevantes de la operación de la interoperabilidad if_kiwi siendo aún menores a la implementación detallada y completa, el resto de las instrucciones resultan más triviales para el programador y están generalmente descritas a detalle en comentarios del código o bien en el código fuente de la implementación.

La interoperabilidad entre el Consejo de la Magistratura y el Ministerio Público Fiscal funcionando ya hace más de dos años resulta ser un hito relevante para un intercambio de información esencial entre las aplicaciones de gestión de justicia de ambas instituciones, iniciativa que ha agilizado la labor de los actores judiciales, aún habiendo dos moles informáticas con criterios diferentes como Kiwi y JusCABA. Como contrapartida, la ausencia de este mecanismo hubiera obligado a abandonar el procedimiento de judicializar una causa al papel, con la perdida de tiempo y ganancia en errores que esto conlleva, dando independencia operativa a la gestión y desarrollo de las principales aplicaciones de justicia en el ámbito de la ciudad de Buenos Aires.
Post date: 2014-11-21 14:37:55
Post date GMT: 2014-11-21 17:37:55
Post modified date: 2015-12-04 12:47:40
Post modified date GMT: 2015-12-04 15:47:40
Powered by [ Universal Post Manager ] plugin. HTML saving format developed by gVectors Team www.gVectors.com