|
@@ -2,79 +2,57 @@
|
|
|
<div>
|
|
<div>
|
|
|
<DefaultHeaderPage title="Contas a Receber" :show-filter-icon="false" />
|
|
<DefaultHeaderPage title="Contas a Receber" :show-filter-icon="false" />
|
|
|
|
|
|
|
|
- <div class="q-px-md"><DevBanner /></div>
|
|
|
|
|
<div class="row q-pa-md q-gutter-md">
|
|
<div class="row q-pa-md q-gutter-md">
|
|
|
<FinancialCard
|
|
<FinancialCard
|
|
|
title="Saldo Tesouraria"
|
|
title="Saldo Tesouraria"
|
|
|
icon="mdi-bank-outline"
|
|
icon="mdi-bank-outline"
|
|
|
:financial-value="0"
|
|
:financial-value="0"
|
|
|
- :integer="0"
|
|
|
|
|
- integer-label="pagamentos pendentes"
|
|
|
|
|
/>
|
|
/>
|
|
|
<FinancialCard
|
|
<FinancialCard
|
|
|
title="Contas Recebidas"
|
|
title="Contas Recebidas"
|
|
|
icon="mdi-check-circle-outline"
|
|
icon="mdi-check-circle-outline"
|
|
|
- :financial-value="0"
|
|
|
|
|
- :integer="0"
|
|
|
|
|
- integer-label="pagamentos pendentes"
|
|
|
|
|
|
|
+ :financial-value="receivedTotal"
|
|
|
|
|
+ :integer="receivedCount"
|
|
|
|
|
+ integer-label="títulos recebidos"
|
|
|
/>
|
|
/>
|
|
|
<FinancialCard
|
|
<FinancialCard
|
|
|
title="Contas a Receber"
|
|
title="Contas a Receber"
|
|
|
icon="mdi-cash-plus"
|
|
icon="mdi-cash-plus"
|
|
|
- :financial-value="0"
|
|
|
|
|
- :integer="0"
|
|
|
|
|
- integer-label="pagamentos pendentes"
|
|
|
|
|
|
|
+ :financial-value="pendingTotal"
|
|
|
|
|
+ :integer="pendingCount"
|
|
|
|
|
+ integer-label="títulos pendentes"
|
|
|
/>
|
|
/>
|
|
|
</div>
|
|
</div>
|
|
|
|
|
|
|
|
<div class="row justify-end items-center q-px-md q-mb-sm q-gutter-sm">
|
|
<div class="row justify-end items-center q-px-md q-mb-sm q-gutter-sm">
|
|
|
- <q-btn
|
|
|
|
|
- :color="showMovimentacoes ? 'secondary' : 'primary'"
|
|
|
|
|
- label="Últimas Movimentações"
|
|
|
|
|
- unelevated
|
|
|
|
|
- no-caps
|
|
|
|
|
- @click="showMovimentacoes = !showMovimentacoes"
|
|
|
|
|
- />
|
|
|
|
|
<q-btn color="primary" label="Exportar Relatório" icon="mdi-download" unelevated no-caps />
|
|
<q-btn color="primary" label="Exportar Relatório" icon="mdi-download" unelevated no-caps />
|
|
|
</div>
|
|
</div>
|
|
|
|
|
|
|
|
<div class="q-px-md">
|
|
<div class="q-px-md">
|
|
|
<DefaultTable
|
|
<DefaultTable
|
|
|
- v-if="!showMovimentacoes"
|
|
|
|
|
v-model:rows="rows"
|
|
v-model:rows="rows"
|
|
|
no-api-call
|
|
no-api-call
|
|
|
- add-item
|
|
|
|
|
|
|
+ :add-item="false"
|
|
|
|
|
+ :loading="loading"
|
|
|
title="Contas a Receber"
|
|
title="Contas a Receber"
|
|
|
description="contas"
|
|
description="contas"
|
|
|
:female="true"
|
|
:female="true"
|
|
|
:columns="columns"
|
|
:columns="columns"
|
|
|
- @on-add-item="handleAddItem"
|
|
|
|
|
- />
|
|
|
|
|
- <DefaultTable
|
|
|
|
|
- v-else
|
|
|
|
|
- v-model:rows="movimentacoesRows"
|
|
|
|
|
- no-api-call
|
|
|
|
|
- :add-item="false"
|
|
|
|
|
- title="Últimas Movimentações"
|
|
|
|
|
- description="movimentações"
|
|
|
|
|
- :female="true"
|
|
|
|
|
- :columns="movimentacoesColumns"
|
|
|
|
|
- @on-add-item="handleAddItem"
|
|
|
|
|
/>
|
|
/>
|
|
|
</div>
|
|
</div>
|
|
|
</div>
|
|
</div>
|
|
|
</template>
|
|
</template>
|
|
|
|
|
|
|
|
<script setup>
|
|
<script setup>
|
|
|
-import { ref } from "vue";
|
|
|
|
|
|
|
+import { ref, computed, onMounted } from "vue";
|
|
|
|
|
+import { Notify } from "quasar";
|
|
|
import DefaultHeaderPage from "src/components/layout/DefaultHeaderPage.vue";
|
|
import DefaultHeaderPage from "src/components/layout/DefaultHeaderPage.vue";
|
|
|
-import DevBanner from "src/components/shared/DevBanner.vue";
|
|
|
|
|
import DefaultTable from "src/components/defaults/DefaultTable.vue";
|
|
import DefaultTable from "src/components/defaults/DefaultTable.vue";
|
|
|
import FinancialCard from "src/components/financial/FinancialCard.vue";
|
|
import FinancialCard from "src/components/financial/FinancialCard.vue";
|
|
|
|
|
+import { getFranchiseeReceivables } from "src/api/franchisee_account_receive";
|
|
|
|
|
|
|
|
-const showMovimentacoes = ref(false);
|
|
|
|
|
-const rows = ref([]);
|
|
|
|
|
-const movimentacoesRows = ref([]);
|
|
|
|
|
|
|
+const loading = ref(false);
|
|
|
|
|
+const items = ref([]);
|
|
|
|
|
|
|
|
const columns = [
|
|
const columns = [
|
|
|
{ name: "unit", label: "Unidade", field: "unit", align: "left" },
|
|
{ name: "unit", label: "Unidade", field: "unit", align: "left" },
|
|
@@ -85,12 +63,63 @@ const columns = [
|
|
|
{ name: "status", label: "Status", field: "status", align: "left" },
|
|
{ name: "status", label: "Status", field: "status", align: "left" },
|
|
|
];
|
|
];
|
|
|
|
|
|
|
|
-const movimentacoesColumns = [
|
|
|
|
|
- { name: "description", label: "Descrição", field: "description", align: "left" },
|
|
|
|
|
- { name: "date", label: "Data", field: "date", align: "left" },
|
|
|
|
|
- { name: "value", label: "Valor", field: "value", align: "left" },
|
|
|
|
|
- { name: "status", label: "Status", field: "status", align: "left" },
|
|
|
|
|
-];
|
|
|
|
|
|
|
+const STATUS_LABEL = {
|
|
|
|
|
+ pending: "Pendente",
|
|
|
|
|
+ awaiting_payment: "Aguardando",
|
|
|
|
|
+ paid: "Pago",
|
|
|
|
|
+ overdue: "Atrasado",
|
|
|
|
|
+ cancelled: "Cancelado",
|
|
|
|
|
+};
|
|
|
|
|
+
|
|
|
|
|
+const formatCurrency = (value) =>
|
|
|
|
|
+ new Intl.NumberFormat("pt-BR", { style: "currency", currency: "BRL" }).format(value ?? 0);
|
|
|
|
|
+
|
|
|
|
|
+const formatDate = (value) => {
|
|
|
|
|
+ if (!value) return "—";
|
|
|
|
|
+ const [y, m, d] = value.split("-");
|
|
|
|
|
+ return `${d}/${m}/${y}`;
|
|
|
|
|
+};
|
|
|
|
|
+
|
|
|
|
|
+const rows = computed(() =>
|
|
|
|
|
+ items.value.map((i) => ({
|
|
|
|
|
+ id: i.id,
|
|
|
|
|
+ unit: i.unit_name ?? `Unidade ${i.unit_id}`,
|
|
|
|
|
+ description: i.history,
|
|
|
|
|
+ category: "TBR",
|
|
|
|
|
+ value: formatCurrency(Number(i.value)),
|
|
|
|
|
+ due_date: formatDate(i.due_date),
|
|
|
|
|
+ status: STATUS_LABEL[i.status] ?? i.status,
|
|
|
|
|
+ })),
|
|
|
|
|
+);
|
|
|
|
|
+
|
|
|
|
|
+const isSettled = (status) => status === "paid";
|
|
|
|
|
+
|
|
|
|
|
+const receivedTotal = computed(() =>
|
|
|
|
|
+ items.value
|
|
|
|
|
+ .filter((i) => isSettled(i.status))
|
|
|
|
|
+ .reduce((acc, i) => acc + Number(i.paid_value || 0), 0),
|
|
|
|
|
+);
|
|
|
|
|
+const receivedCount = computed(() => items.value.filter((i) => isSettled(i.status)).length);
|
|
|
|
|
+
|
|
|
|
|
+const pendingTotal = computed(() =>
|
|
|
|
|
+ items.value
|
|
|
|
|
+ .filter((i) => !isSettled(i.status) && i.status !== "cancelled")
|
|
|
|
|
+ .reduce((acc, i) => acc + (Number(i.value || 0) - Number(i.paid_value || 0)), 0),
|
|
|
|
|
+);
|
|
|
|
|
+const pendingCount = computed(
|
|
|
|
|
+ () => items.value.filter((i) => !isSettled(i.status) && i.status !== "cancelled").length,
|
|
|
|
|
+);
|
|
|
|
|
+
|
|
|
|
|
+const fetchReceivables = async () => {
|
|
|
|
|
+ loading.value = true;
|
|
|
|
|
+ try {
|
|
|
|
|
+ items.value = await getFranchiseeReceivables();
|
|
|
|
|
+ } catch {
|
|
|
|
|
+ Notify.create({ message: "Não foi possível carregar as contas a receber.", type: "negative" });
|
|
|
|
|
+ } finally {
|
|
|
|
|
+ loading.value = false;
|
|
|
|
|
+ }
|
|
|
|
|
+};
|
|
|
|
|
|
|
|
-const handleAddItem = () => {};
|
|
|
|
|
|
|
+onMounted(fetchReceivables);
|
|
|
</script>
|
|
</script>
|