- Corrige la comparación del hash del report para detectar cambios y comentarios nuevos.
- Elimina la generación de documentos artificiales para comentarios. - Añade los estados Nueva denuncia, Actualización ciudadano, Actividad OAAF y Actualizada. - Incorpora circuitos específicos de comunicación SAJ y SDI. - Registra correctamente el tipo de última subida en el histórico. - Añade confirmación al asignar una denuncia a un grupo distinto al del usuario. - Mejora etiquetas, mensajes de ayuda e instrucciones de la aplicación. - Añade la persistencia técnica necesaria para identificar el origen de cada actualización.
This commit is contained in:
@@ -13,6 +13,8 @@ namespace ApiDenuncias.Configuration
|
||||
public string? CircuitUpdateTemplateName { get; set; }
|
||||
public string? CircuitUpdateSajTemplateName { get; set; }
|
||||
public string? CircuitUpdateSdiTemplateName { get; set; }
|
||||
public string? CircuitCommunicationSajTemplateName { get; set; }
|
||||
public string? CircuitCommunicationSdiTemplateName { get; set; }
|
||||
public string? CircuitSignerStampTitle { get; set; }
|
||||
public string? CircuitVersion { get; set; }
|
||||
public string? DocumentMetadataLanguage { get; set; }
|
||||
|
||||
@@ -61,6 +61,16 @@ public sealed class ConfigurationController : ControllerBase
|
||||
return Ok(await _workGroupService.GetAsync(cancellationToken));
|
||||
}
|
||||
|
||||
[HttpGet("work-groups/current")]
|
||||
public async Task<ActionResult<CurrentUserWorkGroupsDto>> GetCurrentUserWorkGroups(
|
||||
CancellationToken cancellationToken)
|
||||
{
|
||||
var username = User.Identity?.Name ??
|
||||
throw new InvalidOperationException("No hay usuario autenticado.");
|
||||
|
||||
return Ok(await _workGroupService.GetUserGroupsAsync(username, cancellationToken));
|
||||
}
|
||||
|
||||
[HttpPut("work-groups/users/{username}")]
|
||||
[Authorize(Policy = "ConfigurationAdministrators")]
|
||||
public async Task<ActionResult<WorkGroupAdministrationDto>> SetUserWorkGroups(
|
||||
|
||||
@@ -194,7 +194,8 @@ public sealed class GestionaController : ControllerBase
|
||||
request.DocumentUrl,
|
||||
request.AssignedGroupCode,
|
||||
request.ComplaintId,
|
||||
request.IsUpdate);
|
||||
request.IsUpdate,
|
||||
request.UpdateSource);
|
||||
|
||||
return Ok(new { ok = true });
|
||||
}
|
||||
|
||||
@@ -316,7 +316,12 @@ public sealed class InboxController : ControllerBase
|
||||
json = null;
|
||||
}
|
||||
|
||||
var result = await _inboxService.ImportFromGlobalLeaksAsync(reportPackage, json, reportDetail, cancellationToken);
|
||||
var result = await _inboxService.ImportFromGlobalLeaksAsync(
|
||||
reportPackage,
|
||||
json,
|
||||
reportDetail,
|
||||
report,
|
||||
cancellationToken);
|
||||
if (result.ImportedCount > 0)
|
||||
{
|
||||
await _trackingService.MarkReportImportedAsync(
|
||||
|
||||
@@ -66,6 +66,7 @@ CREATE TABLE IF NOT EXISTS complaints (
|
||||
gestiona_uploaded_at_utc DATETIME(6) NULL,
|
||||
gestiona_last_upload_type TEXT NOT NULL,
|
||||
gestiona_assigned_group TEXT NOT NULL,
|
||||
pending_update_source VARCHAR(256) NOT NULL DEFAULT '',
|
||||
is_in_gestiona TINYINT(1) NOT NULL DEFAULT 0,
|
||||
is_rejected TINYINT(1) NOT NULL DEFAULT 0,
|
||||
created_at_utc DATETIME(6) NOT NULL DEFAULT CURRENT_TIMESTAMP(6),
|
||||
|
||||
@@ -84,6 +84,7 @@ public sealed class DenunciaInboxService
|
||||
FileDownloadResult reportDownload,
|
||||
FileDownloadResult? jsonDownload,
|
||||
ReportDetailDto? reportDetail,
|
||||
ReportDto inboxReport,
|
||||
CancellationToken cancellationToken = default)
|
||||
{
|
||||
await EnsureStorageReadyAsync(cancellationToken);
|
||||
@@ -102,7 +103,13 @@ public sealed class DenunciaInboxService
|
||||
|
||||
try
|
||||
{
|
||||
var result = await ProcessGlobalLeaksPackageAsync(reportDownload.Content, sourceName, json, reportDetail, cancellationToken);
|
||||
var result = await ProcessGlobalLeaksPackageAsync(
|
||||
reportDownload.Content,
|
||||
sourceName,
|
||||
json,
|
||||
reportDetail,
|
||||
inboxReport,
|
||||
cancellationToken);
|
||||
return new ImportSummary(
|
||||
1,
|
||||
result.ImportedCount,
|
||||
@@ -164,6 +171,7 @@ public sealed class DenunciaInboxService
|
||||
string sourceName,
|
||||
string? globalLeaksJson,
|
||||
ReportDetailDto? reportDetail,
|
||||
ReportDto inboxReport,
|
||||
CancellationToken cancellationToken)
|
||||
{
|
||||
using var packageStream = new MemoryStream(packageBytes, writable: false);
|
||||
@@ -214,6 +222,12 @@ public sealed class DenunciaInboxService
|
||||
$"No se ha podido determinar el identificador de la denuncia en {sourceName}.");
|
||||
}
|
||||
|
||||
denuncia.PendingUpdateSource = inboxReport.CitizenHasNewActivity
|
||||
? ComplaintUpdateSources.Citizen
|
||||
: inboxReport.ReceiverHasNewActivity
|
||||
? ComplaintUpdateSources.Receiver
|
||||
: string.Empty;
|
||||
|
||||
if (reportIsPdf)
|
||||
{
|
||||
reportText = BuildSyntheticReportText(denuncia);
|
||||
@@ -246,14 +260,17 @@ public sealed class DenunciaInboxService
|
||||
var storedComplaint = await _denunciaStore.GetDenunciaByIdAsync(denuncia.Id_Denuncia, cancellationToken);
|
||||
if (IsAlreadyUploadedToGestiona(storedComplaint))
|
||||
{
|
||||
var storedFiles = await GetFicherosMetadataByDenunciaForImportAsync(denuncia.Id_Denuncia, cancellationToken);
|
||||
var storedFiles = await GetFicherosMetadataByDenunciaForImportAsync(
|
||||
denuncia.Id_Denuncia,
|
||||
cancellationToken);
|
||||
if (!HasPendingFilesForGestiona(storedFiles))
|
||||
{
|
||||
storedComplaint!.EsActualizacion = false;
|
||||
storedComplaint.EnGestiona = true;
|
||||
storedComplaint.PendingUpdateSource = string.Empty;
|
||||
await _denunciaStore.UpsertDenunciaAsync(storedComplaint, cancellationToken);
|
||||
|
||||
warnings.Add($"La denuncia #{denuncia.Id_Denuncia} ya esta en Gestiona y no tiene documentos nuevos pendientes de subir.");
|
||||
warnings.Add(BuildNoCitizenUpdateWarning(inboxReport));
|
||||
return new ProcessPackageResult(denuncia.Id_Denuncia, 0, warnings);
|
||||
}
|
||||
}
|
||||
@@ -379,6 +396,13 @@ public sealed class DenunciaInboxService
|
||||
}
|
||||
}
|
||||
|
||||
private static string BuildNoCitizenUpdateWarning(ReportDto inboxReport)
|
||||
{
|
||||
return inboxReport.ReceiverHasNewActivity && !inboxReport.CitizenHasNewActivity
|
||||
? "La actividad detectada procede de la OAAF, pero el report descargado no contiene cambios pendientes de subir a Gestiona."
|
||||
: "La denuncia ya esta en Gestiona y el report no contiene documentos ni comentarios nuevos del ciudadano pendientes de subir.";
|
||||
}
|
||||
|
||||
private static bool HasPendingFilesForGestiona(IReadOnlyList<FicherosDenuncias> files)
|
||||
{
|
||||
var plannedHashes = files
|
||||
@@ -591,6 +615,7 @@ public sealed class DenunciaInboxService
|
||||
target.Pais = source.Pais;
|
||||
target.CamposFormularioJson = source.CamposFormularioJson;
|
||||
target.TextoOriginalReport = source.TextoOriginalReport;
|
||||
target.PendingUpdateSource = source.PendingUpdateSource;
|
||||
}
|
||||
|
||||
private static bool IsSupportedAttachmentEntry(ZipArchiveEntry entry)
|
||||
|
||||
@@ -280,6 +280,7 @@ public sealed class EncryptedDenunciaStore : IDenunciaStore, IFilteredDenunciaSt
|
||||
FechaSubidaAGestiona = source.FechaSubidaAGestiona,
|
||||
UltimaSubidaGestionaTipo = source.UltimaSubidaGestionaTipo,
|
||||
UltimoGrupoAsignadoGestiona = source.UltimoGrupoAsignadoGestiona,
|
||||
PendingUpdateSource = source.PendingUpdateSource,
|
||||
EnGestiona = source.EnGestiona,
|
||||
EnRechazada = source.EnRechazada,
|
||||
|
||||
@@ -361,6 +362,7 @@ public sealed class EncryptedDenunciaStore : IDenunciaStore, IFilteredDenunciaSt
|
||||
target.FechaSubidaAGestiona = stored.FechaSubidaAGestiona;
|
||||
target.UltimaSubidaGestionaTipo = stored.UltimaSubidaGestionaTipo;
|
||||
target.UltimoGrupoAsignadoGestiona = stored.UltimoGrupoAsignadoGestiona;
|
||||
target.PendingUpdateSource = stored.PendingUpdateSource;
|
||||
target.EnGestiona = stored.EnGestiona;
|
||||
target.EnRechazada = stored.EnRechazada;
|
||||
}
|
||||
|
||||
@@ -3,6 +3,7 @@ using System.Security.Cryptography;
|
||||
using System.Globalization;
|
||||
using System.Text;
|
||||
using System.Text.Json;
|
||||
using GestionaDenuncias.Shared.Models;
|
||||
using Microsoft.Extensions.Logging;
|
||||
|
||||
namespace ApiDenuncias.Services;
|
||||
@@ -124,11 +125,20 @@ public sealed class GestionaDocumentWorkflowService
|
||||
string documentUrl,
|
||||
string assignedGroupCode,
|
||||
int? complaintId = null,
|
||||
bool isUpdate = false)
|
||||
bool isUpdate = false,
|
||||
string? updateSource = null)
|
||||
{
|
||||
var docUrlAbs = EnsureAbsoluteGestionaUrl(documentUrl, GestionaApiBase);
|
||||
var operationLabel = isUpdate ? $"actualizacion grupo {NormalizeGroupCode(assignedGroupCode)}" : "nueva denuncia";
|
||||
var (templateHref, payload) = await ResolveCircuitTemplatePayloadAsync(docUrlAbs, isUpdate, assignedGroupCode);
|
||||
var operationLabel = ComplaintUpdateSources.IsReceiver(updateSource)
|
||||
? $"comunicacion OAAF grupo {NormalizeGroupCode(assignedGroupCode)}"
|
||||
: isUpdate
|
||||
? $"actualizacion grupo {NormalizeGroupCode(assignedGroupCode)}"
|
||||
: "nueva denuncia";
|
||||
var (templateHref, payload) = await ResolveCircuitTemplatePayloadAsync(
|
||||
docUrlAbs,
|
||||
isUpdate,
|
||||
assignedGroupCode,
|
||||
updateSource);
|
||||
var (success, statusCode, body) = await TryPostCircuitAsync(docUrlAbs, payload);
|
||||
if (success)
|
||||
{
|
||||
@@ -155,7 +165,8 @@ public sealed class GestionaDocumentWorkflowService
|
||||
private async Task<(string TemplateHref, string Payload)> ResolveCircuitTemplatePayloadAsync(
|
||||
string documentUrl,
|
||||
bool isUpdate,
|
||||
string? assignedGroupCode)
|
||||
string? assignedGroupCode,
|
||||
string? updateSource)
|
||||
{
|
||||
var templatesUrl = $"{documentUrl.TrimEnd('/')}/circuit/templates";
|
||||
var templates = await GetCircuitTemplatesAsync(templatesUrl);
|
||||
@@ -164,7 +175,7 @@ public sealed class GestionaDocumentWorkflowService
|
||||
throw new InvalidOperationException("Gestiona no ha devuelto plantillas de circuito para el documento.");
|
||||
}
|
||||
|
||||
var selection = GetOperationCircuitTemplateSelection(isUpdate, assignedGroupCode);
|
||||
var selection = GetOperationCircuitTemplateSelection(isUpdate, assignedGroupCode, updateSource);
|
||||
if (!string.IsNullOrWhiteSpace(selection.TemplateName))
|
||||
{
|
||||
var resolved = await TryResolveCircuitTemplatePayloadByNameAsync(templates, selection.TemplateName);
|
||||
@@ -211,7 +222,10 @@ public sealed class GestionaDocumentWorkflowService
|
||||
"No se puede seleccionar de forma inequivoca la plantilla de circuito. Configura Gestiona:CircuitTemplateName o Gestiona:CircuitSignerStampTitle.");
|
||||
}
|
||||
|
||||
private CircuitTemplateSelection GetOperationCircuitTemplateSelection(bool isUpdate, string? assignedGroupCode)
|
||||
private CircuitTemplateSelection GetOperationCircuitTemplateSelection(
|
||||
bool isUpdate,
|
||||
string? assignedGroupCode,
|
||||
string? updateSource)
|
||||
{
|
||||
if (!isUpdate)
|
||||
{
|
||||
@@ -221,6 +235,25 @@ public sealed class GestionaDocumentWorkflowService
|
||||
OperationLabel: "nueva denuncia");
|
||||
}
|
||||
|
||||
if (ComplaintUpdateSources.IsReceiver(updateSource))
|
||||
{
|
||||
return NormalizeGroupCode(assignedGroupCode) switch
|
||||
{
|
||||
"510" => new CircuitTemplateSelection(
|
||||
_configuration["Gestiona:CircuitCommunicationSdiTemplateName"],
|
||||
Required: true,
|
||||
OperationLabel: "comunicacion SDI a denunciante"),
|
||||
|
||||
"600" => new CircuitTemplateSelection(
|
||||
_configuration["Gestiona:CircuitCommunicationSajTemplateName"],
|
||||
Required: true,
|
||||
OperationLabel: "comunicacion SAJ a denunciante"),
|
||||
|
||||
_ => throw new InvalidOperationException(
|
||||
"Las comunicaciones de la OAAF solo pueden tramitarse con los grupos 510 o 600.")
|
||||
};
|
||||
}
|
||||
|
||||
var defaultUpdateTemplateName = FirstConfigured(
|
||||
_configuration["Gestiona:CircuitTemplateName"],
|
||||
_configuration["Gestiona:CircuitUpdateTemplateName"]);
|
||||
|
||||
@@ -950,6 +950,15 @@ public sealed class GlobalLeaksClient
|
||||
|
||||
private static DateTimeOffset? GetActivityReference(ReportDto report, DateTimeOffset? fallbackReference)
|
||||
{
|
||||
if (report.AlreadyInGestiona)
|
||||
{
|
||||
var lastGestionaUpload = ParseDate(report.LastGestionaUploadAt);
|
||||
if (lastGestionaUpload is not null)
|
||||
{
|
||||
return lastGestionaUpload;
|
||||
}
|
||||
}
|
||||
|
||||
return ParseDate(report.LastDownloadedAt) ??
|
||||
fallbackReference ??
|
||||
ParseDate(report.LastAccess) ??
|
||||
|
||||
@@ -102,6 +102,7 @@ public sealed class InboxTrackingService : IInboxTrackingService
|
||||
DownloadedByAnotherUser = meta?.DownloadedByAnotherUser ?? false,
|
||||
LastDownloadedByUsername = meta?.LastDownloadedByUsername,
|
||||
LastDownloadedAt = meta?.LastDownloadedAtUtc?.ToString("O", CultureInfo.InvariantCulture),
|
||||
LastGestionaUploadAt = meta?.LastGestionaUploadAtUtc?.ToString("O", CultureInfo.InvariantCulture),
|
||||
AlreadyImported = meta?.AlreadyImported ?? false,
|
||||
AlreadyInGestiona = meta?.AlreadyInGestiona ?? false,
|
||||
OwnerUsername = meta?.OwnerUsername,
|
||||
@@ -535,6 +536,15 @@ public sealed class InboxTrackingService : IInboxTrackingService
|
||||
owner.username AS owner_username,
|
||||
ir.imported_to_store_at_utc,
|
||||
COALESCE(c.is_in_gestiona, 0) AS already_in_gestiona,
|
||||
COALESCE(
|
||||
(
|
||||
SELECT MAX(history.uploaded_at_utc)
|
||||
FROM gestiona_upload_history history
|
||||
WHERE history.external_report_id =
|
||||
COALESCE(ir.imported_complaint_report_id, ir.progressive_id)
|
||||
),
|
||||
c.gestiona_uploaded_at_utc
|
||||
) AS last_gestiona_upload_at_utc,
|
||||
CASE WHEN uir.last_downloaded_at_utc IS NULL THEN 0 ELSE 1 END AS downloaded_by_current_user,
|
||||
CASE WHEN ir.owner_user_id = @userId THEN 1 ELSE 0 END AS owned_by_current_user,
|
||||
CASE
|
||||
@@ -599,6 +609,7 @@ public sealed class InboxTrackingService : IInboxTrackingService
|
||||
DownloadedByAnotherUser = downloadedByAnotherUser,
|
||||
LastDownloadedByUsername = lastDownloadedByUsername,
|
||||
LastDownloadedAtUtc = GetDateTimeOffset(reader, "last_downloaded_at_utc"),
|
||||
LastGestionaUploadAtUtc = GetDateTimeOffset(reader, "last_gestiona_upload_at_utc"),
|
||||
AlreadyImported = !reader.IsDBNull(reader.GetOrdinal("imported_to_store_at_utc")),
|
||||
AlreadyInGestiona = reader.GetInt32(reader.GetOrdinal("already_in_gestiona")) == 1,
|
||||
OwnerUsername = ownerUsername,
|
||||
@@ -748,6 +759,7 @@ public sealed class InboxTrackingService : IInboxTrackingService
|
||||
public bool DownloadedByAnotherUser { get; init; }
|
||||
public string? LastDownloadedByUsername { get; init; }
|
||||
public DateTimeOffset? LastDownloadedAtUtc { get; init; }
|
||||
public DateTimeOffset? LastGestionaUploadAtUtc { get; init; }
|
||||
public bool AlreadyImported { get; init; }
|
||||
public bool AlreadyInGestiona { get; init; }
|
||||
public string? OwnerUsername { get; init; }
|
||||
|
||||
@@ -116,6 +116,7 @@ public sealed class MySqlDenunciaStore : IDenunciaStore
|
||||
gestiona_uploaded_at_utc,
|
||||
gestiona_last_upload_type,
|
||||
gestiona_assigned_group,
|
||||
pending_update_source,
|
||||
is_in_gestiona,
|
||||
is_rejected,
|
||||
key_date,
|
||||
@@ -184,6 +185,7 @@ public sealed class MySqlDenunciaStore : IDenunciaStore
|
||||
("complaints", "encrypted_at_utc", "`encrypted_at_utc` DATETIME(6) NULL"),
|
||||
("complaints", "gestiona_last_upload_type", "`gestiona_last_upload_type` VARCHAR(64) NOT NULL DEFAULT ''"),
|
||||
("complaints", "gestiona_assigned_group", "`gestiona_assigned_group` VARCHAR(255) NOT NULL DEFAULT ''"),
|
||||
("complaints", "pending_update_source", "`pending_update_source` VARCHAR(256) NOT NULL DEFAULT ''"),
|
||||
("inbox_reports", "owner_user_id", "`owner_user_id` BIGINT NULL"),
|
||||
("complaint_attachments", "content_sha256", "`content_sha256` CHAR(64) NOT NULL DEFAULT ''"),
|
||||
("complaint_attachments", "key_date", "`key_date` DATE NULL"),
|
||||
@@ -711,6 +713,7 @@ public sealed class MySqlDenunciaStore : IDenunciaStore
|
||||
gestiona_uploaded_at_utc,
|
||||
gestiona_last_upload_type,
|
||||
gestiona_assigned_group,
|
||||
pending_update_source,
|
||||
is_in_gestiona,
|
||||
is_rejected,
|
||||
key_date,
|
||||
@@ -783,6 +786,7 @@ public sealed class MySqlDenunciaStore : IDenunciaStore
|
||||
@gestionaUploadedAtUtc,
|
||||
@gestionaLastUploadType,
|
||||
@gestionaAssignedGroup,
|
||||
@pendingUpdateSource,
|
||||
@isInGestiona,
|
||||
@isRejected,
|
||||
@keyDate,
|
||||
@@ -855,6 +859,7 @@ public sealed class MySqlDenunciaStore : IDenunciaStore
|
||||
gestiona_uploaded_at_utc = VALUES(gestiona_uploaded_at_utc),
|
||||
gestiona_last_upload_type = VALUES(gestiona_last_upload_type),
|
||||
gestiona_assigned_group = VALUES(gestiona_assigned_group),
|
||||
pending_update_source = VALUES(pending_update_source),
|
||||
is_in_gestiona = VALUES(is_in_gestiona),
|
||||
is_rejected = VALUES(is_rejected),
|
||||
key_date = VALUES(key_date),
|
||||
@@ -932,6 +937,7 @@ public sealed class MySqlDenunciaStore : IDenunciaStore
|
||||
command.Parameters.AddWithValue("@gestionaUploadedAtUtc", ToDbDate(denuncia.FechaSubidaAGestiona));
|
||||
command.Parameters.AddWithValue("@gestionaLastUploadType", denuncia.UltimaSubidaGestionaTipo ?? string.Empty);
|
||||
command.Parameters.AddWithValue("@gestionaAssignedGroup", denuncia.UltimoGrupoAsignadoGestiona ?? string.Empty);
|
||||
command.Parameters.AddWithValue("@pendingUpdateSource", denuncia.PendingUpdateSource ?? string.Empty);
|
||||
command.Parameters.AddWithValue("@isInGestiona", denuncia.EnGestiona);
|
||||
command.Parameters.AddWithValue("@isRejected", denuncia.EnRechazada);
|
||||
command.Parameters.AddWithValue("@keyDate", ToDbDate(denuncia.KeyDate));
|
||||
@@ -996,9 +1002,6 @@ public sealed class MySqlDenunciaStore : IDenunciaStore
|
||||
description = @description,
|
||||
attachment_date_utc = @attachmentDateUtc,
|
||||
notes = @notes,
|
||||
content = @content,
|
||||
content_mime_type = @contentMimeType,
|
||||
content_sha256 = @contentSha256,
|
||||
uploaded_to_gestiona = CASE
|
||||
WHEN complaint_attachments.content_sha256 = @contentSha256 THEN complaint_attachments.uploaded_to_gestiona
|
||||
ELSE @uploadedToGestiona
|
||||
@@ -1007,6 +1010,9 @@ public sealed class MySqlDenunciaStore : IDenunciaStore
|
||||
WHEN complaint_attachments.content_sha256 = @contentSha256 THEN complaint_attachments.uploaded_at_utc
|
||||
ELSE @uploadedAtUtc
|
||||
END,
|
||||
content = @content,
|
||||
content_mime_type = @contentMimeType,
|
||||
content_sha256 = @contentSha256,
|
||||
key_date = @keyDate,
|
||||
encryption_scheme = @encryptionScheme,
|
||||
encrypted_at_utc = @encryptedAtUtc,
|
||||
@@ -1721,6 +1727,7 @@ public sealed class MySqlDenunciaStore : IDenunciaStore
|
||||
FechaSubidaAGestiona = GetDateTime(record, "gestiona_uploaded_at_utc"),
|
||||
UltimaSubidaGestionaTipo = GetString(record, "gestiona_last_upload_type"),
|
||||
UltimoGrupoAsignadoGestiona = GetString(record, "gestiona_assigned_group"),
|
||||
PendingUpdateSource = GetString(record, "pending_update_source"),
|
||||
EnGestiona = GetBoolean(record, "is_in_gestiona"),
|
||||
EnRechazada = GetBoolean(record, "is_rejected"),
|
||||
KeyDate = GetNullableDateOnly(record, "key_date"),
|
||||
|
||||
@@ -69,6 +69,42 @@ public sealed class WorkGroupAdministrationService
|
||||
.ToArray());
|
||||
}
|
||||
|
||||
public async Task<CurrentUserWorkGroupsDto> GetUserGroupsAsync(
|
||||
string username,
|
||||
CancellationToken cancellationToken = default)
|
||||
{
|
||||
await _denunciaStore.EnsureSchemaAsync(cancellationToken);
|
||||
|
||||
var normalizedUsername = username?.Trim();
|
||||
if (string.IsNullOrWhiteSpace(normalizedUsername))
|
||||
{
|
||||
throw new InvalidOperationException("No hay usuario autenticado.");
|
||||
}
|
||||
|
||||
await using var connection = await OpenConnectionAsync(cancellationToken);
|
||||
const string sql = """
|
||||
SELECT wg.code
|
||||
FROM app_users au
|
||||
INNER JOIN app_user_groups aug ON aug.app_user_id = au.id
|
||||
INNER JOIN work_groups wg
|
||||
ON wg.id = aug.work_group_id
|
||||
AND wg.is_active = 1
|
||||
WHERE LOWER(au.username) = LOWER(@username)
|
||||
ORDER BY wg.code;
|
||||
""";
|
||||
|
||||
var groupCodes = new List<string>();
|
||||
await using var command = new MySqlCommand(sql, connection);
|
||||
command.Parameters.AddWithValue("@username", normalizedUsername);
|
||||
await using var reader = await command.ExecuteReaderAsync(cancellationToken);
|
||||
while (await reader.ReadAsync(cancellationToken))
|
||||
{
|
||||
groupCodes.Add(reader.GetString(reader.GetOrdinal("code")));
|
||||
}
|
||||
|
||||
return new CurrentUserWorkGroupsDto(normalizedUsername, groupCodes);
|
||||
}
|
||||
|
||||
public async Task<WorkGroupAdministrationDto> UpdateUserGroupsAsync(
|
||||
string username,
|
||||
IEnumerable<string> groupCodes,
|
||||
|
||||
@@ -44,6 +44,8 @@
|
||||
"CircuitNewComplaintTemplateName": "CT-Nueva denuncia",
|
||||
"CircuitUpdateSajTemplateName": "CT-Actualización denuncia SAJ",
|
||||
"CircuitUpdateSdiTemplateName": "CT-Actualización denuncia SDI",
|
||||
"CircuitCommunicationSajTemplateName": "CT-Comunicación SAJ a denunciante",
|
||||
"CircuitCommunicationSdiTemplateName": "CT-Comunicación SDI a denunciante",
|
||||
"CircuitSignerStampTitle": "oaaf-complaints-tramit",
|
||||
"CircuitVersion": "2",
|
||||
"DocumentMetadataLanguage": "es",
|
||||
|
||||
@@ -95,7 +95,8 @@ public sealed record GestionaTramitarDocumentoRequest(
|
||||
string DocumentUrl,
|
||||
string AssignedGroupCode,
|
||||
int? ComplaintId,
|
||||
bool IsUpdate = false);
|
||||
bool IsUpdate = false,
|
||||
string? UpdateSource = null);
|
||||
|
||||
public sealed record ManualPurgeRequest(string Date);
|
||||
|
||||
@@ -125,6 +126,10 @@ public sealed record WorkGroupAdministrationDto(
|
||||
IReadOnlyList<WorkGroupDto> Groups,
|
||||
IReadOnlyList<UserWorkGroupDto> Users);
|
||||
|
||||
public sealed record CurrentUserWorkGroupsDto(
|
||||
string Username,
|
||||
IReadOnlyList<string> GroupCodes);
|
||||
|
||||
public sealed record UpdateUserWorkGroupsRequest(
|
||||
IReadOnlyList<string> GroupCodes);
|
||||
|
||||
|
||||
@@ -0,0 +1,13 @@
|
||||
namespace GestionaDenuncias.Shared.Models;
|
||||
|
||||
public static class ComplaintUpdateSources
|
||||
{
|
||||
public const string Citizen = "citizen";
|
||||
public const string Receiver = "receiver";
|
||||
|
||||
public static bool IsCitizen(string? value)
|
||||
=> string.Equals(value, Citizen, StringComparison.OrdinalIgnoreCase);
|
||||
|
||||
public static bool IsReceiver(string? value)
|
||||
=> string.Equals(value, Receiver, StringComparison.OrdinalIgnoreCase);
|
||||
}
|
||||
@@ -79,6 +79,7 @@ public class DenunciasGestiona
|
||||
public DateTime FechaSubidaAGestiona { get; set; } = DateTime.MinValue;
|
||||
public string UltimaSubidaGestionaTipo { get; set; } = string.Empty;
|
||||
public string UltimoGrupoAsignadoGestiona { get; set; } = string.Empty;
|
||||
public string PendingUpdateSource { get; set; } = string.Empty;
|
||||
|
||||
public bool EnGestiona { get; set; }
|
||||
public bool EnRechazada { get; set; }
|
||||
|
||||
@@ -30,6 +30,7 @@ public sealed record ReportDto
|
||||
public bool DownloadedByAnotherUser { get; init; }
|
||||
public string? LastDownloadedByUsername { get; init; }
|
||||
public string? LastDownloadedAt { get; init; }
|
||||
public string? LastGestionaUploadAt { get; init; }
|
||||
public bool AlreadyImported { get; init; }
|
||||
public bool AlreadyInGestiona { get; init; }
|
||||
public string? OwnerUsername { get; init; }
|
||||
|
||||
@@ -734,7 +734,7 @@ else
|
||||
nuevoAsunto = string.IsNullOrWhiteSpace(d.NombreDenuncia) ? $"Denuncia-{d.Id_Denuncia}-CD" : d.NombreDenuncia;
|
||||
nombreDocumentos = "";
|
||||
selectedThirdParty = ThirdPartyIdentityData.FromComplaint(d);
|
||||
selectedGroup = NormalizeUpdateGroup(selectedGroup);
|
||||
selectedGroup = NormalizeUpdateGroup(d.UltimoGrupoAsignadoGestiona);
|
||||
operationError = string.Empty;
|
||||
operationNotice = string.Empty;
|
||||
|
||||
@@ -844,12 +844,19 @@ else
|
||||
return;
|
||||
}
|
||||
|
||||
if (!await ConfirmSelectedGroupAsync())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
isUploading = true;
|
||||
operationError = string.Empty;
|
||||
operationNotice = string.Empty;
|
||||
selectedGroup = NormalizeUpdateGroup(selectedGroup);
|
||||
var pendingUpdateSource = selectedDenuncias.PendingUpdateSource;
|
||||
var uploadType = GetUpdateUploadType(pendingUpdateSource, selectedGroup);
|
||||
using var busy = Busy.Show(
|
||||
"Enviando actualizacion",
|
||||
"Preparando expediente, carpeta de actualizacion y documentos.");
|
||||
@@ -1035,7 +1042,8 @@ else
|
||||
documentoParaTramitar,
|
||||
selectedGroup,
|
||||
selectedDenuncias.Id_Denuncia,
|
||||
isUpdate: true);
|
||||
isUpdate: true,
|
||||
updateSource: pendingUpdateSource);
|
||||
}
|
||||
|
||||
foreach (var orig in nombresOriginalesSubidos)
|
||||
@@ -1057,13 +1065,14 @@ else
|
||||
selectedDenuncias.EsActualizacion = false;
|
||||
selectedDenuncias.NombreDenuncia = nuevoAsunto;
|
||||
selectedDenuncias.FechaSubidaAGestiona = ahoraUtc;
|
||||
selectedDenuncias.UltimaSubidaGestionaTipo = "Actualización";
|
||||
selectedDenuncias.UltimaSubidaGestionaTipo = uploadType;
|
||||
selectedDenuncias.UltimoGrupoAsignadoGestiona = GetGestionaGroupDisplay(selectedGroup);
|
||||
selectedDenuncias.PendingUpdateSource = string.Empty;
|
||||
await SincronizarExpedienteGestionaAsync(selectedDenuncias, fileUrl);
|
||||
await ActualizarDenunciaAsync(selectedDenuncias);
|
||||
var historialAviso = await RegistrarHistorialGestionaAsync(
|
||||
selectedDenuncias,
|
||||
"Actualización",
|
||||
uploadType,
|
||||
selectedGroup,
|
||||
ahoraUtc,
|
||||
string.Join("; ", nombresFinalesSubidos));
|
||||
@@ -1358,13 +1367,52 @@ else
|
||||
}
|
||||
|
||||
private static string NormalizeUpdateGroup(string? groupCode)
|
||||
=> groupCode == "510" ? "510" : "600";
|
||||
=> groupCode?.Trim().StartsWith("510", StringComparison.Ordinal) == true
|
||||
? "510"
|
||||
: "600";
|
||||
|
||||
private static string GetGestionaGroupDisplay(string? groupCode)
|
||||
{
|
||||
return string.IsNullOrWhiteSpace(groupCode) ? string.Empty : groupCode.Trim();
|
||||
}
|
||||
|
||||
private static string GetUpdateUploadType(string? updateSource, string groupCode)
|
||||
{
|
||||
if (!ComplaintUpdateSources.IsReceiver(updateSource))
|
||||
{
|
||||
return "Actualización";
|
||||
}
|
||||
|
||||
return NormalizeUpdateGroup(groupCode) == "510"
|
||||
? "Comunic. SDI a denunciante"
|
||||
: "Comunic. SAJ a denunciante";
|
||||
}
|
||||
|
||||
private async Task<bool> ConfirmSelectedGroupAsync()
|
||||
{
|
||||
try
|
||||
{
|
||||
var currentGroups = await ApiDenuncias.GetCurrentUserWorkGroupsAsync();
|
||||
if (currentGroups.GroupCodes.Contains(selectedGroup, StringComparer.OrdinalIgnoreCase))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
var configuredGroups = currentGroups.GroupCodes.Count == 0
|
||||
? "ningún grupo"
|
||||
: string.Join(", ", currentGroups.GroupCodes);
|
||||
return await JSRuntime.InvokeAsync<bool>(
|
||||
"confirm",
|
||||
$"El grupo de destino {selectedGroup} no pertenece a tus grupos configurados ({configuredGroups}). " +
|
||||
"Si continúas, la denuncia cambiará su asignación en Gestiona a un grupo distinto de los tuyos. ¿Deseas continuar?");
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
operationError = $"No se han podido comprobar tus grupos antes de la subida: {ex.Message}";
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
private async Task<string?> RegistrarHistorialGestionaAsync(
|
||||
DenunciasGestiona denuncia,
|
||||
string tipoSubida,
|
||||
|
||||
@@ -314,12 +314,12 @@
|
||||
<th>#</th>
|
||||
<th>Canal</th>
|
||||
<th>Presentacion</th>
|
||||
<th>Actividad ciudadano</th>
|
||||
<th>Actividad OAAF</th>
|
||||
<th>Estado</th>
|
||||
<th>Acceso</th>
|
||||
<th>Seguimiento</th>
|
||||
<th class="inbox-action-cell">Detalle</th>
|
||||
<th title="Fecha de la última aportación o comentario realizado por el ciudadano.">Actividad ciudadano</th>
|
||||
<th title="Fecha de la última comunicación o fichero incorporado por un gestor de la OAAF.">Actividad OAAF</th>
|
||||
<th title="Resume si la denuncia es nueva, tiene cambios pendientes o ya está actualizada en Gestiona.">Estado</th>
|
||||
<th title="Indica si tu usuario gestor del buzón puede acceder a esta denuncia.">Acceso</th>
|
||||
<th title="Indica si el cambio está pendiente, descargado en la aplicación o ya incorporado a Gestiona.">Gestiona</th>
|
||||
<th class="inbox-action-cell" title="Abre el detalle disponible en GlobalLeaks.">Detalle</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
@@ -361,17 +361,17 @@
|
||||
<td class="inbox-activity-cell">@FormatCitizenActivity(report)</td>
|
||||
<td class="inbox-activity-cell" title="@GetReceiverActivityTitle(report)">@FormatReceiverActivity(report)</td>
|
||||
<td>
|
||||
<span class="badge @GetStatusBadgeCss(report)">
|
||||
<span class="badge @GetStatusBadgeCss(report)" title="@GetStatusHelp(report)">
|
||||
@GetStatusLabel(report)
|
||||
</span>
|
||||
</td>
|
||||
<td>
|
||||
<span class="badge @GetAccessBadgeCss(report)">
|
||||
<span class="badge @GetAccessBadgeCss(report)" title="@GetAccessHelp(report)">
|
||||
@GetAccessLabel(report)
|
||||
</span>
|
||||
</td>
|
||||
<td class="inbox-tracking-cell" title="@(report.TrackingNote ?? string.Empty)">
|
||||
<span class="badge @GetTrackingBadgeCss(report)">@GetTrackingLabel(report)</span>
|
||||
<td class="inbox-tracking-cell">
|
||||
<span class="badge @GetTrackingBadgeCss(report)" title="@GetTrackingHelp(report)">@GetTrackingLabel(report)</span>
|
||||
</td>
|
||||
<td class="inbox-action-cell">
|
||||
<button type="button"
|
||||
@@ -1282,7 +1282,7 @@
|
||||
|
||||
if (report.CitizenHasNewActivity)
|
||||
{
|
||||
return "Actualizacion ciudadano";
|
||||
return "Actualización ciudadano";
|
||||
}
|
||||
|
||||
if (IsReceiverOnlyUpdate(report))
|
||||
@@ -1290,14 +1290,19 @@
|
||||
return "Actividad OAAF";
|
||||
}
|
||||
|
||||
if (report.Updated)
|
||||
if (report.AlreadyInGestiona && !report.ActivityAnalyzed)
|
||||
{
|
||||
return "Sin comprobar";
|
||||
}
|
||||
|
||||
if (IsUpToDateInGestiona(report))
|
||||
{
|
||||
return "Actualizada";
|
||||
}
|
||||
|
||||
return string.Equals(report.Status, "closed", StringComparison.OrdinalIgnoreCase)
|
||||
? "Cerrada"
|
||||
: "Abierta";
|
||||
: "Nueva denuncia";
|
||||
}
|
||||
|
||||
private static string GetStatusBadgeCss(ReportDto report)
|
||||
@@ -1317,7 +1322,12 @@
|
||||
return "bg-secondary";
|
||||
}
|
||||
|
||||
if (report.Updated)
|
||||
if (report.AlreadyInGestiona && !report.ActivityAnalyzed)
|
||||
{
|
||||
return "bg-warning text-dark";
|
||||
}
|
||||
|
||||
if (IsUpToDateInGestiona(report))
|
||||
{
|
||||
return "bg-light text-dark";
|
||||
}
|
||||
@@ -1327,6 +1337,47 @@
|
||||
: "bg-primary";
|
||||
}
|
||||
|
||||
private static bool IsUpToDateInGestiona(ReportDto report)
|
||||
{
|
||||
if (!report.AlreadyInGestiona)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
var lastUpload = ParseDate(report.LastGestionaUploadAt);
|
||||
var latestActivity = new[]
|
||||
{
|
||||
ParseDate(report.CitizenLastActivity),
|
||||
ParseDate(report.ReceiverLastActivity)
|
||||
}
|
||||
.Where(value => value is not null)
|
||||
.Select(value => value!.Value)
|
||||
.DefaultIfEmpty()
|
||||
.Max();
|
||||
|
||||
if (lastUpload is not null && latestActivity != default)
|
||||
{
|
||||
return lastUpload.Value >= latestActivity;
|
||||
}
|
||||
|
||||
return report.ActivityAnalyzed &&
|
||||
!report.CitizenHasNewActivity &&
|
||||
!report.ReceiverHasNewActivity;
|
||||
}
|
||||
|
||||
private static string GetStatusHelp(ReportDto report)
|
||||
=> GetStatusLabel(report) switch
|
||||
{
|
||||
"Nueva denuncia" => "La denuncia todavía no tiene expediente creado desde la aplicación y está pendiente de actuación.",
|
||||
"Actualización ciudadano" => "El ciudadano ha añadido un comentario, un fichero o una modificación posterior a la última subida a Gestiona.",
|
||||
"Actividad OAAF" => "Un gestor de la OAAF ha realizado una comunicación o añadido un fichero posterior a la última subida a Gestiona.",
|
||||
"Actualizada" => "La última subida a Gestiona es igual o posterior a la actividad del ciudadano y de la OAAF detectada en el buzón.",
|
||||
"Sin comprobar" => "No se ha podido comparar en este momento la actividad del buzón con la última subida a Gestiona.",
|
||||
"Cerrada" => "La denuncia figura cerrada en GlobalLeaks.",
|
||||
"Sin leer" => "La denuncia todavía no se ha abierto con este usuario en GlobalLeaks.",
|
||||
_ => string.Empty
|
||||
};
|
||||
|
||||
private static string GetAccessLabel(ReportDto report)
|
||||
=> report.Accessible switch
|
||||
{
|
||||
@@ -1343,6 +1394,14 @@
|
||||
_ => "bg-light text-dark"
|
||||
};
|
||||
|
||||
private static string GetAccessHelp(ReportDto report)
|
||||
=> report.Accessible switch
|
||||
{
|
||||
true => "Tu usuario gestor del buzón tiene acceso a esta denuncia.",
|
||||
false => "GlobalLeaks indica que tu usuario gestor del buzón no tiene acceso a esta denuncia.",
|
||||
_ => "GlobalLeaks no ha informado si tu usuario puede acceder a esta denuncia."
|
||||
};
|
||||
|
||||
private static bool CanUseReport(ReportDto report)
|
||||
=> report.Accessible != false;
|
||||
|
||||
@@ -1422,6 +1481,35 @@
|
||||
return "bg-light text-dark";
|
||||
}
|
||||
|
||||
private static string GetTrackingHelp(ReportDto report)
|
||||
{
|
||||
if (report.AlreadyInGestiona)
|
||||
{
|
||||
return "La denuncia ya tiene un expediente creado en Gestiona. El estado indica si existe actividad posterior pendiente.";
|
||||
}
|
||||
|
||||
if (report.DownloadedByAnotherUser)
|
||||
{
|
||||
return string.IsNullOrWhiteSpace(report.TrackingNote)
|
||||
? "Otro usuario ya la descargó en la aplicación, pero todavía no se ha materializado la subida a Gestiona."
|
||||
: $"{report.TrackingNote}. Todavía no se ha materializado la subida a Gestiona.";
|
||||
}
|
||||
|
||||
if (report.DownloadedByCurrentUser)
|
||||
{
|
||||
return string.IsNullOrWhiteSpace(report.TrackingNote)
|
||||
? "Ya la descargaste en la aplicación, pero todavía no se ha materializado la subida a Gestiona."
|
||||
: $"{report.TrackingNote}. Todavía no se ha materializado la subida a Gestiona.";
|
||||
}
|
||||
|
||||
if (report.AlreadyImported)
|
||||
{
|
||||
return "La denuncia está incorporada a la aplicación, pero todavía no se ha subido a Gestiona.";
|
||||
}
|
||||
|
||||
return "La denuncia todavía no se ha descargado ni subido a Gestiona.";
|
||||
}
|
||||
|
||||
private static string? GetReportRowCss(ReportDto report)
|
||||
{
|
||||
if (report.Accessible == false)
|
||||
|
||||
@@ -114,28 +114,28 @@ else
|
||||
<div class="card-header" data-bs-toggle="collapse" data-bs-target="#@collapseId" aria-expanded="false" aria-controls="@collapseId">
|
||||
<h5 class="mb-0">Denuncia ID: @denuncia.Id_Denuncia</h5>
|
||||
<div class="header-info">
|
||||
<span><strong>Asunto:</strong> @GetHeaderSubject(denuncia, latestHistory)</span>
|
||||
<span title="Asunto con el que se identifica el expediente en Gestiona."><strong>Asunto:</strong> @GetHeaderSubject(denuncia, latestHistory)</span>
|
||||
@if (!string.IsNullOrWhiteSpace(denuncia.ExpedienteGestionaMostrable))
|
||||
{
|
||||
<span><strong>Nº expediente:</strong> @denuncia.ExpedienteGestionaMostrable</span>
|
||||
<span title="Número asignado al expediente por Gestiona."><strong>Nº expediente:</strong> @denuncia.ExpedienteGestionaMostrable</span>
|
||||
}
|
||||
@if (!string.IsNullOrWhiteSpace(GetUploadType(denuncia, latestHistory)))
|
||||
{
|
||||
<span><strong>Última subida:</strong> @GetUploadType(denuncia, latestHistory)</span>
|
||||
<span title="Tipo de la última operación enviada desde la aplicación a Gestiona."><strong>Última subida:</strong> @GetUploadType(denuncia, latestHistory)</span>
|
||||
}
|
||||
@if (!string.IsNullOrWhiteSpace(GetAssignedGroup(denuncia, latestHistory)))
|
||||
{
|
||||
<span><strong>Grupo asignado:</strong> @FormatGroupCode(GetAssignedGroup(denuncia, latestHistory))</span>
|
||||
<span title="Grupo al que quedó asignado el expediente tras la última subida."><strong>Asignación en Gestiona:</strong> @FormatGroupCode(GetAssignedGroup(denuncia, latestHistory))</span>
|
||||
}
|
||||
@if (!string.IsNullOrWhiteSpace(GetUploadUser(latestHistory)))
|
||||
{
|
||||
<span><strong>Usuario subida:</strong> @GetUploadUser(latestHistory)</span>
|
||||
<span title="Usuario de la aplicación que realizó la última subida."><strong>Usuario subida:</strong> @GetUploadUser(latestHistory)</span>
|
||||
}
|
||||
<span><strong>Fecha de Subida:</strong> @FormatUploadDate(uploadMoment)</span>
|
||||
<span><strong>Hora de Subida:</strong> @FormatUploadTime(uploadMoment)</span>
|
||||
<span title="Fecha de la última operación enviada a Gestiona."><strong>Fecha de Subida:</strong> @FormatUploadDate(uploadMoment)</span>
|
||||
<span title="Hora local de la última operación enviada a Gestiona."><strong>Hora de Subida:</strong> @FormatUploadTime(uploadMoment)</span>
|
||||
@if (!string.IsNullOrWhiteSpace(GetAuditDateText(denuncia)))
|
||||
{
|
||||
<span><strong>Última actividad Gestiona:</strong> @GetAuditDateText(denuncia)</span>
|
||||
<span title="Último movimiento registrado en la auditoría del expediente de Gestiona."><strong>Última actividad Gestiona:</strong> @GetAuditDateText(denuncia)</span>
|
||||
}
|
||||
</div>
|
||||
</div>
|
||||
@@ -331,16 +331,16 @@ else
|
||||
<div class="card-header">
|
||||
<h5 class="mb-0">Denuncia ID: @item.DenunciaId</h5>
|
||||
<div class="header-info">
|
||||
<span><strong>Asunto:</strong> @DisplayOrDash(item.Asunto)</span>
|
||||
<span><strong>Nº expediente:</strong> @DisplayOrDash(item.CodigoExpedienteGestiona)</span>
|
||||
<span><strong>Última subida:</strong> @DisplayOrDash(item.TipoSubida)</span>
|
||||
<span><strong>Grupo asignado:</strong> @DisplayOrDash(FormatGroupCode(item.GrupoAsignado))</span>
|
||||
<span title="Asunto con el que se identifica el expediente en Gestiona."><strong>Asunto:</strong> @DisplayOrDash(item.Asunto)</span>
|
||||
<span title="Número asignado al expediente por Gestiona."><strong>Nº expediente:</strong> @DisplayOrDash(item.CodigoExpedienteGestiona)</span>
|
||||
<span title="Tipo de la última operación enviada desde la aplicación a Gestiona."><strong>Última subida:</strong> @DisplayOrDash(item.TipoSubida)</span>
|
||||
<span title="Grupo al que quedó asignado el expediente tras la última subida."><strong>Asignación en Gestiona:</strong> @DisplayOrDash(FormatGroupCode(item.GrupoAsignado))</span>
|
||||
@if (!string.IsNullOrWhiteSpace(GetUploadUser(item)))
|
||||
{
|
||||
<span><strong>Usuario subida:</strong> @GetUploadUser(item)</span>
|
||||
<span title="Usuario de la aplicación que realizó la última subida."><strong>Usuario subida:</strong> @GetUploadUser(item)</span>
|
||||
}
|
||||
<span><strong>Fecha de Subida:</strong> @FormatUploadDate(uploadMoment)</span>
|
||||
<span><strong>Hora de Subida:</strong> @FormatUploadTime(uploadMoment)</span>
|
||||
<span title="Fecha de la última operación enviada a Gestiona."><strong>Fecha de Subida:</strong> @FormatUploadDate(uploadMoment)</span>
|
||||
<span title="Hora local de la última operación enviada a Gestiona."><strong>Hora de Subida:</strong> @FormatUploadTime(uploadMoment)</span>
|
||||
<span class="text-muted">Detalle no disponible por purga criptográfica.</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -56,7 +56,7 @@
|
||||
<li>Abre la denuncia para revisar sus datos y adjuntos.</li>
|
||||
<li>En la lista de ficheros, deja marcado solo lo que quieras subir.</li>
|
||||
<li>El report de la denuncia se sube siempre y no se puede desmarcar.</li>
|
||||
<li>Pulsa <strong>Configurar subida</strong> para indicar asunto, grupo destino y modo de subida.</li>
|
||||
<li>Pulsa <strong>Configurar apertura expediente</strong> para indicar asunto, grupo destino y modo de subida.</li>
|
||||
<li>Confirma para crear el expediente, vincular el tercero y subir los documentos a Gestiona.</li>
|
||||
<li>Si la denuncia no procede, usa <strong>Rechazar denuncia</strong> e indica el motivo.</li>
|
||||
</ul>
|
||||
@@ -87,14 +87,15 @@
|
||||
<div class="card-body">
|
||||
<h2 class="h5">Actualizaciones</h2>
|
||||
<p>
|
||||
Esta pantalla recoge comunicaciones o adjuntos nuevos sobre denuncias que ya tienen expediente en Gestiona.
|
||||
Esta pantalla recoge comentarios, comunicaciones o adjuntos nuevos sobre denuncias que ya tienen expediente en Gestiona.
|
||||
</p>
|
||||
<ul class="mb-0">
|
||||
<li>Revisa la actualizacion y sus ficheros.</li>
|
||||
<li>La app propone los adjuntos que parecen nuevos.</li>
|
||||
<li>Puedes desmarcar los adjuntos que no quieras subir.</li>
|
||||
<li>El report de la actualizacion se mantiene obligatorio.</li>
|
||||
<li>Confirma la subida para a<EFBFBD>adir los nuevos documentos al expediente existente.</li>
|
||||
<li>Pulsa <strong>Configurar actualización expediente</strong> y confirma para añadir el cambio al expediente existente.</li>
|
||||
<li>Si la actividad procede de la OAAF, la aplicación utiliza el aviso correspondiente al grupo SAJ o SDI.</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
@@ -105,12 +106,12 @@
|
||||
<div class="card-body">
|
||||
<h2 class="h5">Gestiona</h2>
|
||||
<p>
|
||||
Aqui se consultan las denuncias que ya se han enviado a Gestiona.
|
||||
Aquí se almacena el histórico permanente de los movimientos enviados desde esta aplicación a Gestiona.
|
||||
</p>
|
||||
<ul class="mb-0">
|
||||
<li>Comprueba el numero de expediente y la fecha de envio.</li>
|
||||
<li>Accede al enlace del expediente cuando necesites revisar la tramitacion en Gestiona.</li>
|
||||
<li>Usa esta pantalla como seguimiento de lo que ya salio de Pendientes o Actualizaciones.</li>
|
||||
<li>Comprueba el número de expediente, el tipo de subida, el usuario que la realizó y la asignación en Gestiona.</li>
|
||||
<li>Despliega una operación del día para consultar sus datos y documentos mientras estén disponibles.</li>
|
||||
<li>Por requisitos de seguridad ENS, los detalles sensibles de días anteriores dejan de estar disponibles; la cabecera operativa y la trazabilidad permanecen visibles.</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
@@ -121,7 +122,7 @@
|
||||
<div class="card-body">
|
||||
<h2 class="h5">Rechazados</h2>
|
||||
<p>
|
||||
Aqui quedan las denuncias que se han descartado desde Pendientes.
|
||||
Aquí quedan las denuncias o actualizaciones que no se han subido a Gestiona porque se descartaron desde la pantalla de trabajo.
|
||||
</p>
|
||||
<ul class="mb-0">
|
||||
<li>Consulta el motivo indicado al rechazar.</li>
|
||||
@@ -165,4 +166,4 @@
|
||||
<div class="alert alert-warning mt-3 mb-0">
|
||||
Si una pantalla indica que una denuncia no esta disponible, no intentes tramitarla desde otra ruta: revisa la bandeja de Entrada o consulta con soporte del sistema.
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -602,7 +602,7 @@ else
|
||||
600. Asuntos Jurídicos y Protección a la Persona Denunciante
|
||||
</label>
|
||||
</div>
|
||||
@* <div class="form-check">
|
||||
<div class="form-check">
|
||||
<input class="form-check-input"
|
||||
type="radio"
|
||||
name="selectedGroup"
|
||||
@@ -613,17 +613,6 @@ else
|
||||
510. SDI – Investigación Entradas
|
||||
</label>
|
||||
</div>
|
||||
<div class="form-check">
|
||||
<input class="form-check-input"
|
||||
type="radio"
|
||||
name="selectedGroup"
|
||||
id="grupo700"
|
||||
checked='@(selectedGroup == "700")'
|
||||
@onclick='() => selectedGroup = "700"' />
|
||||
<label class="form-check-label" for="grupo700">
|
||||
700. RESPONSABLE DEL SERVICIO
|
||||
</label>
|
||||
</div> *@
|
||||
|
||||
<!-- DATOS DEL TERCERO -->
|
||||
@{
|
||||
@@ -963,6 +952,11 @@ else
|
||||
return;
|
||||
}
|
||||
|
||||
if (!await ConfirmSelectedGroupAsync())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
isUploading = true;
|
||||
@@ -1348,6 +1342,31 @@ else
|
||||
$"Puedes {action}la porque pertenece a un usuario de tu grupo. Deseas continuar?");
|
||||
}
|
||||
|
||||
private async Task<bool> ConfirmSelectedGroupAsync()
|
||||
{
|
||||
try
|
||||
{
|
||||
var currentGroups = await ApiDenuncias.GetCurrentUserWorkGroupsAsync();
|
||||
if (currentGroups.GroupCodes.Contains(selectedGroup, StringComparer.OrdinalIgnoreCase))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
var configuredGroups = currentGroups.GroupCodes.Count == 0
|
||||
? "ningún grupo"
|
||||
: string.Join(", ", currentGroups.GroupCodes);
|
||||
return await JSRuntime.InvokeAsync<bool>(
|
||||
"confirm",
|
||||
$"El grupo de destino {selectedGroup} no pertenece a tus grupos configurados ({configuredGroups}). " +
|
||||
"Si continúas, la denuncia quedará asignada en Gestiona a un grupo distinto de los tuyos. ¿Deseas continuar?");
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
operationError = $"No se han podido comprobar tus grupos antes de la subida: {ex.Message}";
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
private void CloseModal()
|
||||
{
|
||||
showModal = false;
|
||||
|
||||
@@ -203,10 +203,16 @@ public sealed class ApiDenunciasClient
|
||||
string assignedGroupCode,
|
||||
int? complaintId,
|
||||
bool isUpdate = false,
|
||||
string? updateSource = null,
|
||||
CancellationToken cancellationToken = default)
|
||||
=> PostAsync(
|
||||
"api/gestiona/documents/tramitar",
|
||||
new GestionaTramitarDocumentoRequest(documentUrl, assignedGroupCode, complaintId, isUpdate),
|
||||
new GestionaTramitarDocumentoRequest(
|
||||
documentUrl,
|
||||
assignedGroupCode,
|
||||
complaintId,
|
||||
isUpdate,
|
||||
updateSource),
|
||||
cancellationToken);
|
||||
|
||||
public Task<List<ExpedienteTerceroDto>> GetGestionaExpedientesPorTerceroAsync(
|
||||
@@ -273,6 +279,12 @@ public sealed class ApiDenunciasClient
|
||||
"api/configuration/work-groups",
|
||||
cancellationToken);
|
||||
|
||||
public Task<CurrentUserWorkGroupsDto> GetCurrentUserWorkGroupsAsync(
|
||||
CancellationToken cancellationToken = default)
|
||||
=> GetAsync<CurrentUserWorkGroupsDto>(
|
||||
"api/configuration/work-groups/current",
|
||||
cancellationToken);
|
||||
|
||||
public Task<WorkGroupAdministrationDto> UpdateUserWorkGroupsAsync(
|
||||
string username,
|
||||
IReadOnlyList<string> groupCodes,
|
||||
|
||||
Reference in New Issue
Block a user