Feat: modificaciones modal y agregar boton condonar
This commit is contained in:
parent
83bec44121
commit
a8921833ed
1
.gitignore
vendored
1
.gitignore
vendored
@ -14,6 +14,7 @@ dist-ssr
|
||||
.env
|
||||
colors.css
|
||||
notes.md
|
||||
pnpm-lock.yaml
|
||||
|
||||
# Editor directories and files
|
||||
.vscode/*
|
||||
|
||||
@ -6,6 +6,7 @@ const props = defineProps({
|
||||
isSearching: { type: Boolean, default: false },
|
||||
folioQuery: { type: String, default: "" },
|
||||
curpQuery: { type: String, default: "" },
|
||||
hasSelectedFine: { type: Boolean, default: false },
|
||||
});
|
||||
|
||||
const emit = defineEmits([
|
||||
@ -15,6 +16,7 @@ const emit = defineEmits([
|
||||
"search-folio",
|
||||
"search-curp",
|
||||
"qr-detected",
|
||||
"condone-fine",
|
||||
]);
|
||||
|
||||
const tabs = [
|
||||
@ -25,7 +27,7 @@ const tabs = [
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="rounded-xl bg-white shadow-lg overflow-hidden">
|
||||
<div class="rounded-xl bg-white shadow-lg overflow-hidden ">
|
||||
|
||||
<!-- Pestañas -->
|
||||
<div class="flex border-b border-gray-200">
|
||||
@ -56,6 +58,15 @@ const tabs = [
|
||||
</svg>
|
||||
{{ tab.label }}
|
||||
</button>
|
||||
<div class="ml-auto p-3">
|
||||
<button
|
||||
@click="emit('condone-fine')"
|
||||
:disabled="!hasSelectedFine"
|
||||
class="px-6 py-2.5 bg-[#621132] hover:bg-[#621132]/90 disabled:opacity-50 disabled:cursor-not-allowed text-white text-sm font-semibold rounded-lg transition-colors"
|
||||
>
|
||||
Condonar Multa
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Escanear QR -->
|
||||
@ -121,6 +132,5 @@ const tabs = [
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</template>
|
||||
|
||||
@ -177,6 +177,7 @@ const switchTab = (tab) => {
|
||||
<FineSearchPanel
|
||||
:active-tab="activeTab"
|
||||
:is-searching="isSearching"
|
||||
:has-selected-fine="hasSelection"
|
||||
v-model:folioQuery="folioQuery"
|
||||
v-model:curpQuery="curpQuery"
|
||||
@tab-change="switchTab"
|
||||
|
||||
@ -3,7 +3,7 @@ import { computed } from "vue";
|
||||
import { useForm } from "@Services/Api";
|
||||
import { apiTo, transl } from "../Module";
|
||||
|
||||
import Editview from "@Holos/Modal/Edit.vue";
|
||||
import DialogModal from "@Holos/DialogModal.vue";
|
||||
import Input from "@Holos/Form/Input.vue";
|
||||
import Textarea from "@Holos/Form/Textarea.vue";
|
||||
import Selectable from "@Holos/Form/Selectable.vue";
|
||||
@ -126,13 +126,35 @@ const handleUpdate = async () => {
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<Editview
|
||||
<DialogModal
|
||||
:show="show"
|
||||
:title="transl('edit.title')"
|
||||
max-width="2xl"
|
||||
@close="emit('close')"
|
||||
@update="handleUpdate"
|
||||
>
|
||||
<div class="p-4 space-y-4">
|
||||
<template #title>
|
||||
<div class="flex items-start justify-between gap-4 py-2">
|
||||
<div>
|
||||
<h2 class="text-2xl font-bold leading-tight text-page-t dark:text-page-dt">
|
||||
{{ transl("edit.title") }}
|
||||
</h2>
|
||||
<p class="mt-1 text-sm text-page-t/65 dark:text-page-dt/65">
|
||||
{{ transl("edit.description") }}
|
||||
</p>
|
||||
</div>
|
||||
<button
|
||||
type="button"
|
||||
class="inline-flex h-7 w-7 items-center justify-center rounded-sm text-page-t/65 transition-all duration-200 hover:bg-page-t/10 hover:text-page-t dark:text-page-dt/65 dark:hover:bg-page-dt/10 dark:hover:text-page-dt"
|
||||
:aria-label="$t('close')"
|
||||
@click="emit('close')"
|
||||
>
|
||||
x
|
||||
</button>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<template #content>
|
||||
<div class="space-y-5 px-4 pb-2 pt-1 [&_label]:mb-1 [&_label]:text-[0.72rem] [&_label]:font-bold [&_label]:uppercase [&_label]:tracking-[0.07em] [&_.input-primary]:min-h-10 [&_.input-primary]:border [&_.input-primary]:border-page-t/15 [&_.input-primary]:bg-page-t/5 dark:[&_.input-primary]:border-page-dt/15 dark:[&_.input-primary]:bg-page-dt/5 [&_.multiselect__tags]:min-h-10 [&_.multiselect__tags]:border [&_.multiselect__tags]:border-page-t/15 [&_.multiselect__tags]:bg-page-t/5 dark:[&_.multiselect__tags]:border-page-dt/15 dark:[&_.multiselect__tags]:bg-page-dt/5 [&_textarea.input-primary]:min-h-22 [&_textarea.input-primary]:resize-y [&_.multiselect__single]:mb-0 [&_.multiselect__single]:text-[0.9rem] [&_.multiselect__single]:leading-[1.45] [&_.multiselect__placeholder]:mb-0 [&_.multiselect__placeholder]:text-[0.9rem] [&_.multiselect__placeholder]:leading-[1.45]">
|
||||
<div class="grid grid-cols-1 md:grid-cols-2 gap-4">
|
||||
<Selectable
|
||||
v-model="conceptTypeObject"
|
||||
label="name"
|
||||
@ -148,37 +170,62 @@ const handleUpdate = async () => {
|
||||
:options="addresses"
|
||||
required
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div class="grid grid-cols-1 md:grid-cols-3 gap-4">
|
||||
<Input
|
||||
v-model="model.short_name"
|
||||
:id="$t('concept.shortName')"
|
||||
placeholder="Ej: MANT-01"
|
||||
type="text"
|
||||
required
|
||||
/>
|
||||
<div class="md:col-span-2">
|
||||
<Input
|
||||
v-model="model.name"
|
||||
:id="$t('concept.name')"
|
||||
placeholder="Nombre completo del concepto"
|
||||
type="text"
|
||||
required
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="grid grid-cols-1 md:grid-cols-2 gap-4">
|
||||
<Input
|
||||
v-model="model.legal_instrument"
|
||||
:id="$t('concept.legal')"
|
||||
placeholder="Base legal"
|
||||
type="text"
|
||||
/>
|
||||
<Input
|
||||
v-model="model.article"
|
||||
:id="$t('concept.article')"
|
||||
placeholder="Artículo"
|
||||
type="text"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<Textarea
|
||||
v-model="model.content"
|
||||
:id="$t('concept.description')"
|
||||
placeholder="Descripcion detallada..."
|
||||
rows="4"
|
||||
/>
|
||||
|
||||
<Textarea
|
||||
v-model="model.motivation"
|
||||
:id="$t('concept.motivation')"
|
||||
placeholder="Motivacion del concepto..."
|
||||
rows="3"
|
||||
/>
|
||||
<!-- Selector de tipo de cargo -->
|
||||
|
||||
<section class="rounded-sm border border-page-t/12 dark:border-page-dt/12 bg-primary/5 dark:bg-primary-d/30 p-4 space-y-4">
|
||||
<h3 class="flex items-center gap-2 text-xs font-semibold uppercase tracking-[0.16em] text-page-t dark:text-page-dt">
|
||||
<span class="inline-flex h-5 w-5 items-center justify-center rounded-sm bg-primary text-primary-t text-[10px] font-bold">$</span>
|
||||
{{ $t('concept.defineChargeType') }}
|
||||
</h3>
|
||||
|
||||
<Selectable
|
||||
v-model="chargeTypeObject"
|
||||
label="name"
|
||||
@ -187,8 +234,7 @@ const handleUpdate = async () => {
|
||||
required
|
||||
/>
|
||||
|
||||
<!-- Rango: solo monto mínimo y monto máximo (UMA o pesos) -->
|
||||
<div v-if="editIsRangeType" class="grid grid-cols-2 gap-4">
|
||||
<div v-if="editIsRangeType" class="grid grid-cols-1 md:grid-cols-2 gap-4">
|
||||
<Input
|
||||
v-if="editShowUmaFields"
|
||||
v-model="model.min_amount_uma"
|
||||
@ -223,8 +269,7 @@ const handleUpdate = async () => {
|
||||
/>
|
||||
</div>
|
||||
|
||||
<!-- Tabulador: unidad de medida y costo por unidad (UMA o pesos) -->
|
||||
<div v-if="editIsFixedType" class="grid grid-cols-2 gap-4">
|
||||
<div v-if="editIsFixedType" class="grid grid-cols-1 md:grid-cols-2 gap-4">
|
||||
<Selectable
|
||||
v-model="model.unit"
|
||||
label="name"
|
||||
@ -250,6 +295,28 @@ const handleUpdate = async () => {
|
||||
required
|
||||
/>
|
||||
</div>
|
||||
</section>
|
||||
</div>
|
||||
</Editview>
|
||||
|
||||
</template>
|
||||
|
||||
<template #footer>
|
||||
<div class="flex w-full items-center justify-end gap-3 px-2 pb-2">
|
||||
<button
|
||||
type="button"
|
||||
class="btn btn-secondary bg-transparent text-page-t/80 dark:text-page-dt/80 hover:opacity-80"
|
||||
@click="emit('close')"
|
||||
>
|
||||
{{ $t("close") }}
|
||||
</button>
|
||||
<button
|
||||
type="button"
|
||||
class="btn btn-primary px-6 py-2"
|
||||
@click="handleUpdate"
|
||||
>
|
||||
{{ $t("update") }}
|
||||
</button>
|
||||
</div>
|
||||
</template>
|
||||
</DialogModal>
|
||||
</template>
|
||||
|
||||
@ -4,8 +4,6 @@ import { useForm, useApi } from '@Services/Api';
|
||||
import { apiTo } from '../Module';
|
||||
|
||||
import DialogModal from '@Holos/DialogModal.vue';
|
||||
import PrimaryButton from '@Holos/Button/Primary.vue';
|
||||
import SecondaryButton from '@Holos/Button/Secondary.vue';
|
||||
import SingleFile from '@Holos/Form/SingleFile.vue';
|
||||
import Input from '@Holos/Form/Input.vue';
|
||||
import Textarea from '@Holos/Form/Textarea.vue';
|
||||
@ -123,96 +121,107 @@ const uploadInvoice = () => {
|
||||
@close="emit('close')"
|
||||
>
|
||||
<template #title>
|
||||
<div class="flex items-center gap-3 py-1">
|
||||
<span class="font-bold text-xl">
|
||||
<div class="flex items-start justify-between gap-4 py-1">
|
||||
<div>
|
||||
<div class="flex flex-wrap items-center gap-2">
|
||||
<h2 class="text-2xl font-bold leading-tight text-page-t dark:text-page-dt">
|
||||
Solicitud de Factura #{{ model?.id }}
|
||||
</span>
|
||||
</h2>
|
||||
<span
|
||||
v-if="model?.status"
|
||||
class="inline-flex items-center px-2.5 py-0.5 rounded-full text-xs font-medium"
|
||||
class="inline-flex items-center rounded-full px-2.5 py-0.5 text-xs font-semibold ring-1 ring-inset"
|
||||
:class="statusConfig[model.status]?.cls"
|
||||
>
|
||||
{{ statusConfig[model.status]?.label }}
|
||||
</span>
|
||||
</div>
|
||||
<p class="mt-1 text-sm text-page-t/65 dark:text-page-dt/65">
|
||||
Revisa detalles fiscales, pago asociado y gestiona el flujo de facturacion.
|
||||
</p>
|
||||
</div>
|
||||
<button
|
||||
type="button"
|
||||
class="inline-flex h-7 w-7 items-center justify-center rounded-sm text-page-t/65 transition-all duration-200 hover:bg-page-t/10 hover:text-page-t dark:text-page-dt/65 dark:hover:bg-page-dt/10 dark:hover:text-page-dt"
|
||||
aria-label="Cerrar"
|
||||
@click="emit('close')"
|
||||
>
|
||||
x
|
||||
</button>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<template #content>
|
||||
<!-- Cargando -->
|
||||
<div v-if="loading" class="flex justify-center py-10">
|
||||
<div class="animate-spin rounded-full h-8 w-8 border-b-2 border-primary"></div>
|
||||
<div v-if="loading" class="flex flex-col items-center justify-center gap-3 py-12 text-page-t/70 dark:text-page-dt/70">
|
||||
<div class="h-9 w-9 animate-spin rounded-full border-2 border-page-t/15 border-t-primary dark:border-page-dt/15 dark:border-t-primary-d"></div>
|
||||
<p class="text-sm">Cargando informacion de la solicitud...</p>
|
||||
</div>
|
||||
|
||||
<div v-else-if="model?.id" class="px-4 pt-2 pb-4 space-y-5">
|
||||
<div v-else-if="model?.id" class="space-y-4 px-4 pb-4 pt-2 [&_label]:mb-1 [&_label]:text-[0.72rem] [&_label]:font-bold [&_label]:uppercase [&_label]:tracking-[0.07em] [&_.input-primary]:min-h-10 [&_.input-primary]:border [&_.input-primary]:border-page-t/15 [&_.input-primary]:bg-page-t/5 dark:[&_.input-primary]:border-page-dt/15 dark:[&_.input-primary]:bg-page-dt/5 [&_textarea.input-primary]:min-h-22 [&_textarea.input-primary]:resize-y">
|
||||
|
||||
<!-- ── Datos del ciudadano ── -->
|
||||
<section>
|
||||
<h3 class="text-sm font-semibold text-gray-500 uppercase tracking-wider mb-2 border-b pb-1">
|
||||
<section class="rounded-sm border border-page-t/12 bg-page-t/5 p-4 dark:border-page-dt/12 dark:bg-page-dt/5">
|
||||
<h3 class="mb-3 border-b border-page-t/12 pb-2 text-xs font-semibold uppercase tracking-[0.14em] text-page-t/75 dark:border-page-dt/12 dark:text-page-dt/75">
|
||||
Datos del ciudadano
|
||||
</h3>
|
||||
<div class="grid grid-cols-2 gap-x-6 gap-y-2 text-sm">
|
||||
<div><span class="text-gray-500">RFC:</span> <span class="font-mono font-medium">{{ model.rfc }}</span></div>
|
||||
<div><span class="text-gray-500">Nombre:</span> {{ model.name || '—' }}</div>
|
||||
<div><span class="text-gray-500">Email:</span> {{ model.email }}</div>
|
||||
<div><span class="text-gray-500">Teléfono:</span> {{ model.phone || '—' }}</div>
|
||||
<div><span class="text-gray-500">Razón social:</span> {{ model.business_name || '—' }}</div>
|
||||
<div><span class="text-gray-500">C.P. fiscal:</span> {{ model.fiscal_postal_code }}</div>
|
||||
<div class="col-span-2"><span class="text-gray-500">Dirección:</span> {{ model.address || '—' }}</div>
|
||||
<div class="grid grid-cols-1 gap-x-6 gap-y-3 text-sm md:grid-cols-2">
|
||||
<div class="space-y-0.5"><p class="text-xs font-semibold uppercase tracking-wide text-page-t/55 dark:text-page-dt/55">RFC</p><p class="font-mono font-medium text-page-t dark:text-page-dt">{{ model.rfc }}</p></div>
|
||||
<div class="space-y-0.5"><p class="text-xs font-semibold uppercase tracking-wide text-page-t/55 dark:text-page-dt/55">Nombre</p><p class="text-page-t dark:text-page-dt">{{ model.name || '—' }}</p></div>
|
||||
<div class="space-y-0.5"><p class="text-xs font-semibold uppercase tracking-wide text-page-t/55 dark:text-page-dt/55">Email</p><p class="break-all text-page-t dark:text-page-dt">{{ model.email }}</p></div>
|
||||
<div class="space-y-0.5"><p class="text-xs font-semibold uppercase tracking-wide text-page-t/55 dark:text-page-dt/55">Telefono</p><p class="text-page-t dark:text-page-dt">{{ model.phone || '—' }}</p></div>
|
||||
<div class="space-y-0.5"><p class="text-xs font-semibold uppercase tracking-wide text-page-t/55 dark:text-page-dt/55">Razon social</p><p class="text-page-t dark:text-page-dt">{{ model.business_name || '—' }}</p></div>
|
||||
<div class="space-y-0.5"><p class="text-xs font-semibold uppercase tracking-wide text-page-t/55 dark:text-page-dt/55">C.P. fiscal</p><p class="font-medium text-page-t dark:text-page-dt">{{ model.fiscal_postal_code }}</p></div>
|
||||
<div class="space-y-0.5 md:col-span-2"><p class="text-xs font-semibold uppercase tracking-wide text-page-t/55 dark:text-page-dt/55">Direccion</p><p class="text-page-t dark:text-page-dt">{{ model.address || '—' }}</p></div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- ── Datos fiscales ── -->
|
||||
<section>
|
||||
<h3 class="text-sm font-semibold text-gray-500 uppercase tracking-wider mb-2 border-b pb-1">
|
||||
<section class="rounded-sm border border-page-t/12 bg-page-t/5 p-4 dark:border-page-dt/12 dark:bg-page-dt/5">
|
||||
<h3 class="mb-3 border-b border-page-t/12 pb-2 text-xs font-semibold uppercase tracking-[0.14em] text-page-t/75 dark:border-page-dt/12 dark:text-page-dt/75">
|
||||
Datos fiscales
|
||||
</h3>
|
||||
<div class="grid grid-cols-1 gap-y-2 text-sm">
|
||||
<div>
|
||||
<span class="text-gray-500">Régimen fiscal:</span>
|
||||
<span v-if="model.fiscal_regime" class="ml-1">
|
||||
<div class="grid grid-cols-1 gap-y-3 text-sm">
|
||||
<div class="space-y-0.5">
|
||||
<p class="text-xs font-semibold uppercase tracking-wide text-page-t/55 dark:text-page-dt/55">Regimen fiscal</p>
|
||||
<p v-if="model.fiscal_regime" class="text-page-t dark:text-page-dt">
|
||||
<span class="font-mono font-medium">{{ model.fiscal_regime.code }}</span>
|
||||
— {{ model.fiscal_regime.name }}
|
||||
</span>
|
||||
<span v-else> —</span>
|
||||
</p>
|
||||
<p v-else class="text-page-t dark:text-page-dt">—</p>
|
||||
</div>
|
||||
<div>
|
||||
<span class="text-gray-500">Uso del CFDI:</span>
|
||||
<span v-if="model.cfdi_use" class="ml-1">
|
||||
<div class="space-y-0.5">
|
||||
<p class="text-xs font-semibold uppercase tracking-wide text-page-t/55 dark:text-page-dt/55">Uso del CFDI</p>
|
||||
<p v-if="model.cfdi_use" class="text-page-t dark:text-page-dt">
|
||||
<span class="font-mono font-medium">{{ model.cfdi_use.code }}</span>
|
||||
— {{ model.cfdi_use.name }}
|
||||
</span>
|
||||
<span v-else> —</span>
|
||||
</p>
|
||||
<p v-else class="text-page-t dark:text-page-dt">—</p>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- ── Pago relacionado ── -->
|
||||
<section>
|
||||
<h3 class="text-sm font-semibold text-gray-500 uppercase tracking-wider mb-2 border-b pb-1">
|
||||
<section class="rounded-sm border border-page-t/12 bg-page-t/5 p-4 dark:border-page-dt/12 dark:bg-page-dt/5">
|
||||
<h3 class="mb-3 border-b border-page-t/12 pb-2 text-xs font-semibold uppercase tracking-[0.14em] text-page-t/75 dark:border-page-dt/12 dark:text-page-dt/75">
|
||||
Pago relacionado
|
||||
</h3>
|
||||
<div class="grid grid-cols-2 gap-x-6 gap-y-2 text-sm">
|
||||
<div><span class="text-gray-500">Monto:</span> <span class="font-medium text-green-700">{{ formatAmount(model.payment?.total_amount) }}</span></div>
|
||||
<div><span class="text-gray-500">Pagado el:</span> {{ formatDate(model.payment?.paid_at) }}</div>
|
||||
<div><span class="text-gray-500">Infractor:</span> {{ model.payment?.model?.name || '—' }}</div>
|
||||
<div><span class="text-gray-500">Placa:</span> <span class="font-mono">{{ model.payment?.model?.plate || '—' }}</span></div>
|
||||
<div><span class="text-gray-500">CURP:</span> <span class="font-mono text-xs">{{ model.payment?.model?.curp || '—' }}</span></div>
|
||||
<div class="grid grid-cols-1 gap-x-6 gap-y-3 text-sm md:grid-cols-2">
|
||||
<div class="space-y-0.5"><p class="text-xs font-semibold uppercase tracking-wide text-page-t/55 dark:text-page-dt/55">Monto</p><p class="font-semibold text-emerald-700 dark:text-emerald-400">{{ formatAmount(model.payment?.total_amount) }}</p></div>
|
||||
<div class="space-y-0.5"><p class="text-xs font-semibold uppercase tracking-wide text-page-t/55 dark:text-page-dt/55">Pagado el</p><p class="text-page-t dark:text-page-dt">{{ formatDate(model.payment?.paid_at) }}</p></div>
|
||||
<div class="space-y-0.5"><p class="text-xs font-semibold uppercase tracking-wide text-page-t/55 dark:text-page-dt/55">Infractor</p><p class="text-page-t dark:text-page-dt">{{ model.payment?.model?.name || '—' }}</p></div>
|
||||
<div class="space-y-0.5"><p class="text-xs font-semibold uppercase tracking-wide text-page-t/55 dark:text-page-dt/55">Placa</p><p class="font-mono text-page-t dark:text-page-dt">{{ model.payment?.model?.plate || '—' }}</p></div>
|
||||
<div class="space-y-0.5 md:col-span-2"><p class="text-xs font-semibold uppercase tracking-wide text-page-t/55 dark:text-page-dt/55">CURP</p><p class="break-all font-mono text-xs text-page-t dark:text-page-dt">{{ model.payment?.model?.curp || '—' }}</p></div>
|
||||
</div>
|
||||
|
||||
<!-- Conceptos de cargo -->
|
||||
<div v-if="model.payment?.model?.charge_concepts?.length" class="mt-3">
|
||||
<p class="text-xs font-semibold text-gray-500 mb-1">Conceptos de cargo:</p>
|
||||
<div class="space-y-1">
|
||||
<div v-if="model.payment?.model?.charge_concepts?.length" class="mt-4">
|
||||
<p class="mb-2 text-xs font-semibold uppercase tracking-wide text-page-t/55 dark:text-page-dt/55">Conceptos de cargo</p>
|
||||
<div class="space-y-2">
|
||||
<div
|
||||
v-for="cc in model.payment.model.charge_concepts"
|
||||
:key="cc.id"
|
||||
class="flex justify-between items-center bg-gray-50 rounded px-3 py-1.5 text-xs"
|
||||
class="flex items-center justify-between rounded-sm border border-page-t/12 bg-page p-2.5 text-xs dark:border-page-dt/12 dark:bg-page-d"
|
||||
>
|
||||
<div>
|
||||
<span class="font-medium">{{ cc.name }}</span>
|
||||
<span class="text-gray-500 ml-1">({{ cc.article }})</span>
|
||||
<span class="font-medium text-page-t dark:text-page-dt">{{ cc.name }}</span>
|
||||
<span class="ml-1 text-page-t/55 dark:text-page-dt/55">({{ cc.article }})</span>
|
||||
</div>
|
||||
<span class="font-medium text-gray-700">
|
||||
<span class="font-semibold text-page-t dark:text-page-dt">
|
||||
{{ formatAmount(cc.pivot?.override_amount) }}
|
||||
</span>
|
||||
</div>
|
||||
@ -220,28 +229,23 @@ const uploadInvoice = () => {
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- ── Factura ya generada ── -->
|
||||
<section v-if="model.invoice">
|
||||
<h3 class="text-sm font-semibold text-gray-500 uppercase tracking-wider mb-2 border-b pb-1">
|
||||
<section v-if="model.invoice" class="rounded-sm border border-page-t/12 bg-page-t/5 p-4 dark:border-page-dt/12 dark:bg-page-dt/5">
|
||||
<h3 class="mb-3 border-b border-page-t/12 pb-2 text-xs font-semibold uppercase tracking-[0.14em] text-page-t/75 dark:border-page-dt/12 dark:text-page-dt/75">
|
||||
Factura generada
|
||||
</h3>
|
||||
<div class="grid grid-cols-2 gap-x-6 gap-y-2 text-sm">
|
||||
<div><span class="text-gray-500">Folio:</span> <span class="font-mono font-medium">{{ model.invoice.folio || '—' }}</span></div>
|
||||
<div><span class="text-gray-500">Timbrada el:</span> {{ formatDate(model.invoice.stamped_at) }}</div>
|
||||
<div class="col-span-2">
|
||||
<span class="text-gray-500">UUID SAT:</span>
|
||||
<span class="font-mono text-xs ml-1">{{ model.invoice.uuid || '—' }}</span>
|
||||
<div class="grid grid-cols-1 gap-x-6 gap-y-3 text-sm md:grid-cols-2">
|
||||
<div class="space-y-0.5"><p class="text-xs font-semibold uppercase tracking-wide text-page-t/55 dark:text-page-dt/55">Folio</p><p class="font-mono font-medium text-page-t dark:text-page-dt">{{ model.invoice.folio || '—' }}</p></div>
|
||||
<div class="space-y-0.5"><p class="text-xs font-semibold uppercase tracking-wide text-page-t/55 dark:text-page-dt/55">Timbrada el</p><p class="text-page-t dark:text-page-dt">{{ formatDate(model.invoice.stamped_at) }}</p></div>
|
||||
<div class="space-y-0.5 md:col-span-2"><p class="text-xs font-semibold uppercase tracking-wide text-page-t/55 dark:text-page-dt/55">UUID SAT</p><p class="break-all font-mono text-xs text-page-t dark:text-page-dt">{{ model.invoice.uuid || '—' }}</p></div>
|
||||
<div v-if="model.invoice.notes" class="space-y-0.5 md:col-span-2"><p class="text-xs font-semibold uppercase tracking-wide text-page-t/55 dark:text-page-dt/55">Notas</p><p class="text-page-t dark:text-page-dt">{{ model.invoice.notes }}</p></div>
|
||||
</div>
|
||||
<div v-if="model.invoice.notes" class="col-span-2">
|
||||
<span class="text-gray-500">Notas:</span> {{ model.invoice.notes }}
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex gap-3 mt-3">
|
||||
|
||||
<div class="mt-4 flex flex-wrap gap-3">
|
||||
<a
|
||||
v-if="model.invoice.xml_url"
|
||||
:href="model.invoice.xml_url"
|
||||
target="_blank"
|
||||
class="inline-flex items-center gap-1 text-sm text-blue-600 hover:underline"
|
||||
class="inline-flex items-center gap-1 rounded-sm border border-sky-300 bg-sky-50 px-3 py-1.5 text-sm font-medium text-sky-700 transition-colors hover:bg-sky-100 dark:border-sky-500/30 dark:bg-sky-900/30 dark:text-sky-200 dark:hover:bg-sky-900/50"
|
||||
>
|
||||
<GoogleIcon
|
||||
class="text-base"
|
||||
@ -253,7 +257,7 @@ const uploadInvoice = () => {
|
||||
v-if="model.invoice.pdf_url"
|
||||
:href="model.invoice.pdf_url"
|
||||
target="_blank"
|
||||
class="inline-flex items-center gap-1 text-sm text-red-600 hover:underline"
|
||||
class="inline-flex items-center gap-1 rounded-sm border border-rose-300 bg-rose-50 px-3 py-1.5 text-sm font-medium text-rose-700 transition-colors hover:bg-rose-100 dark:border-rose-500/30 dark:bg-rose-900/30 dark:text-rose-200 dark:hover:bg-rose-900/50"
|
||||
>
|
||||
<GoogleIcon
|
||||
class="text-base"
|
||||
@ -264,22 +268,21 @@ const uploadInvoice = () => {
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- ── Cambiar estado ── -->
|
||||
<section v-if="canChangeStatus">
|
||||
<h3 class="text-sm font-semibold text-gray-500 uppercase tracking-wider mb-2 border-b pb-1">
|
||||
<section v-if="canChangeStatus" class="rounded-sm border border-page-t/12 bg-page-t/5 p-4 dark:border-page-dt/12 dark:bg-page-dt/5">
|
||||
<h3 class="mb-3 border-b border-page-t/12 pb-2 text-xs font-semibold uppercase tracking-[0.14em] text-page-t/75 dark:border-page-dt/12 dark:text-page-dt/75">
|
||||
Cambiar estado
|
||||
</h3>
|
||||
<div class="flex flex-wrap gap-2">
|
||||
<div class="flex flex-wrap gap-2.5">
|
||||
<button
|
||||
v-if="model.status === 'pending'"
|
||||
class="inline-flex items-center gap-1 px-4 py-1.5 rounded text-sm font-medium bg-blue-600 text-white hover:bg-blue-700 disabled:opacity-50 transition-colors"
|
||||
class="inline-flex items-center gap-1 rounded-sm bg-blue-600 px-4 py-2 text-sm font-medium text-white transition-colors hover:bg-blue-700 disabled:cursor-not-allowed disabled:opacity-50"
|
||||
:disabled="apiStatus.processing"
|
||||
@click="changeStatus('processing')"
|
||||
>
|
||||
Marcar en proceso
|
||||
</button>
|
||||
<button
|
||||
class="inline-flex items-center gap-1 px-4 py-1.5 rounded text-sm font-medium bg-red-600 text-white hover:bg-red-700 disabled:opacity-50 transition-colors"
|
||||
class="inline-flex items-center gap-1 rounded-sm bg-red-600 px-4 py-2 text-sm font-medium text-white transition-colors hover:bg-red-700 disabled:cursor-not-allowed disabled:opacity-50"
|
||||
:disabled="apiStatus.processing"
|
||||
@click="changeStatus('rejected')"
|
||||
>
|
||||
@ -288,13 +291,12 @@ const uploadInvoice = () => {
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- ── Subir CFDI ── -->
|
||||
<section v-if="canUpload">
|
||||
<h3 class="text-sm font-semibold text-gray-500 uppercase tracking-wider mb-3 border-b pb-1">
|
||||
<section v-if="canUpload" class="rounded-sm border border-page-t/12 bg-page-t/5 p-4 dark:border-page-dt/12 dark:bg-page-dt/5">
|
||||
<h3 class="mb-3 border-b border-page-t/12 pb-2 text-xs font-semibold uppercase tracking-[0.14em] text-page-t/75 dark:border-page-dt/12 dark:text-page-dt/75">
|
||||
Subir CFDI (XML / PDF)
|
||||
</h3>
|
||||
<div class="space-y-3">
|
||||
<div class="grid grid-cols-2 gap-4">
|
||||
<div class="grid grid-cols-1 gap-4 md:grid-cols-2">
|
||||
<SingleFile
|
||||
v-model="invoiceForm.xml_file"
|
||||
title="Archivo XML"
|
||||
@ -306,7 +308,7 @@ const uploadInvoice = () => {
|
||||
accept=".pdf,application/pdf"
|
||||
/>
|
||||
</div>
|
||||
<div class="grid grid-cols-2 gap-4">
|
||||
<div class="grid grid-cols-1 gap-4 md:grid-cols-2">
|
||||
<Input
|
||||
v-model="invoiceForm.folio"
|
||||
id="Folio"
|
||||
@ -318,7 +320,7 @@ const uploadInvoice = () => {
|
||||
placeholder="xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"
|
||||
/>
|
||||
</div>
|
||||
<div class="grid grid-cols-2 gap-4">
|
||||
<div class="grid grid-cols-1 gap-4 md:grid-cols-2">
|
||||
<Input
|
||||
v-model="invoiceForm.stamped_at"
|
||||
id="Fecha de timbrado"
|
||||
@ -331,9 +333,9 @@ const uploadInvoice = () => {
|
||||
id="Notas internas"
|
||||
placeholder="Ej. Generado con PAC Facturama"
|
||||
/>
|
||||
<div class="pt-1">
|
||||
<div class="pt-1 text-right">
|
||||
<button
|
||||
class="inline-flex items-center gap-2 px-5 py-2 rounded text-sm font-medium bg-green-600 text-white hover:bg-green-700 disabled:opacity-50 transition-colors"
|
||||
class="inline-flex items-center gap-2 rounded-sm bg-emerald-600 px-5 py-2 text-sm font-medium text-white transition-colors hover:bg-emerald-700 disabled:cursor-not-allowed disabled:opacity-50"
|
||||
:disabled="invoiceForm.processing"
|
||||
@click="uploadInvoice"
|
||||
>
|
||||
@ -348,9 +350,15 @@ const uploadInvoice = () => {
|
||||
</template>
|
||||
|
||||
<template #footer>
|
||||
<SecondaryButton @click="emit('close')">
|
||||
<div class="flex w-full items-center justify-end gap-3 px-2 pb-2">
|
||||
<button
|
||||
type="button"
|
||||
class="btn btn-secondary bg-transparent text-page-t/80 dark:text-page-dt/80 hover:opacity-80"
|
||||
@click="emit('close')"
|
||||
>
|
||||
Cerrar
|
||||
</SecondaryButton>
|
||||
</button>
|
||||
</div>
|
||||
</template>
|
||||
</DialogModal>
|
||||
</template>
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user