Mass changes
This commit is contained in:
@@ -0,0 +1,793 @@
|
||||
<script setup>
|
||||
import Modal from "@/Components/Modal.vue";
|
||||
import { useEurFormat } from "../useEurFormat.js";
|
||||
import { ArrowRightIcon, ArrowDownIcon, ArrowUpIcon } from "@heroicons/vue/24/solid";
|
||||
import { computed, ref, watch } from "vue";
|
||||
|
||||
// Props expected by the template
|
||||
const props = defineProps({
|
||||
show: { type: Boolean, default: false },
|
||||
rows: { type: Array, default: () => [] },
|
||||
limit: { type: Number, default: 50 },
|
||||
loading: { type: Boolean, default: false },
|
||||
entities: { type: Array, default: () => [] },
|
||||
});
|
||||
|
||||
// Emits
|
||||
const emit = defineEmits(["close", "update:limit"]);
|
||||
|
||||
// Map technical entity keys to localized labels
|
||||
const entityLabelMap = {
|
||||
account: "računi",
|
||||
payment: "plačila",
|
||||
contract: "pogodbe",
|
||||
person: "osebe",
|
||||
client_case: "primeri",
|
||||
address: "naslovi",
|
||||
email: "emaili",
|
||||
phone: "telefoni",
|
||||
booking: "knjižbe",
|
||||
activity: "aktivnosti",
|
||||
};
|
||||
|
||||
// Formatting helpers
|
||||
const { formatEur } = useEurFormat();
|
||||
const fmt = (v) => formatEur(v);
|
||||
function formatDate(val) {
|
||||
if (!val) return "—";
|
||||
try {
|
||||
const d = val instanceof Date ? val : new Date(val);
|
||||
if (isNaN(d.getTime())) return String(val);
|
||||
return d.toLocaleDateString("sl-SI", {
|
||||
year: "numeric",
|
||||
month: "2-digit",
|
||||
day: "2-digit",
|
||||
});
|
||||
} catch (_) {
|
||||
return String(val);
|
||||
}
|
||||
}
|
||||
|
||||
// Localized list for header
|
||||
const localizedEntities = computed(() =>
|
||||
Array.isArray(props.entities) && props.entities.length
|
||||
? props.entities.map((e) => entityLabelMap[e] ?? e).join(", ")
|
||||
: ""
|
||||
);
|
||||
|
||||
const entitiesWithRows = computed(() => {
|
||||
if (!props.rows?.length || !props.entities?.length) return [];
|
||||
const present = new Set();
|
||||
for (const r of props.rows) {
|
||||
if (!r.entities) continue;
|
||||
for (const k of Object.keys(r.entities)) {
|
||||
if (props.entities.includes(k)) present.add(k);
|
||||
}
|
||||
}
|
||||
return props.entities.filter((e) => present.has(e));
|
||||
});
|
||||
|
||||
const activeEntity = ref(null);
|
||||
const hideChain = ref(false);
|
||||
const showOnlyChanged = ref(false);
|
||||
watch(
|
||||
entitiesWithRows,
|
||||
(val) => {
|
||||
if (!val.length) {
|
||||
activeEntity.value = null;
|
||||
return;
|
||||
}
|
||||
if (!activeEntity.value || !val.includes(activeEntity.value))
|
||||
activeEntity.value = val[0];
|
||||
},
|
||||
{ immediate: true }
|
||||
);
|
||||
|
||||
const entityStats = computed(() => {
|
||||
const stats = {};
|
||||
for (const e of entitiesWithRows.value)
|
||||
stats[e] = {
|
||||
total_rows: 0,
|
||||
create: 0,
|
||||
update: 0,
|
||||
missing_ref: 0,
|
||||
invalid: 0,
|
||||
duplicate: 0,
|
||||
duplicate_db: 0,
|
||||
};
|
||||
for (const r of props.rows || []) {
|
||||
if (!r.entities) continue;
|
||||
for (const [k, ent] of Object.entries(r.entities)) {
|
||||
if (!stats[k]) continue;
|
||||
stats[k].total_rows++;
|
||||
switch (ent.action) {
|
||||
case "create":
|
||||
stats[k].create++;
|
||||
break;
|
||||
case "update":
|
||||
stats[k].update++;
|
||||
break;
|
||||
case "missing_ref":
|
||||
stats[k].missing_ref++;
|
||||
break;
|
||||
case "invalid":
|
||||
stats[k].invalid++;
|
||||
break;
|
||||
}
|
||||
if (ent.duplicate) stats[k].duplicate++;
|
||||
if (ent.duplicate_db) stats[k].duplicate_db++;
|
||||
}
|
||||
}
|
||||
return stats;
|
||||
});
|
||||
const activeSummary = computed(() =>
|
||||
activeEntity.value ? entityStats.value[activeEntity.value] : null
|
||||
);
|
||||
const entityHasDuplicates = (e) => {
|
||||
const s = entityStats.value[e];
|
||||
return s ? s.duplicate + s.duplicate_db > 0 : false;
|
||||
};
|
||||
const visibleRows = computed(() => {
|
||||
if (!props.rows || !activeEntity.value) return [];
|
||||
const eps = 0.0000001;
|
||||
return props.rows
|
||||
.filter((r) => {
|
||||
if (!r.entities || !r.entities[activeEntity.value]) return false;
|
||||
const ent = r.entities[activeEntity.value];
|
||||
if (hideChain.value && ent.existing_chain) return false;
|
||||
if (showOnlyChanged.value) {
|
||||
// Define change criteria per entity
|
||||
if (activeEntity.value === "account") {
|
||||
if (ent.delta !== undefined && Math.abs(ent.delta) > eps) return true;
|
||||
// new account creation counts as change
|
||||
if (ent.action === "create") return true;
|
||||
return false;
|
||||
}
|
||||
if (activeEntity.value === "payment") {
|
||||
// payment with valid amount considered change
|
||||
return ent.amount !== null && ent.amount !== undefined;
|
||||
}
|
||||
// Generic entities: any create/update considered change
|
||||
if (ent.action === "create" || ent.action === "update") return true;
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
})
|
||||
.slice(0, props.limit || props.rows.length);
|
||||
});
|
||||
function referenceOf(entityName, ent) {
|
||||
if (!ent || typeof ent !== "object") return "—";
|
||||
|
||||
const pick = (val) => {
|
||||
if (val === undefined || val === null) return null;
|
||||
if (typeof val === "object") {
|
||||
if (
|
||||
val.normalized !== undefined &&
|
||||
val.normalized !== null &&
|
||||
String(val.normalized).trim() !== ""
|
||||
)
|
||||
return val.normalized;
|
||||
if (
|
||||
val.value !== undefined &&
|
||||
val.value !== null &&
|
||||
String(val.value).trim() !== ""
|
||||
)
|
||||
return val.value;
|
||||
return null;
|
||||
}
|
||||
const s = String(val).trim();
|
||||
return s === "" ? null : val;
|
||||
};
|
||||
|
||||
// 1. direct reference
|
||||
const direct = pick(ent.reference);
|
||||
if (direct !== null) return direct;
|
||||
|
||||
// 2. other plausible keys
|
||||
const candidates = [
|
||||
"ref",
|
||||
"code",
|
||||
"number",
|
||||
"identifier",
|
||||
"external_id",
|
||||
`${entityName}_reference`,
|
||||
`${entityName}Reference`,
|
||||
];
|
||||
for (const k of candidates) {
|
||||
if (k in ent) {
|
||||
const v = pick(ent[k]);
|
||||
if (v !== null) return v;
|
||||
}
|
||||
}
|
||||
|
||||
// 3. any property containing 'reference'
|
||||
for (const [k, v] of Object.entries(ent)) {
|
||||
if (k.toLowerCase().includes("reference")) {
|
||||
const pv = pick(v);
|
||||
if (pv !== null) return pv;
|
||||
}
|
||||
}
|
||||
|
||||
// 4. sources map
|
||||
const sources = ent.sources;
|
||||
if (sources && typeof sources === "object") {
|
||||
const priority = [`${entityName}.reference`, "reference"];
|
||||
for (const k of priority) {
|
||||
if (k in sources) {
|
||||
const pv = pick(sources[k]);
|
||||
if (pv !== null) return pv;
|
||||
}
|
||||
}
|
||||
for (const [k, v] of Object.entries(sources)) {
|
||||
if (k.toLowerCase().includes("reference")) {
|
||||
const pv = pick(v);
|
||||
if (pv !== null) return pv;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return "—";
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<Modal :show="show" max-width="wide" @close="emit('close')">
|
||||
<div class="p-4 space-y-4">
|
||||
<div class="flex items-start justify-between gap-4">
|
||||
<div>
|
||||
<h2 class="text-lg font-semibold text-gray-800">Simulacija uvoza</h2>
|
||||
<p v-if="localizedEntities" class="text-[12px] text-gray-500">
|
||||
Entitete: {{ localizedEntities }}
|
||||
</p>
|
||||
</div>
|
||||
<div class="flex items-center gap-2">
|
||||
<label class="text-[11px] text-gray-600 flex items-center gap-1"
|
||||
>Prikaži:
|
||||
<select
|
||||
class="border rounded px-1 py-0.5 text-[11px]"
|
||||
:value="limit"
|
||||
@change="onLimit"
|
||||
>
|
||||
<option :value="25">25</option>
|
||||
<option :value="50">50</option>
|
||||
<option :value="100">100</option>
|
||||
<option :value="250">250</option>
|
||||
</select>
|
||||
</label>
|
||||
<button
|
||||
type="button"
|
||||
class="text-[11px] px-2 py-1 rounded border bg-white hover:bg-gray-50"
|
||||
@click="toggleVerbose"
|
||||
>
|
||||
{{ verbose ? "Manj" : "Več" }} podrobnosti
|
||||
</button>
|
||||
<label class="flex items-center gap-1 text-[11px] text-gray-600">
|
||||
<input type="checkbox" v-model="hideChain" class="rounded border-gray-300" />
|
||||
Skrij verižne
|
||||
</label>
|
||||
<label class="flex items-center gap-1 text-[11px] text-gray-600">
|
||||
<input
|
||||
type="checkbox"
|
||||
v-model="showOnlyChanged"
|
||||
class="rounded border-gray-300"
|
||||
/>
|
||||
Samo spremenjeni
|
||||
</label>
|
||||
<button
|
||||
type="button"
|
||||
class="text-[11px] px-2 py-1 rounded bg-gray-800 text-white hover:bg-gray-700"
|
||||
@click="emit('close')"
|
||||
>
|
||||
Zapri
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div v-if="entitiesWithRows.length" class="flex flex-wrap gap-1 border-b pb-1">
|
||||
<button
|
||||
v-for="e in entitiesWithRows"
|
||||
:key="e"
|
||||
type="button"
|
||||
@click="activeEntity = e"
|
||||
class="relative px-2 py-1 rounded-t text-[11px] font-medium border"
|
||||
:class="
|
||||
activeEntity === e
|
||||
? 'bg-white border-b-white text-gray-900'
|
||||
: 'bg-gray-100 hover:bg-gray-200 text-gray-600'
|
||||
"
|
||||
>
|
||||
<span class="uppercase tracking-wide">{{ e }}</span>
|
||||
<span
|
||||
v-if="entityHasDuplicates(e)"
|
||||
class="absolute -top-1 -right-1 inline-block w-3 h-3 rounded-full bg-amber-500 ring-2 ring-white"
|
||||
title="Duplikati"
|
||||
></span>
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<div
|
||||
v-if="activeSummary"
|
||||
class="text-[11px] flex flex-wrap items-center gap-3 bg-gray-50 border rounded px-2 py-1"
|
||||
>
|
||||
<div class="font-semibold uppercase tracking-wide text-gray-600">
|
||||
{{ activeEntity }}
|
||||
</div>
|
||||
<div class="flex items-center gap-2">
|
||||
<span class="text-gray-600"
|
||||
>Vrstic:
|
||||
<span class="font-medium text-gray-800">{{
|
||||
activeSummary.total_rows
|
||||
}}</span></span
|
||||
>
|
||||
<span v-if="activeSummary.create" class="text-emerald-700"
|
||||
>+{{ activeSummary.create }} novo</span
|
||||
>
|
||||
<span v-if="activeSummary.update" class="text-blue-700"
|
||||
>{{ activeSummary.update }} posodobitev</span
|
||||
>
|
||||
<span v-if="activeSummary.duplicate" class="text-amber-600"
|
||||
>{{ activeSummary.duplicate }} duplikat</span
|
||||
>
|
||||
<span v-if="activeSummary.duplicate_db" class="text-amber-700"
|
||||
>{{ activeSummary.duplicate_db }} obstaja</span
|
||||
>
|
||||
<span v-if="activeSummary.missing_ref" class="text-red-600"
|
||||
>{{ activeSummary.missing_ref }} manjka referenca</span
|
||||
>
|
||||
<span v-if="activeSummary.invalid" class="text-red-700"
|
||||
>{{ activeSummary.invalid }} neveljavnih</span
|
||||
>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div v-if="activeEntity" class="border rounded bg-white">
|
||||
<div class="max-h-[28rem] overflow-auto">
|
||||
<table class="min-w-full text-[12px]">
|
||||
<thead class="bg-gray-100 text-left sticky top-0 z-10">
|
||||
<tr>
|
||||
<th class="px-2 py-1 border w-14">#</th>
|
||||
<th class="px-2 py-1 border">Podatki</th>
|
||||
<th class="px-2 py-1 border w-48">Učinek (plačilo)</th>
|
||||
<th class="px-2 py-1 border w-24">Opombe</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr v-if="loading">
|
||||
<td :colspan="4" class="p-4 text-center text-gray-500">Nalagam…</td>
|
||||
</tr>
|
||||
<tr
|
||||
v-for="r in visibleRows"
|
||||
:key="r.index"
|
||||
class="border-t"
|
||||
:class="r.status !== 'ok' ? 'bg-red-50' : ''"
|
||||
>
|
||||
<td class="p-2 border text-gray-500 align-top">{{ r.index }}</td>
|
||||
<td class="p-2 border align-top">
|
||||
<div
|
||||
v-if="r.entities && r.entities[activeEntity]"
|
||||
class="text-[11px] border rounded p-2 bg-white/70 max-w-[360px]"
|
||||
>
|
||||
<div
|
||||
class="font-semibold uppercase tracking-wide text-gray-600 mb-1 flex items-center justify-between"
|
||||
>
|
||||
<span>{{ activeEntity }}</span>
|
||||
<span
|
||||
v-if="r.entities[activeEntity].action_label"
|
||||
class="text-[10px] px-1 py-0.5 rounded bg-gray-100"
|
||||
>{{ r.entities[activeEntity].action_label }}</span
|
||||
>
|
||||
<span
|
||||
v-if="r.entities[activeEntity].existing_chain"
|
||||
class="ml-1 text-[9px] px-1 py-0.5 rounded bg-indigo-100 text-indigo-700"
|
||||
title="Iz obstoječe verige (contract → client_case → person)"
|
||||
>chain</span
|
||||
>
|
||||
<span
|
||||
v-if="r.entities[activeEntity].inherited_reference"
|
||||
class="ml-1 text-[9px] px-1 py-0.5 rounded bg-amber-100 text-amber-700"
|
||||
title="Referenca podedovana"
|
||||
>inh</span
|
||||
>
|
||||
<span
|
||||
v-if="r.entities[activeEntity].action === 'implicit'"
|
||||
class="ml-1 text-[9px] px-1 py-0.5 rounded bg-teal-100 text-teal-700"
|
||||
title="Implicitno"
|
||||
>impl</span
|
||||
>
|
||||
</div>
|
||||
|
||||
<template v-if="activeEntity === 'account'">
|
||||
<div class="flex items-center gap-1">
|
||||
Ref:
|
||||
<span class="font-medium flex items-center gap-1">
|
||||
{{ referenceOf(activeEntity, r.entities[activeEntity]) }}
|
||||
<span
|
||||
v-if="r.entities[activeEntity].inherited_reference"
|
||||
class="text-[9px] px-1 py-0.5 rounded bg-indigo-100 text-indigo-700"
|
||||
title="Podedovano iz pogodbe"
|
||||
>inh</span
|
||||
>
|
||||
</span>
|
||||
</div>
|
||||
<div
|
||||
v-if="r.entities[activeEntity].balance_before !== undefined"
|
||||
class="mt-1 space-y-0.5"
|
||||
>
|
||||
<div class="flex items-center gap-1">
|
||||
<span class="text-gray-500">Saldo:</span
|
||||
><span>{{ fmt(r.entities[activeEntity].balance_before) }}</span>
|
||||
</div>
|
||||
<div
|
||||
v-if="r.entities[activeEntity].balance_after !== undefined"
|
||||
class="flex items-center gap-1"
|
||||
>
|
||||
<ArrowRightIcon
|
||||
v-if="
|
||||
(r.entities[activeEntity].balance_after ??
|
||||
r.entities[activeEntity].balance_before) ===
|
||||
r.entities[activeEntity].balance_before
|
||||
"
|
||||
class="h-3 w-3 text-gray-400"
|
||||
/>
|
||||
<ArrowDownIcon
|
||||
v-else-if="
|
||||
(r.entities[activeEntity].balance_after ??
|
||||
r.entities[activeEntity].balance_before) <
|
||||
r.entities[activeEntity].balance_before
|
||||
"
|
||||
class="h-3 w-3 text-emerald-500"
|
||||
/>
|
||||
<ArrowUpIcon v-else class="h-3 w-3 text-red-500" />
|
||||
<span
|
||||
:class="
|
||||
(r.entities[activeEntity].balance_after ??
|
||||
r.entities[activeEntity].balance_before) <
|
||||
r.entities[activeEntity].balance_before
|
||||
? 'text-emerald-600 font-medium'
|
||||
: 'text-red-600 font-medium'
|
||||
"
|
||||
>{{
|
||||
fmt(
|
||||
r.entities[activeEntity].balance_after ??
|
||||
r.entities[activeEntity].balance_before
|
||||
)
|
||||
}}</span
|
||||
>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<template v-else-if="activeEntity === 'payment'">
|
||||
<div>
|
||||
Znesek:
|
||||
<span class="font-medium">{{
|
||||
fmt(
|
||||
r.entities[activeEntity].amount ??
|
||||
r.entities[activeEntity].raw_amount
|
||||
)
|
||||
}}</span>
|
||||
</div>
|
||||
<div>
|
||||
Datum: {{ formatDate(r.entities[activeEntity].payment_date) }}
|
||||
</div>
|
||||
<div v-if="r.entities[activeEntity].reference">
|
||||
Ref:
|
||||
<span class="font-medium">{{
|
||||
r.entities[activeEntity].reference
|
||||
}}</span>
|
||||
</div>
|
||||
<div>
|
||||
Status:
|
||||
<span
|
||||
:class="
|
||||
r.entities[activeEntity].status === 'ok'
|
||||
? 'text-emerald-600'
|
||||
: r.entities[activeEntity].status === 'duplicate' ||
|
||||
r.entities[activeEntity].status === 'duplicate_db'
|
||||
? 'text-amber-600'
|
||||
: 'text-red-600'
|
||||
"
|
||||
>{{
|
||||
r.entities[activeEntity].status_label ||
|
||||
r.entities[activeEntity].status
|
||||
}}</span
|
||||
>
|
||||
</div>
|
||||
</template>
|
||||
<template v-else-if="activeEntity === 'contract'">
|
||||
<div>
|
||||
Ref:
|
||||
<span class="font-medium">{{
|
||||
referenceOf(activeEntity, r.entities[activeEntity])
|
||||
}}</span>
|
||||
</div>
|
||||
<div>
|
||||
Akcija:
|
||||
<span class="font-medium">{{
|
||||
r.entities[activeEntity].action_label ||
|
||||
r.entities[activeEntity].action
|
||||
}}</span>
|
||||
</div>
|
||||
</template>
|
||||
<template v-else>
|
||||
<div class="flex flex-wrap gap-1 mb-1">
|
||||
<span
|
||||
v-if="r.entities[activeEntity].identity_used"
|
||||
class="px-1 py-0.5 rounded bg-indigo-50 text-indigo-700 text-[10px]"
|
||||
title="Uporabljena identiteta"
|
||||
>{{ r.entities[activeEntity].identity_used }}</span
|
||||
>
|
||||
<span
|
||||
v-if="r.entities[activeEntity].duplicate"
|
||||
class="px-1 py-0.5 rounded bg-amber-100 text-amber-700 text-[10px]"
|
||||
title="Podvojen v tej seriji"
|
||||
>duplikat</span
|
||||
>
|
||||
<span
|
||||
v-if="r.entities[activeEntity].duplicate_db"
|
||||
class="px-1 py-0.5 rounded bg-amber-200 text-amber-800 text-[10px]"
|
||||
title="Že obstaja v bazi"
|
||||
>obstaja v bazi</span
|
||||
>
|
||||
</div>
|
||||
<template v-if="activeEntity === 'person'">
|
||||
<div class="grid grid-cols-1 gap-0.5">
|
||||
<div
|
||||
v-if="
|
||||
referenceOf(activeEntity, r.entities[activeEntity]) !== '—'
|
||||
"
|
||||
class="text-[10px] text-gray-600"
|
||||
>
|
||||
Ref:
|
||||
<span class="font-medium text-gray-800">{{
|
||||
referenceOf(activeEntity, r.entities[activeEntity])
|
||||
}}</span>
|
||||
</div>
|
||||
<div
|
||||
v-if="r.entities[activeEntity].full_name"
|
||||
class="text-[10px] text-gray-600"
|
||||
>
|
||||
Ime:
|
||||
<span class="font-medium">{{
|
||||
r.entities[activeEntity].full_name
|
||||
}}</span>
|
||||
</div>
|
||||
<div
|
||||
v-else-if="
|
||||
r.entities[activeEntity].first_name ||
|
||||
r.entities[activeEntity].last_name
|
||||
"
|
||||
class="text-[10px] text-gray-600"
|
||||
>
|
||||
Ime:
|
||||
<span class="font-medium">{{
|
||||
[
|
||||
r.entities[activeEntity].first_name,
|
||||
r.entities[activeEntity].last_name,
|
||||
]
|
||||
.filter(Boolean)
|
||||
.join(" ")
|
||||
}}</span>
|
||||
</div>
|
||||
<div
|
||||
v-if="r.entities[activeEntity].birthday"
|
||||
class="text-[10px] text-gray-600"
|
||||
>
|
||||
Rojstvo:
|
||||
<span class="font-medium">{{
|
||||
r.entities[activeEntity].birthday
|
||||
}}</span>
|
||||
</div>
|
||||
<div
|
||||
v-if="r.entities[activeEntity].description"
|
||||
class="text-[10px] text-gray-600"
|
||||
>
|
||||
Opis:
|
||||
<span class="font-medium">{{
|
||||
r.entities[activeEntity].description
|
||||
}}</span>
|
||||
</div>
|
||||
<div
|
||||
v-if="r.entities[activeEntity].identity_candidates?.length"
|
||||
class="text-[10px] text-gray-600"
|
||||
>
|
||||
Identitete:
|
||||
{{ r.entities[activeEntity].identity_candidates.join(", ") }}
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<template v-else-if="activeEntity === 'email'"
|
||||
><div class="text-[10px] text-gray-600">
|
||||
Email:
|
||||
<span class="font-medium">{{
|
||||
referenceOf(activeEntity, r.entities[activeEntity])
|
||||
}}</span>
|
||||
</div></template
|
||||
>
|
||||
<template v-else-if="activeEntity === 'phone'"
|
||||
><div class="text-[10px] text-gray-600">
|
||||
Telefon:
|
||||
<span class="font-medium">{{
|
||||
referenceOf(activeEntity, r.entities[activeEntity])
|
||||
}}</span>
|
||||
</div></template
|
||||
>
|
||||
<template v-else-if="activeEntity === 'address'">
|
||||
<div class="text-[10px] text-gray-600 space-y-0.5">
|
||||
<div
|
||||
v-if="
|
||||
referenceOf(activeEntity, r.entities[activeEntity]) !== '—'
|
||||
"
|
||||
>
|
||||
Ref:
|
||||
<span class="font-medium">{{
|
||||
referenceOf(activeEntity, r.entities[activeEntity])
|
||||
}}</span>
|
||||
</div>
|
||||
<div v-if="r.entities[activeEntity].address">
|
||||
Naslov:
|
||||
<span class="font-medium">{{
|
||||
r.entities[activeEntity].address
|
||||
}}</span>
|
||||
</div>
|
||||
<div
|
||||
v-if="
|
||||
r.entities[activeEntity].postal_code ||
|
||||
r.entities[activeEntity].country
|
||||
"
|
||||
>
|
||||
Lokacija:
|
||||
<span class="font-medium">{{
|
||||
[
|
||||
r.entities[activeEntity].postal_code,
|
||||
r.entities[activeEntity].country,
|
||||
]
|
||||
.filter(Boolean)
|
||||
.join(" ")
|
||||
}}</span>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<template v-else-if="activeEntity === 'client_case'">
|
||||
<div class="text-[10px] text-gray-600 space-y-0.5">
|
||||
<div
|
||||
v-if="
|
||||
referenceOf(activeEntity, r.entities[activeEntity]) !== '—'
|
||||
"
|
||||
>
|
||||
Ref:
|
||||
<span class="font-medium">{{
|
||||
referenceOf(activeEntity, r.entities[activeEntity])
|
||||
}}</span>
|
||||
</div>
|
||||
<div v-if="r.entities[activeEntity].title">
|
||||
Naslov:
|
||||
<span class="font-medium">{{
|
||||
r.entities[activeEntity].title
|
||||
}}</span>
|
||||
</div>
|
||||
<div v-if="r.entities[activeEntity].status">
|
||||
Status:
|
||||
<span class="font-medium">{{
|
||||
r.entities[activeEntity].status
|
||||
}}</span>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<template v-else>
|
||||
<pre class="text-[10px] whitespace-pre-wrap">{{
|
||||
r.entities[activeEntity]
|
||||
}}</pre>
|
||||
</template>
|
||||
</template>
|
||||
</div>
|
||||
</td>
|
||||
<td class="p-2 border align-top text-[11px]">
|
||||
<div v-if="r.entities.payment">
|
||||
<div class="mb-1 font-semibold text-gray-700">Učinek plačila</div>
|
||||
<div v-if="r.entities.account && r.entities.payment.amount !== null">
|
||||
Saldo:
|
||||
<span class="inline-flex items-center gap-1 font-medium">
|
||||
<ArrowDownIcon
|
||||
v-if="
|
||||
r.entities.account.balance_after -
|
||||
r.entities.account.balance_before <
|
||||
0
|
||||
"
|
||||
class="h-3 w-3 text-emerald-500"
|
||||
/>
|
||||
<ArrowUpIcon
|
||||
v-else-if="
|
||||
r.entities.account.balance_after -
|
||||
r.entities.account.balance_before >
|
||||
0
|
||||
"
|
||||
class="h-3 w-3 text-red-500"
|
||||
/>
|
||||
<ArrowRightIcon v-else class="h-3 w-3 text-gray-400" />
|
||||
<span
|
||||
:class="
|
||||
r.entities.account.balance_after -
|
||||
r.entities.account.balance_before <
|
||||
0
|
||||
? 'text-emerald-600'
|
||||
: r.entities.account.balance_after -
|
||||
r.entities.account.balance_before >
|
||||
0
|
||||
? 'text-red-600'
|
||||
: 'text-gray-700'
|
||||
"
|
||||
>{{
|
||||
fmt(
|
||||
r.entities.account.balance_after -
|
||||
r.entities.account.balance_before
|
||||
)
|
||||
}}</span
|
||||
>
|
||||
</span>
|
||||
</div>
|
||||
<div
|
||||
v-if="r.entities.account && r.entities.account.delta !== undefined"
|
||||
class="text-gray-500"
|
||||
>
|
||||
(pred {{ fmt(r.entities.account.balance_before) }} → po
|
||||
{{ fmt(r.entities.account.balance_after) }})
|
||||
</div>
|
||||
<div
|
||||
v-if="verbose && r.entities.payment.sources"
|
||||
class="mt-2 space-y-1"
|
||||
>
|
||||
<div class="font-semibold text-gray-600">Učinkoviti stolpci</div>
|
||||
<table class="min-w-full border text-[10px] bg-white">
|
||||
<thead>
|
||||
<tr class="bg-gray-50">
|
||||
<th class="px-1 py-0.5 border text-left">Tarča</th>
|
||||
<th class="px-1 py-0.5 border text-left">Izvorni stolpec</th>
|
||||
<th class="px-1 py-0.5 border text-left">Vrednost</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr v-for="(src, key) in r.entities.payment.sources" :key="key">
|
||||
<td class="px-1 py-0.5 border whitespace-nowrap">
|
||||
{{ key }}
|
||||
</td>
|
||||
<td class="px-1 py-0.5 border">{{ src.source_column }}</td>
|
||||
<td class="px-1 py-0.5 border">
|
||||
<span v-if="key === 'payment.amount'"
|
||||
>{{ src.value
|
||||
}}<span
|
||||
v-if="
|
||||
src.normalized !== undefined &&
|
||||
src.normalized !== src.value
|
||||
"
|
||||
class="text-gray-500"
|
||||
>
|
||||
→ {{ src.normalized }}</span
|
||||
></span
|
||||
><span v-else>{{ src.value ?? "—" }}</span>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</td>
|
||||
<td class="p-2 border text-[11px] align-top">
|
||||
<div class="text-gray-400">—</div>
|
||||
</td>
|
||||
</tr>
|
||||
<tr v-if="!loading && !visibleRows.length">
|
||||
<td :colspan="4" class="p-4 text-center text-gray-500">
|
||||
Ni simuliranih vrstic
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
<p class="text-[11px] text-gray-500">
|
||||
Samo simulacija – podatki niso bili spremenjeni. Saldi predpostavljajo zaporedno
|
||||
obdelavo plačil.
|
||||
</p>
|
||||
</div>
|
||||
</Modal>
|
||||
</template>
|
||||
Reference in New Issue
Block a user