Преглед изворни кода

feat(treasury): implement edit and delete functionality for treasury launches in TreasuryPage

ebagabee пре 1 недеља
родитељ
комит
8301fdf13b

+ 9 - 0
src/api/treasury_launch.js

@@ -9,3 +9,12 @@ export const createTreasuryLaunch = async (payload) => {
   const { data } = await api.post("/treasury-launch", payload);
   return data.payload;
 };
+
+export const updateTreasuryLaunch = async (id, payload) => {
+  const { data } = await api.put(`/treasury-launch/${id}`, payload);
+  return data.payload;
+};
+
+export const deleteTreasuryLaunch = async (id) => {
+  await api.delete(`/treasury-launch/${id}`);
+};

+ 23 - 14
src/components/financial/AddTreasuryLaunchDialog.vue

@@ -62,7 +62,7 @@ import { ref, onMounted } from "vue";
 import { useDialogPluginComponent } from "quasar";
 import { useInputRules } from "src/composables/useInputRules";
 import { useSubmitHandler } from "src/composables/useSubmitHandler";
-import { createTreasuryLaunch } from "src/api/treasury_launch";
+import { createTreasuryLaunch, updateTreasuryLaunch } from "src/api/treasury_launch";
 import { getFinancialPlanAccountsForSelect } from "src/api/financial_plan_account";
 
 import DefaultDialogHeader from "src/components/defaults/DefaultDialogHeader.vue";
@@ -72,11 +72,15 @@ import DefaultCurrencyInput from "src/components/defaults/DefaultCurrencyInput.v
 
 defineEmits([...useDialogPluginComponent.emits]);
 
-const { account } = defineProps({
+const { account, launch } = defineProps({
   account: {
     type: Object,
     required: true,
   },
+  launch: {
+    type: Object,
+    default: null,
+  },
 });
 
 const { inputRules } = useInputRules();
@@ -84,7 +88,8 @@ const { inputRules } = useInputRules();
 const { dialogRef, onDialogHide, onDialogOK, onDialogCancel } = useDialogPluginComponent();
 
 const formRef = ref(null);
-const title = `Nova movimentação — ${account.name}`;
+const isEdit = !!launch;
+const title = `${isEdit ? "Editar" : "Nova"} movimentação — ${account.name}`;
 
 const typeOptions = [
   { label: "Entrada", value: "entrada" },
@@ -92,10 +97,10 @@ const typeOptions = [
 ];
 
 const form = ref({
-  transaction_type: null,
-  description: "",
-  financial_plan_account_id: null,
-  amount: 0,
+  transaction_type: launch?.transaction_type ?? null,
+  description: launch?.description ?? "",
+  financial_plan_account_id: launch?.financial_plan_account_id ?? null,
+  amount: launch?.amount ?? 0,
 });
 
 const allPlanAccounts = ref([]);
@@ -135,14 +140,18 @@ const {
 });
 
 const onOKClick = async () => {
+  const payload = {
+    account_id: account.id,
+    transaction_type: form.value.transaction_type,
+    description: form.value.description,
+    financial_plan_account_id: form.value.financial_plan_account_id,
+    amount: form.value.amount,
+  };
+
   await submitForm(() =>
-    createTreasuryLaunch({
-      account_id: account.id,
-      transaction_type: form.value.transaction_type,
-      description: form.value.description,
-      financial_plan_account_id: form.value.financial_plan_account_id,
-      amount: form.value.amount,
-    }),
+    isEdit
+      ? updateTreasuryLaunch(launch.id, payload)
+      : createTreasuryLaunch(payload),
   );
 };
 </script>

+ 73 - 4
src/pages/financial/TreasuryPage.vue

@@ -31,7 +31,36 @@
         :female="false"
         :columns="columns"
         @on-add-item="handleAddItem"
-      />
+      >
+        <template #body-cell-actions="{ row }">
+          <q-td>
+            <div class="row no-wrap q-gutter-xs">
+              <q-btn
+                v-if="canEdit"
+                outline
+                icon="mdi-pencil-outline"
+                style="width: 36px"
+                aria-label="Editar movimentação"
+                @click.prevent.stop="handleEditLaunch(row)"
+              >
+                <q-tooltip>Editar</q-tooltip>
+              </q-btn>
+              <q-btn
+                v-if="canDelete"
+                outline
+                color="negative"
+                icon="mdi-trash-can-outline"
+                style="width: 36px"
+                aria-label="Excluir movimentação"
+                :loading="deletingId === row.id"
+                @click.prevent.stop="handleDeleteLaunch(row)"
+              >
+                <q-tooltip>Excluir</q-tooltip>
+              </q-btn>
+            </div>
+          </q-td>
+        </template>
+      </DefaultTable>
     </div>
   </div>
 </template>
@@ -45,7 +74,7 @@ import FinancialCard from "src/components/financial/FinancialCard.vue";
 import AddEditTreasuryAccountDialog from "src/components/financial/AddEditTreasuryAccountDialog.vue";
 import AddTreasuryLaunchDialog from "src/components/financial/AddTreasuryLaunchDialog.vue";
 import { getTreasuryAccounts } from "src/api/treasury_account";
-import { getTreasuryLaunches } from "src/api/treasury_launch";
+import { getTreasuryLaunches, deleteTreasuryLaunch } from "src/api/treasury_launch";
 import { formatToBRLCurrency, formatDateYMDtoDMY } from "src/helpers/utils";
 import { permissionStore } from "src/stores/permission";
 
@@ -53,10 +82,12 @@ const $q = useQuasar();
 const permissions = permissionStore();
 const canAdd = permissions.getAccess("franchisor_financial", "add");
 const canEdit = permissions.getAccess("franchisor_financial", "edit");
+const canDelete = permissions.getAccess("franchisor_financial", "delete");
 
 const accounts = ref([]);
 const launches = ref([]);
 const loading = ref(false);
+const deletingId = ref(null);
 
 // Variação % do saldo vs. o fim do mês anterior.
 const monthPercentage = (current, previous) => {
@@ -94,8 +125,7 @@ const rows = computed(() =>
   launches.value.map((launch) => {
     const isIncome = launch.transaction_type === "entrada";
     return {
-      id: launch.id,
-      description: launch.description,
+      ...launch,
       plan_account: launch.financial_plan_account?.label ?? "—",
       value: `${isIncome ? "+ " : "- "}${formatToBRLCurrency(launch.amount)}`,
       updated_at: formatDateYMDtoDMY(launch.updated_at),
@@ -108,6 +138,7 @@ const columns = [
   { name: "plan_account", label: "Plano de Contas", field: "plan_account", align: "left" },
   { name: "value", label: "Valor", field: "value", align: "left" },
   { name: "updated_at", label: "Atualização", field: "updated_at", align: "left" },
+  { name: "actions", label: "Ações", field: null, align: "center" },
 ];
 
 const fetchAccounts = async () => {
@@ -162,6 +193,44 @@ const handleAddItem = () => {
   });
 };
 
+const handleEditLaunch = (launch) => {
+  const account = accounts.value.find((item) => item.id === launch.account_id);
+
+  if (!account) {
+    $q.notify({ type: "negative", message: "Banco da movimentação não encontrado." });
+    return;
+  }
+
+  $q.dialog({
+    component: AddTreasuryLaunchDialog,
+    componentProps: { account, launch },
+  }).onOk(() => {
+    $q.notify({ type: "positive", message: "Movimentação atualizada com sucesso." });
+    fetchLaunches();
+    fetchAccounts();
+  });
+};
+
+const handleDeleteLaunch = (launch) => {
+  $q.dialog({
+    title: "Excluir movimentação",
+    message: `Deseja excluir a movimentação "${launch.description}"?`,
+    ok: { color: "negative", label: "Excluir" },
+    cancel: { color: "primary", outline: true, label: "Cancelar" },
+  }).onOk(async () => {
+    deletingId.value = launch.id;
+    try {
+      await deleteTreasuryLaunch(launch.id);
+      $q.notify({ type: "positive", message: "Movimentação excluída com sucesso." });
+      await Promise.all([fetchLaunches(), fetchAccounts()]);
+    } catch {
+      $q.notify({ type: "negative", message: "Erro ao excluir a movimentação." });
+    } finally {
+      deletingId.value = null;
+    }
+  });
+};
+
 watch(selectedBank, fetchLaunches);
 
 onMounted(async () => {