|
|
@@ -0,0 +1,259 @@
|
|
|
+<template>
|
|
|
+ <q-dialog ref="dialogRef" @hide="onDialogHide">
|
|
|
+ <q-card
|
|
|
+ class="q-dialog-plugin"
|
|
|
+ style="width: 980px; max-width: 95vw; max-height: 90vh"
|
|
|
+ >
|
|
|
+ <DefaultDialogHeader :title="title" @close="onDialogCancel" />
|
|
|
+
|
|
|
+ <q-scroll-area style="height: calc(90vh - 50px)">
|
|
|
+ <q-card-section class="q-gutter-md">
|
|
|
+ <q-list bordered separator>
|
|
|
+ <q-item v-for="item in paymentDetails" :key="item.label">
|
|
|
+ <q-item-section>
|
|
|
+ <q-item-label caption>{{ item.label }}</q-item-label>
|
|
|
+ <q-item-label>{{ item.value }}</q-item-label>
|
|
|
+ </q-item-section>
|
|
|
+ </q-item>
|
|
|
+ </q-list>
|
|
|
+
|
|
|
+ <div>
|
|
|
+ <div class="text-subtitle2 q-mb-sm">
|
|
|
+ {{ $t("payments.splits") }}
|
|
|
+ </div>
|
|
|
+ <q-markup-table flat bordered dense>
|
|
|
+ <thead>
|
|
|
+ <tr>
|
|
|
+ <th class="text-left">{{ idLabel }}</th>
|
|
|
+ <th class="text-left">{{ $t("payments.provider") }}</th>
|
|
|
+ <th class="text-left">{{ $t("common.terms.status") }}</th>
|
|
|
+ <th class="text-right">{{ $t("payments.gross_amount") }}</th>
|
|
|
+ <th class="text-right">{{ $t("payments.net_amount") }}</th>
|
|
|
+ <th class="text-left">{{ $t("payments.withdrawal_id") }}</th>
|
|
|
+ </tr>
|
|
|
+ </thead>
|
|
|
+ <tbody>
|
|
|
+ <tr v-for="split in paymentSplits" :key="split.id">
|
|
|
+ <td>{{ split.id }}</td>
|
|
|
+ <td>{{ split.provider_name || split.provider_id || "-" }}</td>
|
|
|
+ <td>
|
|
|
+ <q-chip
|
|
|
+ :label="splitStatusLabel(split.status)"
|
|
|
+ :color="splitStatusColor(split.status)"
|
|
|
+ text-color="white"
|
|
|
+ size="sm"
|
|
|
+ />
|
|
|
+ </td>
|
|
|
+ <td class="text-right">
|
|
|
+ {{ formatToBRLCurrency(split.gross_amount) }}
|
|
|
+ </td>
|
|
|
+ <td class="text-right">
|
|
|
+ {{ formatToBRLCurrency(split.net_amount) }}
|
|
|
+ </td>
|
|
|
+ <td>{{ split.provider_withdrawal_id || "-" }}</td>
|
|
|
+ </tr>
|
|
|
+ <tr v-if="!loading && paymentSplits.length === 0">
|
|
|
+ <td colspan="6" class="text-center text-grey-7 q-pa-md">
|
|
|
+ {{ $t("payments.no_splits") }}
|
|
|
+ </td>
|
|
|
+ </tr>
|
|
|
+ </tbody>
|
|
|
+ </q-markup-table>
|
|
|
+ </div>
|
|
|
+
|
|
|
+ <div>
|
|
|
+ <div class="text-subtitle2 q-mb-sm">
|
|
|
+ {{ $t("payments.withdrawals") }}
|
|
|
+ </div>
|
|
|
+ <q-markup-table flat bordered dense>
|
|
|
+ <thead>
|
|
|
+ <tr>
|
|
|
+ <th class="text-left">{{ idLabel }}</th>
|
|
|
+ <th class="text-left">{{ $t("payments.provider") }}</th>
|
|
|
+ <th class="text-left">{{ $t("common.terms.status") }}</th>
|
|
|
+ <th class="text-right">{{ $t("payments.gross_amount") }}</th>
|
|
|
+ <th class="text-right">{{ $t("payments.net_amount") }}</th>
|
|
|
+ <th class="text-left">{{ $t("common.terms.created_at") }}</th>
|
|
|
+ </tr>
|
|
|
+ </thead>
|
|
|
+ <tbody>
|
|
|
+ <tr
|
|
|
+ v-for="withdrawal in paymentWithdrawals"
|
|
|
+ :key="withdrawal.id"
|
|
|
+ >
|
|
|
+ <td>{{ withdrawal.id }}</td>
|
|
|
+ <td>
|
|
|
+ {{
|
|
|
+ withdrawal.provider_name || withdrawal.provider_id || "-"
|
|
|
+ }}
|
|
|
+ </td>
|
|
|
+ <td>
|
|
|
+ <q-chip
|
|
|
+ :label="withdrawalStatusLabel(withdrawal.status)"
|
|
|
+ :color="withdrawalStatusColor(withdrawal.status)"
|
|
|
+ text-color="white"
|
|
|
+ size="sm"
|
|
|
+ />
|
|
|
+ </td>
|
|
|
+ <td class="text-right">
|
|
|
+ {{ formatToBRLCurrency(withdrawal.gross_amount) }}
|
|
|
+ </td>
|
|
|
+ <td class="text-right">
|
|
|
+ {{ formatToBRLCurrency(withdrawal.net_amount) }}
|
|
|
+ </td>
|
|
|
+ <td>{{ formatDateTime(withdrawal.created_at) }}</td>
|
|
|
+ </tr>
|
|
|
+ <tr v-if="!loading && paymentWithdrawals.length === 0">
|
|
|
+ <td colspan="6" class="text-center text-grey-7 q-pa-md">
|
|
|
+ {{ $t("payments.no_withdrawals") }}
|
|
|
+ </td>
|
|
|
+ </tr>
|
|
|
+ </tbody>
|
|
|
+ </q-markup-table>
|
|
|
+ </div>
|
|
|
+ </q-card-section>
|
|
|
+ </q-scroll-area>
|
|
|
+
|
|
|
+ <q-inner-loading :showing="loading" color="primary" />
|
|
|
+ </q-card>
|
|
|
+ </q-dialog>
|
|
|
+</template>
|
|
|
+
|
|
|
+<script setup>
|
|
|
+import { computed, onMounted, ref } from "vue";
|
|
|
+import { useDialogPluginComponent } from "quasar";
|
|
|
+import { useI18n } from "vue-i18n";
|
|
|
+import { format, parseISO } from "date-fns";
|
|
|
+import DefaultDialogHeader from "src/components/defaults/DefaultDialogHeader.vue";
|
|
|
+import { getPaymentSplits, getProviderWithdrawals } from "src/api/payment";
|
|
|
+import { formatToBRLCurrency } from "src/helpers/utils";
|
|
|
+
|
|
|
+const props = defineProps({
|
|
|
+ payment: {
|
|
|
+ type: Object,
|
|
|
+ required: true,
|
|
|
+ },
|
|
|
+ title: {
|
|
|
+ type: Function,
|
|
|
+ required: true,
|
|
|
+ },
|
|
|
+});
|
|
|
+
|
|
|
+defineEmits([...useDialogPluginComponent.emits]);
|
|
|
+
|
|
|
+const { dialogRef, onDialogHide, onDialogCancel } = useDialogPluginComponent();
|
|
|
+const { t } = useI18n();
|
|
|
+const loading = ref(false);
|
|
|
+const splits = ref([]);
|
|
|
+const withdrawals = ref([]);
|
|
|
+const idLabel = "ID";
|
|
|
+
|
|
|
+const paymentSplits = computed(() =>
|
|
|
+ splits.value.filter((split) => split.payment_id === props.payment.id),
|
|
|
+);
|
|
|
+
|
|
|
+const paymentWithdrawals = computed(() => {
|
|
|
+ const withdrawalIds = new Set(
|
|
|
+ paymentSplits.value
|
|
|
+ .map((split) => split.provider_withdrawal_id)
|
|
|
+ .filter((id) => id !== null && id !== undefined),
|
|
|
+ );
|
|
|
+ return withdrawals.value.filter((withdrawal) =>
|
|
|
+ withdrawalIds.has(withdrawal.id),
|
|
|
+ );
|
|
|
+});
|
|
|
+
|
|
|
+const paymentDetails = computed(() => [
|
|
|
+ { label: idLabel, value: props.payment.id },
|
|
|
+ { label: t("payments.schedule_id"), value: props.payment.schedule_id || "-" },
|
|
|
+ {
|
|
|
+ label: t("payments.client"),
|
|
|
+ value: props.payment.client_name || props.payment.client_id || "-",
|
|
|
+ },
|
|
|
+ {
|
|
|
+ label: t("payments.provider"),
|
|
|
+ value: props.payment.provider_name || props.payment.provider_id || "-",
|
|
|
+ },
|
|
|
+ {
|
|
|
+ label: t("payments.payment_method"),
|
|
|
+ value: paymentMethodLabel(props.payment.payment_method),
|
|
|
+ },
|
|
|
+ { label: t("common.terms.status"), value: statusLabel(props.payment.status) },
|
|
|
+ {
|
|
|
+ label: t("payments.gross_amount"),
|
|
|
+ value: formatToBRLCurrency(props.payment.gross_amount),
|
|
|
+ },
|
|
|
+ {
|
|
|
+ label: t("payments.gateway_fee_amount"),
|
|
|
+ value: formatToBRLCurrency(props.payment.gateway_fee_amount),
|
|
|
+ },
|
|
|
+ {
|
|
|
+ label: t("payments.platform_fee_amount"),
|
|
|
+ value: formatToBRLCurrency(props.payment.platform_fee_amount),
|
|
|
+ },
|
|
|
+ {
|
|
|
+ label: t("payments.net_amount"),
|
|
|
+ value: formatToBRLCurrency(props.payment.net_amount),
|
|
|
+ },
|
|
|
+ {
|
|
|
+ label: t("common.terms.created_at"),
|
|
|
+ value: formatDateTime(props.payment.created_at),
|
|
|
+ },
|
|
|
+]);
|
|
|
+
|
|
|
+function paymentMethodLabel(method) {
|
|
|
+ return method ? t(`payments.payment_methods.${method}`) : "-";
|
|
|
+}
|
|
|
+
|
|
|
+function statusLabel(status) {
|
|
|
+ return status ? t(`payments.statuses.${status}`) : "-";
|
|
|
+}
|
|
|
+
|
|
|
+function splitStatusLabel(status) {
|
|
|
+ return status ? t(`payments.split_statuses.${status}`) : "-";
|
|
|
+}
|
|
|
+
|
|
|
+function withdrawalStatusLabel(status) {
|
|
|
+ return status ? t(`payments.withdrawal_statuses.${status}`) : "-";
|
|
|
+}
|
|
|
+
|
|
|
+function splitStatusColor(status) {
|
|
|
+ const colors = {
|
|
|
+ pending: "orange",
|
|
|
+ processing: "blue",
|
|
|
+ transferred: "green",
|
|
|
+ failed: "negative",
|
|
|
+ cancelled: "grey",
|
|
|
+ };
|
|
|
+ return colors[status] || "grey";
|
|
|
+}
|
|
|
+
|
|
|
+function withdrawalStatusColor(status) {
|
|
|
+ const colors = {
|
|
|
+ pending_transfer: "orange",
|
|
|
+ processing: "blue",
|
|
|
+ transferred: "green",
|
|
|
+ failed: "negative",
|
|
|
+ canceled: "grey",
|
|
|
+ };
|
|
|
+ return colors[status] || "grey";
|
|
|
+}
|
|
|
+
|
|
|
+function formatDateTime(value) {
|
|
|
+ return value ? format(parseISO(value), "dd/MM/yyyy HH:mm") : "-";
|
|
|
+}
|
|
|
+
|
|
|
+onMounted(async () => {
|
|
|
+ loading.value = true;
|
|
|
+ try {
|
|
|
+ const [splitItems, withdrawalItems] = await Promise.all([
|
|
|
+ getPaymentSplits(),
|
|
|
+ getProviderWithdrawals(),
|
|
|
+ ]);
|
|
|
+ splits.value = splitItems;
|
|
|
+ withdrawals.value = withdrawalItems;
|
|
|
+ } finally {
|
|
|
+ loading.value = false;
|
|
|
+ }
|
|
|
+});
|
|
|
+</script>
|