Quellcode durchsuchen

feat(plan-account): conta pai/filho no plano de contas

- Dialog com radio Conta Pai / Conta Filho: filho seleciona o pai e
  herda o tipo (chart_type).
- Coluna "Conta Pai" na listagem do plano de contas.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
ebagabee vor 4 Wochen
Ursprung
Commit
b12396cbc0

+ 112 - 33
src/components/financial/AddFinancialPlanAccountDialog.vue

@@ -3,33 +3,68 @@
     <q-card class="q-dialog-plugin overflow-hidden" style="width: 520px; max-width: 90vw">
       <DefaultDialogHeader title="Nova Conta" @close="onDialogCancel" />
       <q-form ref="formRef" @submit="onOKClick">
-        <q-card-section class="row q-col-gutter-sm q-pt-none">
-          <DefaultInput
-            v-model="form.code"
-            v-model:error="validationErrors.code"
-            :rules="[inputRules.required]"
-            label="Código"
-            placeholder="5.1"
-            class="col-12 col-md-4"
+        <q-card-section class="q-pt-none">
+          <!-- Tipo: conta pai (raiz) ou conta filha (vinculada a um pai) -->
+          <q-option-group
+            v-model="accountKind"
+            :options="kindOptions"
+            color="primary"
+            inline
+            class="q-mb-sm"
           />
 
-          <DefaultInput
-            v-model="form.description"
-            v-model:error="validationErrors.description"
-            :rules="[inputRules.required]"
-            label="Nome da Conta"
-            placeholder="Ex. Receita de Eventos"
-            class="col-12 col-md-8"
-          />
+          <div class="row q-col-gutter-sm">
+            <DefaultInput
+              v-model="form.code"
+              v-model:error="validationErrors.code"
+              :rules="[inputRules.required]"
+              label="Código"
+              :placeholder="accountKind === 'child' ? '3.1.1' : '3'"
+              class="col-12 col-md-4"
+            />
 
-          <DefaultInput
-            v-model="form.chart_type"
-            v-model:error="validationErrors.chart_type"
-            :rules="[inputRules.required]"
-            label="Tipo de Conta"
-            placeholder="Ex. Ativo, Passivo, Receitas, Despesas"
-            class="col-12"
-          />
+            <DefaultInput
+              v-model="form.description"
+              v-model:error="validationErrors.description"
+              :rules="[inputRules.required]"
+              label="Nome da Conta"
+              placeholder="Ex. Contas a Pagar"
+              class="col-12 col-md-8"
+            />
+
+            <!-- Conta pai: define o tipo -->
+            <DefaultInput
+              v-if="accountKind === 'parent'"
+              v-model="form.chart_type"
+              v-model:error="validationErrors.chart_type"
+              :rules="[inputRules.required]"
+              label="Tipo de Conta"
+              placeholder="Ex. Ativo, Passivo, Receitas, Despesas"
+              class="col-12"
+            />
+
+            <!-- Conta filha: escolhe o pai (herda o tipo) -->
+            <DefaultSelect
+              v-else
+              v-model="form.parent_id"
+              :options="parentOptions"
+              option-value="id"
+              option-label="label"
+              emit-value
+              map-options
+              :loading="loadingParents"
+              :rules="[inputRules.required]"
+              label="Conta Pai"
+              class="col-12"
+            />
+          </div>
+
+          <div
+            v-if="accountKind === 'child' && selectedParent"
+            class="text-caption text-grey-7 q-mt-xs"
+          >
+            Tipo herdado do pai: <b>{{ selectedParent.chart_type }}</b>
+          </div>
         </q-card-section>
 
         <q-card-actions align="right">
@@ -42,14 +77,18 @@
 </template>
 
 <script setup>
-import { ref } from "vue";
+import { ref, computed, onMounted } from "vue";
 import { useDialogPluginComponent } from "quasar";
 import { useInputRules } from "src/composables/useInputRules";
 import { useSubmitHandler } from "src/composables/useSubmitHandler";
-import { createFinancialPlanAccount } from "src/api/financial_plan_account";
+import {
+  createFinancialPlanAccount,
+  getFinancialPlanAccounts,
+} from "src/api/financial_plan_account";
 
 import DefaultDialogHeader from "src/components/defaults/DefaultDialogHeader.vue";
 import DefaultInput from "src/components/defaults/DefaultInput.vue";
+import DefaultSelect from "src/components/defaults/DefaultSelect.vue";
 
 defineEmits([...useDialogPluginComponent.emits]);
 
@@ -59,12 +98,45 @@ const { dialogRef, onDialogHide, onDialogOK, onDialogCancel } = useDialogPluginC
 
 const formRef = ref(null);
 
+const accountKind = ref("parent");
+const kindOptions = [
+  { label: "Conta Pai", value: "parent" },
+  { label: "Conta Filho", value: "child" },
+];
+
 const form = ref({
   code: "",
   description: "",
   chart_type: "",
+  parent_id: null,
 });
 
+const accounts = ref([]);
+const loadingParents = ref(false);
+
+const parentOptions = computed(() =>
+  accounts.value.map((a) => ({
+    id: a.id,
+    label: `${a.code} — ${a.description}`,
+    chart_type: a.chart_type,
+  })),
+);
+
+const selectedParent = computed(() =>
+  parentOptions.value.find((o) => o.id === form.value.parent_id),
+);
+
+const loadAccounts = async () => {
+  loadingParents.value = true;
+  try {
+    accounts.value = await getFinancialPlanAccounts();
+  } catch (e) {
+    console.error("Erro ao carregar contas para vínculo:", e);
+  } finally {
+    loadingParents.value = false;
+  }
+};
+
 const {
   loading,
   validationErrors,
@@ -75,12 +147,19 @@ const {
 });
 
 const onOKClick = async () => {
-  await submitForm(() =>
-    createFinancialPlanAccount({
-      code: form.value.code,
-      description: form.value.description,
-      chart_type: form.value.chart_type,
-    }),
-  );
+  const payload = {
+    code: form.value.code,
+    description: form.value.description,
+  };
+
+  if (accountKind.value === "child") {
+    payload.parent_id = form.value.parent_id;
+  } else {
+    payload.chart_type = form.value.chart_type;
+  }
+
+  await submitForm(() => createFinancialPlanAccount(payload));
 };
+
+onMounted(loadAccounts);
 </script>

+ 4 - 0
src/pages/financial/ChartOfAccountsPage.vue

@@ -39,12 +39,16 @@ const rows = computed(() =>
     code: account.code,
     name: account.description,
     type: account.chart_type,
+    parent: account.parent
+      ? `${account.parent.code} — ${account.parent.description}`
+      : "—",
   })),
 );
 
 const columns = [
   { name: "code", label: "Código", field: "code", align: "left" },
   { name: "name", label: "Nome da Conta", field: "name", align: "left" },
+  { name: "parent", label: "Conta Pai", field: "parent", align: "left" },
   { name: "type", label: "Tipo", field: "type", align: "left" },
 ];