0
0
Fork 0

Merge pull request 'Item Basic data' (!346) from hyervoni/salix-front-mindshore:feature/ItemBasicData into dev

Reviewed-on: verdnatura/salix-front#346
Reviewed-by: Javier Segarra <jsegarra@verdnatura.es>
Reviewed-by: Alex Moreno <alexm@verdnatura.es>
This commit is contained in:
Javier Segarra 2024-05-07 10:47:01 +00:00
commit 175746a4a4
7 changed files with 356 additions and 5 deletions

View File

@ -1,7 +1,6 @@
<script setup> <script setup>
import { ref, reactive, computed } from 'vue'; import { ref, reactive, computed } from 'vue';
import { useI18n } from 'vue-i18n'; import { useI18n } from 'vue-i18n';
import { useRoute } from 'vue-router';
import VnRow from 'components/ui/VnRow.vue'; import VnRow from 'components/ui/VnRow.vue';
import FetchData from 'components/FetchData.vue'; import FetchData from 'components/FetchData.vue';
@ -12,10 +11,16 @@ import ItemDescriptorProxy from 'src/pages/Item/Card/ItemDescriptorProxy.vue';
import axios from 'axios'; import axios from 'axios';
import { dashIfEmpty } from 'src/filters'; import { dashIfEmpty } from 'src/filters';
const props = defineProps({
url: {
type: String,
required: true,
},
});
const emit = defineEmits(['itemSelected']); const emit = defineEmits(['itemSelected']);
const { t } = useI18n(); const { t } = useI18n();
const route = useRoute();
const itemFilter = { const itemFilter = {
include: [ include: [
@ -73,7 +78,7 @@ const tableColumns = computed(() => [
{ {
label: t('entry.buys.color'), label: t('entry.buys.color'),
name: 'ink', name: 'ink',
field: 'inkName', field: (row) => row?.ink?.name,
align: 'left', align: 'left',
}, },
]); ]);
@ -100,7 +105,7 @@ const fetchResults = async () => {
} }
filter.where = where; filter.where = where;
const { data } = await axios.get(`Entries/${route.params.id}/lastItemBuys`, { const { data } = await axios.get(props.url, {
params: { filter: JSON.stringify(filter) }, params: { filter: JSON.stringify(filter) },
}); });
tableRows.value = data; tableRows.value = data;

View File

@ -52,6 +52,11 @@ const focus = () => {
defineExpose({ defineExpose({
focus, focus,
}); });
const inputRules = (val) => {
const { min } = vnInputRef.value.$attrs;
if (min >= 0) if (Math.floor(val) < min) return t('inputMin', { value: min });
};
</script> </script>
<template> <template>
@ -68,6 +73,8 @@ defineExpose({
:class="{ required: $attrs.required }" :class="{ required: $attrs.required }"
@keyup.enter="onEnterPress()" @keyup.enter="onEnterPress()"
:clearable="false" :clearable="false"
:rules="[inputRules]"
:lazy-rules="true"
> >
<template v-if="$slots.prepend" #prepend> <template v-if="$slots.prepend" #prepend>
<slot name="prepend" /> <slot name="prepend" />
@ -85,3 +92,9 @@ defineExpose({
</QInput> </QInput>
</div> </div>
</template> </template>
<i18n>
en:
inputMin: Must be more than {value}
es:
inputMin: Debe ser mayor a {value}
</i18n>

View File

@ -251,6 +251,7 @@ const redirectToBuysView = () => {
> >
<template #form> <template #form>
<FilterItemForm <FilterItemForm
:url="`Entries/${route.params.id}/lastItemBuys`"
@item-selected="row[col.field] = $event" @item-selected="row[col.field] = $event"
/> />
</template> </template>

View File

@ -0,0 +1,52 @@
<script setup>
import { reactive, ref, onMounted, nextTick } from 'vue';
import { useI18n } from 'vue-i18n';
import { useRoute } from 'vue-router';
import VnInput from 'src/components/common/VnInput.vue';
import VnRow from 'components/ui/VnRow.vue';
import FormModelPopup from 'components/FormModelPopup.vue';
const { t } = useI18n();
const emit = defineEmits(['onDataSaved']);
const route = useRoute();
const identifierInputRef = ref(null);
const intrastatFormData = reactive({});
const onDataSaved = (formData, requestResponse) => {
emit('onDataSaved', formData, requestResponse);
};
onMounted(async () => {
await nextTick();
identifierInputRef.value.focus();
});
</script>
<template>
<FormModelPopup
:url-update="`Items/${route.params.id}/createIntrastat`"
model="itemGenus"
:title="t('createIntrastatForm.title')"
:form-initial-data="intrastatFormData"
@on-data-saved="onDataSaved"
>
<template #form-inputs="{ data }">
<VnRow class="row q-gutter-md q-mb-md">
<VnInput
ref="identifierInputRef"
:label="t('createIntrastatForm.identifier')"
type="number"
v-model.number="data.intrastatId"
:required="true"
/>
<VnInput
:label="t('createIntrastatForm.description')"
v-model="data.description"
:required="true"
/>
</VnRow>
</template>
</FormModelPopup>
</template>

View File

@ -1 +1,233 @@
<template>Item basic data</template> <script setup>
import { ref } from 'vue';
import { useRoute } from 'vue-router';
import { useI18n } from 'vue-i18n';
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 FilterItemForm from 'src/components/FilterItemForm.vue';
import CreateIntrastatForm from './CreateIntrastatForm.vue';
const route = useRoute();
const { t } = useI18n();
const itemTypesOptions = ref([]);
const itemsWithNameOptions = ref([]);
const intrastatsOptions = ref([]);
const expensesOptions = ref([]);
const onIntrastatCreated = (response, formData) => {
intrastatsOptions.value = [...intrastatsOptions.value, response];
formData.intrastatFk = response.id;
};
</script>
<template>
<FetchData
url="ItemTypes"
:filter="{
fields: ['id', 'name', 'categoryFk'],
include: 'category',
order: 'name ASC',
}"
@on-fetch="(data) => (itemTypesOptions = data)"
auto-load
/>
<FetchData
url="Items/withName"
:filter="{
fields: ['id', 'name'],
order: 'id DESC',
}"
@on-fetch="(data) => (itemsWithNameOptions = data)"
auto-load
/>
<FetchData
url="Intrastats"
:filter="{
fields: ['id', 'description'],
order: 'description ASC',
}"
@on-fetch="(data) => (intrastatsOptions = data)"
auto-load
/>
<FetchData
url="Expenses"
:filter="{
fields: ['id', 'name'],
order: 'name ASC',
}"
@on-fetch="(data) => (expensesOptions = data)"
auto-load
/>
<FormModel
:url="`Items/${route.params.id}`"
:url-update="`Items/${route.params.id}`"
model="item"
auto-load
:clear-store-on-unmount="false"
>
<template #form="{ data }">
<VnRow class="row q-gutter-md q-mb-md">
<VnSelect
:label="t('basicData.type')"
v-model="data.typeFk"
:options="itemTypesOptions"
option-value="id"
option-label="name"
hide-selected
map-options
>
<template #option="scope">
<QItem v-bind="scope.itemProps">
<QItemSection>
<QItemLabel>{{ scope.opt?.name }}</QItemLabel>
<QItemLabel caption>
{{ scope.opt?.category?.name }}
</QItemLabel>
</QItemSection>
</QItem>
</template>
</VnSelect>
<VnInput :label="t('basicData.reference')" v-model="data.comment" />
<VnInput :label="t('basicData.relevancy')" v-model="data.relevancy" />
</VnRow>
<VnRow class="row q-gutter-md q-mb-md">
<VnInput :label="t('basicData.stems')" v-model="data.stems" />
<VnInput
:label="t('basicData.multiplier')"
v-model="data.stemMultiplier"
/>
<VnSelectDialog
:label="t('basicData.generic')"
v-model="data.genericFk"
:options="itemsWithNameOptions"
option-value="id"
option-label="name"
map-options
hide-selected
action-icon="filter_alt"
>
<template #form>
<FilterItemForm
url="Items/withName"
@item-selected="data.genericFk = $event"
/>
</template>
<template #option="scope">
<QItem v-bind="scope.itemProps">
<QItemSection>
<QItemLabel>{{ scope.opt?.name }}</QItemLabel>
<QItemLabel caption> #{{ scope.opt?.id }} </QItemLabel>
</QItemSection>
</QItem>
</template>
</VnSelectDialog>
</VnRow>
<VnRow class="row q-gutter-md q-mb-md">
<VnSelectDialog
:label="t('basicData.intrastat')"
v-model="data.intrastatFk"
:options="intrastatsOptions"
option-value="id"
option-label="description"
map-options
hide-selected
>
<template #form>
<CreateIntrastatForm
@on-data-saved="
(_, requestResponse) =>
onIntrastatCreated(requestResponse, data)
"
/>
</template>
<template #option="scope">
<QItem v-bind="scope.itemProps">
<QItemSection>
<QItemLabel>{{ scope.opt?.description }}</QItemLabel>
<QItemLabel caption> #{{ scope.opt?.id }} </QItemLabel>
</QItemSection>
</QItem>
</template>
</VnSelectDialog>
<div class="col">
<VnSelect
:label="t('basicData.expense')"
v-model="data.expenseFk"
:options="expensesOptions"
option-value="id"
option-label="name"
hide-selected
map-options
/>
</div>
</VnRow>
<VnRow class="row q-gutter-md q-mb-md">
<VnInput
:label="t('basicData.weightByPiece')"
v-model.number="data.weightByPiece"
:min="0"
type="number"
/>
<VnInput
:label="t('basicData.boxUnits')"
v-model.number="data.packingOut"
:min="0"
type="number"
/>
<VnInput
:label="t('basicData.recycledPlastic')"
v-model.number="data.recycledPlastic"
:min="0"
type="number"
/>
<VnInput
:label="t('basicData.nonRecycledPlastic')"
v-model.number="data.nonRecycledPlastic"
:min="0"
type="number"
/>
</VnRow>
<VnRow class="row q-gutter-md q-mb-md">
<QCheckbox v-model="data.isActive" :label="t('basicData.isActive')" />
<QCheckbox v-model="data.hasKgPrice" :label="t('basicData.hasKgPrice')" />
<div>
<QCheckbox
v-model="data.isFragile"
:label="t('basicData.isFragile')"
class="q-mr-sm"
/>
<QIcon name="info" class="cursor-pointer" size="xs">
<QTooltip max-width="300px">
{{ t('basicData.isFragileTooltip') }}
</QTooltip>
</QIcon>
</div>
<div>
<QCheckbox
v-model="data.isPhotoRequested"
:label="t('basicData.isPhotoRequested')"
class="q-mr-sm"
/>
<QIcon name="info" class="cursor-pointer" size="xs">
<QTooltip>
{{ t('basicData.isPhotoRequestedTooltip') }}
</QTooltip>
</QIcon>
</div>
</VnRow>
<VnRow class="row q-gutter-md q-mb-md">
<QInput
:label="t('basicData.description')"
type="textarea"
v-model="data.description"
fill-input
/>
</VnRow>
</template>
</FormModel>
</template>

View File

@ -11,6 +11,30 @@ itemDiary:
showBefore: Show what's before the inventory showBefore: Show what's before the inventory
since: Since since: Since
warehouse: Warehouse warehouse: Warehouse
basicData:
type: Type
reference: Reference
relevancy: Relevancy
stems: Stems
multiplier: Multiplier
generic: Generic
intrastat: Intrastat
expense: Expense
weightByPiece: Weight/Piece
boxUnits: Units/Box
recycledPlastic: Recycled plastic
nonRecycledPlastic: Non recycled plastic
description: Description
isActive: Active
hasKgPrice: Price in kg
isFragile: Fragile
isFragileTooltip: Is shown at website, app that this item cannot travel (wreath, palms, ...)
isPhotoRequested: Do photo
isPhotoRequestedTooltip: This item does need a photo
createIntrastatForm:
title: New intrastat
identifier: Identifier
description: Description
tax: tax:
country: Country country: Country
class: Class class: Class

View File

@ -11,6 +11,30 @@ itemDiary:
showBefore: Mostrar lo anterior al inventario showBefore: Mostrar lo anterior al inventario
since: Desde since: Desde
warehouse: Almacén warehouse: Almacén
basicData:
type: Tipo
reference: Referencia
relevancy: Relevancia
stems: Tallos
multiplier: Multiplicador
generic: Genérico
intrastat: Intrastat
expense: Gasto
weightByPiece: Peso (gramos)/tallo
boxUnits: Unidades/caja
recycledPlastic: Plástico reciclado
nonRecycledPlastic: Plástico no reciclado
description: Descripción
isActive: Activo
hasKgPrice: Precio en kg
isFragile: Frágil
isFragileTooltip: Se muestra en la web app, que este artículo no puede viajar (coronas, palmas, ...)
isPhotoRequested: Hacer foto
isPhotoRequestedTooltip: Este artículo necesita una foto
createIntrastatForm:
title: Nuevo intrastat
identifier: Identificador
description: Descripción
tax: tax:
country: País country: País
class: Clase class: Clase