Compare commits
33 Commits
7527-notCr
...
dev
Author | SHA1 | Date |
---|---|---|
|
a9e3cad8ba | |
|
93e29fdde6 | |
|
22747995cb | |
|
33a6e5ebd3 | |
|
86a3192c17 | |
|
85074b3ca4 | |
|
de4e5ce669 | |
|
90fb1485b0 | |
|
5b5ce033f0 | |
|
e470fa70e2 | |
|
d3b6223473 | |
|
b68f4331b8 | |
|
9d500a0655 | |
|
20aea5b7df | |
|
de93eba293 | |
|
48b5cfe69b | |
|
4e650378a4 | |
|
47f8abe013 | |
|
be88029197 | |
|
6ab54908ed | |
|
8e33c79446 | |
|
c432709a04 | |
|
dd218361f0 | |
|
3ceabd5831 | |
|
8dd67efeb9 | |
|
a8222788ca | |
|
c31218e4fe | |
|
8e10d9d09d | |
|
b85407d8c2 | |
|
753fa8489c | |
|
a8d39a9b96 | |
|
81308230ec | |
|
5b870c2c2c |
|
@ -7,7 +7,7 @@ import { QLayout } from 'quasar';
|
|||
import mainShortcutMixin from './mainShortcutMixin';
|
||||
import { useCau } from 'src/composables/useCau';
|
||||
|
||||
export default boot(({ app }) => {
|
||||
export default boot(({ app, router }) => {
|
||||
QForm.mixins = [qFormMixin];
|
||||
QLayout.mixins = [mainShortcutMixin];
|
||||
|
||||
|
@ -22,6 +22,14 @@ export default boot(({ app }) => {
|
|||
}
|
||||
|
||||
switch (response?.status) {
|
||||
case 401:
|
||||
if (!router.currentRoute.value.name.toLowerCase().includes('login')) {
|
||||
message = 'errors.sessionExpired';
|
||||
} else message = 'login.loginError';
|
||||
break;
|
||||
case 403:
|
||||
if (!message || message.toLowerCase() === 'access denied')
|
||||
message = 'errors.accessDenied';
|
||||
case 422:
|
||||
if (error.name == 'ValidationError')
|
||||
message += ` "${responseError.details.context}.${Object.keys(
|
||||
|
|
|
@ -180,7 +180,11 @@ const col = computed(() => {
|
|||
)
|
||||
newColumn.component = 'checkbox';
|
||||
if ($props.default && !newColumn.component) newColumn.component = $props.default;
|
||||
|
||||
|
||||
if (typeof newColumn.component !== 'string') {
|
||||
newColumn.attrs = { ...newColumn.component.attrs, autofocus: $props.autofocus };
|
||||
newColumn.event = { ...newColumn.component.event, ...$props?.eventHandlers };
|
||||
}
|
||||
return newColumn;
|
||||
});
|
||||
|
||||
|
|
|
@ -250,7 +250,6 @@ watch(
|
|||
defineExpose({
|
||||
create: createForm,
|
||||
showForm,
|
||||
openForm,
|
||||
reload,
|
||||
redirect: redirectFn,
|
||||
selected,
|
||||
|
@ -647,12 +646,6 @@ const rowCtrlClickFunction = computed(() => {
|
|||
};
|
||||
return () => {};
|
||||
});
|
||||
|
||||
function openForm(data) {
|
||||
showForm.value = !showForm.value;
|
||||
createForm.value = { ...$props.create, ...data };
|
||||
}
|
||||
|
||||
const handleHeaderSelection = (evt, data) => {
|
||||
if (evt === 'updateSelected' && selectAll.value) {
|
||||
selected.value = tableRef.value.rows;
|
||||
|
@ -1062,7 +1055,9 @@ const handleHeaderSelection = (evt, data) => {
|
|||
<QBtn
|
||||
@click="
|
||||
() =>
|
||||
createAsDialog ? openForm(create) : handleOnDataSaved(create)
|
||||
createAsDialog
|
||||
? (showForm = !showForm)
|
||||
: handleOnDataSaved(create)
|
||||
"
|
||||
class="cursor-pointer fill-icon"
|
||||
color="primary"
|
||||
|
@ -1081,7 +1076,10 @@ const handleHeaderSelection = (evt, data) => {
|
|||
</CrudModel>
|
||||
<QPageSticky v-if="$props.create" :offset="[20, 20]" style="z-index: 2">
|
||||
<QBtn
|
||||
@click="() => (createAsDialog ? openForm(create) : handleOnDataSaved(create))"
|
||||
@click="
|
||||
() =>
|
||||
createAsDialog ? (showForm = !showForm) : handleOnDataSaved(create)
|
||||
"
|
||||
color="primary"
|
||||
fab
|
||||
icon="add"
|
||||
|
|
|
@ -7,6 +7,7 @@ import axios from 'axios';
|
|||
import { usePrintService } from 'composables/usePrintService';
|
||||
|
||||
import VnUserLink from '../ui/VnUserLink.vue';
|
||||
import { downloadFile } from 'src/composables/downloadFile';
|
||||
import VnImg from 'components/ui/VnImg.vue';
|
||||
import VnPaginate from 'components/ui/VnPaginate.vue';
|
||||
import VnDms from 'src/components/common/VnDms.vue';
|
||||
|
@ -51,10 +52,6 @@ const $props = defineProps({
|
|||
type: String,
|
||||
required: true,
|
||||
},
|
||||
description: {
|
||||
type: String,
|
||||
deafult: undefined,
|
||||
},
|
||||
});
|
||||
|
||||
const dmsFilter = {
|
||||
|
@ -341,7 +338,6 @@ defineExpose({
|
|||
<span
|
||||
v-if="props.col.component == 'span'"
|
||||
style="white-space: wrap"
|
||||
:data-cy="`${props.col.name}_form`"
|
||||
>{{ props.value }}</span
|
||||
>
|
||||
</component>
|
||||
|
|
|
@ -0,0 +1,49 @@
|
|||
<script setup>
|
||||
import { ref, useTemplateRef } from 'vue';
|
||||
import { useI18n } from 'vue-i18n';
|
||||
import { useAccountShortToStandard } from 'src/composables/useAccountShortToStandard';
|
||||
import VnSelectDialog from './VnSelectDialog.vue';
|
||||
import CreateNewExpenseForm from '../CreateNewExpenseForm.vue';
|
||||
import FetchData from '../FetchData.vue';
|
||||
|
||||
const model = defineModel({ type: [String, Number, Object] });
|
||||
const { t } = useI18n();
|
||||
const expenses = ref([]);
|
||||
const selectDialogRef = useTemplateRef('selectDialogRef');
|
||||
|
||||
async function autocompleteExpense(evt) {
|
||||
const val = evt.target.value;
|
||||
if (!val || isNaN(val)) return;
|
||||
const lookup = expenses.value.find(({ id }) => id == useAccountShortToStandard(val));
|
||||
if (selectDialogRef.value)
|
||||
selectDialogRef.value.vnSelectDialogRef.vnSelectRef.toggleOption(lookup);
|
||||
}
|
||||
</script>
|
||||
<template>
|
||||
<VnSelectDialog
|
||||
v-bind="$attrs"
|
||||
ref="selectDialogRef"
|
||||
v-model="model"
|
||||
:options="expenses"
|
||||
option-value="id"
|
||||
:option-label="(x) => `${x.id}: ${x.name}`"
|
||||
:filter-options="['id', 'name']"
|
||||
:tooltip="t('Create a new expense')"
|
||||
:acls="[{ model: 'Expense', props: '*', accessType: 'WRITE' }]"
|
||||
@keydown.tab.prevent="autocompleteExpense"
|
||||
>
|
||||
<template #form>
|
||||
<CreateNewExpenseForm @on-data-saved="$refs.expensesRef.fetch()" />
|
||||
</template>
|
||||
</VnSelectDialog>
|
||||
<FetchData
|
||||
ref="expensesRef"
|
||||
url="Expenses"
|
||||
auto-load
|
||||
@on-fetch="(data) => (expenses = data)"
|
||||
/>
|
||||
</template>
|
||||
<i18n>
|
||||
es:
|
||||
Create a new expense: Crear nuevo gasto
|
||||
</i18n>
|
|
@ -220,10 +220,12 @@ globals:
|
|||
mandates: Mandates
|
||||
contacts: Contacts
|
||||
webPayment: Web payment
|
||||
fileManagement: File management
|
||||
unpaid: Unpaid
|
||||
entries: Entries
|
||||
buys: Buys
|
||||
dms: File management
|
||||
entryCreate: New entry
|
||||
latestBuys: Latest buys
|
||||
reserves: Reserves
|
||||
tickets: Tickets
|
||||
|
@ -242,12 +244,14 @@ globals:
|
|||
invoiceOutCreate: Create invoice out
|
||||
order: Orders
|
||||
orderList: List
|
||||
orderCreate: New order
|
||||
catalog: Catalog
|
||||
volume: Volume
|
||||
shelving: Shelving
|
||||
shelvingList: Shelving List
|
||||
shelvingCreate: New shelving
|
||||
invoiceIns: Invoices In
|
||||
invoiceInCreate: Create invoice in
|
||||
vat: VAT
|
||||
labeler: Labeler
|
||||
dueDay: Due day
|
||||
|
@ -274,18 +278,21 @@ globals:
|
|||
routes: Routes
|
||||
cmrsList: CMRs
|
||||
RouteList: List
|
||||
routeCreate: New route
|
||||
RouteRoadmap: Roadmaps
|
||||
RouteRoadmapCreate: Create roadmap
|
||||
RouteExtendedList: Router
|
||||
autonomous: Autonomous
|
||||
suppliers: Suppliers
|
||||
supplier: Supplier
|
||||
supplierCreate: New supplier
|
||||
accounts: Accounts
|
||||
addresses: Addresses
|
||||
agencyTerm: Agency agreement
|
||||
travel: Travels
|
||||
create: Create
|
||||
extraCommunity: Extra community
|
||||
travelCreate: New travel
|
||||
history: Log
|
||||
thermographs: Thermograph
|
||||
items: Items
|
||||
|
@ -393,6 +400,8 @@ errors:
|
|||
updateUserConfig: Error updating user config
|
||||
tokenConfig: Error fetching token config
|
||||
writeRequest: The requested operation could not be completed
|
||||
sessionExpired: Your session has expired. Please log in again
|
||||
accessDenied: Access denied
|
||||
claimBeginningQuantity: Cannot import a line with a claimed quantity of 0
|
||||
login:
|
||||
title: Login
|
||||
|
|
|
@ -223,10 +223,12 @@ globals:
|
|||
mandates: Mandatos
|
||||
contacts: Contactos
|
||||
webPayment: Pago web
|
||||
fileManagement: Gestión documental
|
||||
unpaid: Impago
|
||||
entries: Entradas
|
||||
buys: Compras
|
||||
dms: Gestión documental
|
||||
entryCreate: Nueva entrada
|
||||
latestBuys: Últimas compras
|
||||
reserves: Reservas
|
||||
tickets: Tickets
|
||||
|
@ -245,12 +247,14 @@ globals:
|
|||
invoiceOutCreate: Crear fact. emitida
|
||||
order: Cesta
|
||||
orderList: Listado
|
||||
orderCreate: Nueva orden
|
||||
catalog: Catálogo
|
||||
volume: Volumen
|
||||
shelving: Carros
|
||||
shelvingList: Listado de carros
|
||||
shelvingCreate: Nuevo carro
|
||||
invoiceIns: Fact. recibidas
|
||||
invoiceInCreate: Crear fact. recibida
|
||||
vat: IVA
|
||||
labeler: Etiquetas
|
||||
dueDay: Vencimiento
|
||||
|
@ -277,18 +281,21 @@ globals:
|
|||
routes: Rutas
|
||||
cmrsList: CMRs
|
||||
RouteList: Listado
|
||||
routeCreate: Nueva ruta
|
||||
RouteRoadmap: Troncales
|
||||
RouteRoadmapCreate: Crear troncal
|
||||
RouteExtendedList: Enrutador
|
||||
autonomous: Autónomos
|
||||
suppliers: Proveedores
|
||||
supplier: Proveedor
|
||||
supplierCreate: Nuevo proveedor
|
||||
accounts: Cuentas
|
||||
addresses: Direcciones
|
||||
agencyTerm: Acuerdo agencia
|
||||
travel: Envíos
|
||||
create: Crear
|
||||
extraCommunity: Extra comunitarios
|
||||
travelCreate: Nuevo envío
|
||||
history: Historial
|
||||
thermographs: Termógrafos
|
||||
items: Artículos
|
||||
|
@ -389,6 +396,8 @@ errors:
|
|||
updateUserConfig: Error al actualizar la configuración de usuario
|
||||
tokenConfig: Error al obtener configuración de token
|
||||
writeRequest: No se pudo completar la operación solicitada
|
||||
sessionExpired: Tu sesión ha expirado, por favor vuelve a iniciar sesión
|
||||
accessDenied: Acceso denegado
|
||||
claimBeginningQuantity: No se puede importar una linea sin una cantidad reclamada
|
||||
login:
|
||||
title: Inicio de sesión
|
||||
|
|
|
@ -1,22 +1,18 @@
|
|||
<script setup>
|
||||
import { ref, watch } from 'vue';
|
||||
import { onBeforeMount, ref, watch } from 'vue';
|
||||
import { useI18n } from 'vue-i18n';
|
||||
import { useRoute } from 'vue-router';
|
||||
import { useRoute, useRouter } from 'vue-router';
|
||||
import FetchData from 'components/FetchData.vue';
|
||||
|
||||
import axios from 'axios';
|
||||
import CustomerAddressForm from '../components/CustomerAddressForm.vue';
|
||||
import CustomerAddressEdit from '../components/CustomerAddressEdit.vue';
|
||||
|
||||
const { t } = useI18n();
|
||||
const route = useRoute();
|
||||
const router = useRouter();
|
||||
|
||||
const addresses = ref([]);
|
||||
const client = ref(null);
|
||||
const showFormCreate = ref();
|
||||
const showFormEdit = ref();
|
||||
const showFormEditModel = ref();
|
||||
const vnPaginateRef = ref();
|
||||
|
||||
const addressFilter = {
|
||||
fields: [
|
||||
'id',
|
||||
|
@ -31,11 +27,6 @@ const addressFilter = {
|
|||
'isEqualizated',
|
||||
'isLogifloraAllowed',
|
||||
'postalCode',
|
||||
'agencyModeFk',
|
||||
'longitude',
|
||||
'latitude',
|
||||
'incotermsFk',
|
||||
'customsAgentFk',
|
||||
],
|
||||
order: ['isDefaultAddress DESC', 'isActive DESC', 'id DESC', 'nickname ASC'],
|
||||
include: [
|
||||
|
@ -57,15 +48,14 @@ const addressFilter = {
|
|||
],
|
||||
},
|
||||
},
|
||||
{
|
||||
relation: 'agencyMode',
|
||||
scope: {
|
||||
fields: ['id', 'name'],
|
||||
},
|
||||
},
|
||||
],
|
||||
};
|
||||
|
||||
onBeforeMount(() => {
|
||||
const { id } = route.params;
|
||||
getClientData(id);
|
||||
});
|
||||
|
||||
watch(
|
||||
() => route.params.id,
|
||||
(newValue) => {
|
||||
|
@ -75,13 +65,16 @@ watch(
|
|||
);
|
||||
|
||||
const getClientData = async (id) => {
|
||||
const { data } = await axios.get(`Clients/${id}`);
|
||||
client.value = data;
|
||||
try {
|
||||
const { data } = await axios.get(`Clients/${id}`);
|
||||
client.value = data;
|
||||
} catch (error) {
|
||||
return error;
|
||||
}
|
||||
};
|
||||
|
||||
const isDefaultAddress = (address) => {
|
||||
address.isDefaultAddress = client?.value?.defaultAddressFk === address.id ? 1 : 0;
|
||||
return address.isDefaultAddress;
|
||||
return client?.value?.defaultAddressFk === address.id ? 1 : 0;
|
||||
};
|
||||
|
||||
const setDefault = async (address) => {
|
||||
|
@ -95,35 +88,35 @@ const setDefault = async (address) => {
|
|||
});
|
||||
};
|
||||
|
||||
const sortAddresses = async (data) => {
|
||||
await getClientData(route.params.id);
|
||||
const sortAddresses = (data) => {
|
||||
if (!client.value || !data) return;
|
||||
addresses.value = data.sort((a, b) => {
|
||||
return isDefaultAddress(b) - isDefaultAddress(a);
|
||||
});
|
||||
openAddressForm();
|
||||
};
|
||||
|
||||
function openAddressForm() {
|
||||
if (route.query.addressId) {
|
||||
const address = addresses.value.find(
|
||||
(address) => address.id == +route.query.addressId,
|
||||
);
|
||||
if (address) {
|
||||
showFormEdit.value = true;
|
||||
showFormEditModel.value = address;
|
||||
}
|
||||
}
|
||||
}
|
||||
const toCustomerAddressCreate = () => {
|
||||
router.push({ name: 'CustomerAddressCreate' });
|
||||
};
|
||||
|
||||
const toCustomerAddressEdit = (addressId) => {
|
||||
router.push({
|
||||
name: 'CustomerAddressEdit',
|
||||
params: {
|
||||
id: route.params.id,
|
||||
addressId,
|
||||
},
|
||||
});
|
||||
};
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<FetchData
|
||||
ref="vnPaginateRef"
|
||||
@on-fetch="sortAddresses"
|
||||
auto-load
|
||||
data-key="CustomerAddresses"
|
||||
order="id DESC"
|
||||
ref="vnPaginateRef"
|
||||
:filter="addressFilter"
|
||||
:url="`Clients/${route.params.id}/addresses`"
|
||||
/>
|
||||
|
@ -138,7 +131,7 @@ function openAddressForm() {
|
|||
'q-mb-md': index < addresses.length - 1,
|
||||
'item-disabled': !item.isActive,
|
||||
}"
|
||||
@click="(showFormEdit = !showFormEdit) && (showFormEditModel = item)"
|
||||
@click="toCustomerAddressEdit(item.id)"
|
||||
>
|
||||
<div class="q-ml-xs q-mr-md flex items-center">
|
||||
<QIcon
|
||||
|
@ -151,7 +144,6 @@ function openAddressForm() {
|
|||
name="star"
|
||||
size="md"
|
||||
@click.stop="!isDefaultAddress(item) && setDefault(item)"
|
||||
data-cy="setDefaultAddress"
|
||||
>
|
||||
<QTooltip>
|
||||
{{
|
||||
|
@ -208,18 +200,19 @@ function openAddressForm() {
|
|||
v-for="(observation, obIndex) in item.observations"
|
||||
>
|
||||
<div class="text-weight-bold q-mr-sm">
|
||||
{{ observation?.observationType?.description }}:
|
||||
{{ observation.observationType.description }}:
|
||||
</div>
|
||||
<div>{{ observation?.description }}</div>
|
||||
<div>{{ observation.description }}</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</QCardSection>
|
||||
</QCard>
|
||||
</div>
|
||||
|
||||
<QPageSticky :offset="[18, 18]">
|
||||
<QBtn
|
||||
@click.stop="showFormCreate = !showFormCreate"
|
||||
@click.stop="toCustomerAddressCreate()"
|
||||
color="primary"
|
||||
fab
|
||||
icon="add"
|
||||
|
@ -229,28 +222,6 @@ function openAddressForm() {
|
|||
{{ t('New consignee') }}
|
||||
</QTooltip>
|
||||
</QPageSticky>
|
||||
<QDialog v-model="showFormEdit" :full-width="true">
|
||||
<CustomerAddressEdit
|
||||
:id="showFormEditModel.id"
|
||||
v-model="showFormEditModel"
|
||||
@on-data-saved="() => vnPaginateRef.fetch()"
|
||||
/>
|
||||
</QDialog>
|
||||
<QDialog v-model="showFormCreate" :full-width="true">
|
||||
<CustomerAddressForm
|
||||
:is-create="true"
|
||||
:form-initial-data="{
|
||||
isDefaultAddress: false,
|
||||
isActive: true,
|
||||
isEqualizated: false,
|
||||
isLogifloraAllowed: false,
|
||||
}"
|
||||
:observe-form-changes="false"
|
||||
:url-create="`Clients/${route.params.id}/createAddress`"
|
||||
model="client"
|
||||
@on-data-saved="() => vnPaginateRef.fetch()"
|
||||
/>
|
||||
</QDialog>
|
||||
</template>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
|
|
|
@ -1,28 +0,0 @@
|
|||
<script setup>
|
||||
import { useI18n } from 'vue-i18n';
|
||||
import VnDmsList from 'src/components/common/VnDmsList.vue';
|
||||
import { useArrayData } from 'src/composables/useArrayData';
|
||||
const arrayData = useArrayData('Customer');
|
||||
const { t } = useI18n();
|
||||
</script>
|
||||
<template>
|
||||
<VnDmsList
|
||||
v-if="arrayData?.store?.data"
|
||||
model="ClientDms"
|
||||
update-model="Clients"
|
||||
default-dms-code="paymentsLaw"
|
||||
filter="clientFk"
|
||||
:description="
|
||||
t('ClientFileDescription', {
|
||||
clientId: $route.params.id,
|
||||
clientName: arrayData.store.data.socialName,
|
||||
})
|
||||
"
|
||||
/>
|
||||
</template>
|
||||
<i18n>
|
||||
en:
|
||||
ClientFileDescription: Payment law from client {clientName} ID {clientId}
|
||||
es:
|
||||
ClientFileDescription: Ley de pagos del cliente {clientName} ID {clientId}
|
||||
</i18n>
|
|
@ -0,0 +1,269 @@
|
|||
<script setup>
|
||||
import { computed, ref } from 'vue';
|
||||
import { useI18n } from 'vue-i18n';
|
||||
import { useRoute, useRouter } from 'vue-router';
|
||||
|
||||
import { QBadge, QBtn, QCheckbox } from 'quasar';
|
||||
|
||||
import { downloadFile } from 'src/composables/downloadFile';
|
||||
import { toDateTimeFormat } from 'src/filters/date';
|
||||
|
||||
import FetchData from 'components/FetchData.vue';
|
||||
import WorkerDescriptorProxy from 'src/pages/Worker/Card/WorkerDescriptorProxy.vue';
|
||||
import CustomerFileManagementActions from 'src/pages/Customer/components/CustomerFileManagementActions.vue';
|
||||
|
||||
const { t } = useI18n();
|
||||
const route = useRoute();
|
||||
const router = useRouter();
|
||||
|
||||
const ClientDmsRef = ref(null);
|
||||
const rows = ref([]);
|
||||
|
||||
const filter = {
|
||||
include: {
|
||||
relation: 'dms',
|
||||
scope: {
|
||||
fields: [
|
||||
'dmsTypeFk',
|
||||
'reference',
|
||||
'hardCopyNumber',
|
||||
'workerFk',
|
||||
'description',
|
||||
'hasFile',
|
||||
'file',
|
||||
'created',
|
||||
],
|
||||
include: [
|
||||
{ relation: 'dmsType', scope: { fields: ['name'] } },
|
||||
{
|
||||
relation: 'worker',
|
||||
scope: {
|
||||
fields: ['id'],
|
||||
include: { relation: 'user', scope: { fields: ['name'] } },
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
where: { clientFk: route.params.id },
|
||||
order: ['dmsFk DESC'],
|
||||
limit: 20,
|
||||
};
|
||||
|
||||
const tableColumnComponents = {
|
||||
id: {
|
||||
component: 'span',
|
||||
props: () => {},
|
||||
event: () => {},
|
||||
},
|
||||
type: {
|
||||
component: 'span',
|
||||
props: () => {},
|
||||
event: () => {},
|
||||
},
|
||||
order: {
|
||||
component: QBadge,
|
||||
props: () => {},
|
||||
event: () => {},
|
||||
},
|
||||
reference: {
|
||||
component: 'span',
|
||||
props: () => {},
|
||||
event: () => {},
|
||||
},
|
||||
description: {
|
||||
component: 'span',
|
||||
props: () => {},
|
||||
event: () => {},
|
||||
},
|
||||
original: {
|
||||
component: QCheckbox,
|
||||
props: (prop) => ({
|
||||
disable: true,
|
||||
'model-value': Boolean(prop.value),
|
||||
}),
|
||||
event: () => {},
|
||||
},
|
||||
file: {
|
||||
component: QBtn,
|
||||
props: () => ({ flat: true }),
|
||||
event: ({ row }) => downloadFile(row.dmsFk),
|
||||
},
|
||||
employee: {
|
||||
component: QBtn,
|
||||
props: () => ({ flat: true }),
|
||||
event: () => {},
|
||||
},
|
||||
created: {
|
||||
component: 'span',
|
||||
props: () => {},
|
||||
event: () => {},
|
||||
},
|
||||
actions: {
|
||||
component: CustomerFileManagementActions,
|
||||
props: (prop) => ({
|
||||
id: prop.row.dmsFk,
|
||||
promise: setData,
|
||||
}),
|
||||
event: () => {},
|
||||
},
|
||||
};
|
||||
|
||||
const columns = computed(() => [
|
||||
{
|
||||
align: 'left',
|
||||
field: ({ dms }) => dms.id,
|
||||
label: t('Id'),
|
||||
name: 'id',
|
||||
},
|
||||
{
|
||||
align: 'left',
|
||||
field: ({ dms }) => dms.dmsType.name,
|
||||
label: t('Type'),
|
||||
name: 'type',
|
||||
},
|
||||
{
|
||||
align: 'left',
|
||||
field: ({ dms }) => dms.hardCopyNumber,
|
||||
label: t('Order'),
|
||||
name: 'order',
|
||||
},
|
||||
{
|
||||
align: 'left',
|
||||
field: ({ dms }) => dms.reference,
|
||||
label: t('Reference'),
|
||||
name: 'reference',
|
||||
},
|
||||
{
|
||||
align: 'left',
|
||||
field: ({ dms }) => dms.description,
|
||||
label: t('Description'),
|
||||
name: 'description',
|
||||
},
|
||||
{
|
||||
align: 'left',
|
||||
field: ({ dms }) => dms.hasFile,
|
||||
label: t('Original'),
|
||||
name: 'original',
|
||||
},
|
||||
{
|
||||
align: 'left',
|
||||
field: ({ dms }) => dms.file,
|
||||
label: t('File'),
|
||||
name: 'file',
|
||||
},
|
||||
{
|
||||
align: 'left',
|
||||
field: ({ dms }) => dms.worker.user.name,
|
||||
label: t('Employee'),
|
||||
name: 'employee',
|
||||
},
|
||||
{
|
||||
align: 'left',
|
||||
field: (value) => value.dms.created,
|
||||
label: t('Created'),
|
||||
name: 'created',
|
||||
format: (value) => toDateTimeFormat(value),
|
||||
},
|
||||
{
|
||||
align: 'right',
|
||||
field: 'actions',
|
||||
label: '',
|
||||
name: 'actions',
|
||||
},
|
||||
]);
|
||||
|
||||
const setData = () => {
|
||||
ClientDmsRef.value.fetch();
|
||||
};
|
||||
|
||||
const toCustomerFileManagementCreate = () => {
|
||||
router.push({ name: 'CustomerFileManagementCreate' });
|
||||
};
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<FetchData
|
||||
ref="ClientDmsRef"
|
||||
:filter="filter"
|
||||
@on-fetch="(data) => (rows = data)"
|
||||
auto-load
|
||||
url="ClientDms"
|
||||
/>
|
||||
|
||||
<QPage class="column items-center q-pa-md">
|
||||
<QTable
|
||||
:columns="columns"
|
||||
:pagination="{ rowsPerPage: 12 }"
|
||||
:rows="rows"
|
||||
class="full-width q-mt-md"
|
||||
row-key="id"
|
||||
v-if="rows?.length"
|
||||
>
|
||||
<template #body-cell="props">
|
||||
<QTd :props="props">
|
||||
<QTr :props="props" class="cursor-pointer">
|
||||
<component
|
||||
:is="
|
||||
props.col.name === 'order' && !props.value
|
||||
? 'span'
|
||||
: tableColumnComponents[props.col.name].component
|
||||
"
|
||||
@click="tableColumnComponents[props.col.name].event(props)"
|
||||
class="col-content"
|
||||
v-bind="tableColumnComponents[props.col.name].props(props)"
|
||||
>
|
||||
<template v-if="props.col.name !== 'original'">
|
||||
<span
|
||||
:class="{
|
||||
link:
|
||||
props.col.name === 'employee' ||
|
||||
props.col.name === 'file',
|
||||
}"
|
||||
>
|
||||
{{ props.value }}
|
||||
</span>
|
||||
</template>
|
||||
|
||||
<WorkerDescriptorProxy
|
||||
:id="props.row.dms.workerFk"
|
||||
v-if="props.col.name === 'employee'"
|
||||
/>
|
||||
</component>
|
||||
</QTr>
|
||||
</QTd>
|
||||
</template>
|
||||
</QTable>
|
||||
|
||||
<h5 class="flex justify-center color-vn-label" v-else>
|
||||
{{ t('globals.noResults') }}
|
||||
</h5>
|
||||
</QPage>
|
||||
|
||||
<QPageSticky :offset="[18, 18]">
|
||||
<QBtn
|
||||
@click.stop="toCustomerFileManagementCreate()"
|
||||
color="primary"
|
||||
fab
|
||||
v-shortcut="'+'"
|
||||
icon="add"
|
||||
/>
|
||||
<QTooltip>
|
||||
{{ t('Upload file') }}
|
||||
</QTooltip>
|
||||
</QPageSticky>
|
||||
</template>
|
||||
|
||||
<i18n>
|
||||
es:
|
||||
Id: Id
|
||||
Type: Tipo
|
||||
Order: Orden
|
||||
Reference: Referencia
|
||||
Description: Descripción
|
||||
Original: Original
|
||||
File: Fichero
|
||||
Employee: Empleado
|
||||
Created: Fecha creación
|
||||
Upload file: Subir fichero
|
||||
</i18n>
|
|
@ -19,7 +19,9 @@ const filter = {
|
|||
{ relation: 'user', scope: { fields: ['id', 'name'] } },
|
||||
{ relation: 'company', scope: { fields: ['code'] } },
|
||||
],
|
||||
where: { clientFk: route.params.id },
|
||||
order: ['created DESC'],
|
||||
limit: 20,
|
||||
};
|
||||
|
||||
const columns = computed(() => [
|
||||
|
@ -74,7 +76,6 @@ const tableRef = ref();
|
|||
data-key="CustomerSamples"
|
||||
auto-load
|
||||
:user-filter="filter"
|
||||
:filter="{ where: { clientFk: route.params.id } }"
|
||||
url="ClientSamples"
|
||||
:columns="columns"
|
||||
:disable-option="{ card: true }"
|
||||
|
|
|
@ -1,35 +1,36 @@
|
|||
<script setup>
|
||||
import { onBeforeMount, ref } from 'vue';
|
||||
import { reactive, ref } from 'vue';
|
||||
import { useI18n } from 'vue-i18n';
|
||||
import { useRoute } from 'vue-router';
|
||||
import { useRoute, useRouter } from 'vue-router';
|
||||
|
||||
import VnLocation from 'src/components/common/VnLocation.vue';
|
||||
import FetchData from 'components/FetchData.vue';
|
||||
import FormModel from 'components/FormModel.vue';
|
||||
import VnRow from 'components/ui/VnRow.vue';
|
||||
import VnInput from 'src/components/common/VnInput.vue';
|
||||
import VnSelect from 'src/components/common/VnSelect.vue';
|
||||
import VnSelectDialog from 'src/components/common/VnSelectDialog.vue';
|
||||
import CustomerNewCustomsAgent from 'src/pages/Customer/components/CustomerNewCustomsAgent.vue';
|
||||
import VnInputNumber from 'src/components/common/VnInputNumber.vue';
|
||||
import FormModelPopup from 'src/components/FormModelPopup.vue';
|
||||
|
||||
const { t } = useI18n();
|
||||
const route = useRoute();
|
||||
const urlUpdate = ref('');
|
||||
const router = useRouter();
|
||||
|
||||
const formInitialData = reactive({ isDefaultAddress: false });
|
||||
|
||||
const agencyModes = ref([]);
|
||||
const incoterms = ref([]);
|
||||
const customsAgents = ref([]);
|
||||
|
||||
const $props = defineProps({
|
||||
isCreate: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
});
|
||||
|
||||
onBeforeMount(() => {
|
||||
urlUpdate.value = `Clients/${route.params.id}/updateAddress/${route.params.addressId}`;
|
||||
});
|
||||
|
||||
const toCustomerAddress = () => {
|
||||
router.push({
|
||||
name: 'CustomerAddress',
|
||||
params: {
|
||||
id: route.params.id,
|
||||
},
|
||||
});
|
||||
};
|
||||
function handleLocation(data, location) {
|
||||
const { town, code, provinceFk, countryFk } = location ?? {};
|
||||
data.postalCode = code;
|
||||
|
@ -37,21 +38,33 @@ function handleLocation(data, location) {
|
|||
data.provinceFk = provinceFk;
|
||||
data.countryFk = countryFk;
|
||||
}
|
||||
|
||||
function onAgentCreated({ id, fiscalName }, data) {
|
||||
customsAgents.value.push({ id, fiscalName });
|
||||
data.customsAgentFk = id;
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<FetchData
|
||||
@on-fetch="(data) => (customsAgents = data)"
|
||||
auto-load
|
||||
url="CustomsAgents"
|
||||
/>
|
||||
<FetchData
|
||||
@on-fetch="(data) => (agencyModes = data)"
|
||||
auto-load
|
||||
url="AgencyModes/isActive"
|
||||
/>
|
||||
<FetchData @on-fetch="(data) => (incoterms = data)" auto-load url="Incoterms" />
|
||||
<FetchData
|
||||
@on-fetch="(data) => (customsAgents = data)"
|
||||
auto-load
|
||||
url="CustomsAgents"
|
||||
/>
|
||||
<FormModelPopup v-bind="$attrs" v-on="$attrs" :reload="false">
|
||||
|
||||
<FormModel
|
||||
:form-initial-data="formInitialData"
|
||||
:observe-form-changes="false"
|
||||
:url-create="`Clients/${route.params.id}/createAddress`"
|
||||
@on-data-saved="toCustomerAddress()"
|
||||
model="client"
|
||||
>
|
||||
<template #moreActions>
|
||||
<QBtn
|
||||
:label="t('globals.cancel')"
|
||||
|
@ -61,53 +74,34 @@ function handleLocation(data, location) {
|
|||
icon="close"
|
||||
/>
|
||||
</template>
|
||||
<template #form-inputs="{ data, validate }">
|
||||
|
||||
<template #form="{ data, validate }">
|
||||
<QCheckbox :label="t('Default')" v-model="data.isDefaultAddress" />
|
||||
|
||||
<VnRow>
|
||||
<QCheckbox
|
||||
:label="t('Default')"
|
||||
v-model="data.isDefaultAddress"
|
||||
checked-icon="star"
|
||||
unchecked-icon="star"
|
||||
indeterminate-icon="star"
|
||||
size="lg"
|
||||
color="primary"
|
||||
:class="{ 'fill-icon': !!data.isDefaultAddress }"
|
||||
data-cy="isDefaultAddress_form"
|
||||
<VnInput
|
||||
:label="t('Consignee')"
|
||||
required
|
||||
clearable
|
||||
v-model="data.nickname"
|
||||
/>
|
||||
<QCheckbox
|
||||
:label="t('Enabled')"
|
||||
v-model="data.isActive"
|
||||
data-cy="enabled_form"
|
||||
/>
|
||||
<QCheckbox
|
||||
:label="t('Is equalizated')"
|
||||
v-model="data.isEqualizated"
|
||||
data-cy="isEqualizated_form"
|
||||
/>
|
||||
<QCheckbox
|
||||
:label="t('Is Loginflora allowed')"
|
||||
v-model="data.isLogifloraAllowed"
|
||||
data-cy="isLoginfloraAllowed_form"
|
||||
|
||||
<VnInput
|
||||
:label="t('Street address')"
|
||||
clearable
|
||||
v-model="data.street"
|
||||
required
|
||||
/>
|
||||
</VnRow>
|
||||
<VnRow>
|
||||
<VnInput :label="t('Consignee')" clearable v-model="data.nickname" />
|
||||
<VnInput :label="t('Street')" clearable v-model="data.street" />
|
||||
</VnRow>
|
||||
<VnRow>
|
||||
<VnLocation
|
||||
:rules="validate('Worker.postcode')"
|
||||
:acls="[{ model: 'Town', props: '*', accessType: 'WRITE' }]"
|
||||
:location="{
|
||||
postcode: data.postalCode,
|
||||
city: data.city,
|
||||
province: data.province,
|
||||
country: data.province?.country,
|
||||
}"
|
||||
@update:model-value="(location) => handleLocation(data, location)"
|
||||
></VnLocation>
|
||||
</VnRow>
|
||||
<VnRow>
|
||||
|
||||
<VnLocation
|
||||
:rules="validate('Worker.postcode')"
|
||||
:acls="[{ model: 'Town', props: '*', accessType: 'WRITE' }]"
|
||||
v-model="data.location"
|
||||
@update:model-value="(location) => handleLocation(data, location)"
|
||||
/>
|
||||
|
||||
<div class="row justify-between q-gutter-md q-mb-md">
|
||||
<VnSelect
|
||||
:label="t('Agency')"
|
||||
:options="agencyModes"
|
||||
|
@ -116,10 +110,17 @@ function handleLocation(data, location) {
|
|||
option-label="name"
|
||||
option-value="id"
|
||||
v-model="data.agencyModeFk"
|
||||
class="col"
|
||||
/>
|
||||
<VnInput :label="t('Phone')" clearable v-model="data.phone" />
|
||||
<VnInput :label="t('Mobile')" clearable v-model="data.mobile" />
|
||||
</VnRow>
|
||||
<VnInput class="col" :label="t('Phone')" clearable v-model="data.phone" />
|
||||
<VnInput
|
||||
class="col"
|
||||
:label="t('Mobile')"
|
||||
clearable
|
||||
v-model="data.mobile"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<VnRow>
|
||||
<VnSelect
|
||||
:label="t('Incoterms')"
|
||||
|
@ -129,17 +130,23 @@ function handleLocation(data, location) {
|
|||
option-value="code"
|
||||
v-model="data.incotermsFk"
|
||||
/>
|
||||
|
||||
<VnSelectDialog
|
||||
url="CustomsAgents"
|
||||
:label="t('Customs agent')"
|
||||
:options="customsAgents"
|
||||
hide-selected
|
||||
option-label="fiscalName"
|
||||
option-value="id"
|
||||
v-model="data.customsAgentFk"
|
||||
:tooltip="t('New customs agent')"
|
||||
:tooltip="t('Create a new expense')"
|
||||
>
|
||||
<template #form>
|
||||
<CustomerNewCustomsAgent />
|
||||
<CustomerNewCustomsAgent
|
||||
@on-data-saved="
|
||||
(requestResponse) => onAgentCreated(requestResponse, data)
|
||||
"
|
||||
/>
|
||||
</template>
|
||||
</VnSelectDialog>
|
||||
</VnRow>
|
||||
|
@ -159,13 +166,13 @@ function handleLocation(data, location) {
|
|||
:positive="false"
|
||||
/>
|
||||
</VnRow>
|
||||
<slot name="more-form" :validate />
|
||||
</template>
|
||||
</FormModelPopup>
|
||||
</FormModel>
|
||||
</template>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.add-icon {
|
||||
cursor: pointer;
|
||||
background-color: $primary;
|
||||
border-radius: 50px;
|
||||
}
|
||||
|
@ -173,11 +180,9 @@ function handleLocation(data, location) {
|
|||
|
||||
<i18n>
|
||||
es:
|
||||
Enabled: Activo
|
||||
Is equalizated: Recargo de equivalencia
|
||||
Is Loginflora allowed: Compra directa en Holanda
|
||||
Default: Predeterminado
|
||||
Consignee: Consignatario
|
||||
Street: Dirección fiscal
|
||||
Street address: Dirección postal
|
||||
Postcode: Código postal
|
||||
City: Población
|
||||
Province: Provincia
|
||||
|
@ -186,17 +191,6 @@ es:
|
|||
Mobile: Movíl
|
||||
Incoterms: Incoterms
|
||||
Customs agent: Agente de aduanas
|
||||
New customs agent: Nuevo agente de aduanas
|
||||
Notes: Notas
|
||||
Observation type: Tipo de observación
|
||||
Description: Descripción
|
||||
Add note: Añadir nota
|
||||
Remove note: Eliminar nota
|
||||
Longitude: Longitud
|
||||
Latitude: Latitud
|
||||
confirmTicket: ¿Desea modificar también los estados de todos los tickets que están a punto de ser servidos?
|
||||
confirmDeletionMessage: Si le das a aceptar, se modificaran todas las notas de los ticket a futuro
|
||||
en:
|
||||
confirmTicket: Do you also want to modify the states of all the tickets that are about to be served?
|
||||
confirmDeletionMessage: If you click accept, all the notes of the future tickets will be modified
|
||||
</i18n>
|
|
@ -4,14 +4,16 @@ import { useI18n } from 'vue-i18n';
|
|||
import { useRoute, useRouter } from 'vue-router';
|
||||
import { useQuasar } from 'quasar';
|
||||
import axios from 'axios';
|
||||
import VnLocation from 'src/components/common/VnLocation.vue';
|
||||
import FetchData from 'components/FetchData.vue';
|
||||
import VnConfirm from 'components/ui/VnConfirm.vue';
|
||||
import CustomerAddressForm from './CustomerAddressForm.vue';
|
||||
import VnRow from 'src/components/ui/VnRow.vue';
|
||||
import FormModel from 'components/FormModel.vue';
|
||||
import VnRow from 'components/ui/VnRow.vue';
|
||||
import VnInput from 'src/components/common/VnInput.vue';
|
||||
import VnSelect from 'src/components/common/VnSelect.vue';
|
||||
|
||||
const emit = defineEmits(['onDataSaved']);
|
||||
import VnSelectDialog from 'src/components/common/VnSelectDialog.vue';
|
||||
import CustomerNewCustomsAgent from 'src/pages/Customer/components/CustomerNewCustomsAgent.vue';
|
||||
import VnInputNumber from 'src/components/common/VnInputNumber.vue';
|
||||
import VnConfirm from 'components/ui/VnConfirm.vue';
|
||||
|
||||
const { t } = useI18n();
|
||||
const route = useRoute();
|
||||
|
@ -20,31 +22,31 @@ const quasar = useQuasar();
|
|||
const urlUpdate = ref('');
|
||||
const agencyModes = ref([]);
|
||||
const incoterms = ref([]);
|
||||
const observationTypes = ref([]);
|
||||
const customsAgents = ref([]);
|
||||
const observationTypes = ref([]);
|
||||
const notes = ref([]);
|
||||
let originalNotes = [];
|
||||
const deletes = ref([]);
|
||||
|
||||
const model = defineModel({ type: Object });
|
||||
const notes = ref(model.value.observations || []);
|
||||
const $props = defineProps({
|
||||
id: {
|
||||
type: Number,
|
||||
required: true,
|
||||
},
|
||||
});
|
||||
|
||||
onBeforeMount(() => {
|
||||
urlUpdate.value = `Clients/${route.params.id}/updateAddress/${$props.id}`;
|
||||
urlUpdate.value = `Clients/${route.params.id}/updateAddress/${route.params.addressId}`;
|
||||
});
|
||||
|
||||
const getData = async (observations) => {
|
||||
observationTypes.value = observations;
|
||||
|
||||
if (observationTypes.value.length) {
|
||||
if (notes.value.length) {
|
||||
originalNotes = JSON.parse(JSON.stringify(notes.value));
|
||||
notes.value = notes.value
|
||||
const filter = {
|
||||
fields: ['id', 'addressFk', 'observationTypeFk', 'description'],
|
||||
where: { addressFk: `${route.params.addressId}` },
|
||||
};
|
||||
const { data } = await axios.get('AddressObservations', {
|
||||
params: { filter: JSON.stringify(filter) },
|
||||
});
|
||||
|
||||
if (data.length) {
|
||||
originalNotes = data;
|
||||
notes.value = originalNotes
|
||||
.map((observation) => {
|
||||
const type = observationTypes.value.find(
|
||||
(type) => type.id === observation.observationTypeFk,
|
||||
|
@ -54,7 +56,7 @@ const getData = async (observations) => {
|
|||
$isNew: false,
|
||||
$oldData: null,
|
||||
$orgIndex: null,
|
||||
addressFk: `${$props.id}`,
|
||||
addressFk: `${route.params.addressId}`,
|
||||
description: observation.description,
|
||||
id: observation.id,
|
||||
observationTypeFk: type.id,
|
||||
|
@ -66,6 +68,22 @@ const getData = async (observations) => {
|
|||
}
|
||||
};
|
||||
|
||||
const addNote = () => {
|
||||
notes.value.push({
|
||||
$isNew: true,
|
||||
$oldData: null,
|
||||
$orgIndex: null,
|
||||
addressFk: `${route.params.addressId}`,
|
||||
description: '',
|
||||
observationTypeFk: '',
|
||||
});
|
||||
};
|
||||
|
||||
const deleteNote = (id, index) => {
|
||||
deletes.value.push(id);
|
||||
notes.value.splice(index, 1);
|
||||
};
|
||||
|
||||
const updateAddress = async (data) => {
|
||||
await axios.patch(urlUpdate.value, data);
|
||||
};
|
||||
|
@ -98,9 +116,8 @@ function cleanPayload(payload) {
|
|||
async function updateAll({ data, payload }) {
|
||||
await updateObservations(payload);
|
||||
await updateAddress(data);
|
||||
emit('onDataSaved');
|
||||
toCustomerAddress();
|
||||
}
|
||||
|
||||
function getPayload() {
|
||||
return {
|
||||
creates: notes.value.filter((note) => note.$isNew),
|
||||
|
@ -145,21 +162,23 @@ async function handleDialog(data) {
|
|||
}
|
||||
}
|
||||
|
||||
const addNote = () => {
|
||||
notes.value.push({
|
||||
$isNew: true,
|
||||
$oldData: null,
|
||||
$orgIndex: null,
|
||||
addressFk: `${$props.id}`,
|
||||
description: '',
|
||||
observationTypeFk: '',
|
||||
const toCustomerAddress = () => {
|
||||
notes.value = [];
|
||||
deletes.value = [];
|
||||
router.push({
|
||||
name: 'CustomerAddress',
|
||||
params: {
|
||||
id: route.params.id,
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
const deleteNote = (id, index) => {
|
||||
deletes.value.push(id);
|
||||
notes.value.splice(index, 1);
|
||||
};
|
||||
function handleLocation(data, location) {
|
||||
const { town, code, provinceFk, countryFk } = location ?? {};
|
||||
data.postalCode = code;
|
||||
data.city = town;
|
||||
data.provinceFk = provinceFk;
|
||||
data.countryFk = countryFk;
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
|
@ -175,77 +194,207 @@ const deleteNote = (id, index) => {
|
|||
url="CustomsAgents"
|
||||
/>
|
||||
<FetchData @on-fetch="getData" auto-load url="ObservationTypes" />
|
||||
<CustomerAddressForm
|
||||
|
||||
<FormModel
|
||||
:observe-form-changes="false"
|
||||
:url-update="urlUpdate"
|
||||
:form-initial-data="model"
|
||||
:url="`Addresses/${route.params.addressId}`"
|
||||
:save-fn="handleDialog"
|
||||
auto-load
|
||||
>
|
||||
<template #more-form="{ validate }">
|
||||
<div class="column">
|
||||
<h4 class="q-mb-xs">{{ t('Notes') }}</h4>
|
||||
<VnRow
|
||||
v-if="!isPopup"
|
||||
:key="index"
|
||||
class="row q-gutter-md q-mb-md"
|
||||
v-for="(note, index) in notes"
|
||||
>
|
||||
<VnSelect
|
||||
:label="t('Observation type')"
|
||||
:options="observationTypes"
|
||||
hide-selected
|
||||
option-label="description"
|
||||
option-value="id"
|
||||
v-model="note.observationTypeFk"
|
||||
<template #moreActions>
|
||||
<QBtn
|
||||
:label="t('globals.cancel')"
|
||||
@click="toCustomerAddress"
|
||||
color="primary"
|
||||
flat
|
||||
icon="close"
|
||||
/>
|
||||
</template>
|
||||
|
||||
<template #form="{ data, validate }">
|
||||
<VnRow>
|
||||
<div class="col">
|
||||
<QCheckbox :label="t('Enabled')" v-model="data.isActive" />
|
||||
</div>
|
||||
<div class="col">
|
||||
<QCheckbox
|
||||
:label="t('Is equalizated')"
|
||||
v-model="data.isEqualizated"
|
||||
/>
|
||||
<VnInput
|
||||
:label="t('Description')"
|
||||
:rules="validate('route.description')"
|
||||
clearable
|
||||
v-model="note.description"
|
||||
</div>
|
||||
<div class="col">
|
||||
<QCheckbox
|
||||
:label="t('Is Loginflora allowed')"
|
||||
v-model="data.isLogifloraAllowed"
|
||||
/>
|
||||
<QIcon
|
||||
:style="{
|
||||
flex: 0,
|
||||
'align-self': $q.screen.gt.xs ? 'end' : 'center',
|
||||
</div>
|
||||
</VnRow>
|
||||
|
||||
<VnRow>
|
||||
<div class="col">
|
||||
<VnInput :label="t('Consignee')" clearable v-model="data.nickname" />
|
||||
</div>
|
||||
<div class="col">
|
||||
<VnInput :label="t('Street')" clearable v-model="data.street" />
|
||||
</div>
|
||||
</VnRow>
|
||||
|
||||
<VnRow>
|
||||
<div class="col">
|
||||
<VnLocation
|
||||
:rules="validate('Worker.postcode')"
|
||||
:acls="[{ model: 'Town', props: '*', accessType: 'WRITE' }]"
|
||||
:location="{
|
||||
postcode: data.postalCode,
|
||||
city: data.city,
|
||||
province: data.province,
|
||||
country: data.province?.country,
|
||||
}"
|
||||
@click.stop="deleteNote(note.id, index)"
|
||||
class="cursor-pointer"
|
||||
color="primary"
|
||||
name="delete"
|
||||
size="sm"
|
||||
>
|
||||
<QTooltip>
|
||||
{{ t('Remove note') }}
|
||||
</QTooltip>
|
||||
</QIcon>
|
||||
</VnRow>
|
||||
<QBtn
|
||||
@click.stop="addNote()"
|
||||
icon="add"
|
||||
v-shortcut="'+'"
|
||||
@update:model-value="(location) => handleLocation(data, location)"
|
||||
></VnLocation>
|
||||
</div>
|
||||
</VnRow>
|
||||
|
||||
<VnRow>
|
||||
<div class="col">
|
||||
<VnSelect
|
||||
:label="t('Agency')"
|
||||
:options="agencyModes"
|
||||
:rules="validate('route.agencyFk')"
|
||||
hide-selected
|
||||
option-label="name"
|
||||
option-value="id"
|
||||
v-model="data.agencyModeFk"
|
||||
/>
|
||||
</div>
|
||||
<div class="col">
|
||||
<VnInput :label="t('Phone')" clearable v-model="data.phone" />
|
||||
</div>
|
||||
<div class="col">
|
||||
<VnInput :label="t('Mobile')" clearable v-model="data.mobile" />
|
||||
</div>
|
||||
</VnRow>
|
||||
<VnRow>
|
||||
<VnSelect
|
||||
:label="t('Incoterms')"
|
||||
:options="incoterms"
|
||||
hide-selected
|
||||
option-label="name"
|
||||
option-value="code"
|
||||
v-model="data.incotermsFk"
|
||||
/>
|
||||
<VnSelectDialog
|
||||
:label="t('Customs agent')"
|
||||
:options="customsAgents"
|
||||
hide-selected
|
||||
option-label="fiscalName"
|
||||
option-value="id"
|
||||
v-model="data.customsAgentFk"
|
||||
:tooltip="t('New customs agent')"
|
||||
>
|
||||
<template #form>
|
||||
<CustomerNewCustomsAgent />
|
||||
</template>
|
||||
</VnSelectDialog>
|
||||
</VnRow>
|
||||
<VnRow>
|
||||
<VnInputNumber
|
||||
:label="t('Longitude')"
|
||||
clearable
|
||||
v-model="data.longitude"
|
||||
:decimal-places="7"
|
||||
:positive="false"
|
||||
/>
|
||||
<VnInputNumber
|
||||
:label="t('Latitude')"
|
||||
clearable
|
||||
v-model="data.latitude"
|
||||
:decimal-places="7"
|
||||
:positive="false"
|
||||
/>
|
||||
</VnRow>
|
||||
<h4 class="q-mb-xs">{{ t('Notes') }}</h4>
|
||||
<VnRow
|
||||
:key="index"
|
||||
class="row q-gutter-md q-mb-md"
|
||||
v-for="(note, index) in notes"
|
||||
>
|
||||
<VnSelect
|
||||
:label="t('Observation type')"
|
||||
:options="observationTypes"
|
||||
hide-selected
|
||||
option-label="description"
|
||||
option-value="id"
|
||||
v-model="note.observationTypeFk"
|
||||
/>
|
||||
<VnInput
|
||||
:label="t('Description')"
|
||||
:rules="validate('route.description')"
|
||||
clearable
|
||||
v-model="note.description"
|
||||
/>
|
||||
<QIcon
|
||||
:style="{ flex: 0, 'align-self': $q.screen.gt.xs ? 'end' : 'center' }"
|
||||
@click.stop="deleteNote(note.id, index)"
|
||||
class="cursor-pointer"
|
||||
color="primary"
|
||||
style="width: 10%"
|
||||
data-cy="addNoteBtn_form"
|
||||
name="delete"
|
||||
size="sm"
|
||||
>
|
||||
<QTooltip>
|
||||
{{ t('Add note') }}
|
||||
{{ t('Remove note') }}
|
||||
</QTooltip>
|
||||
</QBtn>
|
||||
</div>
|
||||
</QIcon>
|
||||
</VnRow>
|
||||
<QBtn
|
||||
@click.stop="addNote()"
|
||||
class="cursor-pointer add-icon q-mt-md"
|
||||
flat
|
||||
icon="add"
|
||||
v-shortcut="'+'"
|
||||
>
|
||||
<QTooltip>
|
||||
{{ t('Add note') }}
|
||||
</QTooltip>
|
||||
</QBtn>
|
||||
</template>
|
||||
</CustomerAddressForm>
|
||||
</FormModel>
|
||||
</template>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.add-icon {
|
||||
background-color: $primary;
|
||||
border-radius: 50px;
|
||||
}
|
||||
</style>
|
||||
|
||||
<i18n>
|
||||
es:
|
||||
Notes: Notas
|
||||
Observation type: Tipo de observación
|
||||
Description: Descripción
|
||||
Add note: Añadir nota
|
||||
Remove note: Eliminar nota
|
||||
confirmTicket: ¿Desea modificar también los estados de todos los tickets que están a punto de ser servidos?
|
||||
confirmDeletionMessage: Si le das a aceptar, se modificaran todas las notas de los ticket a futuro
|
||||
en:
|
||||
confirmTicket: Do you also want to modify the states of all the tickets that are about to be served?
|
||||
confirmDeletionMessage: If you click accept, all the notes of the future tickets will be modified
|
||||
es:
|
||||
Enabled: Activo
|
||||
Is equalizated: Recargo de equivalencia
|
||||
Is Loginflora allowed: Compra directa en Holanda
|
||||
Consignee: Consignatario
|
||||
Street: Dirección fiscal
|
||||
Postcode: Código postal
|
||||
City: Población
|
||||
Province: Provincia
|
||||
Agency: Agencia
|
||||
Phone: Teléfono
|
||||
Mobile: Movíl
|
||||
Incoterms: Incoterms
|
||||
Customs agent: Agente de aduanas
|
||||
New customs agent: Nuevo agente de aduanas
|
||||
Notes: Notas
|
||||
Observation type: Tipo de observación
|
||||
Description: Descripción
|
||||
Add note: Añadir nota
|
||||
Remove note: Eliminar nota
|
||||
Longitude: Longitud
|
||||
Latitude: Latitud
|
||||
confirmTicket: ¿Desea modificar también los estados de todos los tickets que están a punto de ser servidos?
|
||||
confirmDeletionMessage: Si le das a aceptar, se modificaran todas las notas de los ticket a futuro
|
||||
en:
|
||||
confirmTicket: Do you also want to modify the states of all the tickets that are about to be served?
|
||||
confirmDeletionMessage: If you click accept, all the notes of the future tickets will be modified
|
||||
</i18n>
|
||||
|
|
|
@ -0,0 +1,96 @@
|
|||
<script setup>
|
||||
import { useI18n } from 'vue-i18n';
|
||||
import { useRoute, useRouter } from 'vue-router';
|
||||
import { useQuasar } from 'quasar';
|
||||
|
||||
import { usePrintService } from 'composables/usePrintService';
|
||||
import { downloadFile } from 'src/composables/downloadFile';
|
||||
|
||||
import CustomerFileManagementDelete from 'src/pages/Customer/components/CustomerFileManagementDelete.vue';
|
||||
|
||||
const { t } = useI18n();
|
||||
const quasar = useQuasar();
|
||||
const route = useRoute();
|
||||
const router = useRouter();
|
||||
const { openReport } = usePrintService();
|
||||
const $props = defineProps({
|
||||
id: {
|
||||
type: Number,
|
||||
required: true,
|
||||
},
|
||||
promise: {
|
||||
type: Function,
|
||||
required: true,
|
||||
},
|
||||
});
|
||||
|
||||
const setDownloadFile = () => openReport(`dms/${$props.id}/downloadFile`, {}, '_blank');
|
||||
|
||||
const toCustomerFileManagementEdit = () => {
|
||||
router.push({
|
||||
name: 'CustomerFileManagementEdit',
|
||||
params: {
|
||||
id: route.params.id,
|
||||
dmsId: $props.id,
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
const showCustomerFileManagementDeleteDialog = () => {
|
||||
quasar.dialog({
|
||||
component: CustomerFileManagementDelete,
|
||||
componentProps: {
|
||||
id: $props.id,
|
||||
promise: setData,
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
const setData = () => {
|
||||
$props.promise();
|
||||
};
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div>
|
||||
<QIcon
|
||||
@click.stop="setDownloadFile"
|
||||
color="primary"
|
||||
name="cloud_download"
|
||||
size="sm"
|
||||
>
|
||||
<QTooltip>
|
||||
{{ t('actionFile', { action: t('globals.download') }) }}
|
||||
</QTooltip>
|
||||
</QIcon>
|
||||
<QIcon
|
||||
@click.stop="toCustomerFileManagementEdit"
|
||||
class="q-ml-md"
|
||||
color="primary"
|
||||
name="edit"
|
||||
size="sm"
|
||||
>
|
||||
<QTooltip>
|
||||
{{ t('actionFile', { action: t('globals.edit') }) }}
|
||||
</QTooltip>
|
||||
</QIcon>
|
||||
<QIcon
|
||||
@click.stop="showCustomerFileManagementDeleteDialog"
|
||||
class="q-ml-md"
|
||||
color="primary"
|
||||
name="delete"
|
||||
size="sm"
|
||||
>
|
||||
<QTooltip>
|
||||
{{ t('actionFile', { action: t('globals.remove') }) }}
|
||||
</QTooltip>
|
||||
</QIcon>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<i18n>
|
||||
en:
|
||||
actionFile: '{action} file'
|
||||
es:
|
||||
actionFile: '{action} fichero'
|
||||
</i18n>
|
|
@ -0,0 +1,260 @@
|
|||
<script setup>
|
||||
import { onBeforeMount, ref, watch } from 'vue';
|
||||
import { useI18n } from 'vue-i18n';
|
||||
import { useRoute, useRouter } from 'vue-router';
|
||||
|
||||
import axios from 'axios';
|
||||
|
||||
import { useState } from 'src/composables/useState';
|
||||
import { useValidator } from 'src/composables/useValidator';
|
||||
import useNotify from 'src/composables/useNotify';
|
||||
|
||||
import FetchData from 'components/FetchData.vue';
|
||||
import VnRow from 'components/ui/VnRow.vue';
|
||||
import VnSelect from 'src/components/common/VnSelect.vue';
|
||||
import VnInput from 'src/components/common/VnInput.vue';
|
||||
|
||||
const { notify } = useNotify();
|
||||
const { t } = useI18n();
|
||||
const { validate } = useValidator();
|
||||
const route = useRoute();
|
||||
const router = useRouter();
|
||||
const state = useState();
|
||||
const user = state.getUser();
|
||||
|
||||
const filterFindOne = { where: { code: 'paymentsLaw' } };
|
||||
const filterCompanies = { order: ['code'] };
|
||||
const filterWarehouses = { order: ['name'] };
|
||||
|
||||
const inputFileRef = ref();
|
||||
const client = ref({});
|
||||
const findOne = ref([]);
|
||||
const allowedContentTypes = ref([]);
|
||||
const optionsCompanies = ref([]);
|
||||
const optionsWarehouses = ref([]);
|
||||
const optionsDmsTypes = ref([]);
|
||||
const isLoading = ref(false);
|
||||
const dms = ref({
|
||||
hasFile: false,
|
||||
});
|
||||
|
||||
onBeforeMount(() => {
|
||||
const { companyFk, warehouseFk } = user.value;
|
||||
dms.value.reference = route.params.id;
|
||||
dms.value.companyId = companyFk;
|
||||
dms.value.warehouseId = warehouseFk;
|
||||
});
|
||||
|
||||
watch([client, findOne], ([newClient, newFindOne]) => {
|
||||
dms.value.description = t('clientFileDescription', {
|
||||
dmsTypeName: newFindOne.name?.toUpperCase(),
|
||||
clientName: newClient.name?.toUpperCase(),
|
||||
clientId: newClient.id,
|
||||
});
|
||||
dms.value.dmsTypeId = newFindOne.id;
|
||||
});
|
||||
|
||||
const saveData = async () => {
|
||||
try {
|
||||
const formData = new FormData();
|
||||
const files = dms.value.files;
|
||||
|
||||
if (files && files.length > 0) {
|
||||
for (let file of files) {
|
||||
formData.append(file.name, file);
|
||||
}
|
||||
dms.value.hasFileAttached = true;
|
||||
|
||||
const url = `clients/${route.params.id}/uploadFile`;
|
||||
await axios.post(url, formData, {
|
||||
params: dms.value,
|
||||
});
|
||||
notify('globals.dataSaved', 'positive');
|
||||
toCustomerFileManagement();
|
||||
}
|
||||
} catch (error) {
|
||||
notify(error.message, 'negative');
|
||||
}
|
||||
};
|
||||
|
||||
const toCustomerFileManagement = () => {
|
||||
router.push({ name: 'CustomerFileManagement' });
|
||||
};
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<FetchData
|
||||
@on-fetch="(data) => (client = data)"
|
||||
auto-load
|
||||
:url="`Clients/${route.params.id}/getCard`"
|
||||
/>
|
||||
<FetchData
|
||||
:filter="filterFindOne"
|
||||
@on-fetch="(data) => (findOne = data)"
|
||||
auto-load
|
||||
url="DmsTypes/findOne"
|
||||
/>
|
||||
<FetchData
|
||||
@on-fetch="(data) => (allowedContentTypes = data)"
|
||||
auto-load
|
||||
url="DmsContainers/allowedContentTypes"
|
||||
/>
|
||||
<FetchData
|
||||
:filter="filterCompanies"
|
||||
@on-fetch="(data) => (optionsCompanies = data)"
|
||||
auto-load
|
||||
url="Companies"
|
||||
/>
|
||||
<FetchData
|
||||
:filter="filterWarehouses"
|
||||
@on-fetch="(data) => (optionsWarehouses = data)"
|
||||
auto-load
|
||||
url="Warehouses"
|
||||
/>
|
||||
<FetchData
|
||||
:filter="filterWarehouses"
|
||||
@on-fetch="(data) => (optionsDmsTypes = data)"
|
||||
auto-load
|
||||
url="DmsTypes"
|
||||
/>
|
||||
|
||||
<Teleport to="#st-actions">
|
||||
<QBtnGroup push class="q-gutter-x-sm">
|
||||
<QBtn
|
||||
:disabled="isLoading"
|
||||
:label="t('globals.cancel')"
|
||||
:loading="isLoading"
|
||||
@click="toCustomerFileManagement"
|
||||
color="primary"
|
||||
flat
|
||||
icon="close"
|
||||
/>
|
||||
<QBtn
|
||||
:disabled="isLoading"
|
||||
:label="t('globals.save')"
|
||||
:loading="isLoading"
|
||||
@click.stop="saveData"
|
||||
color="primary"
|
||||
icon="save"
|
||||
/>
|
||||
</QBtnGroup>
|
||||
</Teleport>
|
||||
|
||||
<QCard class="q-pa-lg">
|
||||
<QCardSection>
|
||||
<QForm>
|
||||
<VnRow>
|
||||
<div class="col">
|
||||
<VnInput
|
||||
:label="t('Reference')"
|
||||
clearable
|
||||
v-model="dms.reference"
|
||||
/>
|
||||
</div>
|
||||
<div class="col">
|
||||
<VnSelect
|
||||
:label="t('Company')"
|
||||
:options="optionsCompanies"
|
||||
:rules="validate('entry.companyFk')"
|
||||
option-label="code"
|
||||
option-value="id"
|
||||
v-model="dms.companyId"
|
||||
/>
|
||||
</div>
|
||||
</VnRow>
|
||||
|
||||
<VnRow>
|
||||
<div class="col">
|
||||
<VnSelect
|
||||
:label="t('Warehouse')"
|
||||
:options="optionsWarehouses"
|
||||
option-label="name"
|
||||
option-value="id"
|
||||
v-model="dms.warehouseId"
|
||||
/>
|
||||
</div>
|
||||
<div class="col">
|
||||
<VnSelect
|
||||
:label="t('Type')"
|
||||
:options="optionsDmsTypes"
|
||||
option-label="name"
|
||||
option-value="id"
|
||||
v-model="dms.dmsTypeId"
|
||||
/>
|
||||
</div>
|
||||
</VnRow>
|
||||
|
||||
<VnRow>
|
||||
<div class="col">
|
||||
<VnInput
|
||||
:label="t('Description')"
|
||||
:rules="validate('route.description')"
|
||||
clearable
|
||||
type="textarea"
|
||||
v-model="dms.description"
|
||||
/>
|
||||
</div>
|
||||
</VnRow>
|
||||
|
||||
<VnRow>
|
||||
<div class="col">
|
||||
<QFile
|
||||
ref="inputFileRef"
|
||||
class="required"
|
||||
:label="t('File')"
|
||||
v-model="dms.files"
|
||||
multiple
|
||||
:accept="allowedContentTypes.join(',')"
|
||||
clearable
|
||||
clear-icon="close"
|
||||
>
|
||||
<template #append>
|
||||
<QBtn
|
||||
icon="vn:attach"
|
||||
flat
|
||||
round
|
||||
padding="xs"
|
||||
@click="inputFileRef.pickFiles()"
|
||||
>
|
||||
<QTooltip>
|
||||
{{ t('Select a file') }}
|
||||
</QTooltip>
|
||||
</QBtn>
|
||||
<QBtn icon="info" flat round padding="xs">
|
||||
<QTooltip max-width="30rem">
|
||||
{{
|
||||
`${t(
|
||||
'Allowed content types',
|
||||
)}: ${allowedContentTypes.join(', ')}`
|
||||
}}
|
||||
</QTooltip>
|
||||
</QBtn>
|
||||
</template>
|
||||
</QFile>
|
||||
</div>
|
||||
</VnRow>
|
||||
|
||||
<QCheckbox
|
||||
:label="t('Generate identifier for original file')"
|
||||
v-model="dms.hasFile"
|
||||
/>
|
||||
</QForm>
|
||||
</QCardSection>
|
||||
</QCard>
|
||||
</template>
|
||||
|
||||
<i18n>
|
||||
en:
|
||||
clientFileDescription: '{dmsTypeName} FROM CLIENT {clientName} ID {clientId}'
|
||||
es:
|
||||
Reference: Referencia
|
||||
Company: Empresa
|
||||
Warehouse: Almacén
|
||||
Type: Tipo
|
||||
Description: Descripción
|
||||
clientFileDescription: '{dmsTypeName} DEL CLIENTE {clientName} ID {clientId}'
|
||||
File: Fichero
|
||||
Select a file: Selecciona un fichero
|
||||
Allowed content types: Tipos de archivo permitidos
|
||||
Generate identifier for original file: Generar identificador para archivo original
|
||||
</i18n>
|
|
@ -0,0 +1,82 @@
|
|||
<script setup>
|
||||
import { ref } from 'vue';
|
||||
import { useI18n } from 'vue-i18n';
|
||||
|
||||
import { useDialogPluginComponent } from 'quasar';
|
||||
import axios from 'axios';
|
||||
|
||||
import useNotify from 'src/composables/useNotify';
|
||||
|
||||
const $props = defineProps({
|
||||
id: {
|
||||
type: Number,
|
||||
required: true,
|
||||
},
|
||||
promise: {
|
||||
type: Function,
|
||||
required: true,
|
||||
},
|
||||
});
|
||||
|
||||
const { dialogRef } = useDialogPluginComponent();
|
||||
const { notify } = useNotify();
|
||||
const { t } = useI18n();
|
||||
|
||||
const closeButton = ref(null);
|
||||
|
||||
const isLoading = ref(false);
|
||||
|
||||
const deleteDms = async () => {
|
||||
isLoading.value = true;
|
||||
try {
|
||||
await axios.post(`ClientDms/${$props.id}/removeFile`);
|
||||
if ($props.promise) await $props.promise();
|
||||
notify('globals.dataDeleted', 'positive');
|
||||
} catch (error) {
|
||||
notify(error.message, 'negative');
|
||||
} finally {
|
||||
closeButton.value.click();
|
||||
isLoading.value = false;
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<QDialog ref="dialogRef">
|
||||
<QCard class="q-pa-md q-mb-md">
|
||||
<span ref="closeButton" class="row justify-end close-icon" v-close-popup>
|
||||
<QIcon name="close" size="sm" />
|
||||
</span>
|
||||
|
||||
<QCardSection>
|
||||
<div class="mt-1 text-h6">{{ t('This file will be deleted') }}</div>
|
||||
<div>{{ t('Are you sure you want to continue?') }}</div>
|
||||
</QCardSection>
|
||||
|
||||
<QCardActions class="flex justify-end">
|
||||
<QBtn
|
||||
:disabled="isLoading"
|
||||
:label="t('globals.cancel')"
|
||||
:loading="isLoading"
|
||||
class="q-mr-xl"
|
||||
color="primary"
|
||||
flat
|
||||
v-close-popup
|
||||
/>
|
||||
<QBtn
|
||||
:disabled="isLoading"
|
||||
:label="t('globals.save')"
|
||||
:loading="isLoading"
|
||||
@click.stop="deleteDms"
|
||||
color="primary"
|
||||
/>
|
||||
</QCardActions>
|
||||
</QCard>
|
||||
</QDialog>
|
||||
</template>
|
||||
|
||||
<i18n>
|
||||
es:
|
||||
This file will be deleted: Este fichero va a ser borrado
|
||||
Are you sure you want to continue?: ¿Seguro que quieres continuar?
|
||||
</i18n>
|
|
@ -0,0 +1,237 @@
|
|||
<script setup>
|
||||
import { ref } from 'vue';
|
||||
import { useI18n } from 'vue-i18n';
|
||||
import { useRoute, useRouter } from 'vue-router';
|
||||
|
||||
import axios from 'axios';
|
||||
|
||||
import { useValidator } from 'src/composables/useValidator';
|
||||
import useNotify from 'src/composables/useNotify';
|
||||
|
||||
import FetchData from 'components/FetchData.vue';
|
||||
import VnRow from 'components/ui/VnRow.vue';
|
||||
import VnSelect from 'src/components/common/VnSelect.vue';
|
||||
import VnInput from 'src/components/common/VnInput.vue';
|
||||
|
||||
const { notify } = useNotify();
|
||||
const { t } = useI18n();
|
||||
const { validate } = useValidator();
|
||||
const route = useRoute();
|
||||
const router = useRouter();
|
||||
|
||||
const filterCompanies = { order: ['code'] };
|
||||
const filterWarehouses = { order: ['name'] };
|
||||
|
||||
const inputFileRef = ref();
|
||||
const allowedContentTypes = ref([]);
|
||||
const optionsCompanies = ref([]);
|
||||
const optionsWarehouses = ref([]);
|
||||
const optionsDmsTypes = ref([]);
|
||||
const isLoading = ref(false);
|
||||
const dms = ref({
|
||||
hasFile: true,
|
||||
});
|
||||
|
||||
const setCurrentDms = (data) => {
|
||||
dms.value.reference = data.reference;
|
||||
dms.value.companyId = data.companyFk;
|
||||
dms.value.warehouseId = data.warehouseFk;
|
||||
dms.value.dmsTypeId = data.dmsTypeFk;
|
||||
dms.value.description = data.description;
|
||||
};
|
||||
|
||||
const saveData = async () => {
|
||||
try {
|
||||
const formData = new FormData();
|
||||
const files = dms.value.files;
|
||||
|
||||
if (files && files.length > 0) {
|
||||
for (let file of files) {
|
||||
formData.append(file.name, file);
|
||||
}
|
||||
dms.value.hasFileAttached = true;
|
||||
|
||||
const url = `dms/${route.params.dmsId}/updateFile`;
|
||||
await axios.post(url, formData, {
|
||||
params: dms.value,
|
||||
});
|
||||
notify('globals.dataSaved', 'positive');
|
||||
toCustomerFileManagement();
|
||||
}
|
||||
} catch (error) {
|
||||
notify(error.message, 'negative');
|
||||
}
|
||||
};
|
||||
|
||||
const toCustomerFileManagement = () => {
|
||||
router.push({ name: 'CustomerFileManagement' });
|
||||
};
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<FetchData :url="`Dms/${route.params.dmsId}`" @on-fetch="setCurrentDms" auto-load />
|
||||
<FetchData
|
||||
@on-fetch="(data) => (allowedContentTypes = data)"
|
||||
auto-load
|
||||
url="DmsContainers/allowedContentTypes"
|
||||
/>
|
||||
<FetchData
|
||||
:filter="filterCompanies"
|
||||
@on-fetch="(data) => (optionsCompanies = data)"
|
||||
auto-load
|
||||
url="Companies"
|
||||
/>
|
||||
<FetchData
|
||||
:filter="filterWarehouses"
|
||||
@on-fetch="(data) => (optionsWarehouses = data)"
|
||||
auto-load
|
||||
url="Warehouses"
|
||||
/>
|
||||
<FetchData
|
||||
:filter="filterWarehouses"
|
||||
@on-fetch="(data) => (optionsDmsTypes = data)"
|
||||
auto-load
|
||||
url="DmsTypes"
|
||||
/>
|
||||
|
||||
<Teleport to="#st-actions">
|
||||
<QBtnGroup push class="q-gutter-x-sm">
|
||||
<QBtn
|
||||
:disabled="isLoading"
|
||||
:label="t('globals.cancel')"
|
||||
:loading="isLoading"
|
||||
@click="toCustomerFileManagement"
|
||||
color="primary"
|
||||
flat
|
||||
icon="close"
|
||||
/>
|
||||
<QBtn
|
||||
:disabled="isLoading"
|
||||
:label="t('globals.save')"
|
||||
:loading="isLoading"
|
||||
@click.stop="saveData"
|
||||
color="primary"
|
||||
icon="save"
|
||||
/>
|
||||
</QBtnGroup>
|
||||
</Teleport>
|
||||
|
||||
<QCard class="q-pa-lg">
|
||||
<QCardSection>
|
||||
<QForm>
|
||||
<VnRow>
|
||||
<div class="col">
|
||||
<VnInput
|
||||
:label="t('Reference')"
|
||||
clearable
|
||||
v-model="dms.reference"
|
||||
/>
|
||||
</div>
|
||||
<div class="col">
|
||||
<VnSelect
|
||||
:label="t('Company')"
|
||||
:options="optionsCompanies"
|
||||
:rules="validate('entry.companyFk')"
|
||||
option-label="code"
|
||||
option-value="id"
|
||||
v-model="dms.companyId"
|
||||
/>
|
||||
</div>
|
||||
</VnRow>
|
||||
|
||||
<VnRow>
|
||||
<div class="col">
|
||||
<VnSelect
|
||||
:label="t('Warehouse')"
|
||||
:options="optionsWarehouses"
|
||||
option-label="name"
|
||||
option-value="id"
|
||||
v-model="dms.warehouseId"
|
||||
/>
|
||||
</div>
|
||||
<div class="col">
|
||||
<VnSelect
|
||||
:label="t('Type')"
|
||||
:options="optionsDmsTypes"
|
||||
option-label="name"
|
||||
option-value="id"
|
||||
v-model="dms.dmsTypeId"
|
||||
/>
|
||||
</div>
|
||||
</VnRow>
|
||||
|
||||
<VnRow>
|
||||
<div class="col">
|
||||
<VnInput
|
||||
:label="t('Description')"
|
||||
:rules="validate('route.description')"
|
||||
clearable
|
||||
type="textarea"
|
||||
v-model="dms.description"
|
||||
/>
|
||||
</div>
|
||||
</VnRow>
|
||||
|
||||
<VnRow>
|
||||
<div class="col">
|
||||
<QFile
|
||||
ref="inputFileRef"
|
||||
class="required"
|
||||
:label="t('File')"
|
||||
v-model="dms.files"
|
||||
multiple
|
||||
:accept="allowedContentTypes.join(',')"
|
||||
clearable
|
||||
clear-icon="close"
|
||||
>
|
||||
<template #append>
|
||||
<QBtn
|
||||
icon="vn:attach"
|
||||
flat
|
||||
round
|
||||
padding="xs"
|
||||
@click="inputFileRef.pickFiles()"
|
||||
>
|
||||
<QTooltip>
|
||||
{{ t('Select a file') }}
|
||||
</QTooltip>
|
||||
</QBtn>
|
||||
<QBtn icon="info" flat round padding="xs">
|
||||
<QTooltip max-width="30rem">
|
||||
{{
|
||||
`${t(
|
||||
'Allowed content types',
|
||||
)}: ${allowedContentTypes.join(', ')}`
|
||||
}}
|
||||
</QTooltip>
|
||||
</QBtn>
|
||||
</template>
|
||||
</QFile>
|
||||
</div>
|
||||
</VnRow>
|
||||
|
||||
<QCheckbox
|
||||
:label="t('Generate identifier for original file')"
|
||||
v-model="dms.hasFile"
|
||||
disable
|
||||
/>
|
||||
</QForm>
|
||||
</QCardSection>
|
||||
</QCard>
|
||||
</template>
|
||||
|
||||
<i18n>
|
||||
en:
|
||||
clientFileDescription: '{dmsTypeName} FROM CLIENT {clientName} ID {clientId}'
|
||||
es:
|
||||
Reference: Referencia
|
||||
Company: Empresa
|
||||
Warehouse: Almacén
|
||||
Type: Tipo
|
||||
Description: Descripción
|
||||
clientFileDescription: '{dmsTypeName} DEL CLIENTE {clientName} ID {clientId}'
|
||||
File: Fichero
|
||||
Select a file: Selecciona un fichero
|
||||
Allowed content types: Tipos de archivo permitidos
|
||||
Generate identifier for original file: Generar identificador para archivo original
|
||||
</i18n>
|
|
@ -29,7 +29,7 @@ const saveData = async () => {
|
|||
finished: timestamp,
|
||||
};
|
||||
await axios.patch(`CreditClassifications/${$props.id}`, payload);
|
||||
await $props.promise();
|
||||
$props.promise();
|
||||
closeButton.value.click();
|
||||
};
|
||||
</script>
|
||||
|
|
|
@ -0,0 +1,135 @@
|
|||
<script setup>
|
||||
import { reactive, ref } from 'vue';
|
||||
import { useI18n } from 'vue-i18n';
|
||||
import { useRoute, useRouter } from 'vue-router';
|
||||
|
||||
import FormModel from 'components/FormModel.vue';
|
||||
import VnRow from 'components/ui/VnRow.vue';
|
||||
import VnSelect from 'src/components/common/VnSelect.vue';
|
||||
import FetchData from 'components/FetchData.vue';
|
||||
import VnSubToolbar from 'src/components/ui/VnSubToolbar.vue';
|
||||
import VnSearchbar from 'src/components/ui/VnSearchbar.vue';
|
||||
|
||||
import { useStateStore } from 'stores/useStateStore';
|
||||
import { useState } from 'src/composables/useState';
|
||||
import { toDate } from 'src/filters';
|
||||
import VnSelectSupplier from 'src/components/common/VnSelectSupplier.vue';
|
||||
|
||||
const state = useState();
|
||||
const { t } = useI18n();
|
||||
const route = useRoute();
|
||||
const router = useRouter();
|
||||
const stateStore = useStateStore();
|
||||
|
||||
const user = state.getUser();
|
||||
const newEntryForm = reactive({
|
||||
supplierFk: null,
|
||||
travelFk: Number(route.query?.travelFk) || null,
|
||||
companyFk: user.value.companyFk || null,
|
||||
});
|
||||
const travelsOptions = ref([]);
|
||||
const companiesOptions = ref([]);
|
||||
|
||||
const redirectToEntryBasicData = (_, { id }) => {
|
||||
router.push({ name: 'EntryBasicData', params: { id } });
|
||||
};
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<FetchData
|
||||
url="Travels/filter"
|
||||
:filter="{ fields: ['id', 'warehouseInName'] }"
|
||||
order="id"
|
||||
@on-fetch="(data) => (travelsOptions = data)"
|
||||
auto-load
|
||||
/>
|
||||
<FetchData
|
||||
ref="companiesRef"
|
||||
url="Companies"
|
||||
:filter="{ fields: ['id', 'code'] }"
|
||||
order="code"
|
||||
@on-fetch="(data) => (companiesOptions = data)"
|
||||
auto-load
|
||||
/>
|
||||
<template v-if="stateStore.isHeaderMounted()">
|
||||
<Teleport to="#searchbar">
|
||||
<VnSearchbar
|
||||
url="Entries/filter"
|
||||
custom-route-redirect-name="EntrySummary"
|
||||
data-key="Entry"
|
||||
:label="t('Search entries')"
|
||||
:info="t('You can search by entry reference')"
|
||||
/>
|
||||
</Teleport>
|
||||
</template>
|
||||
<QPage>
|
||||
<VnSubToolbar />
|
||||
<FormModel
|
||||
url-create="Entries"
|
||||
model="entry"
|
||||
:form-initial-data="newEntryForm"
|
||||
@on-data-saved="redirectToEntryBasicData"
|
||||
>
|
||||
<template #form="{ data, validate }">
|
||||
<VnRow>
|
||||
<VnSelectSupplier
|
||||
class="full-width"
|
||||
v-model="data.supplierFk"
|
||||
hide-selected
|
||||
:required="true"
|
||||
:rules="validate('entry.supplierFk')"
|
||||
/>
|
||||
</VnRow>
|
||||
<VnRow>
|
||||
<VnSelect
|
||||
:label="t('Travel')"
|
||||
class="full-width"
|
||||
v-model="data.travelFk"
|
||||
:options="travelsOptions"
|
||||
option-value="id"
|
||||
option-label="warehouseInName"
|
||||
map-options
|
||||
hide-selected
|
||||
:required="true"
|
||||
:rules="validate('entry.travelFk')"
|
||||
>
|
||||
<template #option="scope">
|
||||
<QItem v-bind="scope.itemProps">
|
||||
<QItemSection>
|
||||
<QItemLabel
|
||||
>{{ scope.opt?.agencyModeName }} -
|
||||
{{ scope.opt?.warehouseInName }} ({{
|
||||
toDate(scope.opt?.shipped)
|
||||
}}) → {{ scope.opt?.warehouseOutName }} ({{
|
||||
toDate(scope.opt?.landed)
|
||||
}})</QItemLabel
|
||||
>
|
||||
</QItemSection>
|
||||
</QItem>
|
||||
</template>
|
||||
</VnSelect>
|
||||
</VnRow>
|
||||
<VnRow>
|
||||
<VnSelect
|
||||
:label="t('Company')"
|
||||
class="full-width"
|
||||
v-model="data.companyFk"
|
||||
:options="companiesOptions"
|
||||
option-value="id"
|
||||
option-label="code"
|
||||
map-options
|
||||
hide-selected
|
||||
:required="true"
|
||||
:rules="validate('entry.companyFk')"
|
||||
/>
|
||||
</VnRow>
|
||||
</template>
|
||||
</FormModel>
|
||||
</QPage>
|
||||
</template>
|
||||
|
||||
<i18n>
|
||||
es:
|
||||
Travel: Envío
|
||||
Company: Empresa
|
||||
</i18n>
|
|
@ -73,6 +73,7 @@ const columns = computed(() => [
|
|||
optionLabel: 'code',
|
||||
options: companies.value,
|
||||
},
|
||||
orderBy: false,
|
||||
},
|
||||
{
|
||||
name: 'warehouse',
|
||||
|
|
|
@ -1,21 +1,16 @@
|
|||
<script setup>
|
||||
import { ref, computed, nextTick } from 'vue';
|
||||
import { ref, computed, markRaw } from 'vue';
|
||||
import { useRoute } from 'vue-router';
|
||||
import { useI18n } from 'vue-i18n';
|
||||
import { useArrayData } from 'src/composables/useArrayData';
|
||||
import { getTotal } from 'src/composables/getTotal';
|
||||
import { toCurrency } from 'src/filters';
|
||||
import FetchData from 'src/components/FetchData.vue';
|
||||
import VnSelect from 'src/components/common/VnSelect.vue';
|
||||
import CrudModel from 'src/components/CrudModel.vue';
|
||||
import VnInputNumber from 'src/components/common/VnInputNumber.vue';
|
||||
import VnSelectDialog from 'src/components/common/VnSelectDialog.vue';
|
||||
import CreateNewExpenseForm from 'src/components/CreateNewExpenseForm.vue';
|
||||
import { getExchange } from 'src/composables/getExchange';
|
||||
import { useAccountShortToStandard } from 'src/composables/useAccountShortToStandard';
|
||||
import VnTable from 'src/components/VnTable/VnTable.vue';
|
||||
import VnSelectExpense from 'src/components/common/VnSelectExpense.vue';
|
||||
|
||||
const { t } = useI18n();
|
||||
|
||||
const arrayData = useArrayData();
|
||||
const route = useRoute();
|
||||
const invoiceIn = computed(() => arrayData.store.data);
|
||||
|
@ -24,100 +19,142 @@ const expenses = ref([]);
|
|||
const sageTaxTypes = ref([]);
|
||||
const sageTransactionTypes = ref([]);
|
||||
const rowsSelected = ref([]);
|
||||
const invoiceInFormRef = ref();
|
||||
const invoiceInVatTableRef = ref();
|
||||
|
||||
defineProps({
|
||||
actionIcon: {
|
||||
type: String,
|
||||
default: 'add',
|
||||
},
|
||||
});
|
||||
defineProps({ actionIcon: { type: String, default: 'add' } });
|
||||
|
||||
function taxRate(invoiceInTax) {
|
||||
const sageTaxTypeId = invoiceInTax.taxTypeSageFk;
|
||||
const taxRateSelection = sageTaxTypes.value.find(
|
||||
(transaction) => transaction.id == sageTaxTypeId,
|
||||
);
|
||||
const taxTypeSage = taxRateSelection?.rate ?? 0;
|
||||
const taxableBase = invoiceInTax?.taxableBase ?? 0;
|
||||
|
||||
return (taxTypeSage / 100) * taxableBase;
|
||||
}
|
||||
|
||||
const columns = computed(() => [
|
||||
{
|
||||
name: 'expense',
|
||||
name: 'expenseFk',
|
||||
label: t('Expense'),
|
||||
field: (row) => row.expenseFk,
|
||||
options: expenses.value,
|
||||
model: 'expenseFk',
|
||||
optionValue: 'id',
|
||||
optionLabel: (row) => `${row.id}: ${row.name}`,
|
||||
component: markRaw(VnSelectExpense),
|
||||
format: (row) => {
|
||||
const expense = expenses.value.find((e) => e.id === row.expenseFk);
|
||||
return expense ? `${expense.id}: ${expense.name}` : row.expenseFk;
|
||||
},
|
||||
sortable: true,
|
||||
align: 'left',
|
||||
isEditable: true,
|
||||
create: true,
|
||||
width: '250px',
|
||||
},
|
||||
{
|
||||
name: 'taxablebase',
|
||||
name: 'taxableBase',
|
||||
label: t('Taxable base'),
|
||||
field: (row) => row.taxableBase,
|
||||
model: 'taxableBase',
|
||||
component: 'number',
|
||||
attrs: {
|
||||
clearable: true,
|
||||
'clear-icon': 'close',
|
||||
},
|
||||
sortable: true,
|
||||
align: 'left',
|
||||
isEditable: true,
|
||||
create: true,
|
||||
},
|
||||
{
|
||||
name: 'isDeductible',
|
||||
label: t('invoiceIn.isDeductible'),
|
||||
field: (row) => row.isDeductible,
|
||||
model: 'isDeductible',
|
||||
component: 'checkbox',
|
||||
align: 'center',
|
||||
isEditable: true,
|
||||
create: true,
|
||||
createAttrs: {
|
||||
defaultValue: true,
|
||||
},
|
||||
width: '100px',
|
||||
},
|
||||
{
|
||||
name: 'sageiva',
|
||||
name: 'taxTypeSageFk',
|
||||
label: t('Sage iva'),
|
||||
field: (row) => row.taxTypeSageFk,
|
||||
options: sageTaxTypes.value,
|
||||
model: 'taxTypeSageFk',
|
||||
optionValue: 'id',
|
||||
optionLabel: (row) => `${row.id}: ${row.vat}`,
|
||||
component: 'select',
|
||||
attrs: {
|
||||
options: sageTaxTypes.value,
|
||||
optionValue: 'id',
|
||||
optionLabel: (row) => `${row.id}: ${row.vat}`,
|
||||
filterOptions: ['id', 'vat'],
|
||||
'data-cy': 'vat-sageiva',
|
||||
},
|
||||
format: (row) => {
|
||||
const taxType = sageTaxTypes.value.find((t) => t.id === row.taxTypeSageFk);
|
||||
return taxType ? `${taxType.id}: ${taxType.vat}` : row.taxTypeSageFk;
|
||||
},
|
||||
sortable: true,
|
||||
align: 'left',
|
||||
isEditable: true,
|
||||
create: true,
|
||||
},
|
||||
{
|
||||
name: 'sagetransaction',
|
||||
name: 'transactionTypeSageFk',
|
||||
label: t('Sage transaction'),
|
||||
field: (row) => row.transactionTypeSageFk,
|
||||
options: sageTransactionTypes.value,
|
||||
model: 'transactionTypeSageFk',
|
||||
optionValue: 'id',
|
||||
optionLabel: (row) => `${row.id}: ${row.transaction}`,
|
||||
component: 'select',
|
||||
attrs: {
|
||||
options: sageTransactionTypes.value,
|
||||
optionValue: 'id',
|
||||
optionLabel: (row) => `${row.id}: ${row.transaction}`,
|
||||
filterOptions: ['id', 'transaction'],
|
||||
},
|
||||
format: (row) => {
|
||||
const transType = sageTransactionTypes.value.find(
|
||||
(t) => t.id === row.transactionTypeSageFk,
|
||||
);
|
||||
return transType
|
||||
? `${transType.id}: ${transType.transaction}`
|
||||
: row.transactionTypeSageFk;
|
||||
},
|
||||
sortable: true,
|
||||
align: 'left',
|
||||
isEditable: true,
|
||||
create: true,
|
||||
},
|
||||
{
|
||||
name: 'rate',
|
||||
label: t('Rate'),
|
||||
sortable: true,
|
||||
field: (row) => taxRate(row, row.taxTypeSageFk),
|
||||
sortable: false,
|
||||
format: (row) => taxRate(row).toFixed(2),
|
||||
align: 'left',
|
||||
},
|
||||
{
|
||||
name: 'foreignvalue',
|
||||
name: 'foreignValue',
|
||||
label: t('Foreign value'),
|
||||
component: 'number',
|
||||
sortable: true,
|
||||
field: (row) => row.foreignValue,
|
||||
align: 'left',
|
||||
create: true,
|
||||
disable: !isNotEuro(currency.value),
|
||||
},
|
||||
{
|
||||
name: 'total',
|
||||
label: 'Total',
|
||||
label: t('Total'),
|
||||
align: 'left',
|
||||
format: (row) => (Number(row.taxableBase || 0) + Number(taxRate(row))).toFixed(2),
|
||||
},
|
||||
]);
|
||||
|
||||
const tableRows = computed(
|
||||
() => invoiceInVatTableRef.value?.CrudModelRef?.formData || [],
|
||||
);
|
||||
const taxableBaseTotal = computed(() => {
|
||||
return getTotal(invoiceInFormRef.value.formData, 'taxableBase');
|
||||
return getTotal(tableRows.value, 'taxableBase');
|
||||
});
|
||||
|
||||
const taxRateTotal = computed(() => {
|
||||
return getTotal(invoiceInFormRef.value.formData, null, {
|
||||
cb: taxRate,
|
||||
});
|
||||
return tableRows.value.reduce((sum, row) => sum + Number(taxRate(row)), 0);
|
||||
});
|
||||
|
||||
const combinedTotal = computed(() => {
|
||||
return +taxableBaseTotal.value + +taxRateTotal.value;
|
||||
});
|
||||
|
||||
const filter = {
|
||||
const filter = computed(() => ({
|
||||
fields: [
|
||||
'id',
|
||||
'invoiceInFk',
|
||||
|
@ -131,389 +168,75 @@ const filter = {
|
|||
where: {
|
||||
invoiceInFk: route.params.id,
|
||||
},
|
||||
};
|
||||
}));
|
||||
|
||||
const isNotEuro = (code) => code != 'EUR';
|
||||
|
||||
function taxRate(invoiceInTax) {
|
||||
const sageTaxTypeId = invoiceInTax.taxTypeSageFk;
|
||||
const taxRateSelection = sageTaxTypes.value.find(
|
||||
(transaction) => transaction.id == sageTaxTypeId,
|
||||
async function handleForeignValueUpdate(val, row) {
|
||||
if (!isNotEuro(currency.value)) return;
|
||||
row.taxableBase = await getExchange(
|
||||
val,
|
||||
invoiceIn.value?.currencyFk,
|
||||
invoiceIn.value?.issued,
|
||||
);
|
||||
const taxTypeSage = taxRateSelection?.rate ?? 0;
|
||||
const taxableBase = invoiceInTax?.taxableBase ?? 0;
|
||||
|
||||
return ((taxTypeSage / 100) * taxableBase).toFixed(2);
|
||||
}
|
||||
|
||||
function autocompleteExpense(evt, row, col, ref) {
|
||||
const val = evt.target.value;
|
||||
if (!val) return;
|
||||
|
||||
const param = isNaN(val) ? row[col.model] : val;
|
||||
const lookup = expenses.value.find(
|
||||
({ id }) => id == useAccountShortToStandard(param),
|
||||
);
|
||||
|
||||
ref.vnSelectDialogRef.vnSelectRef.toggleOption(lookup);
|
||||
}
|
||||
|
||||
function setCursor(ref) {
|
||||
nextTick(() => {
|
||||
const select = ref.vnSelectDialogRef
|
||||
? ref.vnSelectDialogRef.vnSelectRef
|
||||
: ref.vnSelectRef;
|
||||
select.$el.querySelector('input').setSelectionRange(0, 0);
|
||||
});
|
||||
}
|
||||
</script>
|
||||
<template>
|
||||
<FetchData
|
||||
ref="expensesRef"
|
||||
url="Expenses"
|
||||
auto-load
|
||||
@on-fetch="(data) => (expenses = data)"
|
||||
/>
|
||||
<FetchData url="Expenses" auto-load @on-fetch="(data) => (expenses = data)" />
|
||||
<FetchData url="SageTaxTypes" auto-load @on-fetch="(data) => (sageTaxTypes = data)" />
|
||||
<FetchData
|
||||
url="sageTransactionTypes"
|
||||
auto-load
|
||||
@on-fetch="(data) => (sageTransactionTypes = data)"
|
||||
/>
|
||||
<CrudModel
|
||||
ref="invoiceInFormRef"
|
||||
<VnTable
|
||||
v-if="invoiceIn"
|
||||
ref="invoiceInVatTableRef"
|
||||
data-key="InvoiceInTaxes"
|
||||
url="InvoiceInTaxes"
|
||||
save-url="InvoiceInTaxes/crud"
|
||||
:filter="filter"
|
||||
:data-required="{ invoiceInFk: $route.params.id }"
|
||||
:insert-on-load="true"
|
||||
auto-load
|
||||
v-model:selected="rowsSelected"
|
||||
:go-to="`/invoice-in/${$route.params.id}/due-day`"
|
||||
:columns="columns"
|
||||
:is-editable="true"
|
||||
:table="{ selection: 'multiple', 'row-key': '$index' }"
|
||||
footer
|
||||
:right-search="false"
|
||||
:column-search="false"
|
||||
:disable-option="{ card: true }"
|
||||
class="q-pa-none"
|
||||
:create="{
|
||||
urlCreate: 'InvoiceInTaxes',
|
||||
title: t('Add tax'),
|
||||
formInitialData: { invoiceInFk: $route.params.id, isDeductible: true },
|
||||
onDataSaved: () => invoiceInVatTableRef.reload(),
|
||||
}"
|
||||
:crud-model="{ goTo: `/invoice-in/${$route.params.id}/due-day` }"
|
||||
>
|
||||
<template #body="{ rows }">
|
||||
<QTable
|
||||
v-model:selected="rowsSelected"
|
||||
selection="multiple"
|
||||
:columns="columns"
|
||||
:rows="rows"
|
||||
row-key="$index"
|
||||
:grid="$q.screen.lt.sm"
|
||||
>
|
||||
<template #body-cell-expense="{ row, col }">
|
||||
<QTd>
|
||||
<VnSelectDialog
|
||||
:ref="`expenseRef-${row.$index}`"
|
||||
v-model="row[col.model]"
|
||||
:options="col.options"
|
||||
:option-value="col.optionValue"
|
||||
:option-label="col.optionLabel"
|
||||
:filter-options="['id', 'name']"
|
||||
:tooltip="t('Create a new expense')"
|
||||
:acls="[
|
||||
{ model: 'Expense', props: '*', accessType: 'WRITE' },
|
||||
]"
|
||||
@keydown.tab.prevent="
|
||||
autocompleteExpense(
|
||||
$event,
|
||||
row,
|
||||
col,
|
||||
$refs[`expenseRef-${row.$index}`],
|
||||
)
|
||||
"
|
||||
@update:model-value="
|
||||
setCursor($refs[`expenseRef-${row.$index}`])
|
||||
"
|
||||
>
|
||||
<template #option="scope">
|
||||
<QItem v-bind="scope.itemProps">
|
||||
{{ `${scope.opt.id}: ${scope.opt.name}` }}
|
||||
</QItem>
|
||||
</template>
|
||||
<template #form>
|
||||
<CreateNewExpenseForm
|
||||
@on-data-saved="$refs.expensesRef.fetch()"
|
||||
/>
|
||||
</template>
|
||||
</VnSelectDialog>
|
||||
</QTd>
|
||||
</template>
|
||||
<template #body-cell-isDeductible="{ row }">
|
||||
<QTd align="center">
|
||||
<QCheckbox
|
||||
v-model="row.isDeductible"
|
||||
data-cy="isDeductible_checkbox"
|
||||
/>
|
||||
</QTd>
|
||||
</template>
|
||||
<template #body-cell-taxablebase="{ row }">
|
||||
<QTd shrink>
|
||||
<VnInputNumber
|
||||
clear-icon="close"
|
||||
v-model="row.taxableBase"
|
||||
clearable
|
||||
/>
|
||||
</QTd>
|
||||
</template>
|
||||
<template #body-cell-sageiva="{ row, col }">
|
||||
<QTd>
|
||||
<VnSelect
|
||||
:ref="`sageivaRef-${row.$index}`"
|
||||
v-model="row[col.model]"
|
||||
:options="col.options"
|
||||
:option-value="col.optionValue"
|
||||
:option-label="col.optionLabel"
|
||||
:filter-options="['id', 'vat']"
|
||||
data-cy="vat-sageiva"
|
||||
@update:model-value="
|
||||
setCursor($refs[`sageivaRef-${row.$index}`])
|
||||
"
|
||||
>
|
||||
<template #option="scope">
|
||||
<QItem v-bind="scope.itemProps">
|
||||
<QItemSection>
|
||||
<QItemLabel>{{ scope.opt.vat }}</QItemLabel>
|
||||
<QItemLabel>
|
||||
{{ `#${scope.opt.id}` }}
|
||||
</QItemLabel>
|
||||
</QItemSection>
|
||||
</QItem>
|
||||
</template>
|
||||
</VnSelect>
|
||||
</QTd>
|
||||
</template>
|
||||
<template #body-cell-sagetransaction="{ row, col }">
|
||||
<QTd>
|
||||
<VnSelect
|
||||
:ref="`sagetransactionRef-${row.$index}`"
|
||||
v-model="row[col.model]"
|
||||
:options="col.options"
|
||||
:option-value="col.optionValue"
|
||||
:option-label="col.optionLabel"
|
||||
:filter-options="['id', 'transaction']"
|
||||
@update:model-value="
|
||||
setCursor($refs[`sagetransactionRef-${row.$index}`])
|
||||
"
|
||||
>
|
||||
<template #option="scope">
|
||||
<QItem v-bind="scope.itemProps">
|
||||
<QItemSection>
|
||||
<QItemLabel>{{
|
||||
scope.opt.transaction
|
||||
}}</QItemLabel>
|
||||
<QItemLabel>
|
||||
{{ `#${scope.opt.id}` }}
|
||||
</QItemLabel>
|
||||
</QItemSection>
|
||||
</QItem>
|
||||
</template>
|
||||
</VnSelect>
|
||||
</QTd>
|
||||
</template>
|
||||
<template #body-cell-foreignvalue="{ row }">
|
||||
<QTd shrink>
|
||||
<VnInputNumber
|
||||
:class="{
|
||||
'no-pointer-events': !isNotEuro(currency),
|
||||
}"
|
||||
:disable="!isNotEuro(currency)"
|
||||
v-model="row.foreignValue"
|
||||
@update:model-value="
|
||||
async (val) => {
|
||||
if (!isNotEuro(currency)) return;
|
||||
row.taxableBase = await getExchange(
|
||||
val,
|
||||
row.currencyFk,
|
||||
invoiceIn.issued,
|
||||
);
|
||||
}
|
||||
"
|
||||
/>
|
||||
</QTd>
|
||||
</template>
|
||||
<template #bottom-row>
|
||||
<QTr class="bg">
|
||||
<QTd />
|
||||
<QTd />
|
||||
<QTd>
|
||||
{{ toCurrency(taxableBaseTotal) }}
|
||||
</QTd>
|
||||
<QTd />
|
||||
<QTd />
|
||||
<QTd />
|
||||
<QTd>
|
||||
{{ toCurrency(taxRateTotal) }}
|
||||
</QTd>
|
||||
<QTd />
|
||||
<QTd>
|
||||
{{ toCurrency(combinedTotal) }}
|
||||
</QTd>
|
||||
</QTr>
|
||||
</template>
|
||||
|
||||
<template #item="props">
|
||||
<div class="q-pa-xs col-xs-12 col-sm-6 grid-style-transition">
|
||||
<QCard bordered flat class="q-my-xs">
|
||||
<QCardSection>
|
||||
<QCheckbox v-model="props.selected" dense />
|
||||
</QCardSection>
|
||||
<QSeparator />
|
||||
<QList>
|
||||
<QItem>
|
||||
<VnSelectDialog
|
||||
:label="t('Expense')"
|
||||
class="full-width"
|
||||
v-model="props.row['expenseFk']"
|
||||
:options="expenses"
|
||||
option-value="id"
|
||||
:option-label="(row) => `${row.id}:${row.name}`"
|
||||
:filter-options="['id', 'name']"
|
||||
:tooltip="t('Create a new expense')"
|
||||
>
|
||||
<template #option="scope">
|
||||
<QItem v-bind="scope.itemProps">
|
||||
{{ `${scope.opt.id}: ${scope.opt.name}` }}
|
||||
</QItem>
|
||||
</template>
|
||||
<template #form>
|
||||
<CreateNewExpenseForm />
|
||||
</template>
|
||||
</VnSelectDialog>
|
||||
</QItem>
|
||||
<QItem>
|
||||
<VnInputNumber
|
||||
:label="t('Taxable base')"
|
||||
:class="{
|
||||
'no-pointer-events': isNotEuro(currency),
|
||||
}"
|
||||
class="full-width"
|
||||
:disable="isNotEuro(currency)"
|
||||
clear-icon="close"
|
||||
v-model="props.row.taxableBase"
|
||||
clearable
|
||||
/>
|
||||
</QItem>
|
||||
<QItem>
|
||||
<VnSelect
|
||||
:label="t('Sage iva')"
|
||||
class="full-width"
|
||||
v-model="props.row['taxTypeSageFk']"
|
||||
:options="sageTaxTypes"
|
||||
option-value="id"
|
||||
:option-label="(row) => `${row.id}:${row.vat}`"
|
||||
:filter-options="['id', 'vat']"
|
||||
>
|
||||
<template #option="scope">
|
||||
<QItem v-bind="scope.itemProps">
|
||||
<QItemSection>
|
||||
<QItemLabel>{{
|
||||
scope.opt.vat
|
||||
}}</QItemLabel>
|
||||
<QItemLabel>
|
||||
{{ `#${scope.opt.id}` }}
|
||||
</QItemLabel>
|
||||
</QItemSection>
|
||||
</QItem>
|
||||
</template>
|
||||
</VnSelect>
|
||||
</QItem>
|
||||
<QItem>
|
||||
<VnSelect
|
||||
class="full-width"
|
||||
v-model="props.row['transactionTypeSageFk']"
|
||||
:options="sageTransactionTypes"
|
||||
option-value="id"
|
||||
:option-label="
|
||||
(row) => `${row.id}:${row.transaction}`
|
||||
"
|
||||
:filter-options="['id', 'transaction']"
|
||||
>
|
||||
<template #option="scope">
|
||||
<QItem v-bind="scope.itemProps">
|
||||
<QItemSection>
|
||||
<QItemLabel>{{
|
||||
scope.opt.transaction
|
||||
}}</QItemLabel>
|
||||
<QItemLabel>
|
||||
{{ `#${scope.opt.id}` }}
|
||||
</QItemLabel>
|
||||
</QItemSection>
|
||||
</QItem>
|
||||
</template>
|
||||
</VnSelect>
|
||||
</QItem>
|
||||
<QItem>
|
||||
{{ toCurrency(taxRate(props.row), currency) }}
|
||||
</QItem>
|
||||
<QItem>
|
||||
<VnInputNumber
|
||||
:label="t('Foreign value')"
|
||||
class="full-width"
|
||||
:class="{
|
||||
'no-pointer-events': !isNotEuro(currency),
|
||||
}"
|
||||
:disable="!isNotEuro(currency)"
|
||||
v-model="props.row.foreignValue"
|
||||
/>
|
||||
</QItem>
|
||||
</QList>
|
||||
</QCard>
|
||||
</div>
|
||||
</template>
|
||||
</QTable>
|
||||
<template #column-footer-taxableBase>
|
||||
{{ toCurrency(taxableBaseTotal) }}
|
||||
</template>
|
||||
</CrudModel>
|
||||
<QPageSticky position="bottom-right" :offset="[25, 25]">
|
||||
<QBtn
|
||||
color="primary"
|
||||
icon="add"
|
||||
size="lg"
|
||||
v-shortcut="'+'"
|
||||
round
|
||||
@click="invoiceInFormRef.insert()"
|
||||
>
|
||||
<QTooltip>{{ t('Add tax') }}</QTooltip>
|
||||
</QBtn>
|
||||
</QPageSticky>
|
||||
<template #column-footer-rate>
|
||||
{{ toCurrency(taxRateTotal) }}
|
||||
</template>
|
||||
<template #column-footer-total>
|
||||
{{ toCurrency(combinedTotal) }}
|
||||
</template>
|
||||
</VnTable>
|
||||
</template>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.bg {
|
||||
background-color: var(--vn-light-gray);
|
||||
}
|
||||
@media (max-width: $breakpoint-xs) {
|
||||
.q-dialog {
|
||||
.q-card {
|
||||
&__section:not(:first-child) {
|
||||
.q-item {
|
||||
flex-direction: column;
|
||||
|
||||
.q-checkbox {
|
||||
margin-top: 2rem;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
.q-item {
|
||||
min-height: 0;
|
||||
}
|
||||
.default-icon {
|
||||
cursor: pointer;
|
||||
border-radius: 50px;
|
||||
background-color: $primary;
|
||||
}
|
||||
</style>
|
||||
<i18n>
|
||||
es:
|
||||
Expense: Gasto
|
||||
Create a new expense: Crear nuevo gasto
|
||||
Add tax: Crear gasto
|
||||
Add tax: Añadir Gasto/IVA # Changed label slightly
|
||||
Taxable base: Base imp.
|
||||
Sage tax: Sage iva
|
||||
Sage iva: Sage iva # Kept original label
|
||||
Sage transaction: Sage transacción
|
||||
Rate: Tasa
|
||||
Rate: Cuota # Changed label
|
||||
Foreign value: Divisa
|
||||
Total: Total
|
||||
invoiceIn.isDeductible: Deducible
|
||||
</i18n>
|
||||
|
|
|
@ -0,0 +1,101 @@
|
|||
<script setup>
|
||||
import { reactive, ref } from 'vue';
|
||||
import { useI18n } from 'vue-i18n';
|
||||
import { useRoute, useRouter } from 'vue-router';
|
||||
import FormModel from 'components/FormModel.vue';
|
||||
import VnRow from 'components/ui/VnRow.vue';
|
||||
import VnSelect from 'src/components/common/VnSelect.vue';
|
||||
import FetchData from 'components/FetchData.vue';
|
||||
import VnSubToolbar from 'src/components/ui/VnSubToolbar.vue';
|
||||
import VnSearchbar from 'src/components/ui/VnSearchbar.vue';
|
||||
import { useStateStore } from 'stores/useStateStore';
|
||||
import { useState } from 'src/composables/useState';
|
||||
import VnInputDate from 'src/components/common/VnInputDate.vue';
|
||||
import VnInput from 'src/components/common/VnInput.vue';
|
||||
import VnSelectSupplier from 'src/components/common/VnSelectSupplier.vue';
|
||||
|
||||
const state = useState();
|
||||
const { t } = useI18n();
|
||||
const route = useRoute();
|
||||
const router = useRouter();
|
||||
const stateStore = useStateStore();
|
||||
|
||||
const user = state.getUser();
|
||||
const newInvoiceIn = reactive({
|
||||
supplierFk: +route.query?.supplierFk || null,
|
||||
supplierRef: null,
|
||||
companyFk: user.value.companyFk || null,
|
||||
issued: Date.vnNew(),
|
||||
});
|
||||
const companies = ref([]);
|
||||
|
||||
const redirectToInvoiceInBasicData = (__, { id }) => {
|
||||
router.push({ name: 'InvoiceInBasicData', params: { id } });
|
||||
};
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<FetchData
|
||||
ref="companiesRef"
|
||||
url="Companies"
|
||||
:filter="{ fields: ['id', 'code'] }"
|
||||
order="code"
|
||||
@on-fetch="(data) => (companies = data)"
|
||||
auto-load
|
||||
/>
|
||||
<template v-if="stateStore.isHeaderMounted()">
|
||||
<Teleport to="#searchbar">
|
||||
<VnSearchbar
|
||||
custom-route-redirect-name="InvoiceInSummary"
|
||||
data-key="InvoiceInSummary"
|
||||
/>
|
||||
</Teleport>
|
||||
</template>
|
||||
<QPage>
|
||||
<VnSubToolbar />
|
||||
<FormModel
|
||||
url-create="InvoiceIns"
|
||||
model="InvoiceIn"
|
||||
:form-initial-data="newInvoiceIn"
|
||||
@on-data-saved="redirectToInvoiceInBasicData"
|
||||
>
|
||||
<template #form="{ data, validate }">
|
||||
<VnRow>
|
||||
<VnSelectSupplier
|
||||
v-model="data.supplierFk"
|
||||
hide-selected
|
||||
:required="true"
|
||||
:rules="validate('entry.supplierFk')"
|
||||
/>
|
||||
<VnInput
|
||||
:label="t('invoiceIn.list.supplierRef')"
|
||||
v-model="data.supplierRef"
|
||||
/>
|
||||
</VnRow>
|
||||
<VnRow>
|
||||
<VnSelect
|
||||
:label="t('Company')"
|
||||
v-model="data.companyFk"
|
||||
:options="companies"
|
||||
option-value="id"
|
||||
option-label="code"
|
||||
map-options
|
||||
hide-selected
|
||||
:required="true"
|
||||
:rules="validate('invoiceIn.companyFk')"
|
||||
/>
|
||||
<VnInputDate
|
||||
:label="t('invoiceIn.summary.issued')"
|
||||
v-model="data.issued"
|
||||
/>
|
||||
</VnRow>
|
||||
</template>
|
||||
</FormModel>
|
||||
</QPage>
|
||||
</template>
|
||||
|
||||
<i18n>
|
||||
es:
|
||||
Travel: Envío
|
||||
Company: Empresa
|
||||
</i18n>
|
|
@ -1,12 +1,11 @@
|
|||
<script setup>
|
||||
import { ref } from 'vue';
|
||||
import { Notify } from 'quasar';
|
||||
import { useI18n } from 'vue-i18n';
|
||||
import { useRouter } from 'vue-router';
|
||||
import VnInputPassword from 'src/components/common/VnInputPassword.vue';
|
||||
import { useSession } from 'src/composables/useSession';
|
||||
import { useLogin } from 'src/composables/useLogin';
|
||||
|
||||
import useNotify from 'src/composables/useNotify';
|
||||
import VnLogo from 'components/ui/VnLogo.vue';
|
||||
import VnInput from 'src/components/common/VnInput.vue';
|
||||
import axios from 'axios';
|
||||
|
@ -15,16 +14,14 @@ const session = useSession();
|
|||
const loginCache = useLogin();
|
||||
const router = useRouter();
|
||||
const { t } = useI18n();
|
||||
const { notify } = useNotify();
|
||||
|
||||
const username = ref('');
|
||||
const password = ref('');
|
||||
const keepLogin = ref(true);
|
||||
|
||||
async function onSubmit() {
|
||||
const params = {
|
||||
user: username.value,
|
||||
password: password.value,
|
||||
};
|
||||
const params = { user: username.value, password: password.value };
|
||||
try {
|
||||
const { data } = await axios.post('Accounts/login', params);
|
||||
if (!data) return;
|
||||
|
@ -33,11 +30,7 @@ async function onSubmit() {
|
|||
await session.setLogin(data);
|
||||
} catch (res) {
|
||||
if (res.response?.data?.error?.code === 'REQUIRES_2FA') {
|
||||
Notify.create({
|
||||
message: t('login.twoFactorRequired'),
|
||||
icon: 'phoneLink_lock',
|
||||
type: 'warning',
|
||||
});
|
||||
notify(t('login.twoFactorRequired'), 'warning', 'phoneLink_lock');
|
||||
params.keepLogin = keepLogin.value;
|
||||
loginCache.setUser(params);
|
||||
return router.push({
|
||||
|
@ -45,10 +38,7 @@ async function onSubmit() {
|
|||
query: router.currentRoute.value?.query,
|
||||
});
|
||||
}
|
||||
Notify.create({
|
||||
message: t('login.loginError'),
|
||||
type: 'negative',
|
||||
});
|
||||
throw res;
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
|
|
@ -0,0 +1,57 @@
|
|||
<script setup>
|
||||
import { reactive } from 'vue';
|
||||
import { useI18n } from 'vue-i18n';
|
||||
import { useRouter } from 'vue-router';
|
||||
|
||||
import VnSearchbar from 'components/ui/VnSearchbar.vue';
|
||||
import FormModel from 'components/FormModel.vue';
|
||||
import VnRow from 'components/ui/VnRow.vue';
|
||||
import VnInput from 'src/components/common/VnInput.vue';
|
||||
import VnSubToolbar from 'src/components/ui/VnSubToolbar.vue';
|
||||
|
||||
import { useStateStore } from 'stores/useStateStore';
|
||||
|
||||
const router = useRouter();
|
||||
const { t } = useI18n();
|
||||
const stateStore = useStateStore();
|
||||
|
||||
const newSupplierForm = reactive({
|
||||
name: null,
|
||||
});
|
||||
|
||||
const redirectToSupplierFiscalData = (_, responseData) => {
|
||||
router.push({ name: 'SupplierFiscalData', params: { id: responseData.id } });
|
||||
};
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<template v-if="stateStore.isHeaderMounted()">
|
||||
<Teleport to="#searchbar">
|
||||
<VnSearchbar
|
||||
data-key="SuppliersList"
|
||||
:limit="20"
|
||||
:label="t('Search suppliers')"
|
||||
/>
|
||||
</Teleport>
|
||||
</template>
|
||||
|
||||
<QPage>
|
||||
<VnSubToolbar />
|
||||
<FormModel
|
||||
url-create="Suppliers/newSupplier"
|
||||
model="supplier"
|
||||
:form-initial-data="newSupplierForm"
|
||||
@on-data-saved="redirectToSupplierFiscalData"
|
||||
>
|
||||
<template #form="{ data }">
|
||||
<VnRow>
|
||||
<VnInput
|
||||
v-model="data.name"
|
||||
:label="t('supplier.create.supplierName')"
|
||||
@keyup="newSupplierForm.name = newSupplierForm.name.toUpperCase()"
|
||||
/>
|
||||
</VnRow>
|
||||
</template>
|
||||
</FormModel>
|
||||
</QPage>
|
||||
</template>
|
|
@ -232,9 +232,8 @@ const onFormModelInit = () => {
|
|||
|
||||
const redirectToCustomerAddress = () => {
|
||||
router.push({
|
||||
name: 'CustomerAddress',
|
||||
params: { id: clientId.value },
|
||||
query: { addressId: addressId.value },
|
||||
name: 'CustomerAddressEditCard',
|
||||
params: { id: clientId.value, addressId: addressId.value },
|
||||
});
|
||||
};
|
||||
|
||||
|
|
|
@ -0,0 +1,200 @@
|
|||
<script setup>
|
||||
import { useRoute, useRouter } from 'vue-router';
|
||||
import { onBeforeMount, reactive, ref } from 'vue';
|
||||
import { useI18n } from 'vue-i18n';
|
||||
|
||||
import FormModel from 'components/FormModel.vue';
|
||||
import FetchData from 'components/FetchData.vue';
|
||||
import VnRow from 'components/ui/VnRow.vue';
|
||||
import VnSelect from 'components/common/VnSelect.vue';
|
||||
import VnInputDate from 'components/common/VnInputDate.vue';
|
||||
import VnSubToolbar from 'src/components/ui/VnSubToolbar.vue';
|
||||
import { getClient } from 'src/pages/Customer/composables/getClient';
|
||||
import { getAddresses } from 'src/pages/Customer/composables/getAddresses';
|
||||
import { getAgencies } from 'src/pages/Route/Agency/composables/getAgencies';
|
||||
|
||||
import { useState } from 'composables/useState';
|
||||
|
||||
const { t } = useI18n();
|
||||
const route = useRoute();
|
||||
const router = useRouter();
|
||||
const state = useState();
|
||||
const user = state.getUser();
|
||||
|
||||
const initialFormState = reactive({
|
||||
clientId: Number(route.query?.clientFk) || null,
|
||||
addressId: null,
|
||||
agencyModeId: null,
|
||||
warehouseId: user.value.warehouseFk,
|
||||
landed: null,
|
||||
});
|
||||
const clientOptions = ref([]);
|
||||
const agenciesOptions = ref([]);
|
||||
const addressesOptions = ref([]);
|
||||
const warehousesOptions = ref([]);
|
||||
const selectedClient = ref(null);
|
||||
|
||||
onBeforeMount(async () => {
|
||||
await onClientSelected(initialFormState);
|
||||
});
|
||||
|
||||
function resetAgenciesSelector(formData) {
|
||||
agenciesOptions.value = [];
|
||||
formData.agencyModeId = null;
|
||||
}
|
||||
|
||||
const fetchClient = async (formData) => {
|
||||
const response = await getClient(formData.clientId);
|
||||
if (!response) return;
|
||||
const [client] = response.data;
|
||||
selectedClient.value = client;
|
||||
};
|
||||
|
||||
const fetchAddresses = async (formData) => {
|
||||
const response = await getAddresses(formData.clientId);
|
||||
if (!response) return;
|
||||
addressesOptions.value = response.data;
|
||||
|
||||
const { defaultAddress } = selectedClient.value;
|
||||
formData.addressId = defaultAddress.id;
|
||||
};
|
||||
|
||||
const onClientSelected = async (formData) => {
|
||||
resetAgenciesSelector(formData);
|
||||
await fetchClient(formData);
|
||||
await fetchAddresses(formData);
|
||||
};
|
||||
|
||||
const fetchAvailableAgencies = async (formData) => {
|
||||
resetAgenciesSelector(formData);
|
||||
const response = await getAgencies(formData, selectedClient.value);
|
||||
if (!response) return;
|
||||
|
||||
const { options, agency } = response;
|
||||
if (options) agenciesOptions.value = options;
|
||||
if (agency) formData.agencyModeId = agency;
|
||||
};
|
||||
|
||||
const redirectToTicketList = (_, { id }) => {
|
||||
router.push({ name: 'TicketSummary', params: { id } });
|
||||
};
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<FetchData
|
||||
url="Clients"
|
||||
@on-fetch="(data) => (clientOptions = data)"
|
||||
:filter="{ fields: ['id', 'name', 'defaultAddressFk'], order: 'id' }"
|
||||
auto-load
|
||||
/>
|
||||
<FetchData
|
||||
url="Warehouses"
|
||||
@on-fetch="(data) => (warehousesOptions = data)"
|
||||
:where="{
|
||||
isForTicket: true,
|
||||
}"
|
||||
order="name"
|
||||
auto-load
|
||||
/>
|
||||
<VnSubToolbar />
|
||||
<div class="q-pa-md">
|
||||
<FormModel
|
||||
url-create="Tickets/new"
|
||||
model="ticket"
|
||||
:form-initial-data="initialFormState"
|
||||
@on-data-saved="redirectToTicketList"
|
||||
>
|
||||
<template #form="{ data }">
|
||||
<VnRow>
|
||||
<div class="col">
|
||||
<VnSelect
|
||||
:label="t('globals.client')"
|
||||
v-model="data.clientId"
|
||||
:options="clientOptions"
|
||||
option-value="id"
|
||||
option-label="name"
|
||||
hide-selected
|
||||
@update:model-value="(client) => onClientSelected(data)"
|
||||
>
|
||||
<template #option="scope">
|
||||
<QItem v-bind="scope.itemProps">
|
||||
<QItemSection>
|
||||
<QItemLabel>
|
||||
{{ scope.opt.name }}
|
||||
</QItemLabel>
|
||||
<QItemLabel caption>
|
||||
{{ `#${scope.opt.id}` }}
|
||||
</QItemLabel>
|
||||
</QItemSection>
|
||||
</QItem>
|
||||
</template>
|
||||
</VnSelect>
|
||||
</div>
|
||||
</VnRow>
|
||||
<VnRow>
|
||||
<div class="col">
|
||||
<VnSelect
|
||||
:label="t('ticket.create.address')"
|
||||
v-model="data.addressId"
|
||||
:options="addressesOptions"
|
||||
option-value="id"
|
||||
option-label="nickname"
|
||||
hide-selected
|
||||
:disable="!data.clientId"
|
||||
@update:model-value="() => fetchAvailableAgencies(data)"
|
||||
>
|
||||
<template #option="scope">
|
||||
<QItem v-bind="scope.itemProps">
|
||||
<QItemSection>
|
||||
<QItemLabel>
|
||||
{{ scope.opt.nickname }}
|
||||
</QItemLabel>
|
||||
<QItemLabel caption>
|
||||
{{ `${scope.opt.street}, ${scope.opt.city}` }}
|
||||
</QItemLabel>
|
||||
</QItemSection>
|
||||
</QItem>
|
||||
</template>
|
||||
</VnSelect>
|
||||
</div>
|
||||
</VnRow>
|
||||
<VnRow>
|
||||
<div class="col">
|
||||
<VnInputDate
|
||||
placeholder="dd-mm-aaa"
|
||||
:label="t('globals.landed')"
|
||||
v-model="data.landed"
|
||||
@update:model-value="() => fetchAvailableAgencies(data)"
|
||||
/>
|
||||
</div>
|
||||
</VnRow>
|
||||
<VnRow>
|
||||
<div class="col">
|
||||
<VnSelect
|
||||
:label="t('globals.warehouse')"
|
||||
v-model="data.warehouseId"
|
||||
:options="warehousesOptions"
|
||||
option-value="id"
|
||||
option-label="name"
|
||||
hide-selected
|
||||
@update:model-value="() => fetchAvailableAgencies(data)"
|
||||
/>
|
||||
</div>
|
||||
</VnRow>
|
||||
<VnRow>
|
||||
<div class="col">
|
||||
<VnSelect
|
||||
:label="t('globals.agency')"
|
||||
v-model="data.agencyModeId"
|
||||
:options="agenciesOptions"
|
||||
option-value="agencyModeFk"
|
||||
option-label="agencyMode"
|
||||
hide-selected
|
||||
:disable="!data.clientId || !data.landed || !data.warehouseId"
|
||||
/>
|
||||
</div>
|
||||
</VnRow>
|
||||
</template>
|
||||
</FormModel>
|
||||
</div>
|
||||
</template>
|
|
@ -21,21 +21,25 @@ const { t } = useI18n();
|
|||
const router = useRouter();
|
||||
const quasar = useQuasar();
|
||||
const { notify } = useNotify();
|
||||
const canDelete = computed(() => useAcl().hasAcl('Travel', '*', 'WRITE'));
|
||||
|
||||
function cloneTravel() {
|
||||
router.push({
|
||||
name: 'TravelList',
|
||||
query: { createForm: JSON.stringify($props.travel) },
|
||||
});
|
||||
}
|
||||
const redirectToCreateView = (queryParams) => {
|
||||
router.push({ name: 'TravelCreate', query: { travelData: queryParams } });
|
||||
};
|
||||
|
||||
async function cloneTravelWithEntries() {
|
||||
const cloneTravel = () => {
|
||||
const stringifiedTravelData = JSON.stringify($props.travel);
|
||||
redirectToCreateView(stringifiedTravelData);
|
||||
};
|
||||
|
||||
const cloneTravelWithEntries = async () => {
|
||||
const { data } = await axios.post(`Travels/${$props.travel.id}/cloneWithEntries`);
|
||||
notify('globals.dataSaved', 'positive');
|
||||
router.push({ name: 'TravelBasicData', params: { id: data.id } });
|
||||
}
|
||||
function openDeleteEntryDialog(id) {
|
||||
};
|
||||
|
||||
const canDelete = computed(() => useAcl().hasAcl('Travel', '*', 'WRITE'));
|
||||
|
||||
const openDeleteEntryDialog = (id) => {
|
||||
quasar
|
||||
.dialog({
|
||||
component: VnConfirm,
|
||||
|
@ -47,13 +51,13 @@ function openDeleteEntryDialog(id) {
|
|||
.onOk(async () => {
|
||||
await deleteTravel(id);
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
async function deleteTravel(id) {
|
||||
const deleteTravel = async (id) => {
|
||||
await axios.delete(`Travels/${id}`);
|
||||
router.push({ name: 'TravelList' });
|
||||
notify('globals.dataDeleted', 'positive');
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
||||
<template>
|
||||
|
@ -78,10 +82,7 @@ async function deleteTravel(id) {
|
|||
<QItem v-ripple clickable>
|
||||
<QItemSection>
|
||||
<RouterLink
|
||||
:to="{
|
||||
name: 'EntryList',
|
||||
query: { createForm: JSON.stringify({ travelFk: travel.id }) },
|
||||
}"
|
||||
:to="{ name: 'EntryCreate', query: { travelFk: travel.id } }"
|
||||
class="color-vn-text"
|
||||
>
|
||||
{{ t('travel.summary.AddEntry') }}
|
||||
|
|
|
@ -4,7 +4,7 @@ import { useRoute, useRouter } from 'vue-router';
|
|||
import { useI18n } from 'vue-i18n';
|
||||
import { useQuasar } from 'quasar';
|
||||
|
||||
import VnTable from 'src/components/VnTable/VnTable.vue';
|
||||
import VnPaginate from 'src/components/ui/VnPaginate.vue';
|
||||
import VnConfirm from 'components/ui/VnConfirm.vue';
|
||||
import FetchData from 'src/components/FetchData.vue';
|
||||
|
||||
|
@ -13,7 +13,6 @@ import useNotify from 'src/composables/useNotify.js';
|
|||
import { toDate, toCelsius } from 'src/filters';
|
||||
import { downloadFile } from 'src/composables/downloadFile';
|
||||
import { useArrayData } from 'src/composables/useArrayData';
|
||||
import TravelThermographsForm from './TravelThermographsForm.vue';
|
||||
|
||||
const route = useRoute();
|
||||
const quasar = useQuasar();
|
||||
|
@ -23,10 +22,8 @@ const { notify } = useNotify();
|
|||
|
||||
const travel = computed(() => useArrayData('Travel').store.data);
|
||||
const thermographPaginateRef = ref();
|
||||
const saveType= ref('create');
|
||||
const warehouses = ref([]);
|
||||
const showForm = ref(false);
|
||||
const formData = ref({});
|
||||
|
||||
const thermographFilter = {
|
||||
include: [
|
||||
{
|
||||
|
@ -41,21 +38,13 @@ const thermographFilter = {
|
|||
fields: ['id', 'name'],
|
||||
},
|
||||
},
|
||||
{
|
||||
relation: 'dms',
|
||||
},
|
||||
],
|
||||
where: { travelFk: route.params.id },
|
||||
order: ['created'],
|
||||
};
|
||||
|
||||
const TableColumns = computed(() => {
|
||||
return [
|
||||
{
|
||||
label: t('globals.id'),
|
||||
field: 'id',
|
||||
name: 'id',
|
||||
visible: false,
|
||||
},
|
||||
{
|
||||
label: t('globals.code'),
|
||||
field: 'thermographFk',
|
||||
|
@ -70,23 +59,23 @@ const TableColumns = computed(() => {
|
|||
},
|
||||
{
|
||||
label: t('travel.thermographs.carrier'),
|
||||
field: (row) => row.agencyMode?.name,
|
||||
name: 'agencyModeFk',
|
||||
align: 'left',
|
||||
format: (row) => row.agencyMode?.name,
|
||||
},
|
||||
{
|
||||
label: t('globals.maxTemperature'),
|
||||
field: 'maxTemperature',
|
||||
name: 'maxTemperature',
|
||||
align: 'left',
|
||||
format: ({ maxTemperature }) => toCelsius(maxTemperature),
|
||||
format: (val) => toCelsius(val),
|
||||
},
|
||||
{
|
||||
label: t('globals.minTemperature'),
|
||||
field: 'minTemperature',
|
||||
name: 'minTemperature',
|
||||
align: 'left',
|
||||
format: ({ minTemperature }) => toCelsius(minTemperature),
|
||||
format: (val) => toCelsius(val),
|
||||
},
|
||||
{
|
||||
label: t('globals.state'),
|
||||
|
@ -99,47 +88,60 @@ const TableColumns = computed(() => {
|
|||
field: 'warehouseFk',
|
||||
name: 'destination',
|
||||
align: 'left',
|
||||
format: ({ warehouseFk }) =>
|
||||
warehouses.value.find((warehouse) => warehouse.id === warehouseFk)?.name,
|
||||
format: (val) =>
|
||||
warehouses.value.find((warehouse) => warehouse.id === val)?.name,
|
||||
},
|
||||
{
|
||||
label: t('globals.created'),
|
||||
field: 'created',
|
||||
name: 'created',
|
||||
align: 'left',
|
||||
format: ({ created }) => toDate(created),
|
||||
format: (val) => toDate(val),
|
||||
},
|
||||
{
|
||||
name: 'downloadFile',
|
||||
align: 'left',
|
||||
columnFilter: false,
|
||||
},
|
||||
{
|
||||
name: 'editFile',
|
||||
align: 'left',
|
||||
columnFilter: false,
|
||||
},
|
||||
{
|
||||
name: 'removeThermograph',
|
||||
align: 'left',
|
||||
columnFilter: false,
|
||||
},
|
||||
];
|
||||
});
|
||||
|
||||
const openRemoveDialog = async (id) => {
|
||||
quasar.dialog({
|
||||
component: VnConfirm,
|
||||
componentProps: {
|
||||
message: t('Are you sure you want to remove the thermograph?'),
|
||||
promise: () => removeThermograph(id),
|
||||
},
|
||||
});
|
||||
quasar
|
||||
.dialog({
|
||||
component: VnConfirm,
|
||||
componentProps: {
|
||||
message: t('Are you sure you want to remove the thermograph?'),
|
||||
},
|
||||
})
|
||||
.onOk(async () => {
|
||||
await removeThermograph(id);
|
||||
});
|
||||
};
|
||||
|
||||
const redirectToThermographForm = (action, id) => {
|
||||
const routeDetails = {
|
||||
name: action === 'create' ? 'TravelThermographsCreate' : 'TravelThermographsEdit',
|
||||
};
|
||||
|
||||
if (action === 'edit' && id) {
|
||||
routeDetails.query = { id };
|
||||
} else if (action === 'create') {
|
||||
routeDetails.query = { agencyModeFk: travel.value?.agencyModeFk };
|
||||
}
|
||||
router.push(routeDetails);
|
||||
};
|
||||
|
||||
const removeThermograph = async (id) => {
|
||||
await axios.delete(`Travels/deleteThermograph?id=${id}`);
|
||||
await thermographPaginateRef.value.reload();
|
||||
await thermographPaginateRef.value.fetch();
|
||||
notify(t('Thermograph removed'), 'positive');
|
||||
};
|
||||
</script>
|
||||
|
@ -152,80 +154,75 @@ const removeThermograph = async (id) => {
|
|||
@on-fetch="(data) => (warehouses = data)"
|
||||
auto-load
|
||||
/>
|
||||
<VnTable
|
||||
<VnPaginate
|
||||
ref="thermographPaginateRef"
|
||||
data-key="TravelThermographs"
|
||||
url="TravelThermographs"
|
||||
:user-filter="thermographFilter"
|
||||
:filter="{ where: { travelFk: route.params.id } }"
|
||||
:columns="TableColumns"
|
||||
auto-load
|
||||
>
|
||||
<template #column-downloadFile="{ row }">
|
||||
<QIcon
|
||||
name="cloud_download"
|
||||
color="primary"
|
||||
size="sm"
|
||||
class="cursor-pointer"
|
||||
@click="downloadFile(row.dmsFk)"
|
||||
<template #body="{ rows }">
|
||||
<QTable
|
||||
:rows="rows"
|
||||
:columns="TableColumns"
|
||||
:no-data-label="t('No results')"
|
||||
row-key="id"
|
||||
class="full-width q-mt-md"
|
||||
>
|
||||
<QTooltip>{{ t('Download file') }}</QTooltip>
|
||||
</QIcon>
|
||||
<template #body-cell-downloadFile="{ row }">
|
||||
<QTd auto-width>
|
||||
<QIcon
|
||||
name="cloud_download"
|
||||
color="primary"
|
||||
size="sm"
|
||||
class="cursor-pointer"
|
||||
@click="downloadFile(row.dmsFk)"
|
||||
>
|
||||
<QTooltip>{{ t('Download file') }}</QTooltip>
|
||||
</QIcon>
|
||||
</QTd>
|
||||
</template>
|
||||
<template #body-cell-editFile="{ row }">
|
||||
<QTd auto-width>
|
||||
<QIcon
|
||||
name="edit"
|
||||
color="primary"
|
||||
size="sm"
|
||||
class="cursor-pointer"
|
||||
@click="redirectToThermographForm('edit', row.id)"
|
||||
>
|
||||
<QTooltip>{{ t('Edit file') }}</QTooltip>
|
||||
</QIcon>
|
||||
</QTd>
|
||||
</template>
|
||||
<template #body-cell-removeThermograph="{ row }">
|
||||
<QTd auto-width>
|
||||
<QIcon
|
||||
name="delete"
|
||||
color="primary"
|
||||
size="sm"
|
||||
class="cursor-pointer"
|
||||
@click="openRemoveDialog(row.id)"
|
||||
>
|
||||
<QTooltip>{{ t('Remove thermograph') }}</QTooltip>
|
||||
</QIcon>
|
||||
</QTd>
|
||||
</template>
|
||||
</QTable>
|
||||
</template>
|
||||
<template #column-editFile="{ row }">
|
||||
<QIcon
|
||||
name="edit"
|
||||
color="primary"
|
||||
size="sm"
|
||||
class="cursor-pointer"
|
||||
@click="
|
||||
() => {
|
||||
formData = row;
|
||||
showForm = !showForm;
|
||||
saveType = 'update';
|
||||
}
|
||||
"
|
||||
>
|
||||
<QTooltip>{{ t('Edit file') }}</QTooltip>
|
||||
</QIcon>
|
||||
</template>
|
||||
<template #column-removeThermograph="{ row }">
|
||||
<QIcon
|
||||
name="delete"
|
||||
color="primary"
|
||||
size="sm"
|
||||
class="cursor-pointer"
|
||||
@click="openRemoveDialog(row.id)"
|
||||
>
|
||||
<QTooltip>{{ t('Remove thermograph') }}</QTooltip>
|
||||
</QIcon>
|
||||
</template>
|
||||
</VnTable>
|
||||
</VnPaginate>
|
||||
<QPageSticky :offset="[20, 20]">
|
||||
<QBtn
|
||||
fab
|
||||
icon="add"
|
||||
color="primary"
|
||||
@click="
|
||||
() => {
|
||||
formData = { dms: {} };
|
||||
saveType = 'create';
|
||||
showForm = !showForm;
|
||||
}
|
||||
"
|
||||
@click="redirectToThermographForm('create')"
|
||||
v-shortcut="'+'"
|
||||
/>
|
||||
<QTooltip class="text-no-wrap">
|
||||
{{ t('Add thermograph') }}
|
||||
</QTooltip>
|
||||
</QPageSticky>
|
||||
<QDialog v-model="showForm">
|
||||
<TravelThermographsForm
|
||||
:form-initial-data="formData"
|
||||
:agencyModeFk="travel?.agencyModeFk"
|
||||
:save-type="saveType"
|
||||
/>
|
||||
</QDialog>
|
||||
</template>
|
||||
|
||||
<i18n>
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
<script setup>
|
||||
import { useI18n } from 'vue-i18n';
|
||||
import { ref, onBeforeMount, useAttrs } from 'vue';
|
||||
import { ref, onBeforeMount } from 'vue';
|
||||
import { useRoute, useRouter } from 'vue-router';
|
||||
|
||||
import FetchData from 'components/FetchData.vue';
|
||||
|
@ -11,14 +11,22 @@ import VnInput from 'src/components/common/VnInput.vue';
|
|||
import CreateThermographForm from 'src/components/CreateThermographForm.vue';
|
||||
|
||||
import { useState } from 'src/composables/useState';
|
||||
import { useStateStore } from 'stores/useStateStore';
|
||||
import axios from 'axios';
|
||||
import useNotify from 'src/composables/useNotify.js';
|
||||
import VnInputNumber from 'src/components/common/VnInputNumber.vue';
|
||||
import FormModelPopup from 'src/components/FormModelPopup.vue';
|
||||
|
||||
const attrs = useAttrs();
|
||||
const props = defineProps({
|
||||
viewAction: {
|
||||
type: String,
|
||||
default: 'create',
|
||||
},
|
||||
});
|
||||
|
||||
const stateStore = useStateStore();
|
||||
const { t } = useI18n();
|
||||
const route = useRoute();
|
||||
const router = useRouter();
|
||||
const state = useState();
|
||||
const { notify } = useNotify();
|
||||
|
||||
|
@ -29,27 +37,26 @@ const dmsTypesOptions = ref([]);
|
|||
const companiesOptions = ref([]);
|
||||
const warehousesOptions = ref([]);
|
||||
const temperaturesOptions = ref([]);
|
||||
const thermographForm = ref({});
|
||||
const inputFileRef = ref(null);
|
||||
const agencyModeOptions = ref([]);
|
||||
|
||||
const $props = defineProps({
|
||||
agencyModeFk: {
|
||||
type: Number,
|
||||
default: undefined,
|
||||
},
|
||||
saveType: {
|
||||
type: String,
|
||||
default: 'create',
|
||||
}
|
||||
});
|
||||
|
||||
onBeforeMount(async () => {
|
||||
if (!attrs['form-initial-data'].thermographFk) {
|
||||
await setCreateDefaultParams();
|
||||
if (props.viewAction === 'create') {
|
||||
setCreateDefaultParams();
|
||||
} else {
|
||||
await setEditDefaultParams();
|
||||
}
|
||||
|
||||
if (route.query.thermographData) {
|
||||
const thermographData = JSON.parse(route.query.thermographData);
|
||||
for (let key in thermographForm.value) {
|
||||
thermographForm.value[key] = thermographData[key];
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
async function fetchDmsTypes() {
|
||||
const fetchDmsTypes = async () => {
|
||||
const params = {
|
||||
filter: {
|
||||
where: { code: 'thermograph' },
|
||||
|
@ -57,79 +64,74 @@ async function fetchDmsTypes() {
|
|||
};
|
||||
const { data } = await axios.get('DmsTypes/findOne', { params });
|
||||
return data;
|
||||
}
|
||||
};
|
||||
|
||||
async function setCreateDefaultParams() {
|
||||
const setCreateDefaultParams = async () => {
|
||||
const dataResponse = await fetchDmsTypes();
|
||||
attrs['form-initial-data'].companyFk = user.value.companyFk;
|
||||
attrs['form-initial-data'].warehouseFk = user.value.warehouseFk;
|
||||
attrs['form-initial-data'].dms.reference = route.params.id;
|
||||
attrs['form-initial-data'].dms.dmsTypeFk = dataResponse.id;
|
||||
attrs['form-initial-data'].state = 'Ok';
|
||||
attrs['form-initial-data'].agencyModeFk = $props.agencyModeFk;
|
||||
attrs['form-initial-data'].dms.description = t(
|
||||
'travel.thermographs.travelFileDescription',
|
||||
{
|
||||
travelId: route.params.id,
|
||||
},
|
||||
).toUpperCase();
|
||||
}
|
||||
thermographForm.value.companyId = user.value.companyFk;
|
||||
thermographForm.value.warehouseId = user.value.warehouseFk;
|
||||
thermographForm.value.reference = route.params.id;
|
||||
thermographForm.value.dmsTypeId = dataResponse.id;
|
||||
thermographForm.value.state = 'Ok';
|
||||
thermographForm.value.agencyModeFk = +route.query.agencyModeFk;
|
||||
thermographForm.value.description = t('travel.thermographs.travelFileDescription', {
|
||||
travelId: route.params.id,
|
||||
}).toUpperCase();
|
||||
};
|
||||
|
||||
async function onSubmit(data) {
|
||||
const basicData = {
|
||||
state: data.result,
|
||||
reference: data.dms.reference,
|
||||
warehouseId: +data.warehouseFk,
|
||||
companyId: +data.dms.companyFk,
|
||||
dmsTypeId: +data.dms.dmsTypeFk,
|
||||
description: data.dms.description,
|
||||
hasFile: data.dms.hasFile,
|
||||
maxTemperature: +data.maxTemperature,
|
||||
minTemperature: +data.minTemperature,
|
||||
temperatureFk: data.temperatureFk,
|
||||
agencyModeFk: +data.agencyModeFk,
|
||||
};
|
||||
const setEditDefaultParams = async () => {
|
||||
const filterObj = { include: { relation: 'dms' } };
|
||||
const filter = encodeURIComponent(JSON.stringify(filterObj));
|
||||
const { data } = await axios.get(
|
||||
`TravelThermographs/${route.query.id}?filter=${filter}`,
|
||||
);
|
||||
|
||||
const updateData = {
|
||||
travelThermographFk: data.id,
|
||||
thermographFk: data.thermographFk,
|
||||
}
|
||||
|
||||
const createData = {
|
||||
travelThermographFk: data.thermographFk
|
||||
if (data) {
|
||||
thermographForm.value.thermographFk = data.thermographFk;
|
||||
thermographForm.value.state = data.result;
|
||||
thermographForm.value.reference = data.dms?.reference;
|
||||
thermographForm.value.warehouseId = data.warehouseFk;
|
||||
thermographForm.value.companyId = data.dms?.companyFk;
|
||||
thermographForm.value.dmsTypeId = data.dms?.dmsTypeFk;
|
||||
thermographForm.value.description = data.dms?.description || '';
|
||||
thermographForm.value.hasFile = data.dms?.hasFile;
|
||||
thermographForm.value.hasFileAttached = false;
|
||||
thermographForm.value.maxTemperature = data.maxTemperature;
|
||||
thermographForm.value.minTemperature = data.minTemperature;
|
||||
thermographForm.value.temperatureFk = data.temperatureFk;
|
||||
thermographForm.value.travelThermographFk = data.id;
|
||||
thermographForm.value.agencyModeFk = data.agencyModeFk;
|
||||
}
|
||||
};
|
||||
|
||||
const aditionalData = $props.saveType === 'create' ? createData : updateData
|
||||
|
||||
const dataParsed = {...basicData, ...aditionalData };
|
||||
|
||||
const onSubmit = async () => {
|
||||
const formData = new FormData();
|
||||
if (Array.isArray(data.files)) {
|
||||
dataParsed.hasFileAttached = true;
|
||||
data.files.forEach((file) => {
|
||||
if (Array.isArray(thermographForm.value.files)) {
|
||||
thermographForm.value.hasFileAttached = true;
|
||||
thermographForm.value.files.forEach((file) => {
|
||||
formData.append(file.name, file);
|
||||
});
|
||||
}
|
||||
delete data.files;
|
||||
|
||||
delete dataParsed.dms;
|
||||
delete thermographForm.value.files;
|
||||
await axios.post(`/travels/${route.params.id}/saveThermograph`, formData, {
|
||||
params: dataParsed,
|
||||
params: thermographForm.value,
|
||||
headers: {
|
||||
'Content-Type': 'multipart/form-data',
|
||||
},
|
||||
});
|
||||
router.push({ name: 'TravelThermographsIndex' });
|
||||
notify(t('Thermograph created'), 'positive');
|
||||
}
|
||||
};
|
||||
|
||||
async function onThermographCreated(newThermograph, data) {
|
||||
data = {
|
||||
const onThermographCreated = async (data) => {
|
||||
await fetchTravelThermographsRef.value.fetch();
|
||||
thermographForm.value = {
|
||||
...thermographForm.value,
|
||||
...data,
|
||||
...newThermograph,
|
||||
travelThermographFk: newThermograph.id,
|
||||
warehouseId: newThermograph.warehouseFk,
|
||||
travelThermographFk: data.id,
|
||||
warehouseId: data.warehouseFk,
|
||||
};
|
||||
}
|
||||
};
|
||||
</script>
|
||||
<template>
|
||||
<FetchData
|
||||
|
@ -165,134 +167,161 @@ async function onThermographCreated(newThermograph, data) {
|
|||
auto-load
|
||||
url="AgencyModeIncomings"
|
||||
/>
|
||||
<FormModelPopup
|
||||
v-if="attrs['form-initial-data'].dms?.dmsTypeFk"
|
||||
v-bind="$attrs"
|
||||
:observe-form-changes="viewAction === 'create'"
|
||||
:save-fn="(data) => onSubmit(data)"
|
||||
>
|
||||
<template #form-inputs="{ data }">
|
||||
<VnRow>
|
||||
<VnSelectDialog
|
||||
:label="t('travel.thermographs.thermograph')"
|
||||
v-model="data.thermographFk"
|
||||
url="TravelThermographs"
|
||||
:fields="['id', 'thermographFk']"
|
||||
:where="{
|
||||
or: [{ travelFk: null }, { travelFk: $route.params.id }],
|
||||
}"
|
||||
sort-by="thermographFk ASC"
|
||||
option-label="thermographFk"
|
||||
option-filter-value="thermographFk"
|
||||
:disable="!!$attrs['form-initial-data'].thermographFk"
|
||||
:tooltip="t('New thermograph')"
|
||||
:roles-allowed-to-create="['logistic']"
|
||||
data-key="travelThermographSelect"
|
||||
>
|
||||
<template #form>
|
||||
<CreateThermographForm
|
||||
@on-data-saved="
|
||||
(newThermograph) =>{
|
||||
onThermographCreated(newThermograph, data);
|
||||
}
|
||||
"
|
||||
|
||||
<QPage class="column items-center full-width">
|
||||
<QForm
|
||||
:form-initial-data="thermographForm"
|
||||
:observe-form-changes="viewAction === 'create'"
|
||||
:default-actions="true"
|
||||
@submit="onSubmit()"
|
||||
class="full-width"
|
||||
style="max-width: 800px"
|
||||
>
|
||||
<Teleport to="#st-actions" v-if="stateStore?.isSubToolbarShown()">
|
||||
<div>
|
||||
<QBtnGroup push class="q-gutter-x-sm">
|
||||
<slot name="moreActions" />
|
||||
<QBtn
|
||||
color="primary"
|
||||
icon="restart_alt"
|
||||
flat
|
||||
@click="reset()"
|
||||
:label="t('globals.reset')"
|
||||
/>
|
||||
</template>
|
||||
</VnSelectDialog>
|
||||
<VnInput v-model="data.result" :label="t('globals.state')" />
|
||||
</VnRow>
|
||||
<VnRow>
|
||||
<VnSelect
|
||||
:label="t('travel.thermographs.carrier')"
|
||||
v-model="data.agencyModeFk"
|
||||
:options="agencyModeOptions"
|
||||
option-value="id"
|
||||
option-label="name"
|
||||
/>
|
||||
<QBtn
|
||||
color="primary"
|
||||
icon="save"
|
||||
@click="onSubmit()"
|
||||
:label="t('globals.save')"
|
||||
/>
|
||||
</QBtnGroup>
|
||||
</div>
|
||||
</Teleport>
|
||||
<QCard class="q-pa-lg">
|
||||
<VnRow>
|
||||
<VnSelectDialog
|
||||
:label="t('travel.thermographs.thermograph')"
|
||||
v-model="thermographForm.travelThermographFk"
|
||||
url="TravelThermographs"
|
||||
:fields="['id', 'thermographFk']"
|
||||
:where="{
|
||||
or: [{ travelFk: null }, { travelFk: $route.params.id }],
|
||||
}"
|
||||
sort-by="thermographFk ASC"
|
||||
option-label="thermographFk"
|
||||
option-filter-value="thermographFk"
|
||||
:disable="viewAction === 'edit'"
|
||||
:tooltip="t('New thermograph')"
|
||||
:roles-allowed-to-create="['logistic']"
|
||||
data-key="travelThermographSelect"
|
||||
>
|
||||
<template #form>
|
||||
<CreateThermographForm
|
||||
@on-data-saved="onThermographCreated"
|
||||
/>
|
||||
</template>
|
||||
</VnSelectDialog>
|
||||
<VnInput
|
||||
v-model="thermographForm.state"
|
||||
:label="t('globals.state')"
|
||||
/>
|
||||
</VnRow>
|
||||
<VnRow>
|
||||
<VnSelect
|
||||
:label="t('travel.thermographs.carrier')"
|
||||
v-model="thermographForm.agencyModeFk"
|
||||
:options="agencyModeOptions"
|
||||
option-value="id"
|
||||
option-label="name"
|
||||
/>
|
||||
|
||||
<VnInput v-model="data.dms.reference" :label="t('globals.reference')" />
|
||||
</VnRow>
|
||||
<VnRow>
|
||||
<VnSelect
|
||||
:label="t('globals.type')"
|
||||
v-model="data.dms.dmsTypeFk"
|
||||
:options="dmsTypesOptions"
|
||||
option-value="id"
|
||||
option-label="name"
|
||||
/>
|
||||
<VnSelect
|
||||
:label="t('globals.company')"
|
||||
v-model="data.dms.companyFk"
|
||||
:options="companiesOptions"
|
||||
option-value="id"
|
||||
option-label="code"
|
||||
/>
|
||||
</VnRow>
|
||||
<VnRow>
|
||||
<VnSelect
|
||||
:label="t('globals.warehouse')"
|
||||
v-model="data.warehouseFk"
|
||||
:options="warehousesOptions"
|
||||
option-value="id"
|
||||
option-label="name"
|
||||
/>
|
||||
<VnSelect
|
||||
:label="t('travel.thermographs.temperature')"
|
||||
:options="temperaturesOptions"
|
||||
hide-selected
|
||||
option-label="name"
|
||||
option-value="code"
|
||||
v-model="data.temperatureFk"
|
||||
:required="true"
|
||||
/>
|
||||
</VnRow>
|
||||
<VnRow>
|
||||
<VnInputNumber
|
||||
v-model="data.maxTemperature"
|
||||
:label="t('globals.maxTemperature')"
|
||||
/>
|
||||
<VnInputNumber
|
||||
v-model="data.minTemperature"
|
||||
:label="t('globals.minTemperature')"
|
||||
/>
|
||||
</VnRow>
|
||||
<VnInput
|
||||
v-model="thermographForm.reference"
|
||||
:label="t('globals.reference')"
|
||||
/>
|
||||
</VnRow>
|
||||
<VnRow>
|
||||
<VnSelect
|
||||
:label="t('globals.type')"
|
||||
v-model="thermographForm.dmsTypeId"
|
||||
:options="dmsTypesOptions"
|
||||
option-value="id"
|
||||
option-label="name"
|
||||
/>
|
||||
<VnSelect
|
||||
:label="t('globals.company')"
|
||||
v-model="thermographForm.companyId"
|
||||
:options="companiesOptions"
|
||||
option-value="id"
|
||||
option-label="code"
|
||||
/>
|
||||
</VnRow>
|
||||
<VnRow>
|
||||
<VnSelect
|
||||
:label="t('globals.warehouse')"
|
||||
v-model="thermographForm.warehouseId"
|
||||
:options="warehousesOptions"
|
||||
option-value="id"
|
||||
option-label="name"
|
||||
/>
|
||||
<VnSelect
|
||||
:label="t('travel.thermographs.temperature')"
|
||||
:options="temperaturesOptions"
|
||||
hide-selected
|
||||
option-label="name"
|
||||
option-value="code"
|
||||
v-model="thermographForm.temperatureFk"
|
||||
:required="true"
|
||||
/>
|
||||
</VnRow>
|
||||
<VnRow>
|
||||
<VnInputNumber
|
||||
v-model="thermographForm.maxTemperature"
|
||||
:label="t('globals.maxTemperature')"
|
||||
/>
|
||||
<VnInputNumber
|
||||
v-model="thermographForm.minTemperature"
|
||||
:label="t('globals.minTemperature')"
|
||||
/>
|
||||
</VnRow>
|
||||
|
||||
<VnRow v-if="viewAction === 'edit'" class="row q-gutter-md q-mb-md">
|
||||
<QInput
|
||||
:label="t('globals.description')"
|
||||
type="textarea"
|
||||
v-model="data.description"
|
||||
fill-input
|
||||
/>
|
||||
</VnRow>
|
||||
<VnRow>
|
||||
<QFile
|
||||
ref="inputFileRef"
|
||||
:label="t('globals.file')"
|
||||
multiple
|
||||
:accept="allowedContentTypes"
|
||||
v-model="data.files"
|
||||
>
|
||||
<template #append>
|
||||
<QIcon
|
||||
name="vn:attach"
|
||||
class="cursor-pointer q-mr-sm"
|
||||
@click="inputFileRef.pickFiles()"
|
||||
>
|
||||
<QTooltip>{{ t('Select files') }}</QTooltip>
|
||||
</QIcon>
|
||||
<QIcon name="info" class="cursor-pointer">
|
||||
<QTooltip>{{
|
||||
t('globals.allowedFilesText', {
|
||||
allowedContentTypes: allowedContentTypes,
|
||||
})
|
||||
}}</QTooltip>
|
||||
</QIcon>
|
||||
</template>
|
||||
</QFile>
|
||||
</VnRow>
|
||||
</template>
|
||||
</FormModelPopup>
|
||||
<VnRow v-if="viewAction === 'edit'" class="row q-gutter-md q-mb-md">
|
||||
<QInput
|
||||
:label="t('globals.description')"
|
||||
type="textarea"
|
||||
v-model="thermographForm.description"
|
||||
fill-input
|
||||
/>
|
||||
</VnRow>
|
||||
<VnRow>
|
||||
<QFile
|
||||
ref="inputFileRef"
|
||||
:label="t('globals.file')"
|
||||
multiple
|
||||
:accept="allowedContentTypes"
|
||||
v-model="thermographForm.files"
|
||||
>
|
||||
<template #append>
|
||||
<QIcon
|
||||
name="vn:attach"
|
||||
class="cursor-pointer q-mr-sm"
|
||||
@click="inputFileRef.pickFiles()"
|
||||
>
|
||||
<QTooltip>{{ t('Select files') }}</QTooltip>
|
||||
</QIcon>
|
||||
<QIcon name="info" class="cursor-pointer">
|
||||
<QTooltip>{{
|
||||
t('globals.allowedFilesText', {
|
||||
allowedContentTypes: allowedContentTypes,
|
||||
})
|
||||
}}</QTooltip>
|
||||
</QIcon>
|
||||
</template>
|
||||
</QFile>
|
||||
</VnRow>
|
||||
</QCard>
|
||||
</QForm>
|
||||
</QPage>
|
||||
</template>
|
||||
<i18n>
|
||||
es:
|
||||
|
|
|
@ -0,0 +1,103 @@
|
|||
<script setup>
|
||||
import { useI18n } from 'vue-i18n';
|
||||
import { ref, onBeforeMount } from 'vue';
|
||||
import { useRoute, useRouter } from 'vue-router';
|
||||
|
||||
import FetchData from 'components/FetchData.vue';
|
||||
import VnSelect from 'src/components/common/VnSelect.vue';
|
||||
import FormModel from 'components/FormModel.vue';
|
||||
import VnRow from 'components/ui/VnRow.vue';
|
||||
import VnInput from 'src/components/common/VnInput.vue';
|
||||
import VnSubToolbar from 'src/components/ui/VnSubToolbar.vue';
|
||||
import VnInputDate from 'components/common/VnInputDate.vue';
|
||||
|
||||
const { t } = useI18n();
|
||||
const route = useRoute();
|
||||
const router = useRouter();
|
||||
|
||||
const agenciesOptions = ref([]);
|
||||
const warehousesOptions = ref([]);
|
||||
const viewAction = ref();
|
||||
|
||||
const newTravelForm = ref({});
|
||||
onBeforeMount(() => {
|
||||
viewAction.value = route.query.travelData ? 'clone' : 'create';
|
||||
|
||||
if (route.query.travelData) {
|
||||
const travelData = JSON.parse(route.query.travelData);
|
||||
|
||||
newTravelForm.value = { ...newTravelForm.value, ...travelData };
|
||||
delete newTravelForm.value.id;
|
||||
}
|
||||
});
|
||||
|
||||
const redirectToTravelBasicData = (_, { id }) => {
|
||||
router.push({ name: 'TravelBasicData', params: { id } });
|
||||
};
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<FetchData
|
||||
url="AgencyModes"
|
||||
:filter="{ fields: ['id', 'name'], order: ['name ASC'] }"
|
||||
@on-fetch="(data) => (agenciesOptions = data)"
|
||||
auto-load
|
||||
/>
|
||||
<FetchData
|
||||
url="Warehouses"
|
||||
@on-fetch="(data) => (warehousesOptions = data)"
|
||||
auto-load
|
||||
/>
|
||||
<QPage>
|
||||
<VnSubToolbar />
|
||||
<FormModel
|
||||
url-create="Travels"
|
||||
model="travelCreate"
|
||||
:form-initial-data="newTravelForm"
|
||||
:observe-form-changes="viewAction === 'create'"
|
||||
@on-data-saved="redirectToTravelBasicData"
|
||||
>
|
||||
<template #form="{ data }">
|
||||
<VnRow>
|
||||
<VnInput v-model="data.ref" :label="t('globals.reference')" />
|
||||
<VnSelect
|
||||
:label="t('globals.agency')"
|
||||
v-model="data.agencyModeFk"
|
||||
:options="agenciesOptions"
|
||||
option-value="agencyFk"
|
||||
option-label="name"
|
||||
hide-selected
|
||||
/>
|
||||
</VnRow>
|
||||
<VnRow>
|
||||
<VnInputDate v-model="data.shipped" :label="t('globals.shipped')" />
|
||||
<VnInputDate :label="t('globals.landed')" v-model="data.landed" />
|
||||
</VnRow>
|
||||
<VnRow>
|
||||
<VnSelect
|
||||
:label="t('globals.warehouseOut')"
|
||||
v-model="data.warehouseOutFk"
|
||||
:options="warehousesOptions"
|
||||
option-value="id"
|
||||
option-label="name"
|
||||
hide-selected
|
||||
:where="{
|
||||
isOrigin: true,
|
||||
}"
|
||||
/>
|
||||
<VnSelect
|
||||
:label="t('globals.warehouseIn')"
|
||||
v-model="data.warehouseInFk"
|
||||
:options="warehousesOptions"
|
||||
option-value="id"
|
||||
option-label="name"
|
||||
hide-selected
|
||||
:where="{
|
||||
isDestiny: true,
|
||||
}"
|
||||
/>
|
||||
</VnRow>
|
||||
</template>
|
||||
</FormModel>
|
||||
</QPage>
|
||||
</template>
|
|
@ -28,6 +28,19 @@ const $props = defineProps({
|
|||
});
|
||||
const entityId = computed(() => $props.id || route.params.id);
|
||||
|
||||
const cloneTravel = (travelData) => {
|
||||
const stringifiedTravelData = JSON.stringify(travelData);
|
||||
redirectToCreateView(stringifiedTravelData);
|
||||
};
|
||||
|
||||
const redirectToCreateView = (queryParams) => {
|
||||
router.push({ name: 'TravelCreate', query: { travelData: queryParams } });
|
||||
};
|
||||
|
||||
const redirectCreateEntryView = (travelData) => {
|
||||
router.push({ name: 'EntryCreate', query: { travelFk: travelData.id } });
|
||||
};
|
||||
|
||||
const columns = computed(() => [
|
||||
{
|
||||
name: 'status',
|
||||
|
@ -196,19 +209,6 @@ const columns = computed(() => [
|
|||
],
|
||||
},
|
||||
]);
|
||||
|
||||
function cloneTravel(travelData) {
|
||||
const data = { formInitialData: travelData };
|
||||
delete data.formInitialData.id;
|
||||
tableRef.value.openForm({ formInitialData: travelData });
|
||||
}
|
||||
|
||||
function redirectCreateEntryView(travelData) {
|
||||
router.push({
|
||||
name: 'EntryList',
|
||||
query: { createForm: JSON.stringify({ travelFk: travelData.id }) },
|
||||
});
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
|
|
|
@ -66,6 +66,8 @@ const excludeType = computed({
|
|||
const arrayData = useArrayData('ZoneEvents');
|
||||
|
||||
const exclusionGeoCreate = async () => {
|
||||
if (await zoneHasTickets(route.params.id, dated.value)) return;
|
||||
|
||||
const params = {
|
||||
zoneFk: parseInt(route.params.id),
|
||||
date: dated.value,
|
||||
|
@ -87,6 +89,8 @@ const exclusionCreate = async () => {
|
|||
};
|
||||
const zoneIds = props.zoneIds?.length ? props.zoneIds : [route.params.id];
|
||||
for (const id of zoneIds) {
|
||||
if (await zoneHasTickets(id, dated.value)) return;
|
||||
|
||||
const url = `Zones/${id}/exclusions`;
|
||||
let today = moment(dated.value);
|
||||
let lastDay = today.clone().add(nMonths, 'months').endOf('month');
|
||||
|
@ -123,6 +127,26 @@ const exclusionCreate = async () => {
|
|||
await refetchEvents();
|
||||
};
|
||||
|
||||
const zoneHasTickets = async (zoneId, date) => {
|
||||
const filter = {
|
||||
where: {
|
||||
zoneFk: zoneId,
|
||||
shipped: date,
|
||||
},
|
||||
};
|
||||
const params = { filter: JSON.stringify(filter) };
|
||||
const { data } = await axios.get('Tickets', { params });
|
||||
if (data.length > 0) {
|
||||
quasar.notify({
|
||||
message: t('eventsExclusionForm.cantCloseZone'),
|
||||
type: 'negative',
|
||||
});
|
||||
await refetchEvents();
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
};
|
||||
|
||||
const onSubmit = async () => {
|
||||
if (excludeType.value === 'all') exclusionCreate();
|
||||
else exclusionGeoCreate();
|
||||
|
|
|
@ -80,6 +80,7 @@ eventsExclusionForm:
|
|||
all: All
|
||||
specificLocations: Specific locations
|
||||
rootTreeLabel: Locations where it is not distributed
|
||||
cantCloseZone: Can not close this zone because there are tickets programmed for that day
|
||||
eventsInclusionForm:
|
||||
addEvent: Add event
|
||||
editEvent: Edit event
|
||||
|
|
|
@ -81,6 +81,7 @@ eventsExclusionForm:
|
|||
all: Todo
|
||||
specificLocations: Localizaciones concretas
|
||||
rootTreeLabel: Localizaciones en las que no se reparte
|
||||
cantCloseZone: No se puede cerrar la zona porque hay tickets programados para ese día
|
||||
eventsInclusionForm:
|
||||
addEvent: Añadir evento
|
||||
editEvent: Editar evento
|
||||
|
|
|
@ -75,6 +75,33 @@ const customerCard = {
|
|||
component: () =>
|
||||
import('src/pages/Customer/Card/CustomerAddress.vue'),
|
||||
},
|
||||
{
|
||||
path: 'create',
|
||||
name: 'CustomerAddressCreate',
|
||||
meta: {
|
||||
title: 'address-create',
|
||||
},
|
||||
component: () =>
|
||||
import('src/pages/Customer/components/CustomerAddressCreate.vue'),
|
||||
},
|
||||
{
|
||||
path: ':addressId',
|
||||
name: 'CustomerAddressEditCard',
|
||||
redirect: { name: 'CustomerAddressEdit' },
|
||||
children: [
|
||||
{
|
||||
path: 'edit',
|
||||
name: 'CustomerAddressEdit',
|
||||
meta: {
|
||||
title: 'addressEdit',
|
||||
},
|
||||
component: () =>
|
||||
import(
|
||||
'src/pages/Customer/components/CustomerAddressEdit.vue'
|
||||
),
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
|
@ -185,6 +212,14 @@ const customerCard = {
|
|||
'src/pages/Customer/Card/CustomerCreditContracts.vue'
|
||||
),
|
||||
},
|
||||
{
|
||||
path: 'create',
|
||||
name: 'CustomerCreditContractsCreate',
|
||||
component: () =>
|
||||
import(
|
||||
'src/pages/Customer/components/CustomerCreditContractsCreate.vue'
|
||||
),
|
||||
},
|
||||
{
|
||||
path: 'insurance/:creditId',
|
||||
name: 'CustomerCreditContractsInsurance',
|
||||
|
@ -239,9 +274,9 @@ const customerCard = {
|
|||
icon: 'vn:onlinepayment',
|
||||
},
|
||||
{
|
||||
name: 'CustomerDms',
|
||||
title: 'dms',
|
||||
icon: 'cloud_upload',
|
||||
name: 'CustomerFileManagement',
|
||||
title: 'fileManagement',
|
||||
icon: 'Upload',
|
||||
},
|
||||
{
|
||||
name: 'CustomerUnpaid',
|
||||
|
@ -274,6 +309,14 @@ const customerCard = {
|
|||
component: () =>
|
||||
import('src/pages/Customer/Card/CustomerSamples.vue'),
|
||||
},
|
||||
{
|
||||
path: 'create',
|
||||
name: 'CustomerSamplesCreate',
|
||||
component: () =>
|
||||
import(
|
||||
'src/pages/Customer/components/CustomerSamplesCreate.vue'
|
||||
),
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
|
@ -313,12 +356,47 @@ const customerCard = {
|
|||
import('src/pages/Customer/Card/CustomerWebPayment.vue'),
|
||||
},
|
||||
{
|
||||
path: 'dms',
|
||||
name: 'CustomerDms',
|
||||
path: 'file-management',
|
||||
name: 'CustomerFileManagement',
|
||||
meta: {
|
||||
title: 'dms',
|
||||
title: 'fileManagement',
|
||||
},
|
||||
component: () => import('src/pages/Customer/Card/CustomerDms.vue'),
|
||||
component: () =>
|
||||
import('src/pages/Customer/Card/CustomerFileManagement.vue'),
|
||||
},
|
||||
{
|
||||
path: 'file-management',
|
||||
name: 'CustomerFileManagementCard',
|
||||
redirect: { name: 'CustomerFileManagement' },
|
||||
children: [
|
||||
{
|
||||
path: '',
|
||||
name: 'CustomerFileManagement',
|
||||
meta: {
|
||||
title: 'fileManagement',
|
||||
},
|
||||
component: () =>
|
||||
import(
|
||||
'src/pages/Customer/Card/CustomerFileManagement.vue'
|
||||
),
|
||||
},
|
||||
{
|
||||
path: 'create',
|
||||
name: 'CustomerFileManagementCreate',
|
||||
component: () =>
|
||||
import(
|
||||
'src/pages/Customer/components/CustomerFileManagementCreate.vue'
|
||||
),
|
||||
},
|
||||
{
|
||||
path: ':dmsId/edit',
|
||||
name: 'CustomerFileManagementEdit',
|
||||
component: () =>
|
||||
import(
|
||||
'src/pages/Customer/components/CustomerFileManagementEdit.vue'
|
||||
),
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
path: 'unpaid',
|
||||
|
|
|
@ -116,6 +116,15 @@ export default {
|
|||
entryCard,
|
||||
],
|
||||
},
|
||||
{
|
||||
path: 'create',
|
||||
name: 'EntryCreate',
|
||||
meta: {
|
||||
title: 'entryCreate',
|
||||
icon: 'add',
|
||||
},
|
||||
component: () => import('src/pages/Entry/EntryCreate.vue'),
|
||||
},
|
||||
{
|
||||
path: 'my',
|
||||
name: 'EntrySupplier',
|
||||
|
|
|
@ -122,7 +122,15 @@ export default {
|
|||
invoiceInCard,
|
||||
],
|
||||
},
|
||||
|
||||
{
|
||||
path: 'create',
|
||||
name: 'InvoiceInCreare',
|
||||
meta: {
|
||||
title: 'invoiceInCreate',
|
||||
icon: 'create',
|
||||
},
|
||||
component: () => import('src/pages/InvoiceIn/InvoiceInCreate.vue'),
|
||||
},
|
||||
{
|
||||
path: 'serial',
|
||||
name: 'InvoiceInSerial',
|
||||
|
|
|
@ -93,6 +93,15 @@ export default {
|
|||
orderCard,
|
||||
],
|
||||
},
|
||||
{
|
||||
path: 'create',
|
||||
name: 'OrderCreate',
|
||||
meta: {
|
||||
title: 'orderCreate',
|
||||
icon: 'add',
|
||||
},
|
||||
component: () => import('src/pages/Order/OrderList.vue'),
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
|
|
|
@ -16,7 +16,7 @@ const routeCard = {
|
|||
title: 'basicData',
|
||||
icon: 'vn:settings',
|
||||
},
|
||||
component: () => import('pages/Route/Card/RouteBasicData.vue'),
|
||||
component: () => import('pages/Route/Card/RouteForm.vue'),
|
||||
},
|
||||
{
|
||||
name: 'RouteSummary',
|
||||
|
@ -270,6 +270,15 @@ export default {
|
|||
},
|
||||
component: () => import('src/pages/Route/RouteExtendedList.vue'),
|
||||
},
|
||||
{
|
||||
path: 'create',
|
||||
name: 'RouteCreate',
|
||||
meta: {
|
||||
title: 'routeCreate',
|
||||
icon: 'add',
|
||||
},
|
||||
component: () => import('src/pages/Route/Card/RouteForm.vue'),
|
||||
},
|
||||
{
|
||||
path: 'agency-term',
|
||||
name: 'RouteAutonomous',
|
||||
|
|
|
@ -180,6 +180,15 @@ export default {
|
|||
supplierCard,
|
||||
],
|
||||
},
|
||||
{
|
||||
path: 'create',
|
||||
name: 'SupplierCreate',
|
||||
meta: {
|
||||
title: 'supplierCreate',
|
||||
icon: 'add',
|
||||
},
|
||||
component: () => import('src/pages/Supplier/SupplierCreate.vue'),
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
|
|
|
@ -226,6 +226,15 @@ export default {
|
|||
ticketCard,
|
||||
],
|
||||
},
|
||||
{
|
||||
path: 'create',
|
||||
name: 'TicketCreate',
|
||||
meta: {
|
||||
title: 'createTicket',
|
||||
icon: 'vn:ticketAdd',
|
||||
},
|
||||
component: () => import('src/pages/Ticket/TicketCreate.vue'),
|
||||
},
|
||||
{
|
||||
path: 'negative',
|
||||
redirect: { name: 'TicketNegative' },
|
||||
|
|
|
@ -42,7 +42,31 @@ const travelCard = {
|
|||
title: 'thermographs',
|
||||
icon: 'vn:thermometer',
|
||||
},
|
||||
component: () => import('src/pages/Travel/Card/TravelThermographs.vue'),
|
||||
redirect: {
|
||||
name: 'TravelThermographsIndex',
|
||||
},
|
||||
children: [
|
||||
{
|
||||
name: 'TravelThermographsIndex',
|
||||
path: 'index',
|
||||
component: () =>
|
||||
import('src/pages/Travel/Card/TravelThermographs.vue'),
|
||||
},
|
||||
{
|
||||
name: 'TravelThermographsCreate',
|
||||
path: 'create',
|
||||
props: { viewAction: 'create' },
|
||||
component: () =>
|
||||
import('src/pages/Travel/Card/TravelThermographsForm.vue'),
|
||||
},
|
||||
{
|
||||
name: 'TravelThermographsEdit',
|
||||
path: 'edit',
|
||||
props: { viewAction: 'edit' },
|
||||
component: () =>
|
||||
import('src/pages/Travel/Card/TravelThermographsForm.vue'),
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
};
|
||||
|
@ -91,6 +115,15 @@ export default {
|
|||
},
|
||||
component: () => import('src/pages/Travel/ExtraCommunity.vue'),
|
||||
},
|
||||
{
|
||||
path: 'create',
|
||||
name: 'TravelCreate',
|
||||
meta: {
|
||||
title: 'travelCreate',
|
||||
icon: 'add',
|
||||
},
|
||||
component: () => import('src/pages/Travel/TravelCreate.vue'),
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
|
|
|
@ -24,13 +24,8 @@ export CI=true
|
|||
export TZ=Europe/Madrid
|
||||
|
||||
# IMAGES
|
||||
docker build -t registry.verdnatura.es/salix-back:dev -f "$salix_dir/back/Dockerfile" "$salix_dir"
|
||||
cd "$salix_dir" && npx myt run -t
|
||||
docker exec vn-database sh -c "rm -rf /mysql-template"
|
||||
docker exec vn-database sh -c "cp -a /var/lib/mysql /mysql-template"
|
||||
docker commit vn-database registry.verdnatura.es/salix-db:dev
|
||||
docker rm -f vn-database
|
||||
cd "$current_dir"
|
||||
docker-compose -f test/cypress/docker-compose.yml --project-directory . pull db
|
||||
docker-compose -f test/cypress/docker-compose.yml --project-directory . pull back
|
||||
docker build -f ./docs/Dockerfile.dev -t lilium-dev .
|
||||
# END IMAGES
|
||||
|
||||
|
|
|
@ -0,0 +1,47 @@
|
|||
/// <reference types="cypress" />
|
||||
describe('Client consignee', () => {
|
||||
beforeEach(() => {
|
||||
cy.viewport(1280, 720);
|
||||
cy.login('developer');
|
||||
cy.visit('#/customer/1107/address');
|
||||
});
|
||||
it('Should load layout', () => {
|
||||
cy.get('.q-card').should('be.visible');
|
||||
});
|
||||
|
||||
it('check as equalizated', () => {
|
||||
cy.get('.q-card__section > .address-card').then(($el) => {
|
||||
const addressCards_before = $el.length;
|
||||
|
||||
cy.get('.q-page-sticky > div > .q-btn').click();
|
||||
const addressName = 'test';
|
||||
cy.dataCy('Consignee_input').type(addressName);
|
||||
cy.dataCy('Location_select').click();
|
||||
cy.getOption();
|
||||
cy.dataCy('Street address_input').type('TEST ADDRESS');
|
||||
cy.get('.q-btn-group > .q-btn--standard').click();
|
||||
cy.location('href').should('contain', '#/customer/1107/address');
|
||||
cy.get('.q-card__section > .address-card').should(
|
||||
'have.length',
|
||||
addressCards_before + 1,
|
||||
);
|
||||
cy.get('.q-card__section > .address-card')
|
||||
.eq(addressCards_before)
|
||||
.should('be.visible')
|
||||
.get('.text-weight-bold')
|
||||
.eq(addressCards_before - 1)
|
||||
.should('contain', addressName)
|
||||
.click();
|
||||
});
|
||||
cy.get(
|
||||
'.q-card > :nth-child(1) > :nth-child(2) > .q-checkbox > .q-checkbox__inner',
|
||||
)
|
||||
.should('have.class', 'q-checkbox__inner--falsy')
|
||||
.click();
|
||||
|
||||
cy.get('.q-btn-group > .q-btn--standard > .q-btn__content').click();
|
||||
cy.get(
|
||||
':nth-child(2) > :nth-child(2) > .flex > .q-mr-lg > .q-checkbox__inner',
|
||||
).should('have.class', 'q-checkbox__inner--truthy');
|
||||
});
|
||||
});
|
|
@ -1,5 +1,5 @@
|
|||
/// <reference types="cypress" />
|
||||
describe('CustomerBalance', () => {
|
||||
describe('Client balance', () => {
|
||||
beforeEach(() => {
|
||||
cy.login('developer');
|
||||
cy.visit('#/customer/1101/balance');
|
|
@ -1,5 +1,5 @@
|
|||
/// <reference types="cypress" />
|
||||
describe('CustomerBasicData', () => {
|
||||
describe('Client basic data', () => {
|
||||
beforeEach(() => {
|
||||
cy.viewport(1280, 720);
|
||||
cy.login('developer');
|
|
@ -1,5 +1,5 @@
|
|||
/// <reference types="cypress" />
|
||||
describe('CustomerBillingData', () => {
|
||||
describe('Client billing data', () => {
|
||||
beforeEach(() => {
|
||||
cy.viewport(1280, 720);
|
||||
cy.login('developer');
|
|
@ -1,5 +1,5 @@
|
|||
/// <reference types="cypress" />
|
||||
describe('CustomerCredits', () => {
|
||||
describe('Client credits', () => {
|
||||
beforeEach(() => {
|
||||
cy.viewport(1280, 720);
|
||||
cy.login('developer');
|
|
@ -1,5 +1,5 @@
|
|||
/// <reference types="cypress" />
|
||||
describe('CustomerFiscalData', { testIsolation: true }, () => {
|
||||
describe('Client fiscal data', { testIsolation: true }, () => {
|
||||
beforeEach(() => {
|
||||
cy.viewport(1280, 720);
|
||||
cy.login('developer');
|
|
@ -1,5 +1,5 @@
|
|||
/// <reference types="cypress" />
|
||||
describe('CustomerGreuges', () => {
|
||||
describe('Client greuges', () => {
|
||||
beforeEach(() => {
|
||||
cy.viewport(1280, 720);
|
||||
cy.login('developer');
|
|
@ -1,5 +1,5 @@
|
|||
/// <reference types="cypress" />
|
||||
describe('CustomerList', { testIsolation: true }, () => {
|
||||
describe('Client list', { testIsolation: true }, () => {
|
||||
beforeEach(() => {
|
||||
cy.login('developer');
|
||||
cy.visit('/#/customer/list', {
|
|
@ -1,5 +1,5 @@
|
|||
/// <reference types="cypress" />
|
||||
describe('CustomerNotes', () => {
|
||||
describe('Client notes', () => {
|
||||
beforeEach(() => {
|
||||
cy.viewport(1280, 720);
|
||||
cy.login('developer');
|
|
@ -1,5 +1,5 @@
|
|||
/// <reference types="cypress" />
|
||||
describe('CustomerRecoveries', () => {
|
||||
describe('Client recoveries', () => {
|
||||
beforeEach(() => {
|
||||
cy.viewport(1280, 720);
|
||||
cy.login('developer');
|
|
@ -1,5 +1,5 @@
|
|||
/// <reference types="cypress" />
|
||||
describe('CustomerSms', () => {
|
||||
describe('Client notes', () => {
|
||||
beforeEach(() => {
|
||||
cy.viewport(1280, 720);
|
||||
cy.login('developer');
|
|
@ -1,5 +1,5 @@
|
|||
/// <reference types="cypress" />
|
||||
describe('CustomerWebAccess', () => {
|
||||
describe('Client web-access', () => {
|
||||
beforeEach(() => {
|
||||
cy.viewport(1280, 720);
|
||||
cy.login('developer');
|
|
@ -1,8 +1,5 @@
|
|||
/// <reference types="cypress" />
|
||||
describe('Client credit contracts', () => {
|
||||
const firstCredit = 123;
|
||||
const secondCredit = 321;
|
||||
|
||||
beforeEach(() => {
|
||||
cy.viewport(1280, 720);
|
||||
cy.login('developer');
|
||||
|
@ -10,10 +7,9 @@ describe('Client credit contracts', () => {
|
|||
timeout: 5000,
|
||||
});
|
||||
});
|
||||
|
||||
it('Should add a new contract and an additional credit', () => {
|
||||
cy.dataCy('createBtn').click();
|
||||
cy.dataCy('Credit_input').type(firstCredit);
|
||||
cy.dataCy('Credit_input').type(123);
|
||||
cy.dataCy('Grade_input').type(9);
|
||||
cy.dataCy('FormModelPopup_save').click();
|
||||
cy.checkNotification('Data created');
|
||||
|
@ -23,27 +19,12 @@ describe('Client credit contracts', () => {
|
|||
it('Should add an additional credit', () => {
|
||||
cy.dataCy('viewBtn').eq(0).click();
|
||||
cy.get('.q-page-sticky > div').click();
|
||||
cy.dataCy('Credit_input').type(secondCredit);
|
||||
cy.dataCy('Credit_input').type(321);
|
||||
cy.dataCy('Grade_input').type(89);
|
||||
cy.dataCy('FormModelPopup_save').click();
|
||||
cy.checkNotification('Data created');
|
||||
});
|
||||
|
||||
it('Should view correctly credit contracts', () => {
|
||||
cy.get('.q-card > .q-card__section')
|
||||
.first()
|
||||
.find('[data-cy="vnLvCredit"]')
|
||||
.first()
|
||||
.invoke('text')
|
||||
.should('contain', firstCredit);
|
||||
cy.get('.q-card > .q-card__section')
|
||||
.first()
|
||||
.find('[data-cy="vnLvCredit"]')
|
||||
.last()
|
||||
.invoke('text')
|
||||
.should('contain', secondCredit);
|
||||
});
|
||||
|
||||
it('Should close a contract', () => {
|
||||
cy.dataCy('closeBtn').eq(0).click();
|
||||
cy.get('.q-btn--unelevated').click();
|
|
@ -1,85 +0,0 @@
|
|||
/// <reference types="cypress" />
|
||||
describe('CustomerAddress (consignee)', () => {
|
||||
beforeEach(() => {
|
||||
cy.viewport(1280, 720);
|
||||
cy.login('developer');
|
||||
cy.visit('#/customer/1107/address');
|
||||
});
|
||||
|
||||
it('Should change default address', () => {
|
||||
cy.dataCy('setDefaultAddress')
|
||||
.first()
|
||||
.should('have.attr', 'style')
|
||||
.and('include', '"FILL" 1');
|
||||
cy.dataCy('setDefaultAddress').last().click();
|
||||
cy.dataCy('setDefaultAddress')
|
||||
.first()
|
||||
.should('have.attr', 'style')
|
||||
.and('include', '"FILL" 0');
|
||||
cy.dataCy('setDefaultAddress')
|
||||
.last()
|
||||
.should('have.attr', 'style')
|
||||
.and('include', '"FILL" 1');
|
||||
});
|
||||
|
||||
it('check as equalizated', () => {
|
||||
cy.get('.q-card__section > .address-card').then(($el) => {
|
||||
const addressCards_before = $el.length;
|
||||
|
||||
cy.get('.q-page-sticky > div > .q-btn').click();
|
||||
const addressName = 'test';
|
||||
cy.dataCy('Consignee_input').type(addressName);
|
||||
cy.dataCy('Location_select').click();
|
||||
cy.getOption();
|
||||
cy.dataCy('Street_input').type('TEST ADDRESS');
|
||||
cy.saveCard();
|
||||
|
||||
cy.get('.q-card__section > .address-card').should(
|
||||
'have.length',
|
||||
addressCards_before + 1,
|
||||
);
|
||||
cy.get('.q-card__section > .address-card')
|
||||
.eq(addressCards_before)
|
||||
.should('be.visible')
|
||||
.get('.text-weight-bold')
|
||||
.eq(addressCards_before - 1)
|
||||
.should('contain', addressName)
|
||||
.click();
|
||||
});
|
||||
cy.get('[data-cy="isEqualizated_form"] > .q-checkbox__inner')
|
||||
.should('have.class', 'q-checkbox__inner--falsy')
|
||||
.click();
|
||||
|
||||
cy.saveCard();
|
||||
cy.get(
|
||||
':nth-child(2) > :nth-child(2) > .flex > .q-mr-lg > .q-checkbox__inner',
|
||||
).should('have.class', 'q-checkbox__inner--truthy');
|
||||
});
|
||||
|
||||
it('Should edit address', () => {
|
||||
const updateData = {
|
||||
Consignee: { val: 'Stark tower' },
|
||||
Street: { val: 'test' },
|
||||
Location: { val: 'Algemesi', type: 'select' },
|
||||
Agency: { val: 'inhouse pickup', type: 'select' },
|
||||
Phone: { val: '3333333333' },
|
||||
Mobile: { val: '4444444444' },
|
||||
Incoterms: { val: 'Free Alongside Ship', type: 'select' },
|
||||
'Customs agent': { val: 'Agent two', type: 'select' },
|
||||
Longitude: { val: '123' },
|
||||
Latitude: { val: '123' },
|
||||
};
|
||||
|
||||
cy.get('.address-card').last().click();
|
||||
cy.fillInForm(updateData);
|
||||
cy.dataCy('enabled_form').click();
|
||||
cy.dataCy('isEqualizated_form').click();
|
||||
cy.dataCy('isLoginfloraAllowed_form').click();
|
||||
cy.dataCy('addNoteBtn_form').click();
|
||||
cy.selectOption('[data-cy="Observation type_select"]', '6');
|
||||
cy.dataCy('Description_input').click().type('Test description');
|
||||
cy.dataCy('FormModelPopup_save').click();
|
||||
cy.checkNotification('Data saved');
|
||||
cy.get('.address-card').last().should('have.class', 'item-disabled');
|
||||
});
|
||||
});
|
|
@ -1,16 +0,0 @@
|
|||
describe('CustomerDms', () => {
|
||||
beforeEach(() => {
|
||||
cy.viewport(1920, 1080);
|
||||
cy.login('developer');
|
||||
cy.visit(`/#/customer/1104/others/dms`);
|
||||
});
|
||||
|
||||
it('should display customer DMS', () => {
|
||||
const expectedValue = '104';
|
||||
|
||||
cy.get('[data-cy="reference_form"]').each(($el) => {
|
||||
const actualText = $el.text().trim();
|
||||
expect(actualText).to.contain(expectedValue);
|
||||
});
|
||||
});
|
||||
});
|
|
@ -6,14 +6,11 @@ describe('EntryList', () => {
|
|||
cy.visit(`/#/entry/list`);
|
||||
});
|
||||
|
||||
it('Should create and delete entry', () => {
|
||||
it('View popup summary', () => {
|
||||
cy.createEntry();
|
||||
cy.get('.q-notification__message').eq(0).should('have.text', 'Data created');
|
||||
cy.waitForElement('[data-cy="entry-buys"]');
|
||||
cy.deleteEntry();
|
||||
});
|
||||
|
||||
it('View popup summary', () => {
|
||||
cy.typeSearchbar('{enter}');
|
||||
cy.get('button[title="Summary"]').eq(1).should('be.visible').click();
|
||||
cy.dataCy('entry-summary').should('be.visible');
|
||||
|
|
|
@ -5,33 +5,28 @@ describe('Logout', { testIsolation: true }, () => {
|
|||
cy.visit(`/#/dashboard`);
|
||||
cy.waitForElement('.q-page', 6000);
|
||||
});
|
||||
describe('by user', () => {
|
||||
it('should logout', () => {
|
||||
cy.get('#user').click();
|
||||
cy.get('#logout').click();
|
||||
});
|
||||
|
||||
it('should logout', () => {
|
||||
cy.get('#user').click();
|
||||
cy.get('#logout').click();
|
||||
});
|
||||
describe('not user', () => {
|
||||
beforeEach(() => {
|
||||
cy.intercept('GET', '**StarredModules**', {
|
||||
statusCode: 401,
|
||||
body: {
|
||||
error: {
|
||||
statusCode: 401,
|
||||
name: 'Error',
|
||||
message: 'Authorization Required',
|
||||
code: 'AUTHORIZATION_REQUIRED',
|
||||
},
|
||||
|
||||
it('should throw session expired error if token has expired or is not valid during navigation', () => {
|
||||
cy.intercept('GET', '**StarredModules**', {
|
||||
statusCode: 401,
|
||||
body: {
|
||||
error: {
|
||||
statusCode: 401,
|
||||
name: 'Error',
|
||||
message: 'Authorization Required',
|
||||
code: 'AUTHORIZATION_REQUIRED',
|
||||
},
|
||||
statusMessage: 'AUTHORIZATION_REQUIRED',
|
||||
}).as('badRequest');
|
||||
});
|
||||
},
|
||||
statusMessage: 'AUTHORIZATION_REQUIRED',
|
||||
}).as('badRequest');
|
||||
cy.get('.q-list').should('be.visible').first().should('be.visible').click();
|
||||
cy.wait('@badRequest');
|
||||
|
||||
it('when token not exists', () => {
|
||||
cy.get('.q-list').should('be.visible').first().should('be.visible').click();
|
||||
cy.wait('@badRequest');
|
||||
|
||||
cy.checkNotification('Authorization Required');
|
||||
});
|
||||
cy.checkNotification('Your session has expired. Please log in again');
|
||||
});
|
||||
});
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
describe('RoadMap', () => {
|
||||
describe.skip('RoadMap', () => {
|
||||
const getSelector = (colField) =>
|
||||
`tr:last-child > [data-col-field="${colField}"] > .no-padding`;
|
||||
|
||||
|
|
|
@ -1,46 +0,0 @@
|
|||
describe('Travel List', () => {
|
||||
const selectors = {
|
||||
listItem: '[role="menu"] .q-list .q-item',
|
||||
addEntryOpt: 'Add entry',
|
||||
warhouseIn: 'vnLvWarehouse In',
|
||||
entryTravelReference: 'vnLvReference',
|
||||
descriptorTitle: 'vnDescriptor_title',
|
||||
};
|
||||
|
||||
beforeEach(() => {
|
||||
cy.viewport(1280, 720);
|
||||
cy.login('developer');
|
||||
cy.visit('#/travel/3/summary');
|
||||
});
|
||||
|
||||
it('Should add entry', () => {
|
||||
const data = {
|
||||
Supplier: { val: 'FARMER KING', type: 'select' },
|
||||
Company: { val: 'VNL', type: 'select' },
|
||||
};
|
||||
|
||||
cy.dataCy(selectors.warhouseIn)
|
||||
.find('.value > span')
|
||||
.invoke('attr', 'title')
|
||||
.then((text) => text.trim())
|
||||
.as('warehouseIn');
|
||||
|
||||
cy.dataCy(selectors.descriptorTitle)
|
||||
.invoke('text')
|
||||
.then((text) => text.trim())
|
||||
.as('reference');
|
||||
|
||||
cy.openActionsDescriptor();
|
||||
cy.contains(selectors.listItem, selectors.addEntryOpt).click();
|
||||
|
||||
cy.get('@warehouseIn').then((warehouseIn) => {
|
||||
cy.dataCy('entry-travel-select').invoke('val').should('contain', warehouseIn);
|
||||
});
|
||||
cy.fillInForm(data);
|
||||
cy.dataCy('FormModelPopup_save').click();
|
||||
|
||||
cy.get('@reference').then((reference) => {
|
||||
cy.dataCy(selectors.entryTravelReference).should('contain', reference);
|
||||
});
|
||||
});
|
||||
});
|
|
@ -1,108 +0,0 @@
|
|||
describe('Travel List', () => {
|
||||
const selectors = {
|
||||
cloneBtn: 'tableAction-0',
|
||||
addEntryBtn: 'tableAction-1',
|
||||
openSummaryBtn: 'tableAction-2',
|
||||
summaryGoToSummaryBtn: '.summaryHeader [data-cy="goToSummaryBtn"]',
|
||||
descriptorTitle: 'vnDescriptor_title',
|
||||
warehouseInField: 'vnTableCell_warehouseInFk',
|
||||
referenceField: 'vnTableCell_ref',
|
||||
entryTravelReference: 'vnLvReference',
|
||||
};
|
||||
|
||||
const travelSummaryUrlRegex = /travel\/\d+\/summary/;
|
||||
|
||||
beforeEach(() => {
|
||||
cy.viewport(1280, 720);
|
||||
cy.login('developer');
|
||||
cy.visit('#/travel/list');
|
||||
cy.typeSearchbar('{enter}');
|
||||
});
|
||||
|
||||
it('Should create travel', () => {
|
||||
const data = {
|
||||
Reference: { val: 'Travel' },
|
||||
Agency: { val: 'inhouse pickup', type: 'select' },
|
||||
'Warehouse In': { val: 'Warehouse One', type: 'select' },
|
||||
Shipped: { val: '1.2', type: 'date' },
|
||||
'Warehouse Out': { val: 'Warehouse Two', type: 'select' },
|
||||
Landed: { val: '2.2', type: 'date' },
|
||||
'Total entries': { val: '1' },
|
||||
Availabled: { val: '2.2', type: 'date' },
|
||||
'Available hour': { val: '11:10', type: 'time' },
|
||||
};
|
||||
cy.addBtnClick();
|
||||
cy.fillInForm(data);
|
||||
cy.dataCy('FormModelPopup_save').click();
|
||||
cy.dataCy(selectors.descriptorTitle).should('contain', data.Reference.val);
|
||||
});
|
||||
|
||||
it('Should clone travel', () => {
|
||||
cy.dataCy(selectors.cloneBtn).first().click();
|
||||
const data = {
|
||||
Reference: { val: 'Travel clone' },
|
||||
};
|
||||
cy.fillInForm(data);
|
||||
cy.dataCy('FormModelPopup_save').click();
|
||||
cy.dataCy(selectors.descriptorTitle).should('contain', data.Reference.val);
|
||||
});
|
||||
|
||||
it('Should add entry', () => {
|
||||
const data = {
|
||||
Supplier: { val: 'FARMER KING', type: 'select' },
|
||||
Company: { val: 'VNL', type: 'select' },
|
||||
};
|
||||
|
||||
cy.dataCy(selectors.warehouseInField)
|
||||
.first()
|
||||
.invoke('text')
|
||||
.then((text) => text.trim())
|
||||
.as('warehouseIn');
|
||||
|
||||
cy.dataCy(selectors.referenceField)
|
||||
.first()
|
||||
.invoke('text')
|
||||
.then((text) => text.trim())
|
||||
.as('reference');
|
||||
|
||||
cy.dataCy(selectors.addEntryBtn).first().click();
|
||||
cy.get('@warehouseIn').then((warehouseIn) => {
|
||||
cy.dataCy('entry-travel-select').invoke('val').should('contain', warehouseIn);
|
||||
});
|
||||
cy.fillInForm(data);
|
||||
cy.dataCy('FormModelPopup_save').click();
|
||||
|
||||
cy.get('@reference').then((reference) => {
|
||||
cy.dataCy(selectors.entryTravelReference).should('contain', reference);
|
||||
});
|
||||
});
|
||||
|
||||
it('Should redirect to vehicle summary when click summary icon on summary pop-up', () => {
|
||||
cy.dataCy(selectors.referenceField)
|
||||
.first()
|
||||
.invoke('text')
|
||||
.then((text) => text.trim())
|
||||
.as('reference');
|
||||
|
||||
cy.dataCy(selectors.openSummaryBtn).first().click();
|
||||
cy.get(selectors.summaryGoToSummaryBtn).click();
|
||||
cy.location().should('match', travelSummaryUrlRegex);
|
||||
cy.get('@reference').then((label) => {
|
||||
cy.dataCy(selectors.descriptorTitle).should('contain', label);
|
||||
});
|
||||
});
|
||||
|
||||
it('Should redirect to travel summary when click on row', () => {
|
||||
cy.dataCy(selectors.referenceField)
|
||||
.first()
|
||||
.invoke('text')
|
||||
.then((text) => text.trim())
|
||||
.as('reference');
|
||||
|
||||
cy.dataCy(selectors.referenceField).first().click();
|
||||
cy.location().should('match', travelSummaryUrlRegex);
|
||||
cy.get('@reference').then((label) => {
|
||||
cy.dataCy(selectors.descriptorTitle).should('contain', label);
|
||||
});
|
||||
});
|
||||
});
|
|
@ -1,48 +0,0 @@
|
|||
describe('TravelThermographs', () => {
|
||||
const selectors = {
|
||||
fileInput: 'input[type="file"]',
|
||||
editBtn: 'vnTableCell_editFile',
|
||||
removeBtn: 'vnTableCell_removeThermograph',
|
||||
temperatureField: 'vnTableCell_temperatureFk',
|
||||
codeField: 'vnTableCell_thermographFk',
|
||||
}
|
||||
beforeEach(() => {
|
||||
cy.login('developer');
|
||||
cy.visit(`/#/travel/10/thermographs`);
|
||||
});
|
||||
|
||||
it('Should create thermograph', () => {
|
||||
const data = {
|
||||
Thermograph: { val: 138350-0, type: 'select' },
|
||||
State: { val: 'Ok'},
|
||||
Company: { val: 'VNL', type: 'select' },
|
||||
Temperature: { val: 'Cool', type: 'select' },
|
||||
Max: { val: '10' },
|
||||
Min: { val: '5' },
|
||||
};
|
||||
|
||||
cy.addBtnClick();
|
||||
cy.fillInForm(data);
|
||||
cy.get(selectors.fileInput).selectFile('test/cypress/fixtures/image.jpg', {
|
||||
force: true,
|
||||
});
|
||||
cy.dataCy('FormModelPopup_save').click();
|
||||
cy.dataCy(selectors.codeField).invoke('text').should('contain', data.Thermograph.val);
|
||||
});
|
||||
|
||||
it('Should edit thermograph', () => {
|
||||
cy.dataCy(selectors.editBtn).eq(0).click();
|
||||
const updateData = {
|
||||
Temperature: { val: 'Warm', type: 'select' },
|
||||
}
|
||||
cy.fillInForm(updateData);
|
||||
cy.dataCy('FormModelPopup_save').click();
|
||||
cy.dataCy(selectors.temperatureField).invoke('text').should('contain', 'warm');
|
||||
});
|
||||
|
||||
it('Should delete thermograph', () => {
|
||||
cy.dataCy(selectors.removeBtn).eq(0).click();
|
||||
cy.clickConfirm();
|
||||
cy.checkNotification('Thermograph removed');
|
||||
});
|
||||
});
|
|
@ -1,4 +1,4 @@
|
|||
describe('ZoneCalendar', () => {
|
||||
describe('ZoneCalendar', { testIsolation: true }, () => {
|
||||
const addEventBtn = '.q-page-sticky > div > .q-btn';
|
||||
const submitBtn = '.q-mt-lg > .q-btn--standard';
|
||||
const deleteBtn = 'ZoneEventsPanelDeleteBtn';
|
||||
|
@ -47,4 +47,20 @@ describe('ZoneCalendar', () => {
|
|||
cy.dataCy('ZoneEventExclusionDeleteBtn').click();
|
||||
cy.dataCy('VnConfirm_confirm').click();
|
||||
});
|
||||
|
||||
it(
|
||||
'should not exclude an event if there are tickets for that zone and day',
|
||||
{ testIsoaltion: true },
|
||||
() => {
|
||||
cy.visit(`/#/zone/3/events`);
|
||||
cy.get('.q-mb-sm > .q-radio__inner').click();
|
||||
cy.get(
|
||||
'.q-current-day > .q-calendar-month__day--content > [data-cy="ZoneCalendarDay"]',
|
||||
).click();
|
||||
cy.get('.q-mt-lg > .q-btn--standard').click();
|
||||
cy.checkNotification(
|
||||
'Can not close this zone because there are tickets programmed for that day',
|
||||
);
|
||||
},
|
||||
);
|
||||
});
|
||||
|
|
|
@ -26,27 +26,8 @@ describe('ZoneDeliveryDays', () => {
|
|||
});
|
||||
}).as('events');
|
||||
|
||||
cy.dataCy('ZoneDeliveryDaysPostcodeSelect').type(postcode);
|
||||
cy.get('.q-menu .q-item').contains(postcode).click();
|
||||
cy.get('.q-menu').then(($menu) => {
|
||||
if ($menu.is(':visible')) {
|
||||
cy.get('[data-cy="ZoneDeliveryDaysPostcodeSelect"]')
|
||||
.as('focusedElement')
|
||||
.focus();
|
||||
cy.get('@focusedElement').blur();
|
||||
}
|
||||
});
|
||||
|
||||
cy.dataCy('ZoneDeliveryDaysAgencySelect').type(agency);
|
||||
cy.get('.q-menu .q-item').contains(agency).click();
|
||||
cy.get('.q-menu').then(($menu) => {
|
||||
if ($menu.is(':visible')) {
|
||||
cy.get('[data-cy="ZoneDeliveryDaysAgencySelect"]')
|
||||
.as('focusedElement')
|
||||
.focus();
|
||||
cy.get('@focusedElement').blur();
|
||||
}
|
||||
});
|
||||
cy.selectOption('[data-cy="ZoneDeliveryDaysPostcodeSelect"]', postcode);
|
||||
cy.selectOption('[data-cy="ZoneDeliveryDaysAgencySelect"]', agency);
|
||||
|
||||
cy.get(submitForm).click();
|
||||
cy.wait('@events').then((interception) => {
|
||||
|
|
Loading…
Reference in New Issue