Option to add installment to contract/account to increace balance amount same as payment and can be deleted which will reduce balance amount by new amount of the installment deleted, call later added badge to show active call laters

This commit is contained in:
Simon Pocrnjič
2026-03-11 21:04:20 +01:00
parent 5f9d00b575
commit 9c6878d1bd
17 changed files with 910 additions and 2 deletions
@@ -0,0 +1,160 @@
<script setup>
import DialogModal from "@/Components/DialogModal.vue";
import { ref, watch, computed } from "vue";
import { router } from "@inertiajs/vue3";
import axios from "axios";
const props = defineProps({
show: { type: Boolean, default: false },
contract: { type: Object, default: null },
edit: { type: Boolean, default: true },
});
const emit = defineEmits(["close"]);
const installments = ref([]);
const loading = ref(false);
const contractRef = computed(() => props.contract?.reference || "—");
const accountId = computed(() => props.contract?.account?.id || null);
function formatDate(d) {
if (!d) return "-";
const dt = new Date(d);
return isNaN(dt.getTime()) ? "-" : dt.toLocaleDateString("de");
}
async function loadInstallments() {
if (!accountId.value) {
installments.value = [];
return;
}
loading.value = true;
try {
const { data } = await axios.get(
route("accounts.installments.list", { account: accountId.value })
);
installments.value = data.installments || [];
} finally {
loading.value = false;
}
}
function close() {
emit("close");
installments.value = [];
}
function deleteInstallment(installmentId) {
if (!accountId.value) return;
router.delete(
route("accounts.installments.destroy", {
account: accountId.value,
installment: installmentId,
}),
{
preserveScroll: true,
preserveState: true,
only: ["contracts", "activities"],
onSuccess: async () => {
await loadInstallments();
},
onError: async () => {
await loadInstallments();
},
}
);
}
watch(
() => props.show,
async (visible) => {
if (visible) {
await loadInstallments();
}
}
);
watch(
() => props.contract?.account?.id,
async () => {
if (props.show) {
await loadInstallments();
}
}
);
</script>
<template>
<DialogModal :show="show" @close="close">
<template #title>
Obroki za pogodbo <span class="text-gray-600">{{ contractRef }}</span>
</template>
<template #content>
<div>
<div v-if="loading" class="text-sm text-gray-500">Nalaganje</div>
<template v-else>
<div v-if="installments.length === 0" class="text-sm text-gray-500">Ni obrokov.</div>
<div v-else class="divide-y divide-gray-100 border rounded">
<div
v-for="i in installments"
:key="i.id"
class="px-3 py-2 flex items-center justify-between"
>
<div>
<div class="text-sm text-gray-800">
{{
Intl.NumberFormat("de-DE", {
style: "currency",
currency: i.currency || "EUR",
}).format(i.amount ?? 0)
}}
</div>
<div class="text-xs text-gray-500">
<span>{{ formatDate(i.installment_at) }}</span>
<span v-if="i.reference" class="ml-2">Sklic: {{ i.reference }}</span>
<span v-if="i.balance_before !== undefined" class="ml-2">
Stanje pred:
{{
Intl.NumberFormat("de-DE", {
style: "currency",
currency: i.currency || "EUR",
}).format(i.balance_before ?? 0)
}}
</span>
</div>
</div>
<div class="flex items-center gap-2" v-if="edit">
<button
type="button"
class="inline-flex items-center gap-1 px-2 py-1 rounded text-red-700 hover:bg-red-50"
@click="deleteInstallment(i.id)"
title="Izbriši obrok"
>
<span class="text-sm">Briši</span>
</button>
</div>
</div>
</div>
</template>
</div>
</template>
<template #footer>
<div class="flex justify-end gap-2 w-full">
<button
type="button"
class="px-3 py-2 rounded bg-gray-200 hover:bg-gray-300"
@click="loadInstallments"
>
Osveži
</button>
<button
type="button"
class="px-3 py-2 rounded bg-indigo-600 text-white hover:bg-indigo-700"
@click="close"
>
Zapri
</button>
</div>
</template>
</DialogModal>
</template>