Merge pull request 'refactor: enhance invoice filtering and dropdown menu functionality' (#346) from fix/permisos into development

Reviewed-on: ADUANASOFT/anexo76#346
This commit is contained in:
2026-04-29 14:03:36 +00:00
4 changed files with 30 additions and 23 deletions

View File

@@ -1,7 +1,7 @@
import traceback
from typing import Optional, List, Tuple
from sqlalchemy.orm import Session
from sqlalchemy import func
from sqlalchemy import and_, func, or_
from core.exceptions import ErrorCollector, DuplicateResourceException
from core.context import get_user_context
from .common.mappers import clean_dict
@@ -328,7 +328,6 @@ class InvoiceService:
# Filtro por permisos granulares (allowed_types)
if "allowed_types" in filters:
from sqlalchemy import or_, and_
allowed = filters["allowed_types"]
if allowed is None:
# Acceso global (admin o view_all) - no filtramos por tipos
@@ -337,7 +336,6 @@ class InvoiceService:
# Seguridad: Si el usuario NO tiene permisos para ningún tipo específico
query = query.filter(models.InvoiceHeader.id == -1)
else:
from sqlalchemy import func
conditions = []
for op, inv in allowed:
# Aseguramos comparación insensible a mayúsculas para mayor robustez con la DB

View File

@@ -86,7 +86,7 @@
<span>More</span>
</Sidebar.MenuButton>
<DropdownMenu.Root bind:open>
<DropdownMenu.Root open={open} onOpenChange={(v) => (open = v)}>
<DropdownMenu.Trigger
class="fixed z-50 size-0"
style="top: {position.y}px; left: {position.x}px"

View File

@@ -4,4 +4,4 @@
let { ...restProps }: DropdownMenuPrimitive.RootProps = $props();
</script>
<DropdownMenuPrimitive.Root data-slot="dropdown-menu-root" {...restProps} />
<DropdownMenuPrimitive.Root {...restProps} />

View File

@@ -79,8 +79,8 @@
operation_type: (data.filters?.operation_type || '') as '' | OperationType,
invoice_type: data.filters?.invoice_type || '',
invoice_number: data.filters?.invoice_number || '',
year_from: data.filters?.year_from || '',
year_to: data.filters?.year_to || ''
year_from: data.filters?.year || '',
year_to: data.filters?.year || ''
});
let sorting = $state<import("@tanstack/table-core").SortingState>([]);
@@ -279,22 +279,22 @@
const op = filters.operation_type;
const type = filters.invoice_type;
const base = m.invoice_list_titles_base();
const base = m['invoice_list.titles.base']();
if (op === 'imp') {
if (type === 'TEM') return `${base} ${m.invoice_list_titles_import_temporal()}`;
if (type === 'DEF') return `${base} ${m.invoice_list_titles_import_definitive()}`;
if (type === 'MEX') return `${base} ${m.invoice_list_titles_import_mexican()}`;
if (type === 'CR') return `${base} ${m.invoice_list_titles_import_regime_change()}`;
if (type === 'REP') return `${base} ${m.invoice_list_titles_import_repair()}`;
return `${base} ${m.invoice_list_titles_import()}`;
if (type === 'TEM') return `${base} ${m['invoice_list.titles.import_temporal']()}`;
if (type === 'DEF') return `${base} ${m['invoice_list.titles.import_definitive']()}`;
if (type === 'MEX') return `${base} ${m['invoice_list.titles.import_mexican']()}`;
if (type === 'CR') return `${base} ${m['invoice_list.titles.import_regime_change']()}`;
if (type === 'REP') return `${base} ${m['invoice_list.titles.import_repair']()}`;
return `${base} ${m['invoice_list.titles.import']()}`;
} else if (op === 'exp') {
if (type === 'EXDEF') return `${base} ${m.invoice_list_titles_export_definitive()}`;
if (type === 'REPAR') return `${base} ${m.invoice_list_titles_export_repair()}`;
return `${base} ${m.invoice_list_titles_export()}`;
if (type === 'EXDEF') return `${base} ${m['invoice_list.titles.export_definitive']()}`;
if (type === 'REPAR') return `${base} ${m['invoice_list.titles.export_repair']()}`;
return `${base} ${m['invoice_list.titles.export']()}`;
}
return m.invoice_list_header_title();
return m['invoice_list.header.title']();
});
async function loadMore() {
@@ -1678,14 +1678,16 @@
{#if showVuSubmenu}
<!-- Capa para cerrar el submenú al hacer click fuera -->
<div
class="fixed inset-0 z-40"
<button
type="button"
class="fixed inset-0 z-40 cursor-default border-0 bg-transparent p-0 [&:focus-visible]:outline-none"
aria-label={m.invoice_list_actions_close()}
onclick={() => (showVuSubmenu = false)}
oncontextmenu={(event) => {
event.preventDefault();
showVuSubmenu = false;
}}
></div>
></button>
<!-- Submenú contextual de Interface VU -->
<div
class="fixed z-50 min-w-48 rounded-md border bg-popover p-1 text-sm shadow-md"
@@ -1748,6 +1750,7 @@
<!-- Botones de acción -->
<div
role="toolbar"
tabindex="-1"
aria-label={m.invoice_list_footer_toolbar_aria()}
data-invoice-footer-toolbar
class="flex w-full items-center justify-end gap-2"
@@ -1756,7 +1759,12 @@
{#if hasSelection}
<div transition:fly={{ x: 40, duration: 250 }} class="flex items-center gap-2">
<!-- Dropdown: Reportes -->
<DropdownMenu.Root bind:open={reportesMenuOpen}>
<DropdownMenu.Root
open={reportesMenuOpen}
onOpenChange={(v) => {
reportesMenuOpen = v;
}}
>
<DropdownMenu.Trigger>
{#snippet child({ props })}
<Button
@@ -1823,8 +1831,9 @@
<!-- Dropdown: Más Acciones -->
<DropdownMenu.Root
bind:open={masAccionesMenuOpen}
open={masAccionesMenuOpen}
onOpenChange={(open) => {
masAccionesMenuOpen = open;
if (!open) {
showVuSubmenu = false;
}