feat: refs #7950 Cmr #907

Open
guillermo wants to merge 1 commits from 7950-cmr into dev
9 changed files with 396 additions and 67 deletions

View File

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

View File

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

View File

@ -25,15 +25,21 @@ route:
Route is not served: Route is not served
cmr:
list:
searchCmr: Search cmr
youCanSearch: You can search by id
results: results
cmrFk: CMR id
hasCmrDms: Attached in gestdoc
'true': 'Yes'
'false': 'No'
cmrFk: Id
sender: Sender
loadingPlace: Loading place
deliveryPlace: Delivery place
carrier: Carrier
loadingDate: Loading date
landingDate: Landing date
truckPlate: Truck plate
ticketFk: Ticketd id
routeFk: Route id
country: Country
clientFk: Client id
shipped: Preparation date
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
cmr:
list:
searchCmr: Buscar cmr
youCanSearch: Puedes buscar por id
results: resultados
cmrFk: Id CMR
hasCmrDms: Gestdoc
'true':
'false': 'No'
cmrFk: Id
sender: Remitente
loadingPlace: Lugar de carga
deliveryPlace: Lugar de entrega
carrier: Transportista
loadingDate: Fecha de carga
landingDate: Fecha de descarga
truckPlate: Matrícula
ticketFk: Id ticket
routeFk: Id ruta
country: País
clientFk: Id cliente
shipped: Fecha preparación
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',
meta: {
title: 'cmrsList',
icon: 'fact_check',
icon: 'description',
},
component: () => import('src/pages/Route/Cmr/CmrList.vue'),
component: () => import('src/pages/Route/RouteCmr.vue'),
},
{
path: '/agency',