Merge pull request 'feature/SupplierSubmodules-2' (#66) from feature/SupplierSubmodules-2 into dev
Reviewed-on: hyervoni/salix-front-mindshore#66
This commit is contained in:
commit
3905dd05df
|
@ -7,6 +7,13 @@ import FetchData from 'components/FetchData.vue';
|
|||
import VnRow from 'components/ui/VnRow.vue';
|
||||
import FormModelPopup from './FormModelPopup.vue';
|
||||
|
||||
const props = defineProps({
|
||||
showEntityField: {
|
||||
type: Boolean,
|
||||
default: true,
|
||||
},
|
||||
});
|
||||
|
||||
const emit = defineEmits(['onDataSaved']);
|
||||
|
||||
const { t } = useI18n();
|
||||
|
@ -73,7 +80,7 @@ const onDataSaved = (data) => {
|
|||
:rules="validate('bankEntity.countryFk')"
|
||||
/>
|
||||
</div>
|
||||
<div class="col">
|
||||
<div v-if="showEntityField" class="col">
|
||||
<QInput :label="t('id')" v-model="data.id" />
|
||||
</div>
|
||||
</VnRow>
|
||||
|
|
|
@ -131,7 +131,7 @@ const onProvinceCreated = async () => {
|
|||
es:
|
||||
New postcode: Nuevo código postal
|
||||
Please, ensure you put the correct data!: ¡Por favor, asegúrese de poner los datos correctos!
|
||||
City: Ciudad
|
||||
City: Población
|
||||
Province: Provincia
|
||||
Country: País
|
||||
Postcode: Código postal
|
||||
|
|
|
@ -225,15 +225,19 @@ function getDifferences(obj1, obj2) {
|
|||
delete obj2.$index;
|
||||
|
||||
for (let key in obj1) {
|
||||
if (obj2[key] && obj1[key] !== obj2[key]) {
|
||||
if (obj2[key] && JSON.stringify(obj1[key]) !== JSON.stringify(obj2[key])) {
|
||||
diff[key] = obj2[key];
|
||||
}
|
||||
}
|
||||
for (let key in obj2) {
|
||||
if (obj1[key] === undefined || obj1[key] !== obj2[key]) {
|
||||
if (
|
||||
obj1[key] === undefined ||
|
||||
JSON.stringify(obj1[key]) !== JSON.stringify(obj2[key])
|
||||
) {
|
||||
diff[key] = obj2[key];
|
||||
}
|
||||
}
|
||||
|
||||
return diff;
|
||||
}
|
||||
|
||||
|
|
|
@ -907,6 +907,41 @@ export default {
|
|||
payDemFk: 'Payment deadline',
|
||||
payDay: 'Pay day',
|
||||
},
|
||||
accounts: {
|
||||
iban: 'Iban',
|
||||
bankEntity: 'Bank entity',
|
||||
beneficiary: 'Beneficiary',
|
||||
},
|
||||
contacts: {
|
||||
name: 'Name',
|
||||
phone: 'Phone',
|
||||
mobile: 'Mobile',
|
||||
email: 'Email',
|
||||
observation: 'Notes',
|
||||
},
|
||||
addresses: {
|
||||
street: 'Street',
|
||||
postcode: 'Postcode',
|
||||
phone: 'Phone',
|
||||
name: 'Name',
|
||||
city: 'City',
|
||||
province: 'Province',
|
||||
mobile: 'Mobile',
|
||||
},
|
||||
agencyTerms: {
|
||||
agencyFk: 'Agency',
|
||||
minimumM3: 'Minimum M3',
|
||||
packagePrice: 'Package Price',
|
||||
kmPrice: 'Km Price',
|
||||
m3Price: 'M3 Price',
|
||||
routePrice: 'Route price',
|
||||
minimumKm: 'Minimum Km',
|
||||
},
|
||||
consumption: {
|
||||
entry: 'Entry',
|
||||
date: 'Date',
|
||||
reference: 'Reference',
|
||||
},
|
||||
},
|
||||
travel: {
|
||||
pageTitles: {
|
||||
|
|
|
@ -906,6 +906,41 @@ export default {
|
|||
payDemFk: 'Plazo de pago',
|
||||
payDay: 'Día de pago',
|
||||
},
|
||||
accounts: {
|
||||
iban: 'Iban',
|
||||
bankEntity: 'Entidad bancaria',
|
||||
beneficiary: 'Beneficiario',
|
||||
},
|
||||
contacts: {
|
||||
name: 'Nombre',
|
||||
phone: 'Teléfono',
|
||||
mobile: 'Móvil',
|
||||
email: 'Email',
|
||||
observation: 'Notas',
|
||||
},
|
||||
addresses: {
|
||||
street: 'Dirección',
|
||||
postcode: 'Código postal',
|
||||
phone: 'Teléfono',
|
||||
name: 'Nombre',
|
||||
city: 'Población',
|
||||
province: 'Provincia',
|
||||
mobile: 'Móvil',
|
||||
},
|
||||
agencyTerms: {
|
||||
agencyFk: 'Agencia',
|
||||
minimumM3: 'M3 mínimos',
|
||||
packagePrice: 'Precio bulto',
|
||||
kmPrice: 'Precio Km',
|
||||
m3Price: 'Precio M3',
|
||||
routePrice: 'Precio ruta',
|
||||
minimumKm: 'Km mínimos',
|
||||
},
|
||||
consumption: {
|
||||
entry: 'Entrada',
|
||||
date: 'Fecha',
|
||||
reference: 'Referencia',
|
||||
},
|
||||
},
|
||||
travel: {
|
||||
pageTitles: {
|
||||
|
|
|
@ -1 +1,177 @@
|
|||
<template>Supplier accounts</template>
|
||||
<script setup>
|
||||
import { ref, onMounted } from 'vue';
|
||||
import { useRoute } from 'vue-router';
|
||||
import { useI18n } from 'vue-i18n';
|
||||
|
||||
import FetchData from 'components/FetchData.vue';
|
||||
import CrudModel from 'components/CrudModel.vue';
|
||||
import VnRow from 'components/ui/VnRow.vue';
|
||||
import VnInput from 'src/components/common/VnInput.vue';
|
||||
import CreateBankEntityForm from 'src/components/CreateBankEntityForm.vue';
|
||||
import VnSelectCreate from 'src/components/common/VnSelectCreate.vue';
|
||||
|
||||
import axios from 'axios';
|
||||
import useNotify from 'src/composables/useNotify.js';
|
||||
import { useQuasar } from 'quasar';
|
||||
|
||||
const quasar = useQuasar();
|
||||
const { notify } = useNotify();
|
||||
const route = useRoute();
|
||||
const { t } = useI18n();
|
||||
const supplier = ref(null);
|
||||
const supplierAccountRef = ref(null);
|
||||
const wireTransferFk = ref(null);
|
||||
const bankEntitiesOptions = ref([]);
|
||||
|
||||
const onBankEntityCreated = (data) => {
|
||||
bankEntitiesOptions.value.push(data);
|
||||
};
|
||||
|
||||
const onChangesSaved = () => {
|
||||
if (supplier.value.payMethodFk !== wireTransferFk.value)
|
||||
quasar
|
||||
.dialog({
|
||||
message: t('Do you want to change the pay method to wire transfer?'),
|
||||
ok: {
|
||||
push: true,
|
||||
color: 'primary',
|
||||
},
|
||||
cancel: true,
|
||||
})
|
||||
.onOk(async () => {
|
||||
await setWireTransfer();
|
||||
});
|
||||
};
|
||||
|
||||
const setWireTransfer = async () => {
|
||||
try {
|
||||
const params = {
|
||||
id: route.params.id,
|
||||
payMethodFk: wireTransferFk.value,
|
||||
};
|
||||
|
||||
await axios.patch(`Suppliers/${route.params.id}`, params);
|
||||
notify('globals.dataSaved', 'positive');
|
||||
} catch (err) {
|
||||
console.error('Error setting wire transfer', err);
|
||||
}
|
||||
};
|
||||
|
||||
onMounted(() => {
|
||||
if (supplierAccountRef.value) supplierAccountRef.value.reload();
|
||||
});
|
||||
</script>
|
||||
<template>
|
||||
<FetchData
|
||||
url="BankEntities"
|
||||
@on-fetch="(data) => (bankEntitiesOptions = data)"
|
||||
auto-load
|
||||
/>
|
||||
<FetchData
|
||||
url="payMethods/findOne"
|
||||
@on-fetch="(data) => (wireTransferFk = data.id)"
|
||||
:filter="{ where: { code: 'wireTransfer' } }"
|
||||
auto-load
|
||||
/>
|
||||
<FetchData
|
||||
:url="`Suppliers/${route.params.id}`"
|
||||
@on-fetch="(data) => (supplier = data)"
|
||||
auto-load
|
||||
/>
|
||||
<CrudModel
|
||||
data-key="SupplierAccount"
|
||||
url="SupplierAccounts"
|
||||
model="SupplierAccounts"
|
||||
:filter="{
|
||||
fields: ['id', 'supplierFk', 'iban', 'bankEntityFk', 'beneficiary'],
|
||||
where: { supplierFk: route.params.id },
|
||||
}"
|
||||
ref="supplierAccountRef"
|
||||
:default-remove="false"
|
||||
:data-required="{ supplierFk: route.params.id }"
|
||||
@save-changes="onChangesSaved()"
|
||||
>
|
||||
<template #body="{ rows }">
|
||||
<QCard class="q-pa-md">
|
||||
<VnRow
|
||||
v-for="(row, index) in rows"
|
||||
:key="index"
|
||||
class="row q-gutter-md q-mb-md"
|
||||
>
|
||||
<div class="col">
|
||||
<VnInput
|
||||
:label="t('supplier.accounts.iban')"
|
||||
v-model="row.iban"
|
||||
/>
|
||||
</div>
|
||||
<div class="col">
|
||||
<VnSelectCreate
|
||||
:label="t('worker.create.bankEntity')"
|
||||
v-model="row.bankEntityFk"
|
||||
:options="bankEntitiesOptions"
|
||||
option-label="name"
|
||||
option-value="id"
|
||||
hide-selected
|
||||
>
|
||||
<template #form>
|
||||
<CreateBankEntityForm
|
||||
@on-data-saved="onBankEntityCreated($event)"
|
||||
:show-entity-field="false"
|
||||
/>
|
||||
</template>
|
||||
<template #option="scope">
|
||||
<QItem v-bind="scope.itemProps">
|
||||
<QItemSection v-if="scope.opt">
|
||||
<QItemLabel
|
||||
>{{ scope.opt.bic }}
|
||||
{{ scope.opt.name }}</QItemLabel
|
||||
>
|
||||
</QItemSection>
|
||||
</QItem>
|
||||
</template>
|
||||
</VnSelectCreate>
|
||||
</div>
|
||||
<div class="col">
|
||||
<VnInput
|
||||
:label="t('supplier.accounts.beneficiary')"
|
||||
v-model="row.beneficiary"
|
||||
/>
|
||||
</div>
|
||||
<div class="col-1 row justify-center items-center">
|
||||
<QIcon
|
||||
name="delete"
|
||||
size="sm"
|
||||
class="cursor-pointer"
|
||||
color="primary"
|
||||
@click="supplierAccountRef.remove([row])"
|
||||
>
|
||||
<QTooltip>
|
||||
{{ t('Remove account') }}
|
||||
</QTooltip>
|
||||
</QIcon>
|
||||
</div>
|
||||
</VnRow>
|
||||
<VnRow>
|
||||
<QIcon
|
||||
name="add"
|
||||
size="sm"
|
||||
class="cursor-pointer"
|
||||
color="primary"
|
||||
@click="supplierAccountRef.insert()"
|
||||
>
|
||||
<QTooltip>
|
||||
{{ t('Add account') }}
|
||||
</QTooltip>
|
||||
</QIcon>
|
||||
</VnRow>
|
||||
</QCard>
|
||||
</template>
|
||||
</CrudModel>
|
||||
</template>
|
||||
|
||||
<i18n>
|
||||
es:
|
||||
Do you want to change the pay method to wire transfer?: ¿Quieres modificar la forma de pago a transferencia?
|
||||
Add account: Añadir cuenta
|
||||
Remove account: Remover cuenta
|
||||
</i18n>
|
||||
|
|
|
@ -1 +1,97 @@
|
|||
<template>Supplier addresses</template>
|
||||
<script setup>
|
||||
import { useI18n } from 'vue-i18n';
|
||||
import { useRouter, useRoute } from 'vue-router';
|
||||
|
||||
import VnPaginate from 'src/components/ui/VnPaginate.vue';
|
||||
import CardList from 'src/components/ui/CardList.vue';
|
||||
import VnLv from 'src/components/ui/VnLv.vue';
|
||||
|
||||
const router = useRouter();
|
||||
const route = useRoute();
|
||||
const { t } = useI18n();
|
||||
|
||||
const addressesFilter = {
|
||||
fields: [
|
||||
'id',
|
||||
'nickname',
|
||||
'street',
|
||||
'city',
|
||||
'provinceFk',
|
||||
'phone',
|
||||
'mobile',
|
||||
'postalCode',
|
||||
],
|
||||
order: ['nickname ASC'],
|
||||
include: [
|
||||
{
|
||||
relation: 'province',
|
||||
scope: {
|
||||
fields: ['id', 'name'],
|
||||
},
|
||||
},
|
||||
],
|
||||
};
|
||||
|
||||
const redirectToCreateView = () => {
|
||||
router.push({ name: 'SupplierAddressesCreate' });
|
||||
};
|
||||
|
||||
const redirectToUpdateView = (addressData) => {
|
||||
const stringifiedAddressData = JSON.stringify(addressData);
|
||||
router.push({
|
||||
name: 'SupplierAddressesCreate',
|
||||
query: { addressData: stringifiedAddressData },
|
||||
});
|
||||
};
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<QPage class="column items-center q-pa-md">
|
||||
<div class="card-list">
|
||||
<VnPaginate
|
||||
data-key="SupplierAddress"
|
||||
:url="`Suppliers/${route.params.id}/addresses`"
|
||||
:filter="addressesFilter"
|
||||
auto-load
|
||||
>
|
||||
<template #body="{ rows }">
|
||||
<CardList
|
||||
v-for="row of rows"
|
||||
:key="row.id"
|
||||
:title="row.nickname"
|
||||
:id="row.id"
|
||||
@click="redirectToUpdateView(row)"
|
||||
>
|
||||
<template #list-items>
|
||||
<VnLv
|
||||
:label="t('supplier.addresses.street')"
|
||||
:value="row.street"
|
||||
/>
|
||||
<VnLv
|
||||
:label="t('supplier.addresses.postcode')"
|
||||
:value="`${row.postalCode} - ${row.city}, ${row.province.name}`"
|
||||
/>
|
||||
<VnLv
|
||||
:label="t('supplier.addresses.phone')"
|
||||
:value="`${row.phone}, ${row.mobile}`"
|
||||
/>
|
||||
</template>
|
||||
</CardList>
|
||||
</template>
|
||||
</VnPaginate>
|
||||
</div>
|
||||
<QPageSticky :offset="[20, 20]">
|
||||
<QBtn fab icon="add" color="primary" @click="redirectToCreateView()" />
|
||||
<QTooltip>
|
||||
{{ t('supplier.list.newSupplier') }}
|
||||
</QTooltip>
|
||||
</QPageSticky>
|
||||
</QPage>
|
||||
</template>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.card-list {
|
||||
width: 100%;
|
||||
max-width: 60em;
|
||||
}
|
||||
</style>
|
||||
|
|
|
@ -0,0 +1,182 @@
|
|||
<script setup>
|
||||
import { useI18n } from 'vue-i18n';
|
||||
import { reactive, ref, onMounted, onBeforeMount } from 'vue';
|
||||
import { useRouter, useRoute } from 'vue-router';
|
||||
|
||||
import FetchData from 'components/FetchData.vue';
|
||||
import VnSelectFilter from 'src/components/common/VnSelectFilter.vue';
|
||||
import FormModel from 'components/FormModel.vue';
|
||||
import VnInput from 'src/components/common/VnInput.vue';
|
||||
import VnSelectCreate from 'src/components/common/VnSelectCreate.vue';
|
||||
import VnRow from 'components/ui/VnRow.vue';
|
||||
import CustomerCreateNewPostcode from 'src/components/CreateNewPostcodeForm.vue';
|
||||
|
||||
const { t } = useI18n();
|
||||
const route = useRoute();
|
||||
const router = useRouter();
|
||||
|
||||
const provincesOptions = ref([]);
|
||||
const postcodesOptions = ref([]);
|
||||
const townsLocationOptions = ref([]);
|
||||
const viewAction = ref();
|
||||
const updateAddressId = ref(null);
|
||||
const newAddressForm = reactive({
|
||||
nickname: null,
|
||||
street: null,
|
||||
postalCode: null,
|
||||
city: null,
|
||||
provinceFk: null,
|
||||
phone: null,
|
||||
mobile: null,
|
||||
});
|
||||
|
||||
const onDataSaved = () => {
|
||||
router.push({ name: 'SupplierAddresses' });
|
||||
};
|
||||
|
||||
const updateAddressForm = (addressData) => {
|
||||
for (let key in newAddressForm) {
|
||||
if (key in addressData) {
|
||||
newAddressForm[key] = addressData[key];
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
onBeforeMount(() => {
|
||||
viewAction.value = route.query.addressData ? 'update' : 'create';
|
||||
|
||||
if (viewAction.value === 'create') newAddressForm.supplierFk = route.params.id;
|
||||
});
|
||||
|
||||
onMounted(() => {
|
||||
if (viewAction.value === 'update' && route.query.addressData) {
|
||||
const addressData = JSON.parse(route.query.addressData);
|
||||
updateAddressId.value = addressData.id;
|
||||
updateAddressForm(addressData);
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<FetchData
|
||||
ref="postcodeFetchDataRef"
|
||||
url="Postcodes/location"
|
||||
@on-fetch="(data) => (postcodesOptions = data)"
|
||||
auto-load
|
||||
/>
|
||||
<FetchData
|
||||
ref="provincesFetchDataRef"
|
||||
@on-fetch="(data) => (provincesOptions = data)"
|
||||
auto-load
|
||||
url="Provinces"
|
||||
/>
|
||||
<FetchData
|
||||
ref="townsFetchDataRef"
|
||||
@on-fetch="(data) => (townsLocationOptions = data)"
|
||||
auto-load
|
||||
url="Towns/location"
|
||||
/>
|
||||
<QPage>
|
||||
<FormModel
|
||||
model="supplierAddresses"
|
||||
:form-initial-data="newAddressForm"
|
||||
:url-update="
|
||||
viewAction !== 'create' ? `SupplierAddresses/${updateAddressId}` : null
|
||||
"
|
||||
:url-create="viewAction === 'create' ? 'SupplierAddresses' : null"
|
||||
:observe-form-changes="viewAction === 'create'"
|
||||
@on-data-saved="onDataSaved()"
|
||||
>
|
||||
<template #form="{ data, validate }">
|
||||
<VnRow class="row q-gutter-md q-mb-md">
|
||||
<div class="col">
|
||||
<VnInput
|
||||
v-model="data.nickname"
|
||||
:label="t('supplier.addresses.name')"
|
||||
/>
|
||||
</div>
|
||||
<div class="col">
|
||||
<VnInput
|
||||
v-model="data.street"
|
||||
:label="t('supplier.addresses.street')"
|
||||
/>
|
||||
</div>
|
||||
</VnRow>
|
||||
<VnRow class="row q-gutter-md q-mb-md">
|
||||
<div class="col">
|
||||
<VnSelectCreate
|
||||
v-model="data.postalCode"
|
||||
:label="t('supplier.addresses.postcode')"
|
||||
:rules="validate('supplierAddress.postcode')"
|
||||
:roles-allowed-to-create="['deliveryAssistant']"
|
||||
:options="postcodesOptions"
|
||||
option-label="code"
|
||||
option-value="code"
|
||||
hide-selected
|
||||
>
|
||||
<template #form>
|
||||
<CustomerCreateNewPostcode
|
||||
@on-data-saved="onPostcodeCreated($event)"
|
||||
/>
|
||||
</template>
|
||||
<template #option="scope">
|
||||
<QItem v-bind="scope.itemProps">
|
||||
<QItemSection v-if="scope.opt">
|
||||
<QItemLabel>{{ scope.opt.code }}</QItemLabel>
|
||||
<QItemLabel caption
|
||||
>{{ scope.opt.code }} -
|
||||
{{ scope.opt.town.name }} ({{
|
||||
scope.opt.town.province.name
|
||||
}},
|
||||
{{
|
||||
scope.opt.town.province.country.country
|
||||
}})</QItemLabel
|
||||
>
|
||||
</QItemSection>
|
||||
</QItem>
|
||||
</template>
|
||||
</VnSelectCreate>
|
||||
</div>
|
||||
<div class="col">
|
||||
<VnSelectFilter
|
||||
:label="t('supplier.addresses.city')"
|
||||
:options="townsLocationOptions"
|
||||
v-model="data.city"
|
||||
hide-selected
|
||||
option-label="name"
|
||||
option-value="id"
|
||||
/>
|
||||
</div>
|
||||
</VnRow>
|
||||
<VnRow class="row q-gutter-md q-mb-md">
|
||||
<div class="col">
|
||||
<VnSelectFilter
|
||||
:label="t('supplier.addresses.province')"
|
||||
:options="provincesOptions"
|
||||
hide-selected
|
||||
map-options
|
||||
option-label="name"
|
||||
option-value="id"
|
||||
v-model="data.provinceFk"
|
||||
/>
|
||||
</div>
|
||||
<div class="col">
|
||||
<VnInput
|
||||
v-model="data.phone"
|
||||
:label="t('supplier.addresses.phone')"
|
||||
/>
|
||||
</div>
|
||||
</VnRow>
|
||||
<VnRow class="row q-gutter-md q-mb-md">
|
||||
<div class="col">
|
||||
<VnInput
|
||||
v-model="data.mobile"
|
||||
:label="t('supplier.addresses.mobile')"
|
||||
/>
|
||||
</div>
|
||||
<div class="col" />
|
||||
</VnRow>
|
||||
</template>
|
||||
</FormModel>
|
||||
</QPage>
|
||||
</template>
|
|
@ -1 +1,139 @@
|
|||
<template>Supplier agency term</template>
|
||||
<script setup>
|
||||
import { ref, onMounted } from 'vue';
|
||||
import { useRouter, useRoute } from 'vue-router';
|
||||
import { useI18n } from 'vue-i18n';
|
||||
|
||||
import FetchData from 'components/FetchData.vue';
|
||||
import CrudModel from 'components/CrudModel.vue';
|
||||
import VnRow from 'components/ui/VnRow.vue';
|
||||
|
||||
const route = useRoute();
|
||||
const router = useRouter();
|
||||
const { t } = useI18n();
|
||||
const supplierAgencyTermRef = ref(null);
|
||||
const agenciesOptions = ref(null);
|
||||
|
||||
const supplierAgencyFilter = {
|
||||
include: {
|
||||
relation: 'agency',
|
||||
scope: {
|
||||
fields: ['id', 'name'],
|
||||
},
|
||||
},
|
||||
where: { supplierFk: route.params.id },
|
||||
};
|
||||
|
||||
const redirectToCreateView = () => {
|
||||
router.push({ name: 'SupplierAgencyTermCreate' });
|
||||
};
|
||||
|
||||
onMounted(() => {
|
||||
if (supplierAgencyTermRef.value) supplierAgencyTermRef.value.reload();
|
||||
});
|
||||
</script>
|
||||
<template>
|
||||
<FetchData
|
||||
url="Suppliers/freeAgencies"
|
||||
@on-fetch="(data) => (agenciesOptions = data)"
|
||||
auto-load
|
||||
/>
|
||||
<CrudModel
|
||||
ref="supplierAgencyTermRef"
|
||||
data-key="SupplierAgencyTerm"
|
||||
save-url="SupplierAgencyTerms/crud"
|
||||
url="SupplierAgencyTerms"
|
||||
model="SupplierAgencyTerm"
|
||||
primary-key="agencyFk"
|
||||
:filter="supplierAgencyFilter"
|
||||
:default-remove="false"
|
||||
:data-required="{
|
||||
supplierFk: route.params.id,
|
||||
}"
|
||||
>
|
||||
<template #body="{ rows }">
|
||||
<QCard class="q-pa-md">
|
||||
<VnRow
|
||||
v-for="(row, index) in rows"
|
||||
:key="index"
|
||||
class="row q-gutter-md q-mb-md"
|
||||
>
|
||||
<div class="col">
|
||||
<QField :label="t('supplier.agencyTerms.agencyFk')" stack-label>
|
||||
<template #control>
|
||||
<div tabindex="0">
|
||||
{{ row.agency?.name }}
|
||||
</div>
|
||||
</template>
|
||||
</QField>
|
||||
</div>
|
||||
<div class="col">
|
||||
<QInput
|
||||
:label="t('supplier.agencyTerms.minimumM3')"
|
||||
v-model.number="row.minimumM3"
|
||||
type="number"
|
||||
/>
|
||||
</div>
|
||||
<div class="col">
|
||||
<QInput
|
||||
:label="t('supplier.agencyTerms.packagePrice')"
|
||||
v-model.number="row.packagePrice"
|
||||
type="number"
|
||||
/>
|
||||
</div>
|
||||
<div class="col">
|
||||
<QInput
|
||||
:label="t('supplier.agencyTerms.kmPrice')"
|
||||
v-model.number="row.kmPrice"
|
||||
type="number"
|
||||
/>
|
||||
</div>
|
||||
<div class="col">
|
||||
<QInput
|
||||
:label="t('supplier.agencyTerms.m3Price')"
|
||||
v-model.number="row.m3Price"
|
||||
type="number"
|
||||
/>
|
||||
</div>
|
||||
<div class="col">
|
||||
<QInput
|
||||
:label="t('supplier.agencyTerms.routePrice')"
|
||||
v-model.number="row.routePrice"
|
||||
type="number"
|
||||
/>
|
||||
</div>
|
||||
<div class="col">
|
||||
<QInput
|
||||
:label="t('supplier.agencyTerms.minimumKm')"
|
||||
v-model.number="row.minimumKm"
|
||||
type="number"
|
||||
/>
|
||||
</div>
|
||||
<div class="col-1 row justify-center items-center">
|
||||
<QIcon
|
||||
name="delete"
|
||||
size="sm"
|
||||
class="cursor-pointer"
|
||||
color="primary"
|
||||
@click="supplierAgencyTermRef.remove([row])"
|
||||
>
|
||||
<QTooltip>
|
||||
{{ t('Remove row') }}
|
||||
</QTooltip>
|
||||
</QIcon>
|
||||
</div>
|
||||
</VnRow>
|
||||
</QCard>
|
||||
</template>
|
||||
</CrudModel>
|
||||
<QPageSticky :offset="[20, 20]">
|
||||
<QBtn fab icon="add" color="primary" @click="redirectToCreateView()" />
|
||||
<QTooltip>
|
||||
{{ t('supplier.list.newSupplier') }}
|
||||
</QTooltip>
|
||||
</QPageSticky>
|
||||
</template>
|
||||
|
||||
<i18n>
|
||||
es:
|
||||
Remove row: Eliminar fila
|
||||
</i18n>
|
||||
|
|
|
@ -0,0 +1,113 @@
|
|||
<script setup>
|
||||
import { useI18n } from 'vue-i18n';
|
||||
import { reactive, ref } from 'vue';
|
||||
import { useRouter, useRoute } from 'vue-router';
|
||||
|
||||
import FetchData from 'components/FetchData.vue';
|
||||
import VnSelectFilter from 'src/components/common/VnSelectFilter.vue';
|
||||
import FormModel from 'components/FormModel.vue';
|
||||
import VnRow from 'components/ui/VnRow.vue';
|
||||
|
||||
const { t } = useI18n();
|
||||
const router = useRouter();
|
||||
const route = useRoute();
|
||||
|
||||
const agenciesOptions = ref(null);
|
||||
const newAgencyTermForm = reactive({
|
||||
agencyFk: null,
|
||||
minimumM3: null,
|
||||
packagePrice: null,
|
||||
kmPrice: null,
|
||||
m3Price: null,
|
||||
routePrice: null,
|
||||
minimumKm: null,
|
||||
supplierFk: route.params.id,
|
||||
});
|
||||
|
||||
const onDataSaved = () => {
|
||||
router.push({ name: 'SupplierAgencyTerm' });
|
||||
};
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<FetchData
|
||||
url="Suppliers/freeAgencies"
|
||||
@on-fetch="(data) => (agenciesOptions = data)"
|
||||
auto-load
|
||||
/>
|
||||
|
||||
<QPage>
|
||||
<FormModel
|
||||
model="supplierAgencyTerm"
|
||||
:form-initial-data="newAgencyTermForm"
|
||||
url-create="SupplierAgencyTerms"
|
||||
:observe-form-changes="true"
|
||||
@on-data-saved="onDataSaved()"
|
||||
>
|
||||
<template #form="{ data }">
|
||||
<VnRow class="row q-gutter-md q-mb-md">
|
||||
<div class="col">
|
||||
<VnSelectFilter
|
||||
:label="t('supplier.agencyTerms.agencyFk')"
|
||||
v-model="data.agencyFk"
|
||||
:options="agenciesOptions"
|
||||
option-label="name"
|
||||
option-value="id"
|
||||
hide-selected
|
||||
rounded
|
||||
/>
|
||||
</div>
|
||||
<div class="col">
|
||||
<QInput
|
||||
:label="t('supplier.agencyTerms.minimumM3')"
|
||||
v-model.number="data.minimumM3"
|
||||
type="number"
|
||||
/>
|
||||
</div>
|
||||
</VnRow>
|
||||
<VnRow class="row q-gutter-md q-mb-md">
|
||||
<div class="col">
|
||||
<QInput
|
||||
:label="t('supplier.agencyTerms.packagePrice')"
|
||||
v-model.number="data.packagePrice"
|
||||
type="number"
|
||||
/>
|
||||
</div>
|
||||
<div class="col">
|
||||
<QInput
|
||||
:label="t('supplier.agencyTerms.kmPrice')"
|
||||
v-model.number="data.kmPrice"
|
||||
type="number"
|
||||
/>
|
||||
</div>
|
||||
</VnRow>
|
||||
<VnRow class="row q-gutter-md q-mb-md">
|
||||
<div class="col">
|
||||
<QInput
|
||||
:label="t('supplier.agencyTerms.m3Price')"
|
||||
v-model.number="data.m3Price"
|
||||
type="number"
|
||||
/>
|
||||
</div>
|
||||
<div class="col">
|
||||
<QInput
|
||||
:label="t('supplier.agencyTerms.routePrice')"
|
||||
v-model.number="data.routePrice"
|
||||
type="number"
|
||||
/>
|
||||
</div>
|
||||
</VnRow>
|
||||
<VnRow class="row q-gutter-md q-mb-md">
|
||||
<div class="col">
|
||||
<QInput
|
||||
:label="t('supplier.agencyTerms.minimumKm')"
|
||||
v-model.number="data.minimumKm"
|
||||
type="number"
|
||||
/>
|
||||
</div>
|
||||
<div class="col" />
|
||||
</VnRow>
|
||||
</template>
|
||||
</FormModel>
|
||||
</QPage>
|
||||
</template>
|
|
@ -29,7 +29,6 @@ const { t } = useI18n();
|
|||
<QPageContainer>
|
||||
<QPage>
|
||||
<VnSubToolbar />
|
||||
|
||||
<div class="q-pa-md"><RouterView></RouterView></div>
|
||||
</QPage>
|
||||
</QPageContainer>
|
||||
|
|
|
@ -1 +1,192 @@
|
|||
<template>Supplier consumption</template>
|
||||
<script setup>
|
||||
import { useRoute } from 'vue-router';
|
||||
import { ref, computed } from 'vue';
|
||||
import { useI18n } from 'vue-i18n';
|
||||
import { useQuasar } from 'quasar';
|
||||
|
||||
import FetchData from 'components/FetchData.vue';
|
||||
import FetchedTags from 'components/ui/FetchedTags.vue';
|
||||
import SendEmailDialog from 'components/common/SendEmailDialog.vue';
|
||||
|
||||
import { toDate, toDateString } from 'src/filters';
|
||||
import { dashIfEmpty } from 'src/filters';
|
||||
import { usePrintService } from 'composables/usePrintService';
|
||||
import useNotify from 'src/composables/useNotify.js';
|
||||
import axios from 'axios';
|
||||
|
||||
const { t } = useI18n();
|
||||
const route = useRoute();
|
||||
const { openReport, sendEmail } = usePrintService();
|
||||
const quasar = useQuasar();
|
||||
const { notify } = useNotify();
|
||||
|
||||
const suppliersConsumption = ref();
|
||||
|
||||
const userParams = computed(() => {
|
||||
const minDate = Date.vnNew();
|
||||
minDate.setHours(0, 0, 0, 0);
|
||||
minDate.setMonth(minDate.getMonth() - 2);
|
||||
|
||||
const maxDate = Date.vnNew();
|
||||
maxDate.setHours(23, 59, 59, 59);
|
||||
|
||||
return {
|
||||
from: toDateString(minDate),
|
||||
to: toDateString(maxDate),
|
||||
};
|
||||
});
|
||||
|
||||
const reportParams = computed(() => ({
|
||||
recipientId: Number(route.params.id),
|
||||
...userParams.value,
|
||||
}));
|
||||
|
||||
const rows = computed(() => suppliersConsumption.value || []);
|
||||
|
||||
const openReportPdf = () => {
|
||||
openReport(`Suppliers/${route.params.id}/campaign-metrics-pdf`, reportParams.value);
|
||||
};
|
||||
|
||||
const getSupplierContacts = async () => {
|
||||
try {
|
||||
const params = {
|
||||
filter: {
|
||||
where: {
|
||||
supplierFk: route.params.id,
|
||||
email: { neq: null },
|
||||
},
|
||||
limit: 1,
|
||||
},
|
||||
};
|
||||
|
||||
const { data } = await axios.get('SupplierContacts', params);
|
||||
|
||||
if (data && data.length) return data[0].email;
|
||||
} catch (err) {
|
||||
notify('This supplier does not have a contact with an email address', 'negative');
|
||||
console.error('Error fetching supplierContacts: ', err);
|
||||
}
|
||||
};
|
||||
|
||||
const openSendEmailDialog = async () => {
|
||||
const email = await getSupplierContacts();
|
||||
quasar.dialog({
|
||||
component: SendEmailDialog,
|
||||
componentProps: {
|
||||
data: {
|
||||
address: email,
|
||||
},
|
||||
promise: sendCampaignMetricsEmail,
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
const sendCampaignMetricsEmail = ({ address }) => {
|
||||
sendEmail(`Suppliers/${route.params.id}/campaign-metrics-email`, {
|
||||
recipient: address,
|
||||
...reportParams.value,
|
||||
});
|
||||
};
|
||||
|
||||
const calculateTotal = (buysArray) => {
|
||||
return buysArray.reduce((accumulator, { total }) => accumulator + total, 0);
|
||||
};
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<FetchData
|
||||
url="Suppliers/consumption"
|
||||
@on-fetch="(data) => (suppliersConsumption = data)"
|
||||
:filter="{
|
||||
where: { supplierFk: route.params.id },
|
||||
order: ['itemTypeFk', 'itemName', 'itemSize'],
|
||||
}"
|
||||
:params="userParams"
|
||||
auto-load
|
||||
/>
|
||||
<QToolbar class="bg-vn-dark justify-end">
|
||||
<div id="st-data">
|
||||
<QBtn
|
||||
v-if="userParams.from && userParams.to"
|
||||
color="primary"
|
||||
icon-right="picture_as_pdf"
|
||||
no-caps
|
||||
class="q-mr-md"
|
||||
@click="openReportPdf()"
|
||||
>
|
||||
<QTooltip>
|
||||
{{ t('Open as PDF') }}
|
||||
</QTooltip>
|
||||
</QBtn>
|
||||
<QBtn
|
||||
v-if="userParams.from && userParams.to"
|
||||
color="primary"
|
||||
icon-right="email"
|
||||
no-caps
|
||||
@click="openSendEmailDialog()"
|
||||
>
|
||||
<QTooltip>
|
||||
{{ t('Send to email') }}
|
||||
</QTooltip>
|
||||
</QBtn>
|
||||
</div>
|
||||
<QSpace />
|
||||
<div id="st-actions"></div>
|
||||
</QToolbar>
|
||||
<QPage class="column items-center q-pa-md">
|
||||
<QTable
|
||||
:rows="rows"
|
||||
hide-bottom
|
||||
row-key="id"
|
||||
hide-header
|
||||
:pagination="{ rowsPerPage: 0 }"
|
||||
class="full-width q-mt-md"
|
||||
>
|
||||
<template #body="{ row }">
|
||||
<QTr>
|
||||
<QTd no-hover class="label">{{
|
||||
t('supplier.consumption.entry')
|
||||
}}</QTd>
|
||||
<QTd no-hover>{{ row.id }}</QTd>
|
||||
<QTd no-hover class="label">{{ t('supplier.consumption.date') }}</QTd>
|
||||
<QTd no-hover>{{ toDate(row.shipped) }}</QTd>
|
||||
<QTd no-hover class="label">{{
|
||||
t('supplier.consumption.reference')
|
||||
}}</QTd>
|
||||
<QTd no-hover>{{ row.invoiceNumber }}</QTd>
|
||||
</QTr>
|
||||
<QTr v-for="(buy, index) in row.buys" :key="index">
|
||||
<QTd no-hover> {{ buy.itemName }}</QTd>
|
||||
|
||||
<QTd no-hover>
|
||||
<span>{{ buy.subName }}</span>
|
||||
<fetched-tags :item="buy" :max-length="5" />
|
||||
</QTd>
|
||||
<QTd no-hover> {{ dashIfEmpty(buy.quantity) }}</QTd>
|
||||
<QTd no-hover> {{ dashIfEmpty(buy.price) }}</QTd>
|
||||
<QTd colspan="2" no-hover> {{ dashIfEmpty(buy.total) }}</QTd>
|
||||
</QTr>
|
||||
<QTr>
|
||||
<QTd colspan="6" no-hover>
|
||||
<span class="label">{{ t('Total entry') }}: </span>
|
||||
<span>{{ calculateTotal(row.buys) }}</span>
|
||||
</QTd>
|
||||
</QTr>
|
||||
</template>
|
||||
</QTable>
|
||||
</QPage>
|
||||
</template>
|
||||
|
||||
<style scoped lang="scss">
|
||||
.label {
|
||||
color: var(--vn-label);
|
||||
}
|
||||
</style>
|
||||
|
||||
<i18n>
|
||||
es:
|
||||
Total entry: Total entrada
|
||||
Open as PDF: Abrir como PDF
|
||||
Send to email: Enviar por email
|
||||
This supplier does not have a contact with an email address: Este proveedor no tiene un email de contacto
|
||||
</i18n>
|
||||
|
|
|
@ -1 +1,118 @@
|
|||
<template>Supplier contacts</template>
|
||||
<script setup>
|
||||
import { ref, onMounted } from 'vue';
|
||||
import { useRoute } from 'vue-router';
|
||||
import { useI18n } from 'vue-i18n';
|
||||
|
||||
import CrudModel from 'components/CrudModel.vue';
|
||||
import VnRow from 'components/ui/VnRow.vue';
|
||||
import VnInput from 'src/components/common/VnInput.vue';
|
||||
|
||||
const route = useRoute();
|
||||
const { t } = useI18n();
|
||||
const supplierContactRef = ref(null);
|
||||
|
||||
onMounted(() => {
|
||||
if (supplierContactRef.value) supplierContactRef.value.reload();
|
||||
});
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<CrudModel
|
||||
data-key="SupplierContact"
|
||||
url="SupplierContacts"
|
||||
model="SupplierContact"
|
||||
:filter="{
|
||||
where: { supplierFk: route.params.id },
|
||||
}"
|
||||
ref="supplierContactRef"
|
||||
:default-remove="false"
|
||||
:data-required="{ supplierFk: route.params.id }"
|
||||
>
|
||||
<template #body="{ rows }">
|
||||
<QCard class="q-pa-md">
|
||||
<QCardSection
|
||||
v-for="(row, index) in rows"
|
||||
:key="index"
|
||||
class="border q-pa-md q-mb-md"
|
||||
>
|
||||
<VnRow class="row q-gutter-md">
|
||||
<div class="col">
|
||||
<VnInput
|
||||
:label="t('supplier.contacts.name')"
|
||||
v-model="row.name"
|
||||
/>
|
||||
</div>
|
||||
<div class="col">
|
||||
<VnInput
|
||||
:label="t('supplier.contacts.phone')"
|
||||
v-model="row.phone"
|
||||
/>
|
||||
</div>
|
||||
<div class="col">
|
||||
<VnInput
|
||||
:label="t('supplier.contacts.mobile')"
|
||||
v-model="row.mobile"
|
||||
/>
|
||||
</div>
|
||||
<div class="col">
|
||||
<VnInput
|
||||
:label="t('supplier.contacts.email')"
|
||||
v-model="row.email"
|
||||
/>
|
||||
</div>
|
||||
</VnRow>
|
||||
<VnRow class="row q-gutter-md">
|
||||
<div class="col">
|
||||
<QInput
|
||||
:label="t('supplier.contacts.observation')"
|
||||
type="textarea"
|
||||
v-model="row.observation"
|
||||
fill-input
|
||||
autogrow
|
||||
/>
|
||||
</div>
|
||||
<div class="col-1 row justify-center items-center">
|
||||
<QIcon
|
||||
name="delete"
|
||||
size="sm"
|
||||
class="cursor-pointer"
|
||||
color="primary"
|
||||
@click="supplierContactRef.remove([row])"
|
||||
>
|
||||
<QTooltip>
|
||||
{{ t('Remove contact') }}
|
||||
</QTooltip>
|
||||
</QIcon>
|
||||
</div>
|
||||
</VnRow>
|
||||
</QCardSection>
|
||||
<VnRow>
|
||||
<QIcon
|
||||
name="add"
|
||||
size="sm"
|
||||
class="cursor-pointer"
|
||||
color="primary"
|
||||
@click="supplierContactRef.insert()"
|
||||
>
|
||||
<QTooltip>
|
||||
{{ t('Add contact') }}
|
||||
</QTooltip>
|
||||
</QIcon>
|
||||
</VnRow>
|
||||
</QCard>
|
||||
</template>
|
||||
</CrudModel>
|
||||
</template>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.border {
|
||||
border-radius: 0px !important;
|
||||
border: 1px solid var(--vn-text) !important;
|
||||
}
|
||||
</style>
|
||||
|
||||
<i18n>
|
||||
es:
|
||||
Add contact: Añadir contacto
|
||||
Remove contact: Remover contacto
|
||||
</i18n>
|
||||
|
|
|
@ -262,7 +262,16 @@ onMounted(async () => {
|
|||
<div id="st-data"></div>
|
||||
<QSpace />
|
||||
<div id="st-actions">
|
||||
<QBtn color="primary" icon-right="archive" no-caps @click="openReportPdf()" />
|
||||
<QBtn
|
||||
color="primary"
|
||||
icon-right="picture_as_pdf"
|
||||
no-caps
|
||||
@click="openReportPdf()"
|
||||
>
|
||||
<QTooltip>
|
||||
{{ t('Open as PDF') }}
|
||||
</QTooltip>
|
||||
</QBtn>
|
||||
</div>
|
||||
</QToolbar>
|
||||
<QDrawer v-model="stateStore.rightDrawer" side="right" :width="256" show-if-above>
|
||||
|
@ -415,4 +424,5 @@ es:
|
|||
physicKg: KG físico
|
||||
shipped: F. envío
|
||||
landed: F. llegada
|
||||
Open as PDF: Abrir como PDF
|
||||
</i18n>
|
||||
|
|
|
@ -134,6 +134,12 @@ export default {
|
|||
component: () =>
|
||||
import('src/pages/Supplier/Card/SupplierAddresses.vue'),
|
||||
},
|
||||
{
|
||||
path: 'address/create',
|
||||
name: 'SupplierAddressesCreate',
|
||||
component: () =>
|
||||
import('src/pages/Supplier/Card/SupplierAddressesCreate.vue'),
|
||||
},
|
||||
{
|
||||
path: 'consumption',
|
||||
name: 'SupplierConsumption',
|
||||
|
@ -154,6 +160,12 @@ export default {
|
|||
component: () =>
|
||||
import('src/pages/Supplier/Card/SupplierAgencyTerm.vue'),
|
||||
},
|
||||
{
|
||||
path: 'agency-term/create',
|
||||
name: 'SupplierAgencyTermCreate',
|
||||
component: () =>
|
||||
import('src/pages/Supplier/Card/SupplierAgencyTermCreate.vue'),
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
|
|
Loading…
Reference in New Issue