diff --git a/Jenkinsfile b/Jenkinsfile index 7f4144a548..05ef34791b 100644 --- a/Jenkinsfile +++ b/Jenkinsfile @@ -126,7 +126,7 @@ pipeline { sh "docker-compose ${env.COMPOSE_PARAMS} up -d" image.inside("--network ${env.COMPOSE_PROJECT}_default -e CI -e TZ --init") { - sh 'sh test/cypress/cypressParallel.sh 2' + sh 'sh test/cypress/cypressParallel.sh 1' } } } diff --git a/src/components/VnTable/VnTable.vue b/src/components/VnTable/VnTable.vue index c642171983..e8dd1b5263 100644 --- a/src/components/VnTable/VnTable.vue +++ b/src/components/VnTable/VnTable.vue @@ -633,6 +633,7 @@ const rowCtrlClickFunction = computed(() => { :data-key="$attrs['data-key']" :columns="columns" :redirect="redirect" + v-bind="$attrs?.['table-filter']" > diff --git a/src/components/ui/EntityDescriptor.vue b/src/components/ui/EntityDescriptor.vue new file mode 100644 index 0000000000..a5dced5513 --- /dev/null +++ b/src/components/ui/EntityDescriptor.vue @@ -0,0 +1,78 @@ + + + diff --git a/src/components/ui/VnDescriptor.vue b/src/components/ui/VnDescriptor.vue new file mode 100644 index 0000000000..47da98d74a --- /dev/null +++ b/src/components/ui/VnDescriptor.vue @@ -0,0 +1,318 @@ + + + + + + + + + en: + globals: + copyId: Copy ID + es: + globals: + copyId: Copiar ID + diff --git a/src/composables/__tests__/downloadFile.spec.js b/src/composables/__tests__/downloadFile.spec.js index f53b56b3e3..f83a973b02 100644 --- a/src/composables/__tests__/downloadFile.spec.js +++ b/src/composables/__tests__/downloadFile.spec.js @@ -6,10 +6,12 @@ const session = useSession(); const token = session.getToken(); describe('downloadFile', () => { - const baseUrl = 'http://localhost:9000'; let defaulCreateObjectURL; beforeAll(() => { + vi.mock('src/composables/getUrl', () => ({ + getUrl: vi.fn().mockResolvedValue(''), + })); defaulCreateObjectURL = window.URL.createObjectURL; window.URL.createObjectURL = vi.fn(() => 'blob:http://localhost:9000/blob-id'); }); @@ -22,15 +24,14 @@ describe('downloadFile', () => { headers: { 'content-disposition': 'attachment; filename="test-file.txt"' }, }; vi.spyOn(axios, 'get').mockImplementation((url) => { - if (url == 'Urls/getUrl') return Promise.resolve({ data: baseUrl }); - else if (url.includes('downloadFile')) return Promise.resolve(res); + if (url.includes('downloadFile')) return Promise.resolve(res); }); await downloadFile(1); expect(axios.get).toHaveBeenCalledWith( - `${baseUrl}/api/dms/1/downloadFile?access_token=${token}`, - { responseType: 'blob' } + `/api/dms/1/downloadFile?access_token=${token}`, + { responseType: 'blob' }, ); }); }); diff --git a/src/composables/downloadFile.js b/src/composables/downloadFile.js index 4588265a2f..302836e09e 100644 --- a/src/composables/downloadFile.js +++ b/src/composables/downloadFile.js @@ -5,20 +5,30 @@ import { exportFile } from 'quasar'; const { getTokenMultimedia } = useSession(); const token = getTokenMultimedia(); +const appUrl = (await getUrl('', 'lilium')).replace('/#/', ''); export async function downloadFile(id, model = 'dms', urlPath = '/downloadFile', url) { - const appUrl = (await getUrl('', 'lilium')).replace('/#/', ''); const response = await axios.get( url ?? `${appUrl}/api/${model}/${id}${urlPath}?access_token=${token}`, { responseType: 'blob' } ); + download(response); +} + +export async function downloadDocuware(url, params) { + const response = await axios.get(`${appUrl}/api/` + url, { + responseType: 'blob', + params, + }); + + download(response); +} + +function download(response) { const contentDisposition = response.headers['content-disposition']; const matches = /filename[^;=\n]*=((['"]).*?\2|[^;\n]*)/.exec(contentDisposition); - const filename = - matches != null && matches[1] - ? matches[1].replace(/['"]/g, '') - : 'downloaded-file'; + const filename = matches?.[1] ? matches[1].replace(/['"]/g, '') : 'downloaded-file'; exportFile(filename, response.data); } diff --git a/src/i18n/locale/en.yml b/src/i18n/locale/en.yml index c1286267c7..7374cda68d 100644 --- a/src/i18n/locale/en.yml +++ b/src/i18n/locale/en.yml @@ -646,6 +646,7 @@ worker: model: Model serialNumber: Serial number removePDA: Deallocate PDA + sendToTablet: Send to tablet create: lastName: Last name birth: Birth @@ -892,6 +893,8 @@ components: VnLv: copyText: '{copyValue} has been copied to the clipboard' iban_tooltip: 'IBAN: ES21 1234 5678 90 0123456789' + VnNotes: + clientWithoutPhone: 'The following clients do not have a phone number and the message will not be sent to them: {clientWithoutPhone}' weekdays: sun: Sunday mon: Monday diff --git a/src/i18n/locale/es.yml b/src/i18n/locale/es.yml index 681781d113..f0ce53e37b 100644 --- a/src/i18n/locale/es.yml +++ b/src/i18n/locale/es.yml @@ -731,6 +731,7 @@ worker: model: Modelo serialNumber: Número de serie removePDA: Desasignar PDA + sendToTablet: Enviar a la tablet create: lastName: Apellido birth: Fecha de nacimiento @@ -976,6 +977,8 @@ components: VnLv: copyText: '{copyValue} se ha copiado al portapepeles' iban_tooltip: 'IBAN: ES21 1234 5678 90 0123456789' + VnNotes: + clientWithoutPhone: 'Estos clientes no tienen asociado número de télefono y el sms no les será enviado: {clientWithoutPhone}' weekdays: sun: Domingo mon: Lunes diff --git a/src/pages/Account/Alias/Card/AliasDescriptor.vue b/src/pages/Account/Alias/Card/AliasDescriptor.vue index 671ef7fbcd..957047cc3b 100644 --- a/src/pages/Account/Alias/Card/AliasDescriptor.vue +++ b/src/pages/Account/Alias/Card/AliasDescriptor.vue @@ -4,7 +4,7 @@ import { useRoute, useRouter } from 'vue-router'; import { useI18n } from 'vue-i18n'; import { useQuasar } from 'quasar'; -import CardDescriptor from 'components/ui/CardDescriptor.vue'; +import EntityDescriptor from 'components/ui/EntityDescriptor.vue'; import VnLv from 'src/components/ui/VnLv.vue'; import axios from 'axios'; @@ -48,11 +48,12 @@ const removeAlias = () => { - - -es: - Click to allow the user to be disabled: Marcar para deshabilitar - Click to exclude the user from getting disabled: Marcar para no deshabilitar - diff --git a/src/pages/Worker/Card/WorkerDescriptorMenu.vue b/src/pages/Worker/Card/WorkerDescriptorMenu.vue index 0dcb4fd711..3b6b144d6e 100644 --- a/src/pages/Worker/Card/WorkerDescriptorMenu.vue +++ b/src/pages/Worker/Card/WorkerDescriptorMenu.vue @@ -63,3 +63,8 @@ const showChangePasswordDialog = () => { + + es: + Click to allow the user to be disabled: Marcar para deshabilitar + Click to exclude the user from getting disabled: Marcar para no deshabilitar + diff --git a/src/pages/Worker/Card/WorkerPda.vue b/src/pages/Worker/Card/WorkerPda.vue index d329414946..001eb368ae 100644 --- a/src/pages/Worker/Card/WorkerPda.vue +++ b/src/pages/Worker/Card/WorkerPda.vue @@ -5,24 +5,25 @@ import { ref, computed } from 'vue'; import axios from 'axios'; import useNotify from 'src/composables/useNotify.js'; +import { useVnConfirm } from 'composables/useVnConfirm'; +import { useArrayData } from 'src/composables/useArrayData'; +import { downloadDocuware } from 'src/composables/downloadFile'; + import FetchData from 'components/FetchData.vue'; import FormModelPopup from 'src/components/FormModelPopup.vue'; -import { useVnConfirm } from 'composables/useVnConfirm'; - -import VnPaginate from 'src/components/ui/VnPaginate.vue'; import VnRow from 'components/ui/VnRow.vue'; import VnSelect from 'src/components/common/VnSelect.vue'; -import VnInput from 'src/components/common/VnInput.vue'; +import VnTable from 'src/components/VnTable/VnTable.vue'; const { t } = useI18n(); const { notify } = useNotify(); - -const paginate = ref(); +const loadingDocuware = ref(true); +const tableRef = ref(); const dialog = ref(); const route = useRoute(); const { openConfirmationModal } = useVnConfirm(); const routeId = computed(() => route.params.id); - +const worker = computed(() => useArrayData('Worker').store.data); const initialData = computed(() => { return { userFk: routeId.value, @@ -31,154 +32,268 @@ const initialData = computed(() => { }; }); -const deallocatePDA = async (deviceProductionFk) => { - await axios.post(`Workers/${route.params.id}/deallocatePDA`, { - pda: deviceProductionFk, - }); - notify(t('PDA deallocated'), 'positive'); - - paginate.value.fetch(); -}; +const columns = computed(() => [ + { + align: 'center', + label: t('globals.state'), + name: 'state', + format: (row) => row?.docuware?.state, + columnFilter: false, + chip: { + condition: (_, row) => !!row.docuware, + color: (row) => (isSigned(row) ? 'bg-positive' : 'bg-warning'), + }, + visible: false, + }, + { + align: 'right', + label: t('worker.pda.currentPDA'), + name: 'deviceProductionFk', + columnClass: 'shrink', + cardVisible: true, + }, + { + align: 'left', + label: t('Model'), + name: 'modelFk', + format: ({ deviceProduction }) => deviceProduction.modelFk, + cardVisible: true, + }, + { + align: 'right', + label: t('Serial number'), + name: 'serialNumber', + format: ({ deviceProduction }) => deviceProduction.serialNumber, + cardVisible: true, + }, + { + align: 'left', + label: t('Current SIM'), + name: 'simFk', + cardVisible: true, + }, + { + align: 'right', + name: 'actions', + columnFilter: false, + cardVisible: true, + }, +]); function reloadData() { initialData.value.deviceProductionFk = null; initialData.value.simFk = null; - paginate.value.fetch(); + tableRef.value.reload(); +} + +async function fetchDocuware() { + loadingDocuware.value = true; + + const id = `${worker.value?.lastName} ${worker.value?.firstName}`; + const rows = tableRef.value.CrudModelRef.formData; + + const promises = rows.map(async (row) => { + const { data } = await axios.post(`Docuwares/${id}/checkFile`, { + fileCabinet: 'hr', + signed: false, + mergeFilter: [ + { + DBName: 'TIPO_DOCUMENTO', + Value: ['PDA'], + }, + { + DBName: 'FILENAME', + Value: [`${row.deviceProductionFk}-pda`], + }, + ], + }); + row.docuware = data; + }); + + await Promise.allSettled(promises); + loadingDocuware.value = false; +} + +async function sendToTablet(rows) { + const promises = rows.map(async (row) => { + await axios.post(`Docuwares/upload-pda-pdf`, { + ids: [row.deviceProductionFk], + }); + row.docuware = true; + }); + await Promise.allSettled(promises); + notify(t('PDF sended to signed'), 'positive'); + tableRef.value.reload(); +} + +async function deallocatePDA(deviceProductionFk) { + await axios.post(`Workers/${route.params.id}/deallocatePDA`, { + pda: deviceProductionFk, + }); + const index = tableRef.value.CrudModelRef.formData.findIndex( + (data) => data?.deviceProductionFk == deviceProductionFk, + ); + delete tableRef.value.CrudModelRef.formData[index]; + notify(t('PDA deallocated'), 'positive'); +} + +function isSigned(row) { + return row.docuware?.state === 'Firmado'; } - es: Model: Modelo @@ -190,4 +305,6 @@ es: Do you want to remove this PDA?: ¿Desea eliminar este PDA? You can only have one PDA: Solo puedes tener un PDA si no eres autonomo This PDA is already assigned to another user: Este PDA ya está asignado a otro usuario + Are you sure you want to send it?: ¿Seguro que quieres enviarlo? + Sign PDA: Firmar PDA diff --git a/src/pages/Worker/Department/Card/DepartmentDescriptor.vue b/src/pages/Worker/Department/Card/DepartmentDescriptor.vue index 4b7dfd9b80..8206585935 100644 --- a/src/pages/Worker/Department/Card/DepartmentDescriptor.vue +++ b/src/pages/Worker/Department/Card/DepartmentDescriptor.vue @@ -4,7 +4,7 @@ import { useRoute, useRouter } from 'vue-router'; import { useI18n } from 'vue-i18n'; import { useVnConfirm } from 'composables/useVnConfirm'; import VnLv from 'src/components/ui/VnLv.vue'; -import CardDescriptor from 'src/components/ui/CardDescriptor.vue'; +import EntityDescriptor from 'src/components/ui/EntityDescriptor.vue'; import axios from 'axios'; import useNotify from 'src/composables/useNotify.js'; @@ -40,7 +40,7 @@ const removeDepartment = async () => { const { openConfirmationModal } = useVnConfirm(); - + diff --git a/src/pages/Worker/Department/Card/DepartmentDescriptorProxy.vue b/src/pages/Worker/Department/Card/DepartmentDescriptorProxy.vue index 5b556f6554..c793e93195 100644 --- a/src/pages/Worker/Department/Card/DepartmentDescriptorProxy.vue +++ b/src/pages/Worker/Department/Card/DepartmentDescriptorProxy.vue @@ -16,6 +16,7 @@ const $props = defineProps({ v-if="$props.id" :id="$props.id" :summary="DepartmentSummary" + data-key="DepartmentDescriptorProxy" /> diff --git a/src/pages/Zone/Card/ZoneDescriptor.vue b/src/pages/Zone/Card/ZoneDescriptor.vue index 27676212e6..f2bcc12478 100644 --- a/src/pages/Zone/Card/ZoneDescriptor.vue +++ b/src/pages/Zone/Card/ZoneDescriptor.vue @@ -2,7 +2,7 @@ import { computed } from 'vue'; import { useRoute } from 'vue-router'; -import CardDescriptor from 'components/ui/CardDescriptor.vue'; +import EntityDescriptor from 'components/ui/EntityDescriptor.vue'; import VnLv from 'src/components/ui/VnLv.vue'; import { toTimeFormat } from 'src/filters/date'; import { toCurrency } from 'filters/index'; @@ -25,7 +25,7 @@ const entityId = computed(() => { - + diff --git a/src/router/modules/worker.js b/src/router/modules/worker.js index 3eb95a96ee..ff3d483cf5 100644 --- a/src/router/modules/worker.js +++ b/src/router/modules/worker.js @@ -271,12 +271,14 @@ export default { path: 'department', name: 'Department', redirect: { name: 'WorkerDepartment' }, - component: () => import('src/pages/Worker/WorkerDepartment.vue'), + meta: { title: 'department', icon: 'vn:greuge' }, children: [ { + component: () => + import('src/pages/Worker/WorkerDepartment.vue'), + meta: { title: 'department', icon: 'vn:greuge' }, name: 'WorkerDepartment', path: 'list', - meta: { title: 'department', icon: 'vn:greuge' }, }, departmentCard, ], diff --git a/test/cypress/integration/vnComponent/VnLog.spec.js b/test/cypress/integration/vnComponent/VnLog.spec.js index e857457a7d..ae0013150c 100644 --- a/test/cypress/integration/vnComponent/VnLog.spec.js +++ b/test/cypress/integration/vnComponent/VnLog.spec.js @@ -25,7 +25,7 @@ describe('VnLog', () => { it('should show claimDescriptor', () => { cy.dataCy('iconLaunch-claimFk').first().click(); - cy.dataCy('cardDescriptor_subtitle').contains('1'); + cy.dataCy('vnDescriptor_subtitle').contains('1'); cy.dataCy('iconLaunch-claimFk').first().click(); }); }); diff --git a/test/cypress/integration/worker/workerPda.spec.js b/test/cypress/integration/worker/workerPda.spec.js index 31ec19eda0..2623e81cf4 100644 --- a/test/cypress/integration/worker/workerPda.spec.js +++ b/test/cypress/integration/worker/workerPda.spec.js @@ -1,23 +1,80 @@ describe('WorkerPda', () => { - const select = '[data-cy="pda-dialog-select"]'; + const deviceId = 4; beforeEach(() => { - cy.viewport(1920, 1080); cy.login('developer'); cy.visit(`/#/worker/1110/pda`); }); - it('assign pda', () => { - cy.addBtnClick(); - cy.get(select).click(); - cy.get(select).type('{downArrow}{enter}'); - cy.get('.q-notification__message').should('have.text', 'Data created'); + it('assign and delete pda', () => { + creatNewPDA(); + cy.checkNotification('Data created'); + cy.visit(`/#/worker/1110/pda`); + removeNewPDA(); + cy.checkNotification('PDA deallocated'); }); - it('delete pda', () => { - cy.get('.btn-delete').click(); - cy.get( - '.q-card__actions > .q-btn--unelevated > .q-btn__content > .block' - ).click(); - cy.get('.q-notification__message').should('have.text', 'PDA deallocated'); + it('send and download pdf to docuware', () => { + //Send + cy.intercept('POST', '/api/Docuwares/upload-pda-pdf', (req) => { + req.reply({ + statusCode: 200, + body: {}, + }); + }); + + creatNewPDA(); + + cy.dataCy('workerPda-send').click(); + cy.clickConfirm(); + cy.checkNotification('PDF sended to signed'); + + //Download + cy.intercept('POST', /\/api\/Docuwares\/Jones%20Jessica\/checkFile/, (req) => { + req.reply({ + statusCode: 200, + body: { + id: deviceId, + state: 'Firmado', + }, + }); + }); + cy.get('#st-actions').contains('refresh').click(); + cy.intercept('GET', '/api/Docuwares/download-pda-pdf**', (req) => { + req.reply({ + statusCode: 200, + body: {}, + }); + }); + + cy.dataCy('workerPda-download').click(); + removeNewPDA(); }); + + it('send 2 pdfs to docuware', () => { + cy.intercept('POST', '/api/Docuwares/upload-pda-pdf', (req) => { + req.reply({ + statusCode: 200, + body: {}, + }); + }); + + creatNewPDA(); + creatNewPDA(2); + cy.selectRows([1, 2]); + cy.get('#st-actions').contains('Send').click(); + cy.checkNotification('PDF sended to signed'); + + removeNewPDA(); + }); + + function creatNewPDA(id = deviceId) { + cy.addBtnClick(); + cy.selectOption('[data-cy="pda-dialog-select"]', id); + cy.saveCard(); + } + + function removeNewPDA() { + cy.dataCy('workerPda-remove').first().click(); + cy.clickConfirm(); + } }); diff --git a/test/cypress/support/commands.js b/test/cypress/support/commands.js index de25959b2c..fe8d38e799 100755 --- a/test/cypress/support/commands.js +++ b/test/cypress/support/commands.js @@ -371,7 +371,7 @@ Cypress.Commands.add('validateContent', (selector, expectedValue) => { }); Cypress.Commands.add('openActionsDescriptor', () => { - cy.get('[data-cy="cardDescriptor"] [data-cy="descriptor-more-opts"]').click(); + cy.get('[data-cy="vnDescriptor"] [data-cy="descriptor-more-opts"]').click(); }); Cypress.Commands.add('openUserPanel', () => { @@ -466,16 +466,16 @@ Cypress.Commands.add('validateDescriptor', (toCheck = {}) => { const popupSelector = popup ? '[role="menu"] ' : ''; - if (title) cy.get(`${popupSelector}[data-cy="cardDescriptor_title"]`).contains(title); + if (title) cy.get(`${popupSelector}[data-cy="vnDescriptor_title"]`).contains(title); if (description) - cy.get(`${popupSelector}[data-cy="cardDescriptor_description"]`).contains( + cy.get(`${popupSelector}[data-cy="vnDescriptor_description"]`).contains( description, ); if (subtitle) - cy.get(`${popupSelector}[data-cy="cardDescriptor_subtitle"]`).contains(subtitle); + cy.get(`${popupSelector}[data-cy="vnDescriptor_subtitle"]`).contains(subtitle); for (const index in listbox) - cy.get(`${popupSelector}[data-cy="cardDescriptor_listbox"] > *`) + cy.get(`${popupSelector}[data-cy="vnDescriptor_listbox"] > *`) .eq(index) .should('contain.text', listbox[index]); });