Resolve conflicts
gitea/salix-front/pipeline/pr-dev This commit looks good Details

This commit is contained in:
William Buezas 2024-05-03 08:57:39 -03:00
commit d15a92ce7d
32 changed files with 1067 additions and 79 deletions

View File

@ -124,11 +124,16 @@ async function onSubmit() {
});
}
isLoading.value = true;
await saveChanges();
await saveChanges($props.saveFn ? formData.value : null);
}
async function saveChanges(data) {
if ($props.saveFn) return $props.saveFn(data, getChanges);
if ($props.saveFn) {
$props.saveFn(data, getChanges);
isLoading.value = false;
hasChanges.value = false;
return;
}
const changes = data || getChanges();
try {
await axios.post($props.saveUrl || $props.url + '/crud', changes);

View File

@ -15,6 +15,10 @@ const props = defineProps({
type: Boolean,
default: false,
},
emitDateFormat: {
type: Boolean,
default: false,
},
});
const hover = ref(false);
@ -37,7 +41,10 @@ const value = computed({
return props.modelValue;
},
set(value) {
emit('update:modelValue', joinDateAndTime(value, time.value));
emit(
'update:modelValue',
props.emitDateFormat ? new Date(value) : joinDateAndTime(value, time.value)
);
},
});

View File

@ -141,15 +141,6 @@ select:-webkit-autofill {
background-color: var(--vn-section-color);
}
.q-checkbox {
& .q-checkbox__label {
color: var(--vn-text-color);
}
& .q-checkbox__inner {
color: var(--vn-label-color);
}
}
.tr-header {
color: var(--vn-label-color);
}

View File

@ -521,7 +521,7 @@ claim:
records: records
card:
claimId: Claim ID
assignedTo: Assigned
attendedBy: Attended by
created: Created
state: State
ticketId: Ticket ID
@ -559,6 +559,7 @@ claim:
responsible: Responsible
worker: Worker
redelivery: Redelivery
changeState: Change state
basicData:
customer: Customer
assignedTo: Assigned
@ -990,7 +991,7 @@ supplier:
billingData: Billing data
payMethod: Pay method
payDeadline: Pay deadline
payDay: Día de pago
payDay: Pay day
account: Account
fiscalData: Fiscal data
sageTaxType: Sage tax type
@ -1132,12 +1133,13 @@ item:
fixedPrice: Fixed prices
wasteBreakdown: Waste breakdown
itemCreate: New item
log: Log
barcode: Barcodes
tax: Tax
barcode: Barcode
log: Log
botanical: Botanical
itemTypeCreate: New item type
family: Item Type
lastEntries: Last entries
descriptor:
item: Item
buyer: Buyer
@ -1227,6 +1229,12 @@ item/itemType:
itemType: Item type
basicData: Basic data
summary: Summary
zone:
pageTitles:
zones: Zone
zonesList: Zones
deliveryList: Delivery days
upcomingList: Upcoming deliveries
components:
topbar: {}
itemsFilterPanel:

View File

@ -519,7 +519,7 @@ claim:
records: registros
card:
claimId: ID reclamación
assignedTo: Asignada a
attendedBy: Atendida por
created: Creada
state: Estado
ticketId: ID ticket
@ -557,6 +557,7 @@ claim:
responsible: Responsable
worker: Trabajador
redelivery: Devolución
changeState: Cambiar estado
basicData:
customer: Cliente
assignedTo: Asignada a
@ -1137,6 +1138,7 @@ item:
log: Historial
itemTypeCreate: Nueva familia
family: Familia
lastEntries: Últimas entradas
descriptor:
item: Artículo
buyer: Comprador
@ -1226,6 +1228,12 @@ item/itemType:
itemType: Familia
basicData: Datos básicos
summary: Resumen
zone:
pageTitles:
zones: Zona
zonesList: Zonas
deliveryList: Días de entrega
upcomingList: Próximos repartos
components:
topbar: {}
itemsFilterPanel:

View File

@ -41,10 +41,6 @@ const claimStates = ref([]);
const claimStatesCopy = ref([]);
const optionsList = ref([]);
function setWorkers(data) {
workers.value = data;
workersCopy.value = data;
}
const workersOptions = ref([]);
function setClaimStates(data) {

View File

@ -11,6 +11,7 @@ import VnLv from 'src/components/ui/VnLv.vue';
import useCardDescription from 'src/composables/useCardDescription';
import VnUserLink from 'src/components/ui/VnUserLink.vue';
import { getUrl } from 'src/composables/getUrl';
import ZoneDescriptorProxy from 'src/pages/Zone/Card/ZoneDescriptorProxy.vue';
const $props = defineProps({
id: {
@ -73,8 +74,9 @@ const filter = {
const STATE_COLOR = {
pending: 'warning',
managed: 'info',
incomplete: 'info',
resolved: 'positive',
canceled: 'negative',
};
function stateColor(code) {
return STATE_COLOR[code];
@ -127,17 +129,24 @@ onMounted(async () => {
</VnLv>
<VnLv
v-if="entity.worker"
:label="t('claim.card.assignedTo')"
:label="t('claim.card.attendedBy')"
:value="entity.worker.user.name"
>
<template #value>
<VnUserLink
:name="entity.worker.user.name"
:name="entity.worker.user.nickname"
:worker-id="entity.worker.id"
/>
</template>
</VnLv>
<VnLv :label="t('claim.card.zone')" :value="entity.ticket?.zone?.name" />
<VnLv :label="t('claim.card.zone')">
<template #value>
<span class="link">
{{ entity.ticket?.zone?.name }}
<ZoneDescriptorProxy :id="entity.ticket?.zone?.id" />
</span>
</template>
</VnLv>
<VnLv
:label="t('claim.card.province')"
:value="entity.ticket?.address?.province?.name"

View File

@ -1,6 +1,6 @@
<script setup>
import { onMounted, ref, computed } from 'vue';
import { useRoute } from 'vue-router';
import { useRoute, useRouter } from 'vue-router';
import { useI18n } from 'vue-i18n';
import { toDate, toCurrency } from 'src/filters';
import CardSummary from 'components/ui/CardSummary.vue';
@ -13,8 +13,11 @@ import VnUserLink from 'src/components/ui/VnUserLink.vue';
import ItemDescriptorProxy from 'src/pages/Item/Card/ItemDescriptorProxy.vue';
import VnTitle from 'src/components/common/VnTitle.vue';
import CustomerDescriptorProxy from 'src/pages/Customer/Card/CustomerDescriptorProxy.vue';
import axios from 'axios';
import dashIfEmpty from 'src/filters/dashIfEmpty';
const route = useRoute();
const router = useRouter();
const { t } = useI18n();
const { getTokenMultimedia } = useSession();
const token = getTokenMultimedia();
@ -27,7 +30,7 @@ const $props = defineProps({
});
const entityId = computed(() => $props.id || route.params.id);
const ClaimStates = ref([]);
const claimUrl = ref();
const salixUrl = ref();
const claimDmsRef = ref();
@ -99,8 +102,9 @@ const detailsColumns = ref([
const STATE_COLOR = {
pending: 'warning',
managed: 'info',
incomplete: 'info',
resolved: 'positive',
canceled: 'negative',
};
function stateColor(code) {
return STATE_COLOR[code];
@ -162,6 +166,10 @@ function openDialog(dmsId) {
multimediaSlide.value = dmsId;
multimediaDialog.value = true;
}
async function changeState(value) {
await axios.patch(`Claims/updateClaim/${entityId.value}`, { claimStateFk: value });
router.go(route.fullPath);
}
</script>
<template>
@ -171,6 +179,7 @@ function openDialog(dmsId) {
@on-fetch="(data) => setClaimDms(data)"
ref="claimDmsRef"
/>
<FetchData url="ClaimStates" @on-fetch="(data) => (ClaimStates = data)" auto-load />
<CardSummary
ref="summary"
:url="`Claims/${entityId}/getSummary`"
@ -180,6 +189,36 @@ function openDialog(dmsId) {
<template #header="{ entity: { claim } }">
{{ claim.id }} - {{ claim.client.name }} ({{ claim.client.id }})
</template>
<template #header-right>
<QBtnDropdown
side
top
color="black"
text-color="white"
:label="t('ticket.summary.changeState')"
>
<QList>
<QVirtualScroll
style="max-height: 300px"
:items="ClaimStates"
separator
v-slot="{ item, index }"
>
<QItem
:key="index"
dense
clickable
v-close-popup
@click="changeState(item.id)"
>
<QItemSection>
<QItemLabel>{{ item.description }}</QItemLabel>
</QItemSection>
</QItem>
</QVirtualScroll>
</QList>
</QBtnDropdown>
</template>
<template #body="{ entity: { claim, salesClaimed, developments } }">
<QCard class="vn-one">
<VnTitle
@ -223,7 +262,7 @@ function openDialog(dmsId) {
</VnLv>
<VnLv
:label="t('claim.basicData.pickup')"
:value="t(`claim.basicData.${claim.pickup}`)"
:value="`${dashIfEmpty(claim.pickup)}`"
/>
</QCard>
<QCard class="vn-three">
@ -447,4 +486,8 @@ function openDialog(dmsId) {
.zindex {
z-index: 1;
}
.change-state {
width: 10%;
}
</style>

View File

@ -1,5 +1,5 @@
<script setup>
import { ref, onMounted } from 'vue';
import { ref } from 'vue';
import { useRoute } from 'vue-router';
import { useI18n } from 'vue-i18n';
@ -11,10 +11,6 @@ const route = useRoute();
const { t } = useI18n();
const customerContactsRef = ref(null);
onMounted(() => {
if (customerContactsRef.value) customerContactsRef.value.reload();
});
</script>
<template>
<div class="full-width flex justify-center">
@ -30,6 +26,7 @@ onMounted(() => {
model="CustomerContacts"
ref="customerContactsRef"
url="ClientContacts"
auto-load
>
<template #body="{ rows }">
<QCard class="q-pl-lg q-py-md">

View File

@ -1,5 +1,5 @@
<script setup>
import { ref, computed, onMounted } from 'vue';
import { ref, computed } from 'vue';
import { useRoute } from 'vue-router';
import { useI18n } from 'vue-i18n';
@ -21,10 +21,6 @@ const sortEntryObservationOptions = (data) => {
);
};
onMounted(() => {
if (entryObservationsRef.value) entryObservationsRef.value.reload();
});
const columns = computed(() => [
{
name: 'observationType',
@ -65,6 +61,7 @@ const columns = computed(() => [
ref="entryObservationsRef"
:data-required="{ entryFk: params.id }"
v-model:selected="selected"
auto-load
>
<template #body="{ rows, validate }">
<QTable

View File

@ -70,7 +70,7 @@ const columns = computed(() => [
const isNotEuro = (code) => code != 'EUR';
async function insert() {
await axios.post('/InvoiceInDueDays/new ', { id: +invoiceId });
await axios.post('/InvoiceInDueDays/new', { id: +invoiceId });
await invoiceInFormRef.value.reload();
}
</script>

View File

@ -1,5 +1,5 @@
<script setup>
import { ref, onMounted, nextTick } from 'vue';
import { ref, nextTick } from 'vue';
import { useRoute } from 'vue-router';
import { useI18n } from 'vue-i18n';
@ -23,10 +23,6 @@ const focusLastInput = () => {
if (lastInput) lastInput.focus();
});
};
onMounted(async () => {
if (itemBarcodeRef.value) itemBarcodeRef.value.reload();
});
</script>
<template>
<div class="full-width flex justify-center">
@ -42,6 +38,7 @@ onMounted(async () => {
model="ItemBarcodes"
ref="itemBarcodeRef"
url="ItemBarcodes"
auto-load
>
<template #body="{ rows }">
<QCard class="q-px-lg q-py-md">

View File

@ -0,0 +1,317 @@
<script setup>
import { onMounted, computed, onUnmounted, reactive, ref } from 'vue';
import { useI18n } from 'vue-i18n';
import { useRoute } from 'vue-router';
import EntryDescriptorProxy from 'src/pages/Entry/Card/EntryDescriptorProxy.vue';
import VnInputDate from 'src/components/common/VnInputDate.vue';
import { useStateStore } from 'stores/useStateStore';
import { toDateTimeFormat } from 'src/filters/date.js';
import { dashIfEmpty } from 'src/filters';
import { toCurrency } from 'filters/index';
import { useArrayData } from 'composables/useArrayData';
const { t } = useI18n();
const route = useRoute();
const stateStore = useStateStore();
const exprBuilder = (param, value) => {
switch (param) {
case 'id':
case 'quantity':
case 'packagingFk':
return { [`b.${param}`]: value };
case 'supplierFk':
return { [`s.id`]: value };
case 'warehouseFk':
return { 'tr.warehouseInFk': value };
case 'landed':
return {
'tr.landed': {
between: getDateRange(value),
},
};
}
};
const dateRange = reactive({
from: null,
to: null,
});
const getDateRange = (val) => {
const minHour = new Date(val);
minHour.setHours(0, 0, 0, 0);
const maxHour = new Date(val);
maxHour.setHours(23, 59, 59, 59);
return [minHour, maxHour];
};
const from = computed({
get: () => dateRange.from,
set: (val) => {
updateFrom(val);
updateFilter();
},
});
const to = computed({
get: () => dateRange.to,
set: (val) => {
updateTo(val);
updateFilter();
},
});
const arrayData = useArrayData('ItemLastEntries', {
url: 'Items/lastEntriesFilter',
order: ['landed DESC', 'buyFk DESC'],
exprBuilder: exprBuilder,
userFilter: {
where: {
itemFk: route.params.id,
},
},
});
const itemLastEntries = ref([]);
const columns = computed(() => [
{
label: t('lastEntries.ig'),
name: 'ig',
align: 'center',
},
{
label: t('lastEntries.warehouse'),
name: 'warehouse',
field: 'warehouse',
align: 'left',
},
{
label: t('lastEntries.landed'),
name: 'id',
field: 'landed',
align: 'left',
format: (val) => toDateTimeFormat(val),
},
{
label: t('lastEntries.entry'),
name: 'entry',
field: 'stateName',
align: 'left',
format: (val) => dashIfEmpty(val),
},
{
label: t('lastEntries.pvp'),
name: 'pvp',
field: 'reference',
align: 'left',
format: (_, row) => toCurrency(row.price2) + ' / ' + toCurrency(row.price3),
},
{
label: t('lastEntries.label'),
name: 'label',
field: 'stickers',
align: 'center',
format: (val) => dashIfEmpty(val),
},
{
label: t('lastEntries.packing'),
name: 'packing',
align: 'center',
},
{
label: t('lastEntries.grouping'),
name: 'grouping',
align: 'center',
},
{
label: t('lastEntries.stems'),
name: 'stems',
field: 'stems',
align: 'center',
},
{
label: t('lastEntries.quantity'),
name: 'stems',
field: 'quantity',
align: 'center',
},
{
label: t('lastEntries.cost'),
name: 'cost',
align: 'left',
},
{
label: t('lastEntries.kg'),
name: 'stems',
field: 'weight',
align: 'center',
},
{
label: t('lastEntries.cube'),
name: 'cube',
field: 'packagingFk',
align: 'center',
},
{
label: t('lastEntries.supplier'),
name: 'stems',
field: 'supplier',
align: 'left',
},
]);
const fetchItemLastEntries = async () => {
const { data } = await arrayData.fetch({ append: false });
itemLastEntries.value = data;
};
const updateFrom = async (date) => {
date.setHours(0, 0, 0, 0);
dateRange.from = date.toISOString();
};
const updateTo = async (date) => {
date.setHours(23, 59, 59, 59);
dateRange.to = date.toISOString();
};
const updateFilter = async () => {
arrayData.store.userFilter.where.landed = {
between: [dateRange.from, dateRange.to],
};
await fetchItemLastEntries();
};
onMounted(async () => {
const _from = Date.vnNew();
_from.setDate(_from.getDate() - 75);
updateFrom(_from);
const _to = Date.vnNew();
_to.setDate(_to.getDate() + 10);
updateTo(_to);
updateFilter();
});
onUnmounted(() => (stateStore.rightDrawer = false));
</script>
<template>
<QToolbar class="justify-end">
<div id="st-data" class="row">
<VnInputDate
:label="t('lastEntries.since')"
dense
emit-date-format
v-model="from"
class="q-mr-lg"
/>
<VnInputDate
:label="t('lastEntries.to')"
dense
emit-date-format
v-model="to"
/>
</div>
<QSpace />
<div id="st-actions"></div>
</QToolbar>
<QPage class="column items-center q-pa-md">
<QTable
:rows="itemLastEntries"
:columns="columns"
class="full-width q-mt-md"
:no-data-label="t('globals.noResults')"
>
<template #body-cell-ig="{ row }">
<QTd @click.stop>
<QCheckbox
v-model="row.isIgnored"
:disable="true"
:false-value="0"
:true-value="1"
/>
</QTd>
</template>
<template #body-cell-entry="{ row }">
<QTd @click.stop>
<div class="full-width flex justify-center">
<EntryDescriptorProxy :id="row.entryFk" class="q-ma-none" dense />
<span class="link">{{ row.entryFk }}</span>
</div>
</QTd>
</template>
<template #body-cell-packing="{ row }">
<QTd @click.stop>
<QBadge
class="center-content"
rounded
:color="row.groupingMode == 'packing' ? 'grey-13' : 'black'"
>
{{ dashIfEmpty(row.packing) }}
<QTooltip>{{ t('lastEntries.packing') }}</QTooltip>
</QBadge>
</QTd>
</template>
<template #body-cell-pvp="{ value }">
<QTd @click.stop
><span> {{ value }}</span>
<QTooltip>
{{ t('lastEntries.grouping') }}/{{ t('lastEntries.packing') }}
</QTooltip></QTd
>
</template>
<template #body-cell-grouping="{ row }">
<QTd @click.stop>
<QBadge
class="center-content"
rounded
:color="row.groupingMode == 'grouping' ? 'grey-13' : 'black'"
>
{{ dashIfEmpty(row.grouping) }}
<QTooltip>{{ t('lastEntries.grouping') }}</QTooltip>
</QBadge>
</QTd>
</template>
<template #body-cell-cost="{ row }">
<QTd @click.stop>
<span>
{{ toCurrency(row.cost, 'EUR', 3) }}
<QTooltip>
{{ t('lastEntries.cost') }}:
{{ toCurrency(dashIfEmpty(row.buyingValue), 'EUR', 3) }}<br />
{{ t('lastEntries.package') }}:
{{ toCurrency(dashIfEmpty(row.packageValue), 'EUR', 3)
}}<br />
{{ $t('lastEntries.freight') }}:
{{ toCurrency(dashIfEmpty(row.freightValue), 'EUR', 3)
}}<br />
{{ t('lastEntries.comission') }}:
{{ toCurrency(dashIfEmpty(row.comissionValue), 'EUR', 3) }}
</QTooltip>
</span>
</QTd>
</template>
</QTable>
</QPage>
</template>
<style lang="scss" scoped>
.q-badge--rounded {
border-radius: 50%;
}
.center-content {
display: flex;
max-width: max-content;
margin: auto;
padding: 0 11px;
height: 28px;
}
</style>

View File

@ -1 +1,91 @@
<template>Item tax</template>
<script setup>
import { ref } from 'vue';
import { useRoute } from 'vue-router';
import { useI18n } from 'vue-i18n';
import FetchData from 'components/FetchData.vue';
import VnInput from 'src/components/common/VnInput.vue';
import VnRow from 'components/ui/VnRow.vue';
import CrudModel from 'components/CrudModel.vue';
import VnSelect from 'src/components/common/VnSelect.vue';
import axios from 'axios';
import useNotify from 'src/composables/useNotify.js';
const route = useRoute();
const { t } = useI18n();
const { notify } = useNotify();
const taxesFilter = {
fields: ['id', 'countryFk', 'taxClassFk'],
include: [
{
relation: 'country',
scope: {
fields: ['country'],
},
},
],
};
const ItemTaxRef = ref(null);
const taxesOptions = ref([]);
const submitTaxes = async (data) => {
try {
let payload = data.map((tax) => ({
id: tax.id,
taxClassFk: tax.taxClassFk,
}));
await axios.post(`Items/updateTaxes`, payload);
notify(t('globals.dataSaved'), 'positive');
} catch (err) {
console.error('Error saving taxes', err);
}
};
</script>
<template>
<FetchData
url="TaxClasses"
:filter="{
fields: ['id', 'description', 'code'],
}"
@on-fetch="(data) => (taxesOptions = data)"
auto-load
/>
<CrudModel
:url="`items/${route.params.id}/taxes`"
:save-fn="submitTaxes"
:filter="taxesFilter"
:default-remove="false"
data-key="ItemTax"
model="ItemTax"
ref="ItemTaxRef"
auto-load
>
<template #body="{ rows }">
<QCard class="q-px-lg q-py-md">
<VnRow
v-for="(row, index) in rows"
:key="index"
class="row q-gutter-md q-mb-md"
>
<VnInput
:label="t('tax.country')"
v-model="row.country.country"
disable
/>
<VnSelect
:label="t('tax.class')"
v-model="row.taxClassFk"
:options="taxesOptions"
option-label="description"
option-value="id"
hide-selected
/>
</VnRow>
</QCard>
</template>
</CrudModel>
</template>

View File

@ -35,3 +35,26 @@ createIntrastatForm:
title: New intrastat
identifier: Identifier
description: Description
tax:
country: Country
class: Class
lastEntries:
since: Since
to: To
ig: Ig
warehouse: Warehouse
landed: Landed
entry: Entry
pvp: PVP
label: Label
packing: Packing
grouping: Grouping
stems: Stems
quantity: Quantity
cost: Cost
kg: Kg.
cube: Cube
supplier: Supplier
package: Package
freight: Freight
comission: Comission

View File

@ -35,3 +35,26 @@ createIntrastatForm:
title: Nuevo intrastat
identifier: Identificador
description: Descripción
tax:
country: País
class: Clase
lastEntries:
since: Desde
to: Hasta
ig: Ig
warehouse: Almacén
landed: F. Entrega
entry: Entrada
pvp: PVP
label: Etiquetas
packing: Packing
grouping: Grouping
stems: Tallos
quantity: Cantidad
cost: Coste
kg: Kg.
cube: Cubo
supplier: Proveedor
package: Embalaje
freight: Porte
comission: Comisión

View File

@ -3,9 +3,9 @@ import { useI18n } from 'vue-i18n';
import { useRoute } from 'vue-router';
import VnSubToolbar from 'src/components/ui/VnSubToolbar.vue';
import FetchData from 'components/FetchData.vue';
import { onMounted, ref } from 'vue';
import { ref } from 'vue';
import CrudModel from 'components/CrudModel.vue';
import RoadmapAddStopForm from "pages/Route/Roadmap/RoadmapAddStopForm.vue";
import RoadmapAddStopForm from 'pages/Route/Roadmap/RoadmapAddStopForm.vue';
const { t } = useI18n();
const route = useRoute();
@ -21,10 +21,6 @@ const updateDefaultStop = (data) => {
eta.setDate(eta.getDate() + 1);
defaultStop.value.eta = eta.toISOString();
};
onMounted(() => {
if (roadmapStopsCrudRef.value) roadmapStopsCrudRef.value.reload();
});
</script>
<template>
<VnSubToolbar />
@ -43,6 +39,7 @@ onMounted(() => {
:filter="{ where: { roadmapFk: route.params?.id } }"
:default-remove="false"
:data-required="defaultStop"
auto-load
>
<template #body="{ rows }">
<QCard class="q-pa-md">
@ -51,7 +48,10 @@ onMounted(() => {
:key="index"
class="row no-wrap"
>
<RoadmapAddStopForm :roadmap-fk="route.params?.id" :form-data="row" />
<RoadmapAddStopForm
:roadmap-fk="route.params?.id"
:form-data="row"
/>
<div class="col-1 row justify-center items-center">
<QIcon
name="delete"

View File

@ -72,7 +72,6 @@ function exprBuilder(param, value) {
:filter="filter"
:expr-builder="exprBuilder"
:limit="20"
auto-load
>
<template #body="{ rows }">
<CardList

View File

@ -1,5 +1,5 @@
<script setup>
import { ref, onMounted } from 'vue';
import { ref } from 'vue';
import { useRoute } from 'vue-router';
import { useI18n } from 'vue-i18n';
@ -59,10 +59,6 @@ const setWireTransfer = async () => {
console.error('Error setting wire transfer', err);
}
};
onMounted(() => {
if (supplierAccountRef.value) supplierAccountRef.value.reload();
});
</script>
<template>
<FetchData
@ -94,6 +90,7 @@ onMounted(() => {
:default-remove="false"
:data-required="{ supplierFk: route.params.id }"
@save-changes="onChangesSaved()"
auto-load
>
<template #body="{ rows }">
<QCard class="q-pa-md">

View File

@ -1,5 +1,5 @@
<script setup>
import { ref, onMounted } from 'vue';
import { ref } from 'vue';
import { useRouter, useRoute } from 'vue-router';
import { useI18n } from 'vue-i18n';
@ -26,10 +26,6 @@ const supplierAgencyFilter = {
const redirectToCreateView = () => {
router.push({ name: 'SupplierAgencyTermCreate' });
};
onMounted(() => {
if (supplierAgencyTermRef.value) supplierAgencyTermRef.value.reload();
});
</script>
<template>
<FetchData
@ -49,6 +45,7 @@ onMounted(() => {
:data-required="{
supplierFk: route.params.id,
}"
auto-load
>
<template #body="{ rows }">
<QCard class="q-pa-md">

View File

@ -1,5 +1,5 @@
<script setup>
import { ref, onMounted, nextTick } from 'vue';
import { ref, nextTick } from 'vue';
import { useRoute } from 'vue-router';
import { useI18n } from 'vue-i18n';
@ -19,10 +19,6 @@ const insertRow = () => {
if (lastInput) lastInput.focus();
});
};
onMounted(() => {
if (supplierContactRef.value) supplierContactRef.value.reload();
});
</script>
<template>
@ -36,6 +32,7 @@ onMounted(() => {
ref="supplierContactRef"
:default-remove="false"
:data-required="{ supplierFk: route.params.id }"
auto-load
>
<template #body="{ rows }">
<QCard class="q-pa-md">

View File

@ -188,7 +188,7 @@ async function changeState(value) {
:label="t('ticket.summary.landed')"
:value="toDate(ticket.landed)"
/>
<VnLv :label="t('global.packages')" :value="ticket.packages" />
<VnLv :label="t('globals.packages')" :value="ticket.packages" />
<VnLv :value="ticket.address.phone">
<template #label>
{{ t('ticket.summary.consigneePhone') }}

View File

@ -0,0 +1,6 @@
<script setup>
import VnCard from 'components/common/VnCard.vue';
</script>
<template>
<VnCard data-key="Zone" base-url="Zones" />
</template>

View File

@ -0,0 +1,103 @@
<script setup>
import { ref, computed } from 'vue';
import { useRoute } from 'vue-router';
import { useI18n } from 'vue-i18n';
import CardDescriptor from 'components/ui/CardDescriptor.vue';
import VnLv from 'src/components/ui/VnLv.vue';
import ZoneDescriptorMenuItems from './ZoneDescriptorMenuItems.vue';
import useCardDescription from 'src/composables/useCardDescription';
const $props = defineProps({
id: {
type: Number,
required: false,
default: null,
},
});
const route = useRoute();
const { t } = useI18n();
const filter = {
include: [
{
relation: 'agencyMode',
scope: {
fields: ['name', 'id'],
},
},
],
};
const entityId = computed(() => {
return $props.id || route.params.id;
});
const data = ref(useCardDescription());
const setData = (entity) => {
data.value = useCardDescription(entity.ref, entity.id);
};
function extractHour(dateTime) {
const date = new Date(dateTime);
const hours = date.getHours().toString().padStart(2, '0');
const minutes = date.getMinutes().toString().padStart(2, '0');
return `${hours}:${minutes}`;
}
</script>
<template>
<CardDescriptor
module="Zone"
:url="`Zones/${entityId}`"
:title="data.title"
:subtitle="data.subtitle"
:filter="filter"
@on-fetch="setData"
data-key="zoneData"
>
<template #header-extra-action>
<QBtn
round
flat
dense
size="md"
icon="preview"
color="white"
class="link"
:to="{ name: 'ZoneList' }"
>
<QTooltip>
{{ t('Summary') }}
</QTooltip>
</QBtn>
</template>
<!-- <template #menu="{ entity }">
<ZoneDescriptorMenuItems :zone="entity" />
</template> -->
<template #body="{ entity }">
{{ console.log('entity', entity) }}
<VnLv :label="t('Agency')" :value="entity.agencyMode.name" />
<VnLv :label="t('Closing hour')" :value="extractHour(entity.hour)" />
<VnLv :label="t('zoneing days')" :value="entity.zoneingDays" />
<VnLv :label="t('Price')" :value="entity.price" />
<VnLv :label="t('Bonus')" :value="entity.bonus" />
</template>
</CardDescriptor>
</template>
<i18n>
es:
Summary: Detalles
The zone will be deleted: El envío será eliminado
Do you want to delete this zone?: ¿Quieres eliminar este envío?
All zones with current agency: Todos los envíos con la agencia actual
Agency: Agencia
Closing hour: Hora de cierre
zoneing days: Días de viaje
Price: Precio
Bonus: Bonificación
</i18n>

View File

@ -0,0 +1,93 @@
<script setup>
import { useQuasar } from 'quasar';
import { useRouter } from 'vue-router';
import { useI18n } from 'vue-i18n';
const { dialog, notify } = useQuasar();
import VnConfirm from 'components/ui/VnConfirm.vue';
import axios from 'axios';
const $props = defineProps({
zone: {
type: Object,
default: () => {},
},
});
const { t } = useI18n();
const { push, currentRoute } = useRouter();
const zoneId = currentRoute.value.params.id;
const actions = {
clone: async () => {
const opts = { message: t('Zone cloned'), type: 'positive' };
let clonedZoneId;
try {
const { data } = await axios.post(`Zones/${zoneId}/clone`, {
shipped: $props.zone.value.shipped,
});
clonedZoneId = data;
} catch (e) {
opts.message = t('It was not able to clone the zone');
opts.type = 'negative';
} finally {
notify(opts);
if (clonedZoneId) push({ name: 'ZoneSummary', params: { id: clonedZoneId } });
}
},
remove: async () => {
try {
await axios.post(`Zones/${zoneId}/setDeleted`);
notify({ message: t('Zone deleted'), type: 'positive' });
notify({
message: t('You can undo this action within the first hour'),
icon: 'info',
});
push({ name: 'ZoneList' });
} catch (e) {
notify({ message: e.message, type: 'negative' });
}
},
};
function openConfirmDialog(callback) {
dialog({
component: VnConfirm,
componentProps: {
promise: actions[callback],
},
});
}
</script>
<template>
<QItem @click="openConfirmDialog('clone')" v-ripple clickable>
<QItemSection avatar>
<QIcon name="content_copy" />
</QItemSection>
<QItemSection>{{ t('To clone zone') }}</QItemSection>
</QItem>
<QItem @click="openConfirmDialog('remove')" v-ripple clickable>
<QItemSection avatar>
<QIcon name="delete" />
</QItemSection>
<QItemSection>{{ t('deleteOrder') }}</QItemSection>
</QItem>
</template>
<i18n>
en:
deleteOrder: Delete order
confirmDeletion: Confirm deletion
confirmDeletionMessage: Are you sure you want to delete this order?
es:
To clone zone: Clonar zone
deleteOrder: Eliminar pedido
confirmDeletion: Confirmar eliminación
confirmDeletionMessage: Seguro que quieres eliminar este pedido?
</i18n>

View File

@ -0,0 +1,16 @@
<script setup>
import ZoneDescriptor from './ZoneDescriptor.vue';
const $props = defineProps({
id: {
type: Number,
required: true,
},
});
</script>
<template>
<QPopupProxy>
<ZoneDescriptor v-if="$props.id" :id="$props.id" />
</QPopupProxy>
</template>

View File

@ -0,0 +1,94 @@
<script setup>
import { ref, onMounted, computed } from 'vue';
import { useRoute } from 'vue-router';
import { useI18n } from 'vue-i18n';
import { dashIfEmpty } from 'src/filters';
import { getUrl } from 'src/composables/getUrl';
import VnLv from 'src/components/ui/VnLv.vue';
import VnLinkPhone from 'src/components/ui/VnLinkPhone.vue';
import CardSummary from 'components/ui/CardSummary.vue';
import VnUserLink from 'src/components/ui/VnUserLink.vue';
import VnTitle from 'src/components/common/VnTitle.vue';
const route = useRoute();
const { t } = useI18n();
const $props = defineProps({
id: {
type: Number,
default: 0,
},
});
const entityId = computed(() => $props.id || route.params.id);
const zoneUrl = ref();
onMounted(async () => {
zoneUrl.value = (await getUrl('')) + `zone/${entityId.value}/`;
});
const filter = computed(() => {
return { where: { id: entityId.value } };
});
</script>
<template>
<CardSummary
data-key="zoneData"
ref="summary"
:url="`Zones/summary`"
:filter="filter"
>
<template #header="{ entity }">
<div>{{ entity.id }} - {{ entity.firstName }} {{ entity.lastName }}</div>
</template>
<template #body="{ entity: zone }">
<QCard class="vn-one">
<VnTitle
:url="zoneUrl + `basic-data`"
:text="t('zone.summary.basicData')"
/>
<VnLv :label="t('zone.card.name')" :value="zone.user?.nickname" />
<VnLv
:label="t('zone.list.department')"
:value="zone.department?.department?.name"
/>
<VnLv :label="t('zone.list.email')" :value="zone.user.email" copy />
<VnLv :label="t('zone.summary.boss')" link>
<template #value>
<VnUserLink
v-if="zone.boss"
:name="dashIfEmpty(zone.boss?.name)"
:zone-id="zone.bossFk"
/>
</template>
</VnLv>
<VnLv :value="zone.mobileExtension">
<template #label>
{{ t('zone.summary.phoneExtension') }}
<VnLinkPhone :phone-number="zone.mobileExtension" />
</template>
</VnLv>
<VnLv :value="zone.phone">
<template #label>
{{ t('zone.summary.entPhone') }}
<VnLinkPhone :phone-number="zone.phone" />
</template>
</VnLv>
<VnLv :label="t('zone.summary.locker')" :value="zone.locker" />
</QCard>
<QCard class="vn-one">
<VnTitle :text="t('zone.summary.userData')" />
<VnLv :label="t('zone.summary.userId')" :value="zone.user.id" />
<VnLv :label="t('zone.card.name')" :value="zone.user.nickname" />
<VnLv :label="t('zone.summary.role')" :value="zone.user.role.name" />
<VnLv :value="zone?.sip?.extension">
<template #label>
{{ t('zone.summary.sipExtension') }}
<VnLinkPhone :phone-number="zone?.sip?.extension" />
</template>
</VnLv>
</QCard>
</template>
</CardSummary>
</template>

View File

@ -17,6 +17,7 @@ import roadmap from './roadmap';
import Parking from './parking';
import Agency from './agency';
import ItemType from './itemType';
import Zone from './zone';
export default [
Item,
@ -38,4 +39,5 @@ export default [
Parking,
Agency,
ItemType,
Zone,
];

View File

@ -26,6 +26,7 @@ export default {
'ItemTax',
'ItemBotanical',
'ItemBarcode',
'ItemLastEntries',
],
},
children: [
@ -135,6 +136,15 @@ export default {
},
component: () => import('src/pages/Item/Card/ItemTags.vue'),
},
{
path: 'last-entries',
name: 'ItemLastEntries',
meta: {
title: 'lastEntries',
icon: 'vn:regentry',
},
component: () => import('src/pages/Item/Card/ItemLastEntries.vue'),
},
{
path: 'tax',
name: 'ItemTax',
@ -144,6 +154,15 @@ export default {
},
component: () => import('src/pages/Item/Card/ItemTax.vue'),
},
{
path: 'botanical',
name: 'ItemBotanical',
meta: {
title: 'botanical',
icon: 'local_florist',
},
component: () => import('src/pages/Item/Card/ItemBotanical.vue'),
},
{
path: 'barcode',
name: 'ItemBarcode',
@ -171,15 +190,6 @@ export default {
},
component: () => import('src/pages/Item/Card/ItemLog.vue'),
},
{
path: 'botanical',
name: 'ItemBotanical',
meta: {
title: 'botanical',
icon: 'vn:botanical',
},
component: () => import('src/pages/Item/Card/ItemBotanical.vue'),
},
],
},
],

160
src/router/modules/zone.js Normal file
View File

@ -0,0 +1,160 @@
import { RouterView } from 'vue-router';
export default {
path: '/zone',
name: 'Zone',
meta: {
title: 'zones',
icon: 'vn:zone',
moduleName: 'Zone',
},
component: RouterView,
redirect: { name: 'ZoneMain' },
menus: {
main: [
/*'ZoneList', 'ZoneDeliveryList', 'ZoneUpcomingList'*/
],
card: [
//
],
},
children: [
// {
// path: '/zone',
// name: 'ZoneMain',
// component: () => import('src/pages/Zone/ZoneMain.vue'),
// redirect: { name: 'ZoneList' },
// children: [
// {
// path: 'list',
// name: 'ZoneList',
// meta: {
// title: 'zonesList',
// icon: 'vn:zone',
// },
// component: () => import('src/pages/Zone/ZoneList.vue'),
// },
// {
// path: 'create',
// name: 'ZoneCreate',
// meta: {
// title: 'zoneCreate',
// icon: 'create',
// },
// component: () => import('src/pages/Zone/ZoneCreate.vue'),
// },
// {
// path: ':id/edit',
// name: 'ZoneEdit',
// meta: {
// title: 'zoneEdit',
// icon: 'edit',
// },
// component: () => import('src/pages/Zone/ZoneCreate.vue'),
// },
// {
// path: 'counter',
// name: 'ZoneCounter',
// meta: {
// title: 'zoneCounter',
// icon: 'add_circle',
// },
// component: () => import('src/pages/Zone/ZoneCounter.vue'),
// },
// ],
// },
{
name: 'ZoneCard',
path: ':id',
component: () => import('src/pages/Zone/Card/ZoneCard.vue'),
redirect: { name: 'ZoneSummary' },
children: [
{
name: 'ZoneSummary',
path: 'summary',
meta: {
title: 'summary',
icon: 'launch',
},
component: () => import('src/pages/Zone/Card/ZoneSummary.vue'),
},
// {
// path: '/zone/delivery',
// name: 'ZoneDeliveryMain',
// component: () => import('src/pages/Zone/ZoneMain.vue'),
// redirect: { name: 'ZoneDeliveryList' },
// children: [
// {
// path: 'list',
// name: 'ZoneDeliveryList',
// meta: {
// title: 'deliveryList',
// icon: 'today',
// },
// component: () =>
// import('src/pages/Zone/Delivery/ZoneDeliveryList.vue'),
// },
// {
// path: 'create',
// name: 'ZoneDeliveryCreate',
// meta: {
// title: 'deliveryCreate',
// icon: 'create',
// },
// component: () =>
// import('src/pages/Zone/Delivery/ZoneDeliveryCreate.vue'),
// },
// {
// path: ':id/edit',
// name: 'ZoneDeliveryEdit',
// meta: {
// title: 'deliveryEdit',
// icon: 'edit',
// },
// component: () =>
// import('src/pages/Zone/Delivery/ZoneDeliveryCreate.vue'),
// },
// ],
// },
// {
// path: '/zone/upcoming',
// name: 'ZoneUpcomingMain',
// component: () => import('src/pages/Zone/ZoneMain.vue'),
// redirect: { name: 'ZoneUpcomingList' },
// children: [
// {
// path: 'list',
// name: 'ZoneUpcomingList',
// meta: {
// title: 'upcomingList',
// icon: 'today',
// },
// component: () =>
// import('src/pages/Zone/Upcoming/ZoneUpcomingList.vue'),
// },
// {
// path: 'create',
// name: 'ZoneUpcomingCreate',
// meta: {
// title: 'upcomingCreate',
// icon: 'create',
// },
// component: () =>
// import('src/pages/Zone/Upcoming/ZoneUpcomingCreate.vue'),
// },
// {
// path: ':id/edit',
// name: 'ZoneUpcomingEdit',
// meta: {
// title: 'upcomingEdit',
// icon: 'edit',
// },
// component: () =>
// import('src/pages/Zone/Upcoming/ZoneUpcomingCreate.vue'),
// },
// ],
// },
],
},
],
};

View File

@ -17,6 +17,7 @@ import entry from 'src/router/modules/entry';
import roadmap from 'src/router/modules/roadmap';
import parking from 'src/router/modules/parking';
import agency from 'src/router/modules/agency';
import zone from 'src/router/modules/zone';
const routes = [
{
@ -75,6 +76,7 @@ const routes = [
parking,
agency,
ItemType,
zone,
{
path: '/:catchAll(.*)*',
name: 'NotFound',

View File

@ -21,6 +21,7 @@ export const useNavigationStore = defineStore('navigationStore', () => {
'ticket',
'worker',
'wagon',
'zone',
];
const pinnedModules = ref([]);
const role = useRole();