feat: refs #7950 Cmr
gitea/salix-front/pipeline/pr-dev This commit looks good Details

This commit is contained in:
Guillermo Bonet 2024-11-11 14:12:30 +01:00
parent 5d0c91187e
commit 3e8fc291fa
9 changed files with 396 additions and 67 deletions

View File

@ -209,7 +209,7 @@ globals:
roadmap: Roadmap roadmap: Roadmap
stops: Stops stops: Stops
routes: Routes routes: Routes
cmrsList: CMRs cmrsList: CMR
RouteList: List RouteList: List
routeCreate: New route routeCreate: New route
RouteRoadmap: Roadmaps RouteRoadmap: Roadmaps

View File

@ -213,7 +213,7 @@ globals:
roadmap: Troncales roadmap: Troncales
stops: Paradas stops: Paradas
routes: Rutas routes: Rutas
cmrsList: CMRs cmrsList: CMR
RouteList: Listado RouteList: Listado
routeCreate: Nueva ruta routeCreate: Nueva ruta
RouteRoadmap: Troncales RouteRoadmap: Troncales

View File

@ -0,0 +1,113 @@
<script setup>
import { useI18n } from 'vue-i18n';
import { useRoute, useRouter } from 'vue-router';
import VnRow from 'components/ui/VnRow.vue';
import FormModel from 'components/FormModel.vue';
import VnInputDate from 'components/common/VnInputDate.vue';
import VnInput from 'components/common/VnInput.vue';
import VnInputTime from 'components/common/VnInputTime.vue';
import VnSelect from 'components/common/VnSelect.vue';
import FetchData from 'components/FetchData.vue';
import { ref } from 'vue';
const { t } = useI18n();
const router = useRouter();
const route = useRoute();
const supplierList = ref([]);
const filter = { include: [{ relation: 'supplier' }] };
const onSave = (data, response) => {
router.push({ name: 'RoadmapSummary', params: { id: response?.id } });
};
</script>
<template>
<FetchData
url="Suppliers"
auto-load
:filter="{ fields: ['id', 'nickname'] }"
sort-by="nickname"
limit="30"
@on-fetch="(data) => (supplierList = data)"
/>
<FormModel
:url="`Roadmaps/${route.params?.id}`"
observe-form-changes
:filter="filter"
model="roadmap"
auto-load
@on-data-saved="onSave"
>
<template #form="{ data }">
<VnRow>
<VnInput v-model="data.name" :label="t('Roadmap')" clearable />
<VnInputDate v-model="data.etd" :label="t('ETD date')" />
<VnInputTime v-model="data.etd" :label="t('ETD hour')" />
</VnRow>
<VnRow>
<VnInput
v-model="data.tractorPlate"
:label="t('Tractor plate')"
clearable
/>
<VnInput
v-model="data.trailerPlate"
:label="t('Trailer plate')"
clearable
/>
</VnRow>
<VnRow>
<VnSelect
:label="t('Carrier')"
v-model="data.supplierFk"
:options="supplierList"
option-value="id"
option-label="nickname"
emit-value
map-options
use-input
:input-debounce="0"
>
<template #option="{ itemProps, opt }">
<QItem v-bind="itemProps">
<QItemSection>
<QItemLabel
>{{ opt.id }} - {{ opt.nickname }}
</QItemLabel>
</QItemSection>
</QItem>
</template>
</VnSelect>
<VnInput
v-model="data.price"
:label="t('Price')"
type="number"
clearable
/>
</VnRow>
<VnRow>
<VnInput v-model="data.driverName" :label="t('Driver name')" clearable />
<VnInput v-model="data.phone" :label="t('Phone')" clearable />
</VnRow>
<VnRow>
<VnInput
v-model="data.observations"
:label="t('Observations')"
clearable
/>
</VnRow>
</template>
</FormModel>
</template>
<i18n>
es:
Roadmap: Troncal
ETD date: Fecha ETD
ETD hour: Hora ETD
Tractor plate: Matrícula tractora
Trailer plate: Matrícula remolque
Carrier: Transportista
Price: Precio
Driver name: Nombre del conductor
Phone: Teléfono
Observations: Observaciones
</i18n>

View File

@ -0,0 +1,156 @@
<script setup>
import { computed, onMounted, onUnmounted, ref } from 'vue';
import { useRoute } from 'vue-router';
import { useI18n } from 'vue-i18n';
import { QIcon } from 'quasar';
import { dashIfEmpty, toDateHourMin } from 'src/filters';
import { useStateStore } from 'stores/useStateStore';
import VnLv from 'components/ui/VnLv.vue';
import VnTitle from 'src/components/common/VnTitle.vue';
import CardSummary from 'components/ui/CardSummary.vue';
import SupplierDescriptorProxy from 'pages/Supplier/Card/SupplierDescriptorProxy.vue';
import VnLinkPhone from 'components/ui/VnLinkPhone.vue';
const $props = defineProps({
id: {
type: Number,
default: 0,
},
});
const route = useRoute();
const stateStore = useStateStore();
const { t } = useI18n();
const summary = ref(null);
const entityId = computed(() => $props.id || route.params.id);
const isDialog = Boolean($props.id);
const hideRightDrawer = () => {
if (!isDialog) {
stateStore.rightDrawer = false;
}
};
onMounted(hideRightDrawer);
onUnmounted(hideRightDrawer);
const columns = ref([
{
name: 'address',
label: t('Address'),
field: (row) => dashIfEmpty(row?.address?.addressFk),
sortable: true,
align: 'left',
},
{
name: 'ETA',
label: t('ETA'),
field: (row) => toDateHourMin(row?.eta),
sortable: false,
align: 'left',
},
]);
const filter = {
include: [
{ relation: 'supplier' },
{ relation: 'worker' },
{
relation: 'roadmapStop',
scope: {
include: [
{
relation: 'address',
scope: {
fields: ['nickname'],
},
},
],
},
},
],
where: { id: entityId },
};
</script>
<template>
<div class="q-pa-md full-width">
<CardSummary data-key="CmrSummary" ref="summary" :url="`Cmr`" :filter="filter">
<template #header-left>
<RouterLink :to="{ name: `CmrSummary`, params: { id: entityId } }">
<QIcon name="open_in_new" color="white" size="sm" />
</RouterLink>
</template>
<template #header="{ entity }">
<span>{{ `${entity?.id} - ${entity?.name}` }}</span>
</template>
<template #body="{ entity }">
<QCard class="vn-one">
<VnTitle
:url="`#/route/cmr/${entityId}/basic-data`"
:text="t('Basic Data')"
/>
<VnLv :label="t('Carrier')">
<template #value>
<span class="link" v-if="entity?.supplier?.id">
{{ dashIfEmpty(entity?.supplier?.nickname) }}
<SupplierDescriptorProxy :id="entity?.supplier?.id" />
</span>
</template>
</VnLv>
<VnLv :label="t('ETD')" :value="toDateHourMin(entity?.etd)" />
<VnLv
:label="t('Tractor Plate')"
:value="dashIfEmpty(entity?.tractorPlate)"
/>
<VnLv
:label="t('Trailer Plate')"
:value="dashIfEmpty(entity?.trailerPlate)"
/>
<VnLv :label="t('Phone')" :value="dashIfEmpty(entity?.phone)">
<template #value>
<span>
{{ dashIfEmpty(entity?.phone) }}
<VnLinkPhone :phone-number="entity?.phone" />
</span>
</template>
</VnLv>
<VnLv
:label="t('Worker')"
:value="
entity?.worker?.firstName
? `${entity?.worker?.firstName} ${entity?.worker?.lastName}`
: '-'
"
/>
<VnLv
:label="t('Observations')"
:value="dashIfEmpty(entity?.observations)"
/>
</QCard>
<QCard class="vn-max">
<VnTitle
:url="`#/route/roadmap/${entityId}/stops`"
:text="t('Stops')"
/>
<QTable
:columns="columns"
:rows="entity?.roadmapStop"
:rows-per-page-options="[0]"
row-key="id"
/>
</QCard>
</template>
</CardSummary>
</div>
</template>
<i18n>
es:
Carrier: Transportista
Tractor Plate: Matrícula tractora
Trailer Plate: Matrícula remolque
Phone: Teléfono
Worker: Trabajador
Observations: Observaciones
Stops: Paradas
Address: Dirección
Go to stops: Ir a paradas
Add stop: Añadir parada
</i18n>

View File

@ -3,18 +3,21 @@ import { onBeforeMount, onMounted, computed, ref } from 'vue';
import { useI18n } from 'vue-i18n'; import { useI18n } from 'vue-i18n';
import { Notify } from 'quasar'; import { Notify } from 'quasar';
import { useSession } from 'src/composables/useSession'; import { useSession } from 'src/composables/useSession';
import { toDateHourMin } from 'filters/index';
import { useStateStore } from 'src/stores/useStateStore'; import { useStateStore } from 'src/stores/useStateStore';
import axios from 'axios'; import axios from 'axios';
import TicketDescriptorProxy from 'pages/Ticket/Card/TicketDescriptorProxy.vue'; import TicketDescriptorProxy from 'pages/Ticket/Card/TicketDescriptorProxy.vue';
import CustomerDescriptorProxy from 'pages/Customer/Card/CustomerDescriptorProxy.vue'; import CustomerDescriptorProxy from 'pages/Customer/Card/CustomerDescriptorProxy.vue';
import { toDateTimeFormat } from 'src/filters/date.js';
import { toDate } from 'src/filters';
import VnSearchbar from 'components/ui/VnSearchbar.vue';
import VnSubToolbar from 'src/components/ui/VnSubToolbar.vue'; import VnSubToolbar from 'src/components/ui/VnSubToolbar.vue';
import VnTable from 'components/VnTable/VnTable.vue'; import VnTable from 'components/VnTable/VnTable.vue';
const { t } = useI18n(); const { t } = useI18n();
const { getTokenMultimedia } = useSession(); const { getTokenMultimedia } = useSession();
const tableRef = ref(0);
const token = getTokenMultimedia(); const token = getTokenMultimedia();
const state = useStateStore(); const state = useStateStore();
const warehouses = ref([]); const warehouses = ref([]);
@ -30,66 +33,53 @@ const columns = computed(() => [
isId: true, isId: true,
}, },
{ {
align: 'center', label: t('route.cmr.list.sender'),
name: 'hasCmrDms', name: 'sender',
label: t('route.cmr.list.hasCmrDms'), component: 'select',
component: 'checkbox',
cardVisible: true,
},
{
align: 'left',
label: t('route.cmr.list.ticketFk'),
name: 'ticketFk',
},
{
align: 'left',
label: t('route.cmr.list.routeFk'),
name: 'routeFk',
},
{
align: 'left',
label: t('route.cmr.list.clientFk'),
name: 'clientFk',
},
{
align: 'right',
label: t('route.cmr.list.country'),
name: 'countryFk',
cardVisible: true, cardVisible: true,
attrs: { attrs: {
url: 'countries', url: 'companies',
fields: ['id', 'name'], fields: ['code'],
optionLabel: 'name', optionLabel: 'code',
optionValue: 'id', optionFilterValue: 'code',
}, },
columnFilter: { columnFilter: {
inWhere: true, inWhere: true,
component: 'select',
}, },
format: ({ countryName }) => countryName, create: true,
}, },
{ {
align: 'right', name: 'loadingPlace',
label: t('route.cmr.list.shipped'), label: t('route.cmr.list.loadingPlace'),
name: 'shipped', create: true,
cardVisible: true, },
{
label: t('route.cmr.list.deliveryPlace'),
name: 'deliveryPlace',
},
{
label: t('route.cmr.list.carrier'),
name: 'carrier',
},
{
label: t('route.cmr.list.loadingDate'),
name: 'loadingDate',
columnFilter: { columnFilter: {
component: 'date', component: 'date',
inWhere: true,
}, },
format: ({ shipped }) => toDateHourMin(shipped), format: ({ loadingDate }) => toDateTimeFormat(loadingDate),
}, },
{ {
align: 'right', label: t('route.cmr.list.landingDate'),
name: 'warehouseFk', name: 'landingDate',
label: t('globals.warehouse'),
columnFilter: { columnFilter: {
component: 'select', component: 'date',
}, },
attrs: { format: ({ landingDate }) => toDate(landingDate),
options: warehouses.value, },
}, {
format: ({ warehouseName }) => warehouseName, label: t('route.cmr.list.truckPlate'),
name: 'truckPlate',
}, },
{ {
align: 'center', align: 'center',
@ -116,7 +106,7 @@ function getApiUrl() {
return new URL(window.location).origin; return new URL(window.location).origin;
} }
function getCmrUrl(value) { function getCmrUrl(value) {
return `${getApiUrl()}/api/Routes/${value}/cmr?access_token=${token}`; return `${getApiUrl()}/api/Cmrs/${value}/print?access_token=${token}`;
} }
function downloadPdfs() { function downloadPdfs() {
if (!selectedRows.value.length) { if (!selectedRows.value.length) {
@ -129,28 +119,35 @@ function downloadPdfs() {
let cmrs = []; let cmrs = [];
for (let value of selectedRows.value) cmrs.push(value.cmrFk); for (let value of selectedRows.value) cmrs.push(value.cmrFk);
// prettier-ignore // prettier-ignore
return window.open(`${getApiUrl()}/api/Routes/downloadCmrsZip?ids=${cmrs.join(',')}&access_token=${token}`); return window.open(`${getApiUrl()}/api/Cmrs/downloadZip?ids=${cmrs.join(',')}&access_token=${token}`);
} }
</script> </script>
<template> <template>
<VnSearchbar
data-key="CmrList"
:label="t('route.cmr.list.searchCmr')"
:info="t('route.cmr.list.youCanSearch')"
/>
<VnSubToolbar> <VnSubToolbar>
<template #st-actions> <template #st-actions>
<QBtn <QBtn
icon="cloud_download" icon="download"
color="primary" color="primary"
class="q-mr-sm" class="q-mr-sm"
:disable="!selectedRows?.length" :disable="!selectedRows?.length"
@click="downloadPdfs" @click="downloadPdfs"
> >
<QTooltip>{{ t('route.cmr.list.downloadCmrs') }}</QTooltip> <QTooltip>{{ t('route.cmr.list.download') }}</QTooltip>
</QBtn> </QBtn>
</template> </template>
</VnSubToolbar> </VnSubToolbar>
<VnTable <VnTable
ref="tableRef" ref="tableRef"
data-key="CmrList" data-key="CmrList"
url="Routes/cmrs" url="Cmrs/filter"
:order="['cmrFk DESC']"
:columns="columns" :columns="columns"
auto-load
:right-search="true" :right-search="true"
default-mode="table" default-mode="table"
v-model:selected="selectedRows" v-model:selected="selectedRows"
@ -159,6 +156,13 @@ function downloadPdfs() {
'row-key': 'cmrFk', 'row-key': 'cmrFk',
selection: 'multiple', selection: 'multiple',
}" }"
redirect="route/cmr"
:create="{
urlCreate: 'Cmrs',
title: t('route.cmr.list.createCmr'),
onDataSaved: ({ cmrFk }) => tableRef.redirect(cmrFk),
formInitialData: {},
}"
:disable-option="{ card: true }" :disable-option="{ card: true }"
> >
<template #column-ticketFk="{ row }"> <template #column-ticketFk="{ row }">

View File

@ -25,15 +25,21 @@ route:
Route is not served: Route is not served Route is not served: Route is not served
cmr: cmr:
list: list:
searchCmr: Search cmr
youCanSearch: You can search by id
results: results results: results
cmrFk: CMR id cmrFk: Id
hasCmrDms: Attached in gestdoc sender: Sender
'true': 'Yes' loadingPlace: Loading place
'false': 'No' deliveryPlace: Delivery place
carrier: Carrier
loadingDate: Loading date
landingDate: Landing date
truckPlate: Truck plate
ticketFk: Ticketd id ticketFk: Ticketd id
routeFk: Route id routeFk: Route id
country: Country
clientFk: Client id clientFk: Client id
shipped: Preparation date shipped: Preparation date
viewCmr: View CMR viewCmr: View CMR
downloadCmrs: Download CMRs download: Download as pdf
createCmr: Create CMR

View File

@ -25,15 +25,21 @@ route:
Route is not served: La ruta no está servida Route is not served: La ruta no está servida
cmr: cmr:
list: list:
searchCmr: Buscar cmr
youCanSearch: Puedes buscar por id
results: resultados results: resultados
cmrFk: Id CMR cmrFk: Id
hasCmrDms: Gestdoc sender: Remitente
'true': loadingPlace: Lugar de carga
'false': 'No' deliveryPlace: Lugar de entrega
carrier: Transportista
loadingDate: Fecha de carga
landingDate: Fecha de descarga
truckPlate: Matrícula
ticketFk: Id ticket ticketFk: Id ticket
routeFk: Id ruta routeFk: Id ruta
country: País
clientFk: Id cliente clientFk: Id cliente
shipped: Fecha preparación shipped: Fecha preparación
viewCmr: Ver CMR viewCmr: Ver CMR
downloadCmrs: Descargar CMRs download: Descargar como pdf
createCmr: Crear CMR

44
src/router/modules/cmr.js Normal file
View File

@ -0,0 +1,44 @@
import { RouterView } from 'vue-router';
export default {
path: '/route/cmr',
name: 'Cmr',
meta: {
title: 'Cmr',
icon: 'description',
moduleName: 'Cmr',
},
component: RouterView,
redirect: { name: 'RouteMain' },
menus: {
card: ['CmrBasicData'],
},
children: [
{
name: 'RouteCmrCard',
path: ':id',
component: () => import('src/pages/Route/Cmr/CmrCard.vue'),
redirect: { name: 'CmrSummary' },
children: [
{
name: 'CmrSummary',
path: 'summary',
meta: {
title: 'summary',
icon: 'open_in_new',
},
component: () => import('pages/Route/Cmr/CmrSummary.vue'),
},
{
name: 'CmrBasicData',
path: 'basic-data',
meta: {
title: 'basicData',
icon: 'vn:settings',
},
component: () => import('pages/Route/Cmr/CmrBasicData.vue'),
},
],
},
],
};

View File

@ -78,9 +78,9 @@ export default {
name: 'CmrList', name: 'CmrList',
meta: { meta: {
title: 'cmrsList', title: 'cmrsList',
icon: 'fact_check', icon: 'description',
}, },
component: () => import('src/pages/Route/Cmr/CmrList.vue'), component: () => import('src/pages/Route/RouteCmr.vue'),
}, },
{ {
path: '/agency', path: '/agency',