Forráskód Böngészése

feat: feat(importação exames) Foi adicionado a função correta para a importação, juntamente com um campo novo

Foi adicionado o imput da forma correta para importação e tambem foi adicionado o novo campo que abriga o codigo do exame

fase:dev | origin:escopo
kayo henrique 1 hete
szülő
commit
ebd547d435

+ 17 - 0
src/api/partnerAgreementService.js

@@ -50,3 +50,20 @@ export const uploadServiceMedia = async (id, file) => {
 export const deleteServiceMedia = async (id, mediaId) => {
   await api.delete(`/partner-agreement-service/${id}/media/${mediaId}`);
 };
+
+export const importServices = async (partnerAgreementId, file) => {
+  const form = new FormData();
+
+  form.append("file", file);
+
+  const { data } = await api.post(`/partner-agreement-service/partner/${partnerAgreementId}/import`,
+    form,
+    {
+      headers: {
+        "Content-Type": "multipart/form-data",
+      },
+    },
+  );
+
+  return data.payload;
+};

+ 7 - 1
src/i18n/locales/en.json

@@ -994,5 +994,11 @@
     "on_leave": "On leave",
     "inactivated": "Inactivated",
     "no_history": "No imports recorded"
-  }
+  },
+  "import_partner": {
+  "import_exams": "Import Exams",
+  "import_exams_result": "Import completed. Exams created: {created}. Exams updated: {updated}.",
+  "import_exams_processing": "The exam import is being processed.",
+  "import_exams_error": "Unable to import the exams."
+}
 }

+ 7 - 1
src/i18n/locales/es.json

@@ -994,5 +994,11 @@
     "on_leave": "En licencia",
     "inactivated": "Desactivados",
     "no_history": "Ninguna importación registrada"
+  },
+  "import_partner": {
+    "import_exams": "Importar Exámenes",
+    "import_exams_result": "Importación completada. Exámenes creados: {created}. Exámenes actualizados: {updated}.",
+    "import_exams_processing": "La importación de los exámenes está siendo procesada.",
+    "import_exams_error": "No fue posible importar los exámenes."
   }
-}
+}

+ 7 - 1
src/i18n/locales/pt.json

@@ -995,5 +995,11 @@
     "on_leave": "Afastados",
     "inactivated": "Desativados",
     "no_history": "Nenhuma importação registrada"
+  },
+  "import_parceiro": {
+    "import_exames": "Importar Exames",
+    "import_exames_result": "Importação concluída. Exames criados: {created}. Exames atualizados: {updated}.",
+    "import_exames_processing": "A importação dos exames está sendo processada.",
+    "import_exames_error": "Não foi possível importar os exames."
   }
-}
+}

+ 111 - 1
src/pages/parceiros-convenios/components/CadastroFormPanel.vue

@@ -319,6 +319,27 @@
         <template v-if="!serviceFormVisible">
           <div class="bg-violet-light q-pb-md">
             <div class="row justify-end q-mb-sm q-gutter-sm">
+
+                <input
+                    ref="importExamesInput"
+                    type="file"
+                    accept=".xlsx,.csv"
+                    class="hidden"
+                    @change="onExamesFileSelected"
+                  />
+
+               <q-btn
+                  v-if="serviceTab.serviceType === 'exame'"
+                  unelevated
+                  icon="mdi-upload"
+                  :label="$t('import_parceiro.import_exames')"
+                  padding="6px 12px"
+                  :disable="!entityId"
+                  :loading="importingExames"
+                  class="btn-gradient"
+                  @click="onImportExamesClick"
+                />
+
               <q-btn
                 unelevated
                 icon="mdi-plus"
@@ -395,7 +416,8 @@ import {
   deletePartnerMedia,
 } from "src/api/partnerAgreement";
 import { permissionStore } from "src/stores/permission";
-import { getServicesByPartner } from "src/api/partnerAgreementService";
+import { getServicesByPartner, importServices } from "src/api/partnerAgreementService";
+import { useImportPoller } from "src/composables/useImportPoller";
 import { formatToBRLCurrencyOrDash } from "src/helpers/utils";
 import axios from "axios";
 
@@ -695,6 +717,87 @@ const loadServices = async () => {
   }
 };
 
+const onImportExamesClick = () => {
+  if (!permission_store.getAccess("parceiro.servico", "add")) {
+    $q.notify({
+      type: "negative",
+      message: t("validation.permissions.add"),
+    });
+    return;
+  }
+
+  if (!entityId.value) {
+    return;
+  }
+
+  const input = importExamesInput.value?.[0];
+
+  if (!input) {
+    console.error("Input de importação de exames não encontrado.");
+    return;
+  }
+
+  input.value = null;
+  input.click();
+};
+
+const onExamesFileSelected = async (event) => {
+  const file = event.target.files?.[0];
+
+  if (!file) {
+    return;
+  }
+
+  if (!entityId.value) {
+    return;
+  }
+
+  try {
+    const { import_id } = await importServices(
+      entityId.value,
+      file,
+    );
+
+    startExamesPolling(import_id, {
+      onComplete: async (stats) => {
+        $q.notify({
+          type: "positive",
+          message: t("import_parceiro.import_exames_result", {
+            created: stats?.created ?? 0,
+            updated: stats?.updated ?? 0,
+          }),
+          timeout: 7000,
+        });
+
+        await loadServices();
+      },
+
+      onError: () => {
+        $q.notify({
+          type: "negative",
+          message: t("http.errors.failed"),
+        });
+      },
+
+      onTimeout: () => {
+        $q.notify({
+          type: "warning",
+          message: t("import_parceiro.import_exames_processing"),
+        });
+      },
+    });
+  } catch (error) {
+    console.error(error);
+
+    $q.notify({
+      type: "negative",
+      message: t("http.errors.failed"),
+    });
+  } finally {
+    event.target.value = null;
+  }
+};
+
 const onAddService = () => {
   editingServiceId.value   = null;
   serviceFormVisible.value = true;
@@ -746,6 +849,13 @@ const populateForms = (p) => {
   contractMedia.value = p.media ?? [];
 };
 
+//import de exames/serviços
+const importExamesInput = useTemplateRef("importExamesInput");
+const {
+  polling: importingExames,
+  start: startExamesPolling,
+} = useImportPoller();
+
 onMounted(async () => {
   if (entityId.value) {
     try {

+ 9 - 0
src/pages/parceiros-convenios/components/ServicoFormPanel.vue

@@ -16,6 +16,13 @@
                 readonly
                 class="col-3 input-violet"
               />
+
+              <DefaultInput
+                  v-model="form.code_exams"
+                  label="Código do exame"
+                  class="col-2 input-violet"
+                />
+
               <DefaultInput
                 v-model="form.name"
                 v-model:error="validationErrors.name"
@@ -201,6 +208,7 @@ const categoryOptions   = ref([]);
 
 const form = ref({
   partner_agreement_id: props.partnerId,
+  code_exams:           "",
   name:                 "",
   description:          "",
   service_number:       "",
@@ -240,6 +248,7 @@ const loadService = async () => {
   try {
     const svc = await getPartnerAgreementService(props.serviceId);
     form.value.name                = svc.name                ?? "";
+    form.value.code_exams = svc.code_exams ?? "";
     form.value.description         = svc.description         ?? "";
     form.value.service_number      = svc.service_number      ?? "";
     form.value.category_id         = svc.category_id         ?? null;