Pārlūkot izejas kodu

feat: adiciona edicao de contrato

ebagabee 1 mēnesi atpakaļ
vecāks
revīzija
d1d157e894

+ 23 - 0
src/api/franchisee_contract.js

@@ -0,0 +1,23 @@
+import api from "src/api";
+
+export const getFranchiseeContractsByUnit = async (unitId) => {
+  const { data } = await api.get("/franchisee-contract", {
+    params: { unit_id: unitId },
+  });
+  return data.payload;
+};
+
+export const createFranchiseeContract = async (payload) => {
+  const { data } = await api.post("/franchisee-contract", payload);
+  return data.payload;
+};
+
+export const updateFranchiseeContract = async (id, payload) => {
+  const { data } = await api.put(`/franchisee-contract/${id}`, payload);
+  return data.payload;
+};
+
+export const deleteFranchiseeContract = async (id) => {
+  const { data } = await api.delete(`/franchisee-contract/${id}`);
+  return data;
+};

+ 6 - 0
src/api/inhabitant_classification.js

@@ -0,0 +1,6 @@
+import api from "src/api";
+
+export const getInhabitantClassificationsForSelect = async () => {
+  const { data } = await api.get("/inhabitant-classification/all/select");
+  return data.payload;
+};

+ 5 - 0
src/api/tbr.js

@@ -15,6 +15,11 @@ export const updateTbr = async (id, payload) => {
   return data.payload;
 };
 
+export const getLatestTbr = async () => {
+  const { data } = await api.get("/tbr/current");
+  return data.payload;
+};
+
 export const getFranchiseeTbrs = async () => {
   const { data } = await api.get("/franchisee-tbr");
   return data.payload;

+ 33 - 16
src/pages/packages/components/AddEditPackageDialog.vue

@@ -170,14 +170,23 @@
                     color="primary"
                     icon="mdi-plus"
                     unelevated
-                    style="border-radius: 8px; height: 40px; width: 40px; flex-shrink: 0"
+                    style="
+                      border-radius: 8px;
+                      height: 40px;
+                      width: 40px;
+                      flex-shrink: 0;
+                    "
                   />
                 </div>
 
                 <!-- Lista de Unidades -->
                 <div
                   class="rounded-borders q-pa-sm"
-                  style="background-color: #f5f5f5; max-height: 280px; overflow-y: auto"
+                  style="
+                    background-color: #f5f5f5;
+                    max-height: 280px;
+                    overflow-y: auto;
+                  "
                 >
                   <div v-if="loadingUnits" class="flex flex-center q-py-md">
                     <q-spinner color="secondary" size="sm" />
@@ -200,13 +209,17 @@
 
                     <div class="row q-px-sm q-py-xs">
                       <span class="col text-caption text-grey-6">Unidade</span>
-                      <span class="col-auto text-caption text-grey-6">Status</span>
+                      <span class="col-auto text-caption text-grey-6"
+                        >Status</span
+                      >
                     </div>
 
                     <template v-for="unit in filteredUnits" :key="unit.id">
                       <q-separator />
                       <div class="row items-center q-px-sm q-py-sm">
-                        <span class="col text-body2">{{ unit.fantasy_name }}</span>
+                        <span class="col text-body2">{{
+                          unit.fantasy_name
+                        }}</span>
                         <div class="col-auto row q-gutter-x-xs">
                           <q-btn
                             round
@@ -292,7 +305,11 @@ const tabs = [
 const products = ref([]);
 
 const productOptions = computed(() =>
-  products.value.map((p) => ({ label: p.name, value: p.id, price_sale: p.price_sale }))
+  products.value.map((p) => ({
+    label: p.name,
+    value: p.id,
+    price_sale: p.price_sale,
+  })),
 );
 
 const form = ref({
@@ -305,7 +322,9 @@ const form = ref({
 });
 
 const onProductSelected = (material) => {
-  const option = productOptions.value.find((o) => o.value === material.product_id);
+  const option = productOptions.value.find(
+    (o) => o.value === material.product_id,
+  );
   if (option) material.price = option.price_sale;
 };
 
@@ -317,13 +336,13 @@ const removeMaterial = (index) => {
   form.value.materials.splice(index, 1);
 };
 
-const contractMaterialValue = computed(() =>
-  form.value.materials.reduce((sum, m) => {
-    const qty = Number(m.quantity) || 0;
-    const price = Number(m.price) || 0;
-    return sum + qty * price;
-  }, 0)
-);
+// const contractMaterialValue = computed(() =>
+//   form.value.materials.reduce((sum, m) => {
+//     const qty = Number(m.quantity) || 0;
+//     const price = Number(m.price) || 0;
+//     return sum + qty * price;
+//   }, 0)
+// );
 
 // Unidades tab
 const unitSearch = ref("");
@@ -332,9 +351,7 @@ const units = ref([]);
 const filteredUnits = computed(() => {
   const q = unitSearch.value.toLowerCase();
   if (!q) return units.value;
-  return units.value.filter((u) =>
-    u.fantasy_name.toLowerCase().includes(q)
-  );
+  return units.value.filter((u) => u.fantasy_name.toLowerCase().includes(q));
 });
 
 const setAllVisible = (visible) => {

+ 21 - 4
src/pages/tbr/tabs/ContractsTab.vue

@@ -25,7 +25,9 @@
     </template>
 
     <template #body-cell-ref_month="{ row }">
-      <q-td>{{ formatRefMonth(row.contract_month_current, row.contract_validity_months) }}</q-td>
+      <q-td>{{
+        formatRefMonth(row.contract_month_current, row.contract_validity_months)
+      }}</q-td>
     </template>
 
     <template #body-cell-actions>
@@ -48,10 +50,25 @@ const columns = [
   { name: "id", label: "ID", field: "id", align: "left" },
   { name: "unit_name", label: "Unidade", field: "unit_name", align: "left" },
   { name: "tbr_value", label: "TBR", field: "tbr_value", align: "left" },
-  { name: "royalties", label: "Royalties", field: "base_royalties_percentage", align: "left" },
+  {
+    name: "royalties",
+    label: "Royalties",
+    field: "base_royalties_percentage",
+    align: "left",
+  },
   { name: "fnm", label: "FNM", field: "base_fnm_percentage", align: "left" },
-  { name: "maintenance", label: "Manutenção", field: "maintenance_percentage", align: "left" },
-  { name: "ref_month", label: "Ref. Mês", field: "contract_month_current", align: "left" },
+  {
+    name: "maintenance",
+    label: "Manutenção",
+    field: "maintenance_percentage",
+    align: "left",
+  },
+  {
+    name: "ref_month",
+    label: "Ref. Mês",
+    field: "contract_month_current",
+    align: "left",
+  },
   { name: "actions", label: "Ações", field: "actions", align: "center" },
 ];
 

+ 123 - 24
src/pages/unit/components/CreateContractDialog.vue

@@ -14,35 +14,39 @@
 
         <div class="row q-col-gutter-x-sm">
           <DefaultInput
-            :model-value="contractForm.id"
+            :model-value="unitData.id"
             label="ID"
             color="secondary"
             label-color="secondary"
             class="col-md-3 col-12"
+            disable
           />
 
           <DefaultInput
-            v-model="contractForm.franchisee_name"
+            :model-value="unitData.franchisee_name"
             label="Nome do Franqueado"
             color="secondary"
             label-color="secondary"
             class="col-md-3 col-12"
+            disable
           />
 
           <DefaultInput
-            v-model="contractForm.franchisee_document"
+            :model-value="unitData.franchisee_document"
             label="CPF/CNH"
             color="secondary"
             label-color="secondary"
             class="col-md-3 col-12"
+            disable
           />
 
-          <DefaultInputDatePicker
-            v-model="contractForm.franchisee_birthday"
+          <DefaultInput
+            :model-value="unitData.franchisee_birthday"
             label="Data de Nascimento"
             color="secondary"
             label-color="secondary"
             class="col-md-3 col-12"
+            disable
           />
         </div>
       </q-card-section>
@@ -52,7 +56,7 @@
 
         <div class="row q-col-gutter-sm">
           <DefaultInputDatePicker
-            v-model="contractForm.contract_start_date"
+            v-model:untreated-date="contractForm.start_date"
             label="Data de Início"
             color="secondary"
             label-color="secondary"
@@ -60,7 +64,7 @@
           />
 
           <DefaultInputDatePicker
-            v-model="contractForm.contract_end_date"
+            v-model:untreated-date="contractForm.end_date"
             label="Data de Fim"
             color="secondary"
             label-color="secondary"
@@ -68,7 +72,7 @@
           />
 
           <DefaultCurrencyInput
-            v-model="contractForm.contract_tbr_value"
+            v-model="contractForm.tbr_fixed_value"
             label="TBR $"
             color="secondary"
             label-color="secondary"
@@ -76,7 +80,7 @@
           />
 
           <DefaultInputDatePicker
-            v-model="contractForm.contract_due_date_price"
+            v-model:untreated-date="contractForm.invoice_due_date"
             label="Vencimento Boleto"
             color="secondary"
             label-color="secondary"
@@ -84,11 +88,16 @@
           />
 
           <DefaultSelect
-            v-model="contractForm.inhabitants_range"
+            v-model="contractForm.inhabitant_classification_id"
             label="Faixa de Habitante"
             color="secondary"
             label-color="secondary"
-            :options="inhabitantRangeOptions"
+            :options="inhabitantOptions"
+            emit-value
+            map-options
+            use-input
+            fill-input
+            input-debounce="0"
             class="col-md-3 col-12"
           />
 
@@ -97,6 +106,7 @@
             label="Taxa Base Royalties"
             color="secondary"
             label-color="secondary"
+            type="number"
             class="col-md-3 col-12"
           >
             <template #append>
@@ -109,6 +119,7 @@
             label="Taxa Base FMN"
             color="secondary"
             label-color="secondary"
+            type="number"
             class="col-md-3 col-12"
           >
             <template #append>
@@ -120,8 +131,8 @@
             v-model="contractForm.tax_base_maintenance"
             label="Taxa Base Manutenção"
             color="secondary"
-            outlined
             label-color="secondary"
+            type="number"
             class="col-md-3 col-12"
           >
             <template #append>
@@ -138,13 +149,19 @@
           label="Cancelar"
           @click="onDialogCancel"
         />
-        <q-btn color="primary" label="Salvar" />
+        <q-btn
+          color="primary"
+          label="Salvar"
+          :loading="saving"
+          @click="save"
+        />
       </q-card-actions>
     </q-card>
   </q-dialog>
 </template>
 
 <script setup>
+import { ref, reactive, onMounted } from "vue";
 import { useDialogPluginComponent } from "quasar";
 
 import DefaultDialogHeader from "src/components/defaults/DefaultDialogHeader.vue";
@@ -152,28 +169,110 @@ import DefaultInput from "src/components/defaults/DefaultInput.vue";
 import DefaultInputDatePicker from "src/components/defaults/DefaultInputDatePicker.vue";
 import DefaultCurrencyInput from "src/components/defaults/DefaultCurrencyInput.vue";
 import DefaultSelect from "src/components/defaults/DefaultSelect.vue";
-import { useFormUpdateTracker } from "src/composables/useFormUpdateTracker";
+
+import { getUnit } from "src/api/unit";
+import { getLatestTbr } from "src/api/tbr";
+import { getInhabitantClassificationsForSelect } from "src/api/inhabitant_classification";
+import { createFranchiseeContract } from "src/api/franchisee_contract";
 
 defineEmits([...useDialogPluginComponent.emits]);
 
-const { dialogRef, onDialogHide, onDialogCancel } = useDialogPluginComponent();
+const props = defineProps({
+  unitId: {
+    type: Number,
+    required: true,
+  },
+});
+
+const { dialogRef, onDialogHide, onDialogCancel, onDialogOK } =
+  useDialogPluginComponent();
 
-const inhabitantRangeOptions = [{ label: "Selecione", value: null }];
+const saving = ref(false);
+const inhabitantOptions = ref([]);
 
-const { form: contractForm } = useFormUpdateTracker({
-  unit_id: null,
+const unitData = reactive({
+  id: null,
   franchisee_name: null,
   franchisee_document: null,
   franchisee_birthday: null,
+});
 
-  contract_start_date: null,
-  contract_end_date: null,
-  contract_tbr_value: null,
-  contract_due_date_price: null,
-
-  inhabitants_range: null,
+const contractForm = reactive({
+  start_date: null,
+  end_date: null,
+  tbr_fixed_value: null,
+  invoice_due_date: null,
+  inhabitant_classification_id: null,
   tax_base_royalts: null,
   tax_base_fnm: null,
   tax_base_maintenance: null,
 });
+
+async function loadData() {
+  const [unit, latestTbr, classifications] = await Promise.all([
+    getUnit(props.unitId),
+    getLatestTbr(),
+    getInhabitantClassificationsForSelect(),
+  ]);
+
+  unitData.id = unit.id;
+  unitData.franchisee_name = unit.name_responsible;
+
+  const firstPartner = unit.partners?.[0];
+  if (firstPartner) {
+    unitData.franchisee_document = firstPartner.cpf;
+    unitData.franchisee_birthday = firstPartner.birth_date;
+  }
+
+  if (latestTbr) {
+    contractForm.tbr_fixed_value = parseFloat(latestTbr.tbr_value);
+    contractForm.tax_base_royalts = parseFloat(
+      (latestTbr.royalties_percentage * 100).toFixed(4),
+    );
+    contractForm.tax_base_fnm = parseFloat(
+      (latestTbr.fnm_percentage * 100).toFixed(4),
+    );
+    contractForm.tax_base_maintenance = parseFloat(
+      (latestTbr.maintenance_percentage * 100).toFixed(4),
+    );
+  }
+
+  inhabitantOptions.value = classifications.map((c) => ({
+    label: `${c.description} (${c.acronym})`,
+    value: c.id,
+  }));
+}
+
+async function save() {
+  saving.value = true;
+  try {
+    await createFranchiseeContract({
+      unit_id: props.unitId,
+      start_date: contractForm.start_date,
+      end_date: contractForm.end_date,
+      tbr_fixed_value: contractForm.tbr_fixed_value,
+      invoice_due_date: contractForm.invoice_due_date,
+      inhabitant_classification_id: contractForm.inhabitant_classification_id,
+      tbr_fixed_value_percentage:
+        contractForm.tax_base_royalts != null
+          ? contractForm.tax_base_royalts / 100
+          : null,
+      marketing_fund_percentage:
+        contractForm.tax_base_fnm != null
+          ? contractForm.tax_base_fnm / 100
+          : null,
+      maintance_tax_percentage:
+        contractForm.tax_base_maintenance != null
+          ? contractForm.tax_base_maintenance / 100
+          : null,
+    });
+    onDialogOK();
+  } catch (error) {
+    console.error(error);
+  } finally {
+    saving.value = false;
+  }
+}
+
+onMounted(loadData);
 </script>

+ 314 - 0
src/pages/unit/components/EditContractDialog.vue

@@ -0,0 +1,314 @@
+<template>
+  <q-dialog ref="dialogRef" @hide="onDialogHide">
+    <q-card
+      class="q-dialog-plugin overflow-hidden"
+      style="width: 100%; max-width: 1100px"
+    >
+      <DefaultDialogHeader
+        :title="() => 'Editar Contrato'"
+        @close="onDialogCancel"
+      />
+
+      <q-card-section>
+        <div class="text-body2 q-mb-sm">Dados da Unidade</div>
+
+        <div class="row q-col-gutter-x-sm">
+          <DefaultInput
+            :model-value="unitData.id"
+            label="ID"
+            color="secondary"
+            label-color="secondary"
+            class="col-md-3 col-12"
+            disable
+          />
+
+          <DefaultInput
+            :model-value="unitData.franchisee_name"
+            label="Nome do Franqueado"
+            color="secondary"
+            label-color="secondary"
+            class="col-md-3 col-12"
+            disable
+          />
+
+          <DefaultInput
+            :model-value="unitData.franchisee_document"
+            label="CPF / CNH"
+            color="secondary"
+            label-color="secondary"
+            class="col-md-3 col-12"
+            disable
+          />
+
+          <DefaultInput
+            :model-value="unitData.franchisee_birthday"
+            label="Data de Nascimento"
+            color="secondary"
+            label-color="secondary"
+            class="col-md-3 col-12"
+            disable
+          />
+        </div>
+      </q-card-section>
+
+      <q-card-section>
+        <div class="row q-col-gutter-sm">
+          <DefaultInputDatePicker
+            v-model:untreated-date="contractForm.start_date"
+            label="Data de Início"
+            color="secondary"
+            label-color="secondary"
+            class="col-md-3 col-12"
+          />
+
+          <DefaultInputDatePicker
+            v-model:untreated-date="contractForm.end_date"
+            label="Data de Fim"
+            color="secondary"
+            label-color="secondary"
+            class="col-md-3 col-12"
+          />
+
+          <DefaultInputDatePicker
+            v-model:untreated-date="contractForm.invoice_due_date"
+            label="Dia de Vencimento"
+            color="secondary"
+            label-color="secondary"
+            class="col-md-3 col-12"
+          />
+
+          <DefaultSelect
+            v-model="contractForm.inhabitant_classification_id"
+            label="Faixa de Habitantes"
+            color="secondary"
+            label-color="secondary"
+            :options="inhabitantOptions"
+            emit-value
+            map-options
+            use-input
+            fill-input
+            hide-selected
+            input-debounce="0"
+            class="col-md-3 col-12"
+          />
+        </div>
+
+        <div class="row q-col-gutter-sm q-mt-xs">
+          <DefaultCurrencyInput
+            v-model="contractForm.tbr_fixed_value"
+            label="TBR $"
+            color="secondary"
+            label-color="secondary"
+            class="col-md-3 col-12"
+          />
+
+          <DefaultInput
+            v-model="contractForm.tax_base_royalts"
+            label="Taxa Base Royalties"
+            color="secondary"
+            label-color="secondary"
+            type="number"
+            class="col-md-3 col-12"
+          >
+            <template #append>
+              <span class="text-secondary">%</span>
+            </template>
+          </DefaultInput>
+
+          <DefaultInput
+            v-model="contractForm.tax_base_fnm"
+            label="Fundo Nacional de Marketing"
+            color="secondary"
+            label-color="secondary"
+            type="number"
+            class="col-md-3 col-12"
+          >
+            <template #append>
+              <span class="text-secondary">%</span>
+            </template>
+          </DefaultInput>
+
+          <DefaultInput
+            v-model="contractForm.tax_base_maintenance"
+            label="Taxa de Manutenção"
+            color="secondary"
+            label-color="secondary"
+            type="number"
+            class="col-md-3 col-12"
+          >
+            <template #append>
+              <span class="text-secondary">%</span>
+            </template>
+          </DefaultInput>
+        </div>
+      </q-card-section>
+
+      <q-card-section>
+        <div class="text-body2 q-mb-sm">Histórico de TBR</div>
+
+        <q-table
+          flat
+          dense
+          :rows="tbrHistory"
+          :columns="tbrColumns"
+          row-key="id"
+          :loading="loadingHistory"
+          :pagination="{ rowsPerPage: 5 }"
+          no-data-label="Nenhum histórico disponível"
+        />
+      </q-card-section>
+
+      <q-card-actions align="right">
+        <q-btn
+          outline
+          color="primary"
+          label="Cancelar"
+          @click="onDialogCancel"
+        />
+        <q-btn color="primary" label="Salvar" :loading="saving" @click="save" />
+      </q-card-actions>
+    </q-card>
+  </q-dialog>
+</template>
+
+<script setup>
+import { ref, reactive, onMounted } from "vue";
+import { useDialogPluginComponent } from "quasar";
+
+import DefaultDialogHeader from "src/components/defaults/DefaultDialogHeader.vue";
+import DefaultInput from "src/components/defaults/DefaultInput.vue";
+import DefaultInputDatePicker from "src/components/defaults/DefaultInputDatePicker.vue";
+import DefaultCurrencyInput from "src/components/defaults/DefaultCurrencyInput.vue";
+import DefaultSelect from "src/components/defaults/DefaultSelect.vue";
+
+import { getUnit } from "src/api/unit";
+import { getInhabitantClassificationsForSelect } from "src/api/inhabitant_classification";
+import { updateFranchiseeContract } from "src/api/franchisee_contract";
+
+defineEmits([...useDialogPluginComponent.emits]);
+
+const props = defineProps({
+  unitId: {
+    type: Number,
+    required: true,
+  },
+  contract: {
+    type: Object,
+    required: true,
+  },
+});
+
+const { dialogRef, onDialogHide, onDialogCancel, onDialogOK } =
+  useDialogPluginComponent();
+
+const saving = ref(false);
+const loadingHistory = ref(false);
+const inhabitantOptions = ref([]);
+const tbrHistory = ref([]);
+
+const unitData = reactive({
+  id: null,
+  franchisee_name: null,
+  franchisee_document: null,
+  franchisee_birthday: null,
+});
+
+const contractForm = reactive({
+  start_date: props.contract.start_date ?? null,
+  end_date: props.contract.end_date ?? null,
+  tbr_fixed_value: props.contract.tbr_fixed_value
+    ? parseFloat(props.contract.tbr_fixed_value)
+    : null,
+  invoice_due_date: props.contract.invoice_due_date ?? null,
+  inhabitant_classification_id:
+    props.contract.inhabitant_classification_id ?? null,
+  tax_base_royalts:
+    props.contract.tbr_fixed_value_percentage != null
+      ? parseFloat((props.contract.tbr_fixed_value_percentage * 100).toFixed(4))
+      : null,
+  tax_base_fnm:
+    props.contract.marketing_fund_percentage != null
+      ? parseFloat((props.contract.marketing_fund_percentage * 100).toFixed(4))
+      : null,
+  tax_base_maintenance:
+    props.contract.maintance_tax_percentage != null
+      ? parseFloat((props.contract.maintance_tax_percentage * 100).toFixed(4))
+      : null,
+});
+
+const tbrColumns = [
+  { name: "year", label: "Ano", field: "year", align: "left" },
+  { name: "tbr_value", label: "TBR $", field: "tbr_value", align: "left" },
+  {
+    name: "royalties_percentage",
+    label: "Royalties %",
+    field: "royalties_percentage",
+    align: "left",
+  },
+  {
+    name: "fnm_percentage",
+    label: "FNM %",
+    field: "fnm_percentage",
+    align: "left",
+  },
+  {
+    name: "maintenance_percentage",
+    label: "Manutenção %",
+    field: "maintenance_percentage",
+    align: "left",
+  },
+];
+
+async function loadData() {
+  const [unit, classifications] = await Promise.all([
+    getUnit(props.unitId),
+    getInhabitantClassificationsForSelect(),
+  ]);
+
+  unitData.id = unit.id;
+  unitData.franchisee_name = unit.name_responsible;
+
+  const firstPartner = unit.partners?.[0];
+  if (firstPartner) {
+    unitData.franchisee_document = firstPartner.cpf;
+    unitData.franchisee_birthday = firstPartner.birth_date;
+  }
+
+  inhabitantOptions.value = classifications.map((c) => ({
+    label: `${c.description} (${c.acronym})`,
+    value: c.id,
+  }));
+}
+
+async function save() {
+  saving.value = true;
+  try {
+    await updateFranchiseeContract(props.contract.id, {
+      start_date: contractForm.start_date,
+      end_date: contractForm.end_date,
+      tbr_fixed_value: contractForm.tbr_fixed_value,
+      invoice_due_date: contractForm.invoice_due_date,
+      inhabitant_classification_id: contractForm.inhabitant_classification_id,
+      tbr_fixed_value_percentage:
+        contractForm.tax_base_royalts != null
+          ? contractForm.tax_base_royalts / 100
+          : null,
+      marketing_fund_percentage:
+        contractForm.tax_base_fnm != null
+          ? contractForm.tax_base_fnm / 100
+          : null,
+      maintance_tax_percentage:
+        contractForm.tax_base_maintenance != null
+          ? contractForm.tax_base_maintenance / 100
+          : null,
+    });
+    onDialogOK();
+  } catch (error) {
+    console.error(error);
+  } finally {
+    saving.value = false;
+  }
+}
+
+onMounted(loadData);
+</script>

+ 59 - 19
src/pages/unit/tabs/ContractsTab.vue

@@ -1,8 +1,9 @@
 <template>
   <div class="q-pa-md">
     <DefaultTable
+      ref="tableRef"
       :columns="columns"
-      :no-api-call="true"
+      :api-call="loadContracts"
       :show-search-field="true"
       :add-item="true"
       :female="false"
@@ -11,20 +12,28 @@
       @on-add-item="openCreateDialog"
     >
       <template #body-cell-contract_dates="{ row }">
-        <q-td>{{ row.contract_start_date }} - {{ row.contract_end_date }}</q-td>
+        <q-td>{{ row.start_date }} - {{ row.end_date }}</q-td>
       </template>
 
       <template #body-cell-actions="{ row: contract }">
-        <q-td auto-width>
+        <q-td align="center">
           <div class="row no-wrap" style="gap: 4px">
-            <q-btn flat round dense icon="mdi-eye-outline" size="sm" />
             <q-btn
-              v-show="contract.status !== 'active'"
               flat
               round
               dense
               icon="mdi-file-edit-outline"
               size="sm"
+              @click="openEditDialog(contract)"
+            />
+            <q-btn
+              flat
+              round
+              dense
+              icon="mdi-trash-can-outline"
+              size="sm"
+              color="negative"
+              @click="confirmDelete(contract)"
             />
           </div>
         </q-td>
@@ -34,15 +43,23 @@
 </template>
 
 <script setup>
-import { defineAsyncComponent } from "vue";
+import { ref, defineAsyncComponent } from "vue";
 import { useQuasar } from "quasar";
 import DefaultTable from "src/components/defaults/DefaultTable.vue";
+import {
+  getFranchiseeContractsByUnit,
+  deleteFranchiseeContract,
+} from "src/api/franchisee_contract";
 
 const CreateContractDialog = defineAsyncComponent(
   () => import("src/pages/unit/components/CreateContractDialog.vue"),
 );
 
-defineProps({
+const EditContractDialog = defineAsyncComponent(
+  () => import("src/pages/unit/components/EditContractDialog.vue"),
+);
+
+const props = defineProps({
   unitId: {
     type: Number,
     default: null,
@@ -50,34 +67,57 @@ defineProps({
 });
 
 const $q = useQuasar();
+const tableRef = ref(null);
+
+const loadContracts = () => getFranchiseeContractsByUnit(props.unitId);
 
 function openCreateDialog() {
-  $q.dialog({ component: CreateContractDialog });
+  $q.dialog({
+    component: CreateContractDialog,
+    componentProps: { unitId: props.unitId },
+  }).onOk(() => {
+    tableRef.value?.refresh();
+  });
+}
+
+function openEditDialog(contract) {
+  $q.dialog({
+    component: EditContractDialog,
+    componentProps: { unitId: props.unitId, contract },
+  }).onOk(() => {
+    tableRef.value?.refresh();
+  });
+}
+
+function confirmDelete(contract) {
+  $q.dialog({
+    title: "Excluir contrato",
+    message: `Deseja excluir o contrato #${contract.protocol}?`,
+    ok: { color: "negative", label: "Excluir" },
+    cancel: { color: "primary", outline: true, label: "Cancelar" },
+  }).onOk(async () => {
+    await deleteFranchiseeContract(contract.id);
+    tableRef.value?.refresh();
+  });
 }
 
 const columns = [
   {
-    name: "contract_number",
+    name: "protocol",
     label: "Contrato",
-    field: "contract_number",
+    field: "protocol",
     align: "left",
   },
   {
     name: "contract_dates",
     label: "Data Inicial - Final",
-    field: "contract_start_date",
+    field: "start_date",
     align: "left",
   },
   {
-    name: "contract_tbr",
+    name: "tbr_fixed_value",
     label: "TBR",
-    field: "contract_tbr",
-    align: "left",
-  },
-  {
-    name: "contract_status",
-    label: "Status Contrato",
-    field: "contract_status",
+    field: "tbr_fixed_value",
     align: "left",
   },
   {