diff --git a/src/components/ui/VnMoreOptions.vue b/src/components/ui/VnMoreOptions.vue
new file mode 100644
index 000000000..39e84be2b
--- /dev/null
+++ b/src/components/ui/VnMoreOptions.vue
@@ -0,0 +1,20 @@
+
+
+
+ {{ $t('components.cardDescriptor.moreOptions') }}
+
+
+
+
+
+
+
+
diff --git a/src/components/ui/VnNotes.vue b/src/components/ui/VnNotes.vue
index e308ea9bb..1690a94ba 100644
--- a/src/components/ui/VnNotes.vue
+++ b/src/components/ui/VnNotes.vue
@@ -110,7 +110,7 @@ onBeforeRouteLeave((to, from, next) => {
:url="$props.url"
order="created DESC"
:limit="0"
- :filter="$props.filter"
+ :user-filter="$props.filter"
auto-load
ref="vnPaginateRef"
class="show"
diff --git a/src/components/ui/VnPaginate.vue b/src/components/ui/VnPaginate.vue
index 3649ba8f5..0111366f5 100644
--- a/src/components/ui/VnPaginate.vue
+++ b/src/components/ui/VnPaginate.vue
@@ -74,6 +74,10 @@ const props = defineProps({
type: Boolean,
default: false,
},
+ mapKey: {
+ type: String,
+ default: '',
+ },
});
const emit = defineEmits(['onFetch', 'onPaginate', 'onChange']);
@@ -96,15 +100,20 @@ const arrayData = useArrayData(props.dataKey, {
exprBuilder: props.exprBuilder,
keepOpts: props.keepOpts,
searchUrl: props.searchUrl,
+ mapKey: props.mapKey,
});
const store = arrayData.store;
onMounted(async () => {
if (props.autoLoad && !store.data?.length) await fetch();
+ else emit('onFetch', store.data);
mounted.value = true;
});
-onBeforeUnmount(() => arrayData.reset());
+onBeforeUnmount(() => {
+ if (!store.keepData) arrayData.reset(['data']);
+ arrayData.resetPagination();
+});
watch(
() => props.data,
@@ -132,8 +141,8 @@ const addFilter = async (filter, params) => {
async function fetch(params) {
useArrayData(props.dataKey, params);
- arrayData.reset(['filter.skip', 'skip', 'page']);
- await arrayData.fetch({ append: false, updateRouter: mounted.value });
+ arrayData.resetPagination();
+ await arrayData.fetch({ append: false });
return emitStoreData();
}
@@ -195,13 +204,20 @@ async function onLoad(index, done) {
done(isDone);
}
-defineExpose({ fetch, update, addFilter, paginate });
+defineExpose({
+ fetch,
+ update,
+ addFilter,
+ paginate,
+ userParams: arrayData.store.userParams,
+ currentFilter: arrayData.store.currentFilter,
+});
diff --git a/src/components/ui/VnSearchbar.vue b/src/components/ui/VnSearchbar.vue
index 4e90245d6..a5ca97b70 100644
--- a/src/components/ui/VnSearchbar.vue
+++ b/src/components/ui/VnSearchbar.vue
@@ -1,14 +1,16 @@
+
+
+ {{ t('link') }}
+
+
-
-
-
-
+
+en:
+ link: click to search, ctrl + click to open in a new tab, shift + click to open in a new window
+es:
+ link: clic para buscar, ctrl + clic para abrir en una nueva pestaña, shift + clic para abrir en una nueva ventana
+
diff --git a/src/components/ui/VnSms.vue b/src/components/ui/VnSms.vue
index bf6e0695e..8b25ba5da 100644
--- a/src/components/ui/VnSms.vue
+++ b/src/components/ui/VnSms.vue
@@ -54,6 +54,7 @@ function formatNumber(number) {
:offset="100"
:limit="5"
auto-load
+ map-key="smsFk"
>
{
+ let vm;
+ let wrapper;
+
+ beforeAll(() => {
+ vi.spyOn(axios, 'get').mockResolvedValue({ data: [] });
+ });
+
+ vi.spyOn(vueRouter, 'useRoute').mockReturnValue({
+ query: {},
+ params: {},
+ meta: { moduleName: 'mockName' },
+ path: 'mockName/1/summary',
+ name: 'CardSummary',
+ });
+
+ beforeEach(() => {
+ wrapper = createWrapper(CardSummary, {
+ propsData: {
+ dataKey: 'cardSummaryKey',
+ url: 'cardSummaryUrl',
+ filter: 'cardFilter',
+ },
+ });
+ vm = wrapper.vm;
+ wrapper = wrapper.wrapper;
+ });
+
+ afterEach(() => {
+ vi.clearAllMocks();
+ });
+
+ it('should fetch data correctly', async () => {
+ const fetchSpy = vi
+ .spyOn(vm.arrayData, 'fetch')
+ .mockResolvedValue({ data: [{ id: 1, name: 'Test Entity' }] });
+ await vm.fetch();
+
+ expect(fetchSpy).toHaveBeenCalledWith({ append: false, updateRouter: false });
+ expect(wrapper.emitted('onFetch')).toBeTruthy();
+ expect(vm.isLoading).toBe(false);
+ });
+
+ it('should set correct props to the store', () => {
+ expect(vm.store.url).toEqual('cardSummaryUrl');
+ expect(vm.store.filter).toEqual('cardFilter');
+ });
+
+ it('should compute entity correctly from store data', () => {
+ vm.store.data = [{ id: 1, name: 'Entity 1' }];
+ expect(vm.entity).toEqual({ id: 1, name: 'Entity 1' });
+ });
+
+ it('should handle empty data gracefully', () => {
+ vm.store.data = [];
+ expect(vm.entity).toBeUndefined();
+ });
+
+ it('should respond to prop changes and refetch data', async () => {
+ const newUrl = 'CardSummary/35';
+ const newKey = 'cardSummaryKey/35';
+ const fetchSpy = vi.spyOn(vm.arrayData, 'fetch');
+ await wrapper.setProps({ url: newUrl, filter: { key: newKey } });
+
+ expect(fetchSpy).toHaveBeenCalled();
+ expect(vm.store.url).toBe(newUrl);
+ expect(vm.store.filter).toEqual({ key: newKey });
+ });
+
+ it('should return true if route path ends with /summary' , () => {
+ expect(vm.isSummary).toBe(true);
+ });
+});
\ No newline at end of file
diff --git a/src/components/ui/__tests__/FetchedTags.spec.js b/src/components/ui/__tests__/FetchedTags.spec.js
new file mode 100644
index 000000000..3c658a80e
--- /dev/null
+++ b/src/components/ui/__tests__/FetchedTags.spec.js
@@ -0,0 +1,81 @@
+import { describe, expect, it } from 'vitest';
+import { createWrapper } from 'app/test/vitest/helper';
+import FetchedTags from 'src/components/ui/FetchedTags.vue';
+
+describe('tags computed property', () => {
+ it('returns an object with the correct keys and values', () => {
+ const vm = createWrapper(FetchedTags, {
+ props: {
+ item: {
+ tag1: 'JavaScript',
+ value1: 'Programming Language',
+ tag2: 'Vue',
+ value2: 'Framework',
+ tag3: 'EmptyTag',
+ },
+ tag: 'tag',
+ value: 'value',
+ columns: 2,
+ },
+ }).vm;
+ expect(vm.tags).toEqual({
+ JavaScript: 'Programming Language',
+ Vue: 'Framework',
+ EmptyTag: '',
+ });
+ });
+
+ it('returns an empty object if the item prop is an empty object', () => {
+ const vm = createWrapper(FetchedTags, {
+ props: {
+ item: {},
+ tag: 'tag',
+ value: 'value',
+ },
+ }).vm;
+ expect(vm.tags).toEqual({});
+ });
+
+ it('should calculate the correct columnStyle when columns prop is defined', () => {
+ const vm = createWrapper(FetchedTags, {
+ props: {
+ item: {
+ tag1: 'JavaScript',
+ value1: 'Programming Language',
+ tag2: 'Vue',
+ value2: 'Framework',
+ tag3: 'EmptyTag',
+ },
+ tag: 'tag',
+ value: 'value',
+ columns: 2,
+ },
+ }).vm;
+
+ const expectedStyle = {
+ 'grid-template-columns': 'repeat(2, 1fr)',
+ 'max-width': '8rem',
+ };
+
+ expect(vm.columnStyle).toEqual(expectedStyle);
+ });
+
+ it('should return an empty object for columnStyle when columns prop is not defined', () => {
+ const vm = createWrapper(FetchedTags, {
+ props: {
+ item: {
+ tag1: 'JavaScript',
+ value1: 'Programming Language',
+ tag2: 'Vue',
+ value2: 'Framework',
+ tag3: 'EmptyTag',
+ },
+ tag: 'tag',
+ value: 'value',
+ columns: null,
+ },
+ }).vm;
+
+ expect(vm.columnStyle).toEqual({});
+ });
+});
diff --git a/test/vitest/__tests__/components/Paginate.spec.js b/src/components/ui/__tests__/Paginate.spec.js
similarity index 76%
rename from test/vitest/__tests__/components/Paginate.spec.js
rename to src/components/ui/__tests__/Paginate.spec.js
index 345903c1a..a67dfcdc6 100644
--- a/test/vitest/__tests__/components/Paginate.spec.js
+++ b/src/components/ui/__tests__/Paginate.spec.js
@@ -4,7 +4,11 @@ import VnPaginate from 'src/components/ui/VnPaginate.vue';
describe('VnPaginate', () => {
const expectedUrl = '/api/customers';
-
+ const defaultData = [
+ { id: 1, name: 'Tony Stark' },
+ { id: 2, name: 'Jessica Jones' },
+ { id: 3, name: 'Bruce Wayne' },
+ ];
let vm;
beforeAll(() => {
const options = {
@@ -28,11 +32,7 @@ describe('VnPaginate', () => {
describe('paginate()', () => {
it('should call to the paginate() method and set the data on the rows property', async () => {
vi.spyOn(vm.arrayData, 'loadMore');
- vm.store.data = [
- { id: 1, name: 'Tony Stark' },
- { id: 2, name: 'Jessica Jones' },
- { id: 3, name: 'Bruce Wayne' },
- ];
+ vm.store.data = defaultData;
await vm.paginate();
@@ -42,26 +42,25 @@ describe('VnPaginate', () => {
it('should call to the paginate() method and then call it again to paginate', async () => {
vi.spyOn(axios, 'get').mockResolvedValue({
- data: [
- { id: 1, name: 'Tony Stark' },
- { id: 2, name: 'Jessica Jones' },
- { id: 3, name: 'Bruce Wayne' },
- ],
+ data: defaultData,
});
vm.store.hasMoreData = true;
await vm.$nextTick();
- vm.store.data = [
- { id: 1, name: 'Tony Stark' },
- { id: 2, name: 'Jessica Jones' },
- { id: 3, name: 'Bruce Wayne' },
- ];
+ vm.store.data = defaultData;
await vm.paginate();
expect(vm.store.skip).toEqual(3);
expect(vm.store.data.length).toEqual(6);
+ vi.spyOn(axios, 'get').mockResolvedValue({
+ data: [
+ { id: 4, name: 'Peter Parker' },
+ { id: 5, name: 'Clark Kent' },
+ { id: 6, name: 'Barry Allen' },
+ ],
+ });
await vm.paginate();
expect(vm.store.skip).toEqual(6);
@@ -85,11 +84,7 @@ describe('VnPaginate', () => {
const index = 1;
const done = vi.fn();
- vm.store.data = [
- { id: 1, name: 'Tony Stark' },
- { id: 2, name: 'Jessica Jones' },
- { id: 3, name: 'Bruce Wayne' },
- ];
+ vm.store.data = defaultData;
await vm.onLoad(index, done);
@@ -105,11 +100,7 @@ describe('VnPaginate', () => {
],
});
- vm.store.data = [
- { id: 1, name: 'Tony Stark' },
- { id: 2, name: 'Jessica Jones' },
- { id: 3, name: 'Bruce Wayne' },
- ];
+ vm.store.data = defaultData;
expect(vm.pagination.page).toEqual(1);
diff --git a/src/components/ui/__tests__/VnImg.spec.js b/src/components/ui/__tests__/VnImg.spec.js
new file mode 100644
index 000000000..39dd10775
--- /dev/null
+++ b/src/components/ui/__tests__/VnImg.spec.js
@@ -0,0 +1,89 @@
+import { vi, describe, expect, it, beforeEach, afterEach } from 'vitest';
+import { createWrapper } from 'app/test/vitest/helper';
+import VnImg from 'src/components/ui/VnImg.vue';
+
+let wrapper;
+let vm;
+const isEmployeeMock = vi.fn();
+
+function generateWrapper(storage = 'images') {
+ wrapper = createWrapper(VnImg, {
+ props: {
+ id: 123,
+ zoomResolution: '400x400',
+ storage,
+ }
+ });
+ wrapper = wrapper.wrapper;
+ vm = wrapper.vm;
+ vm.timeStamp = 'timestamp';
+};
+
+vi.mock('src/composables/useSession', () => ({
+ useSession: () => ({
+ getTokenMultimedia: () => 'token',
+ }),
+}));
+
+vi.mock('src/composables/useRole', () => ({
+ useRole: () => ({
+ isEmployee: isEmployeeMock,
+ }),
+}));
+
+
+describe('VnImg', () => {
+ beforeEach(() => {
+ isEmployeeMock.mockReset();
+ });
+
+ afterEach(() => {
+ vi.clearAllMocks();
+ });
+
+ describe('getUrl', () => {
+ it('should return /api/{storage}/{id}/downloadFile?access_token={token} when storage is dms', async () => {
+ isEmployeeMock.mockReturnValue(false);
+ generateWrapper('dms');
+ await vm.$nextTick();
+ const url = vm.getUrl();
+ expect(url).toBe('/api/dms/123/downloadFile?access_token=token');
+ });
+
+ it('should return /no-user.png when role is not employee and storage is not dms', async () => {
+ isEmployeeMock.mockReturnValue(false);
+ generateWrapper();
+ await vm.$nextTick();
+ const url = vm.getUrl();
+ expect(url).toBe('/no-user.png');
+ });
+
+ it('should return /api/{storage}/{collection}/{curResolution}/{id}/download?access_token={token}&{timeStamp} when zoom is false and role is employee and storage is not dms', async () => {
+ isEmployeeMock.mockReturnValue(true);
+ generateWrapper();
+ await vm.$nextTick();
+ const url = vm.getUrl();
+ expect(url).toBe('/api/images/catalog/200x200/123/download?access_token=token×tamp');
+ });
+
+ it('should return /api/{storage}/{collection}/{curResolution}/{id}/download?access_token={token}&{timeStamp} when zoom is true and role is employee and storage is not dms', async () => {
+ isEmployeeMock.mockReturnValue(true);
+ generateWrapper();
+ await vm.$nextTick();
+ const url = vm.getUrl(true);
+ expect(url).toBe('/api/images/catalog/400x400/123/download?access_token=token×tamp');
+ });
+ });
+
+ describe('reload', () => {
+ it('should update the timestamp', async () => {
+ generateWrapper();
+ const initialTimestamp = wrapper.vm.timeStamp;
+
+ wrapper.vm.reload();
+ const newTimestamp = wrapper.vm.timeStamp;
+
+ expect(initialTimestamp).not.toEqual(newTimestamp);
+ });
+ });
+});
\ No newline at end of file
diff --git a/test/vitest/__tests__/components/common/VnLinkPhone.spec.js b/src/components/ui/__tests__/VnLinkPhone.spec.js
similarity index 100%
rename from test/vitest/__tests__/components/common/VnLinkPhone.spec.js
rename to src/components/ui/__tests__/VnLinkPhone.spec.js
diff --git a/test/vitest/__tests__/components/common/VnSms.spec.js b/src/components/ui/__tests__/VnSms.spec.js
similarity index 100%
rename from test/vitest/__tests__/components/common/VnSms.spec.js
rename to src/components/ui/__tests__/VnSms.spec.js
diff --git a/test/vitest/__tests__/composables/downloadFile.spec.js b/src/composables/__tests__/downloadFile.spec.js
similarity index 100%
rename from test/vitest/__tests__/composables/downloadFile.spec.js
rename to src/composables/__tests__/downloadFile.spec.js
diff --git a/src/composables/__tests__/getExchange.spec.js b/src/composables/__tests__/getExchange.spec.js
new file mode 100644
index 000000000..dba31458e
--- /dev/null
+++ b/src/composables/__tests__/getExchange.spec.js
@@ -0,0 +1,45 @@
+import { describe, expect, it, vi } from 'vitest';
+import axios from 'axios';
+import { getExchange } from 'src/composables/getExchange';
+
+vi.mock('axios');
+
+describe('getExchange()', () => {
+ it('should return the correct exchange rate', async () => {
+ axios.get.mockResolvedValue({
+ data: { value: 1.2 },
+ });
+
+ const amount = 100;
+ const currencyFk = 1;
+ const dated = '2023-01-01';
+ const result = await getExchange(amount, currencyFk, dated);
+
+ expect(result).toBe('83.33');
+ });
+
+ it('should return the correct exchange rate with custom decimal places', async () => {
+ axios.get.mockResolvedValue({
+ data: { value: 1.2 },
+ });
+
+ const amount = 100;
+ const currencyFk = 1;
+ const dated = '2023-01-01';
+ const decimalPlaces = 3;
+ const result = await getExchange(amount, currencyFk, dated, decimalPlaces);
+
+ expect(result).toBe('83.333');
+ });
+
+ it('should return null if the API call fails', async () => {
+ axios.get.mockRejectedValue(new Error('Network error'));
+
+ const amount = 100;
+ const currencyFk = 1;
+ const dated = '2023-01-01';
+ const result = await getExchange(amount, currencyFk, dated);
+
+ expect(result).toBeNull();
+ });
+});
diff --git a/src/composables/__tests__/getTotal.spec.js b/src/composables/__tests__/getTotal.spec.js
new file mode 100644
index 000000000..789e3fbcf
--- /dev/null
+++ b/src/composables/__tests__/getTotal.spec.js
@@ -0,0 +1,55 @@
+import { vi, describe, expect, it } from 'vitest';
+import { getTotal } from 'src/composables/getTotal';
+
+vi.mock('src/filters', () => ({
+ toCurrency: vi.fn((value, currency) => `${currency} ${value.toFixed(2)}`),
+}));
+
+describe('getTotal()', () => {
+ const rows = [
+ { amount: 10.5, tax: 2.1 },
+ { amount: 20.75, tax: 3.25 },
+ { amount: 30.25, tax: 4.75 },
+ ];
+
+ it('should calculate the total for a given key', () => {
+ const total = getTotal(rows, 'amount');
+ expect(total).toBe('61.50');
+ });
+
+ it('should calculate the total with a callback function', () => {
+ const total = getTotal(rows, null, { cb: (row) => row.amount + row.tax });
+ expect(total).toBe('71.60');
+ });
+
+ it('should format the total as currency', () => {
+ const total = getTotal(rows, 'amount', { currency: 'USD' });
+ expect(total).toBe('USD 61.50');
+ });
+
+ it('should format the total as currency with default currency', () => {
+ const total = getTotal(rows, 'amount', { currency: 'default' });
+ expect(total).toBe('undefined 61.50');
+ });
+
+ it('should calculate the total with integer formatting', () => {
+ const total = getTotal(rows, 'amount', { decimalPlaces: 0 });
+ expect(total).toBe('62');
+ });
+
+ it('should calculate the total with custom decimal places', () => {
+ const total = getTotal(rows, 'amount', { decimalPlaces: 1 });
+ expect(total).toBe('61.5');
+ });
+
+ it('should handle rows with missing keys', () => {
+ const rowsWithMissingKeys = [{ amount: 10.5 }, { amount: 20.75 }, {}];
+ const total = getTotal(rowsWithMissingKeys, 'amount');
+ expect(total).toBe('31.25');
+ });
+
+ it('should handle empty rows', () => {
+ const total = getTotal([], 'amount');
+ expect(total).toBe('0.00');
+ });
+});
diff --git a/src/composables/__tests__/useAccountShortToStandard.spec.js b/src/composables/__tests__/useAccountShortToStandard.spec.js
new file mode 100644
index 000000000..d24585812
--- /dev/null
+++ b/src/composables/__tests__/useAccountShortToStandard.spec.js
@@ -0,0 +1,9 @@
+import { describe, expect, it } from 'vitest';
+import { useAccountShortToStandard } from 'src/composables/useAccountShortToStandard';
+
+describe('useAccountShortToStandard()', () => {
+ it('should pad the decimal part with zeros for short numbers', () => {
+ expect(useAccountShortToStandard('123.45')).toBe('1230000045');
+ expect(useAccountShortToStandard('123.')).toBe('1230000000');
+ });
+});
diff --git a/test/vitest/__tests__/composables/useAcl.spec.js b/src/composables/__tests__/useAcl.spec.js
similarity index 100%
rename from test/vitest/__tests__/composables/useAcl.spec.js
rename to src/composables/__tests__/useAcl.spec.js
diff --git a/test/vitest/__tests__/composables/useArrayData.spec.js b/src/composables/__tests__/useArrayData.spec.js
similarity index 100%
rename from test/vitest/__tests__/composables/useArrayData.spec.js
rename to src/composables/__tests__/useArrayData.spec.js
diff --git a/test/vitest/__tests__/composables/useRole.spec.js b/src/composables/__tests__/useRole.spec.js
similarity index 100%
rename from test/vitest/__tests__/composables/useRole.spec.js
rename to src/composables/__tests__/useRole.spec.js
diff --git a/test/vitest/__tests__/composables/useSession.spec.js b/src/composables/__tests__/useSession.spec.js
similarity index 100%
rename from test/vitest/__tests__/composables/useSession.spec.js
rename to src/composables/__tests__/useSession.spec.js
diff --git a/test/vitest/__tests__/composables/useTokenConfig.spec.js b/src/composables/__tests__/useTokenConfig.spec.js
similarity index 100%
rename from test/vitest/__tests__/composables/useTokenConfig.spec.js
rename to src/composables/__tests__/useTokenConfig.spec.js
diff --git a/src/composables/getExchange.js b/src/composables/getExchange.js
new file mode 100644
index 000000000..e81e9e895
--- /dev/null
+++ b/src/composables/getExchange.js
@@ -0,0 +1,16 @@
+import axios from 'axios';
+export async function getExchange(amount, currencyFk, dated, decimalPlaces = 2) {
+ try {
+ const { data } = await axios.get('ReferenceRates/findOne', {
+ params: {
+ filter: {
+ fields: ['value'],
+ where: { currencyFk, dated },
+ },
+ },
+ });
+ return (amount / data.value).toFixed(decimalPlaces);
+ } catch (e) {
+ return null;
+ }
+}
diff --git a/src/composables/getTotal.js b/src/composables/getTotal.js
index 41c4330c4..24ac3aa27 100644
--- a/src/composables/getTotal.js
+++ b/src/composables/getTotal.js
@@ -1,10 +1,10 @@
import { toCurrency } from 'src/filters';
export function getTotal(rows, key, opts = {}) {
- const { currency, cb } = opts;
+ const { currency, cb, decimalPlaces } = opts;
const total = rows.reduce((acc, row) => acc + +(cb ? cb(row) : row[key] || 0), 0);
return currency
? toCurrency(total, currency == 'default' ? undefined : currency)
- : total;
+ : parseFloat(total).toFixed(decimalPlaces ?? 2);
}
diff --git a/src/composables/useAccountShortToStandard.js b/src/composables/useAccountShortToStandard.js
new file mode 100644
index 000000000..ca221433e
--- /dev/null
+++ b/src/composables/useAccountShortToStandard.js
@@ -0,0 +1,4 @@
+export function useAccountShortToStandard(val) {
+ if (!val || !/^\d+(\.\d*)$/.test(val)) return;
+ return val?.replace('.', '0'.repeat(11 - val.length));
+}
diff --git a/src/composables/useArrayData.js b/src/composables/useArrayData.js
index da62eee3e..d76053ce9 100644
--- a/src/composables/useArrayData.js
+++ b/src/composables/useArrayData.js
@@ -7,7 +7,9 @@ import { isDialogOpened } from 'src/filters';
const arrayDataStore = useArrayDataStore();
-export function useArrayData(key = useRoute().meta.moduleName, userOptions) {
+export function useArrayData(key, userOptions) {
+ key ??= useRoute().meta.moduleName;
+
if (!key) throw new Error('ArrayData: A key is required to use this composable');
if (!arrayDataStore.get(key)) arrayDataStore.set(key);
@@ -25,13 +27,17 @@ export function useArrayData(key = useRoute().meta.moduleName, userOptions) {
const searchUrl = store.searchUrl;
if (query[searchUrl]) {
const params = JSON.parse(query[searchUrl]);
- const filter = params?.filter && JSON.parse(params?.filter ?? '{}');
+ const filter =
+ params?.filter && typeof params?.filter == 'object'
+ ? params?.filter
+ : JSON.parse(params?.filter ?? '{}');
delete params.filter;
- store.userParams = { ...store.userParams, ...params };
- store.userFilter = { ...filter, ...store.userFilter };
+ store.userParams = params;
+ store.filter = { ...filter, ...store.userFilter };
if (filter?.order) store.order = filter.order;
}
+ setCurrentFilter();
});
if (key && userOptions) setOptions();
@@ -49,6 +55,8 @@ export function useArrayData(key = useRoute().meta.moduleName, userOptions) {
'exprBuilder',
'searchUrl',
'navigate',
+ 'mapKey',
+ 'keepData',
];
if (typeof userOptions === 'object') {
for (const option in userOptions) {
@@ -60,6 +68,7 @@ export function useArrayData(key = useRoute().meta.moduleName, userOptions) {
store[option] = userOptions.keepOpts?.includes(option)
? Object.assign(defaultOpts, store[option])
: defaultOpts;
+ if (option === 'userParams') store.defaultParams = store[option];
}
}
}
@@ -70,31 +79,7 @@ export function useArrayData(key = useRoute().meta.moduleName, userOptions) {
cancelRequest();
canceller = new AbortController();
-
- const filter = {
- limit: store.limit,
- };
-
- let userParams = { ...store.userParams };
-
- Object.assign(filter, store.userFilter);
-
- let where;
- if (filter?.where || store.filter?.where)
- where = Object.assign(filter?.where ?? {}, store.filter?.where ?? {});
- Object.assign(filter, store.filter);
- filter.where = where;
- const params = { filter };
-
- Object.assign(params, userParams);
- if (params.filter) params.filter.skip = store.skip;
- if (store?.order && typeof store?.order == 'string') store.order = [store.order];
- if (store.order?.length) params.filter.order = [...store.order];
- else delete params.filter.order;
-
- store.currentFilter = JSON.parse(JSON.stringify(params));
- delete store.currentFilter.filter.include;
- store.currentFilter.filter = JSON.stringify(store.currentFilter.filter);
+ const { params, limit } = setCurrentFilter();
let exprFilter;
if (store?.exprBuilder) {
@@ -116,20 +101,16 @@ export function useArrayData(key = useRoute().meta.moduleName, userOptions) {
params,
});
- const { limit } = filter;
store.hasMoreData = limit && response.data.length >= limit;
- if (append) {
- if (!store.data) store.data = [];
- for (const row of response.data) store.data.push(row);
- } else {
- store.data = response.data;
- if (!isDialogOpened()) updateRouter && updateStateParams();
+ if (!append && !isDialogOpened() && updateRouter) {
+ if (updateStateParams(response.data)?.redirect && !store.keepData) return;
}
-
store.isLoading = false;
-
canceller = null;
+
+ processData(response.data, { map: !!store.mapKey, append });
+
return response;
}
@@ -147,6 +128,10 @@ export function useArrayData(key = useRoute().meta.moduleName, userOptions) {
if (arrayDataStore.get(key)) arrayDataStore.reset(key, opts);
}
+ function resetPagination() {
+ if (arrayDataStore.get(key)) arrayDataStore.resetPagination(key);
+ }
+
function cancelRequest() {
if (canceller) {
canceller.abort();
@@ -154,12 +139,12 @@ export function useArrayData(key = useRoute().meta.moduleName, userOptions) {
}
}
- async function applyFilter({ filter, params }) {
+ async function applyFilter({ filter, params }, fetchOptions = {}) {
if (filter) store.userFilter = filter;
store.filter = {};
if (params) store.userParams = { ...params };
- const response = await fetch({});
+ const response = await fetch(fetchOptions);
return response;
}
@@ -170,7 +155,7 @@ export function useArrayData(key = useRoute().meta.moduleName, userOptions) {
userParams = sanitizerParams(userParams, store?.exprBuilder);
store.userParams = userParams;
- reset(['skip', 'filter.skip', 'page']);
+ resetPagination();
await fetch({});
return { filter, params };
@@ -197,7 +182,7 @@ export function useArrayData(key = useRoute().meta.moduleName, userOptions) {
}
store.order = order;
- reset(['skip', 'filter.skip', 'page']);
+ resetPagination();
fetch({});
index++;
@@ -255,7 +240,7 @@ export function useArrayData(key = useRoute().meta.moduleName, userOptions) {
if (Object.values(store.userParams).length) await fetch({});
}
- function updateStateParams() {
+ function updateStateParams(data) {
if (!route?.path) return;
const newUrl = { path: route.path, query: { ...(route.query ?? {}) } };
if (store?.searchUrl)
@@ -272,22 +257,79 @@ export function useArrayData(key = useRoute().meta.moduleName, userOptions) {
const { path } = matches.at(-1);
const to =
- store?.data?.length === 1
- ? path.replace(/\/(list|:id)|-list/, `/${store.data[0].id}`)
+ data?.length === 1
+ ? path.replace(/\/(list|:id)|-list/, `/${data[0].id}`)
: path.replace(/:id.*/, '');
if (route.path != to) {
const pushUrl = { path: to };
if (to.endsWith('/list') || to.endsWith('/'))
pushUrl.query = newUrl.query;
- else destroy();
- return router.push(pushUrl);
+ return router.push(pushUrl) && { redirect: true };
}
}
router.replace(newUrl);
}
+ function getCurrentFilter() {
+ if (!Object.keys(store.userParams).length)
+ store.userParams = store.defaultParams ?? {};
+
+ const filter = {
+ limit: store.limit,
+ ...store.userFilter,
+ };
+
+ let where;
+ if (filter?.where || store.filter?.where)
+ where = Object.assign(filter?.where ?? {}, store.filter?.where ?? {});
+ Object.assign(filter, store.filter);
+ filter.where = where;
+ const params = { filter };
+
+ Object.assign(params, store.userParams);
+ if (params.filter) params.filter.skip = store.skip;
+ if (store?.order && typeof store?.order == 'string') store.order = [store.order];
+ if (store.order?.length) params.filter.order = [...store.order];
+ else delete params.filter.order;
+
+ return { filter, params, limit: filter.limit };
+ }
+
+ function setCurrentFilter() {
+ const { params, limit } = getCurrentFilter();
+ store.currentFilter = JSON.parse(JSON.stringify(params));
+ delete store.currentFilter.filter.include;
+ store.currentFilter.filter = JSON.stringify(store.currentFilter.filter);
+ return { params, limit };
+ }
+
+ function processData(data, { map = true, append = true }) {
+ if (!append) {
+ store.data = [];
+ store.map = new Map();
+ }
+
+ if (!Array.isArray(data)) store.data = data;
+ else if (!map && append) for (const row of data) store.data.push(row);
+ else
+ for (const row of data) {
+ const key = row[store.mapKey];
+ const val = { ...row, key };
+ if (key && store.map.has(key)) {
+ const { position } = store.map.get(key);
+ val.position = position;
+ store.map.set(key, val);
+ store.data[position] = val;
+ } else {
+ val.position = store.map.size;
+ store.map.set(key, val);
+ store.data.push(val);
+ }
+ }
+ }
+
const totalRows = computed(() => (store.data && store.data.length) || 0);
const isLoading = computed(() => store.isLoading || false);
@@ -295,6 +337,8 @@ export function useArrayData(key = useRoute().meta.moduleName, userOptions) {
fetch,
applyFilter,
addFilter,
+ getCurrentFilter,
+ setCurrentFilter,
addFilterWhere,
addOrder,
deleteOrder,
@@ -307,5 +351,6 @@ export function useArrayData(key = useRoute().meta.moduleName, userOptions) {
isLoading,
deleteOption,
reset,
+ resetPagination,
};
}
diff --git a/src/composables/useFilterParams.js b/src/composables/useFilterParams.js
new file mode 100644
index 000000000..07dcdf99b
--- /dev/null
+++ b/src/composables/useFilterParams.js
@@ -0,0 +1,69 @@
+import { useArrayData } from 'src/composables/useArrayData';
+import { onBeforeMount, ref, watch } from 'vue';
+
+export function useFilterParams(key) {
+ if (!key) throw new Error('ArrayData: A key is required to use this composable');
+ const params = ref({});
+ const orders = ref({});
+ const arrayData = ref({});
+
+ onBeforeMount(() => {
+ arrayData.value = useArrayData(key);
+ });
+
+ watch(
+ () => arrayData.value.store?.currentFilter,
+ (val, oldValue) => (val || oldValue) && setUserParams(val),
+ { immediate: true, deep: true }
+ );
+
+ function parseOrder(urlOrders) {
+ const orderObject = {};
+ if (urlOrders) {
+ if (typeof urlOrders == 'string') urlOrders = [urlOrders];
+ for (const [index, orders] of urlOrders.entries()) {
+ const [name, direction] = orders.split(' ');
+ orderObject[name] = { direction, index: index + 1 };
+ }
+ }
+ orders.value = orderObject;
+ }
+
+ function setUserParams(watchedParams = {}) {
+ if (Object.keys(watchedParams).length == 0) {
+ params.value = {};
+ orders.value = {};
+ return;
+ }
+
+ if (typeof watchedParams == 'string') watchedParams = JSON.parse(watchedParams);
+ if (typeof watchedParams?.filter == 'string')
+ watchedParams.filter = JSON.parse(watchedParams.filter);
+
+ watchedParams = { ...watchedParams, ...watchedParams.filter?.where };
+ parseOrder(watchedParams.filter?.order);
+
+ delete watchedParams.filter;
+ params.value = sanitizer(watchedParams);
+ }
+
+ function sanitizer(params) {
+ for (const [key, value] of Object.entries(params)) {
+ if (key === 'and' && Array.isArray(value)) {
+ value.forEach((item) => {
+ Object.assign(params, item);
+ });
+ delete params[key];
+ } else if (value && typeof value === 'object') {
+ const param = Object.values(value)[0];
+ if (typeof param == 'string') params[key] = param.replaceAll('%', '');
+ }
+ }
+ return params;
+ }
+
+ return {
+ params,
+ orders,
+ };
+}
diff --git a/src/composables/useHasAccount.js b/src/composables/useHasAccount.js
new file mode 100644
index 000000000..1014bedf3
--- /dev/null
+++ b/src/composables/useHasAccount.js
@@ -0,0 +1,6 @@
+import axios from 'axios';
+
+export default async (id) => {
+ const { data } = await axios.get(`Accounts/${id}/exists`);
+ return data.exists;
+};
diff --git a/src/composables/useHasContent.js b/src/composables/useHasContent.js
new file mode 100644
index 000000000..8ab018376
--- /dev/null
+++ b/src/composables/useHasContent.js
@@ -0,0 +1,24 @@
+import { onMounted, ref } from 'vue';
+
+export function useHasContent(selector) {
+ const container = ref({});
+ const hasContent = ref();
+
+ onMounted(() => {
+ container.value = document.querySelector(selector);
+ if (!container.value) return;
+
+ const observer = new MutationObserver(() => {
+ if (document.querySelector(selector))
+ hasContent.value = !!container.value.childNodes.length;
+ });
+
+ observer.observe(container.value, {
+ subtree: true,
+ childList: true,
+ attributes: true,
+ });
+ });
+
+ return hasContent;
+}
diff --git a/src/css/app.scss b/src/css/app.scss
index abb388be9..a28a04a16 100644
--- a/src/css/app.scss
+++ b/src/css/app.scss
@@ -3,19 +3,23 @@
@import '@quasar/quasar-ui-qcalendar/src/QCalendarMonth.sass';
body.body--light {
- --font-color: black;
--vn-header-color: #cecece;
--vn-page-color: #ffffff;
--vn-section-color: #e0e0e0;
--vn-section-hover-color: #b9b9b9;
- --vn-text-color: var(--font-color);
+ --vn-text-color: black;
--vn-label-color: #5f5f5f;
--vn-accent-color: #e7e3e3;
+ --vn-search-color: #d4d4d4;
+ --vn-search-color-hover: #cfcfcf;
+ --vn-empty-tag: #acacac;
+ --vn-black-text-color: black;
+ --vn-text-color-contrast: white;
background-color: var(--vn-page-color);
.q-header .q-toolbar {
- color: var(--font-color);
+ color: var(--vn-text-color);
}
}
body.body--dark {
@@ -26,6 +30,11 @@ body.body--dark {
--vn-text-color: white;
--vn-label-color: #a8a8a8;
--vn-accent-color: #424242;
+ --vn-search-color: #4b4b4b;
+ --vn-search-color-hover: #5b5b5b;
+ --vn-empty-tag: #2d2d2d;
+ --vn-black-text-color: black;
+ --vn-text-color-contrast: black;
background-color: var(--vn-page-color);
}
@@ -84,6 +93,10 @@ select:-webkit-autofill {
background-color: var(--vn-section-hover-color);
}
+.bg-vn-page {
+ background-color: var(--vn-page-color);
+}
+
.color-vn-label {
color: var(--vn-label-color);
}
@@ -149,7 +162,8 @@ select:-webkit-autofill {
.q-card,
.q-table,
.q-table__bottom,
-.q-drawer {
+.q-drawer,
+.bottomButton {
background-color: var(--vn-section-color);
}
@@ -186,7 +200,7 @@ select:-webkit-autofill {
.q-tooltip {
background-color: var(--vn-page-color);
- color: var(--font-color);
+ color: var(--vn-text-color);
font-size: medium;
}
@@ -240,7 +254,7 @@ input::-webkit-inner-spin-button {
.q-table {
th,
td {
- padding: 1px 10px 1px 10px;
+ padding: 1px 3px 1px 3px;
max-width: 130px;
div span {
overflow: hidden;
@@ -296,3 +310,28 @@ input::-webkit-inner-spin-button {
.no-visible {
visibility: hidden;
}
+
+.q-item > .q-item__section:has(.q-checkbox) {
+ max-width: min-content;
+}
+
+.row > .column:has(.q-checkbox) {
+ max-width: min-content;
+}
+.q-field__inner {
+ .q-field__control {
+ min-height: auto !important;
+ display: flex;
+ align-items: flex-end;
+ padding-bottom: 2px;
+ .q-field__native.row {
+ min-height: auto !important;
+ }
+ }
+}
+
+.q-date__header-today {
+ border-radius: 12px;
+ border: 1px solid;
+ box-shadow: 0 4px 6px #00000000;
+}
diff --git a/src/filters/index.js b/src/filters/index.js
index a92d2eb07..bf1429aee 100644
--- a/src/filters/index.js
+++ b/src/filters/index.js
@@ -16,6 +16,7 @@ import getUpdatedValues from './getUpdatedValues';
import getParamWhere from './getParamWhere';
import parsePhone from './parsePhone';
import isDialogOpened from './isDialogOpened';
+import toCelsius from './toCelsius';
export {
getUpdatedValues,
@@ -36,4 +37,5 @@ export {
dashIfEmpty,
dateRange,
getParamWhere,
+ toCelsius,
};
diff --git a/src/filters/toCelsius.js b/src/filters/toCelsius.js
new file mode 100644
index 000000000..83cab32ca
--- /dev/null
+++ b/src/filters/toCelsius.js
@@ -0,0 +1,3 @@
+export default function toCelsius(value) {
+ return value ? `${value}°C` : '';
+}
diff --git a/src/filters/toDateHourMin.js b/src/filters/toDateHourMin.js
index 2b6995c01..c813840cb 100644
--- a/src/filters/toDateHourMin.js
+++ b/src/filters/toDateHourMin.js
@@ -1,5 +1,6 @@
export default function toDateHourMin(date) {
- const dateHour = new Date(date).toLocaleDateString('es-ES', {
+ if (!date) return date;
+ return new Date(date).toLocaleDateString('es-ES', {
timeZone: 'Europe/Madrid',
year: 'numeric',
month: '2-digit',
@@ -7,5 +8,4 @@ export default function toDateHourMin(date) {
hour: '2-digit',
minute: '2-digit',
});
- return dateHour;
}
diff --git a/src/filters/toDateHourMinSec.js b/src/filters/toDateHourMinSec.js
index cfc9506fb..51df725e4 100644
--- a/src/filters/toDateHourMinSec.js
+++ b/src/filters/toDateHourMinSec.js
@@ -1,5 +1,6 @@
export default function toDateHourMinSec(date) {
- const dateHour = new Date(date).toLocaleDateString('es-ES', {
+ if (!date) return date;
+ return new Date(date).toLocaleDateString('es-ES', {
timeZone: 'Europe/Madrid',
year: 'numeric',
month: '2-digit',
@@ -8,5 +9,4 @@ export default function toDateHourMinSec(date) {
minute: '2-digit',
second: '2-digit',
});
- return dateHour;
}
diff --git a/src/i18n/locale/en.yml b/src/i18n/locale/en.yml
index 1162f0b07..473446970 100644
--- a/src/i18n/locale/en.yml
+++ b/src/i18n/locale/en.yml
@@ -142,7 +142,7 @@ globals:
workCenters: Work centers
modes: Modes
zones: Zones
- zonesList: Zones
+ zonesList: List
deliveryDays: Delivery days
upcomingDeliveries: Upcoming deliveries
role: Role
@@ -333,11 +333,24 @@ globals:
packing: ITP
myTeam: My team
departmentFk: Department
+ from: From
+ to: To
+ supplierFk: Supplier
+ supplierRef: Supplier ref
+ serial: Serial
+ amount: Importe
+ awbCode: AWB
+ correctedFk: Rectified
+ correctingFk: Rectificative
+ daysOnward: Days onward
countryFk: Country
+ companyFk: Company
changePass: Change password
+ setPass: Set password
deleteConfirmTitle: Delete selected elements
changeState: Change state
raid: 'Raid {daysInForward} days'
+ isVies: Vies
errors:
statusUnauthorized: Access denied
statusInternalServerError: An internal server error has ocurred
@@ -376,74 +389,19 @@ cau:
subtitle: By sending this ticket, all the data related to the error, the section, the user, etc., are already sent.
inputLabel: Explain why this error should not appear
askPrivileges: Ask for privileges
-entry:
- list:
- newEntry: New entry
- tableVisibleColumns:
- created: Creation
- supplierFk: Supplier
- isBooked: Booked
- isConfirmed: Confirmed
- isOrdered: Ordered
- companyFk: Company
- travelFk: Travel
- isExcludedFromAvailable: Inventory
- invoiceAmount: Import
- summary:
- commission: Commission
- currency: Currency
- invoiceNumber: Invoice number
- ordered: Ordered
- booked: Booked
- excludedFromAvailable: Inventory
- travelReference: Reference
- travelAgency: Agency
- travelShipped: Shipped
- travelDelivered: Delivered
- travelLanded: Landed
- travelReceived: Received
- buys: Buys
- stickers: Stickers
- package: Package
- packing: Pack.
- grouping: Group.
- buyingValue: Buying value
- import: Import
- pvp: PVP
- basicData:
- travel: Travel
- currency: Currency
- commission: Commission
- observation: Observation
- booked: Booked
- excludedFromAvailable: Inventory
- buys:
- observations: Observations
- packagingFk: Box
- color: Color
- printedStickers: Printed stickers
- notes:
- observationType: Observation type
- latestBuys:
- tableVisibleColumns:
- image: Picture
- itemFk: Item ID
- weightByPiece: Weight/Piece
- isActive: Active
- family: Family
- entryFk: Entry
- freightValue: Freight value
- comissionValue: Commission value
- packageValue: Package value
- isIgnored: Is ignored
- price2: Grouping
- price3: Packing
- minPrice: Min
- ektFk: Ekt
- packingOut: Package out
- landing: Landing
- isExcludedFromAvailable: Es inventory
ticket:
+ params:
+ ticketFk: Ticket ID
+ weekDay: Weekday
+ agencyModeFk: Agency
+ id: Worker
+ state: State
+ created: Created
+ externalId: External ID
+ counter: Counter
+ freightItemName: Freight item name
+ packageItemName: Package item name
+ longName: Long name
card:
customerId: Customer ID
customerCard: Customer card
@@ -494,6 +452,7 @@ invoiceOut:
card:
issued: Issued
customerCard: Customer card
+ ticketList: Ticket List
summary:
issued: Issued
dued: Due
@@ -546,27 +505,6 @@ parking:
searchBar:
info: You can search by parking code
label: Search parking...
-order:
- field:
- salesPersonFk: Sales Person
- form:
- clientFk: Client
- addressFk: Address
- agencyModeFk: Agency
- list:
- newOrder: New Order
- summary:
- basket: Basket
- notConfirmed: Not confirmed
- created: Created
- createdFrom: Created From
- address: Address
- total: Total
- items: Items
- orderTicketList: Order Ticket List
- amount: Amount
- confirm: Confirm
- confirmLines: Confirm lines
department:
chat: Chat
bossDepartment: Boss Department
@@ -599,7 +537,7 @@ worker:
fi: DNI/NIE/NIF
birth: Birth
isFreelance: Freelance
- isSsDiscounted: Bonificación SS
+ isSsDiscounted: SS Bonification
hasMachineryAuthorized: Machinery authorized
isDisable: Disable
notificationsManager:
@@ -685,6 +623,11 @@ wagon:
minHeightBetweenTrays: 'The minimum height between trays is '
maxWagonHeight: 'The maximum height of the wagon is '
uncompleteTrays: There are incomplete trays
+ params:
+ label: Label
+ plate: Plate
+ volume: Volume
+ name: Name
supplier:
list:
@@ -731,7 +674,6 @@ supplier:
sageTransactionTypeFk: Sage transaction type
supplierActivityFk: Supplier activity
isTrucker: Trucker
- isVies: Vies
billingData:
payMethodFk: Billing data
payDemFk: Payment deadline
@@ -762,6 +704,7 @@ travel:
totalEntries: Total entries
totalEntriesTooltip: Total entries
daysOnward: Landed days onwards
+ awb: AWB
summary:
entryId: Entry Id
freight: Freight
@@ -846,13 +789,17 @@ components:
value: Value
# ItemFixedPriceFilter
buyerFk: Buyer
+ warehouseFk: Warehouse
started: From
ended: To
mine: For me
hasMinPrice: Minimum price
# LatestBuysFilter
salesPersonFk: Buyer
+ supplierFk: Supplier
from: From
+ to: To
+ visible: Is visible
active: Is active
floramondo: Is floramondo
showBadDates: Show future items
diff --git a/src/i18n/locale/es.yml b/src/i18n/locale/es.yml
index 5710a324a..b764b1e43 100644
--- a/src/i18n/locale/es.yml
+++ b/src/i18n/locale/es.yml
@@ -144,7 +144,7 @@ globals:
workCenters: Centros de trabajo
modes: Modos
zones: Zonas
- zonesList: Zonas
+ zonesList: Listado
deliveryDays: Días de entrega
upcomingDeliveries: Próximos repartos
role: Role
@@ -336,12 +336,23 @@ globals:
SSN: NSS
fi: NIF
myTeam: Mi equipo
+ from: Desde
+ to: Hasta
+ supplierFk: Proveedor
+ supplierRef: Ref. proveedor
+ serial: Serie
+ amount: Importe
+ awbCode: AWB
+ daysOnward: Días adelante
packing: ITP
countryFk: País
+ companyFk: Empresa
changePass: Cambiar contraseña
+ setPass: Establecer contraseña
deleteConfirmTitle: Eliminar los elementos seleccionados
changeState: Cambiar estado
raid: 'Redada {daysInForward} días'
+ isVies: Vies
errors:
statusUnauthorized: Acceso denegado
statusInternalServerError: Ha ocurrido un error interno del servidor
@@ -378,75 +389,19 @@ cau:
subtitle: Al enviar este cau ya se envían todos los datos relacionados con el error, la sección, el usuario, etc
inputLabel: Explique el motivo por el que no deberia aparecer este fallo
askPrivileges: Solicitar permisos
-entry:
- list:
- newEntry: Nueva entrada
- tableVisibleColumns:
- created: Creación
- supplierFk: Proveedor
- isBooked: Asentado
- isConfirmed: Confirmado
- isOrdered: Pedida
- companyFk: Empresa
- travelFk: Envio
- isExcludedFromAvailable: Inventario
- invoiceAmount: Importe
- summary:
- commission: Comisión
- currency: Moneda
- invoiceNumber: Núm. factura
- ordered: Pedida
- booked: Contabilizada
- excludedFromAvailable: Inventario
- travelReference: Referencia
- travelAgency: Agencia
- travelShipped: F. envio
- travelWarehouseOut: Alm. salida
- travelDelivered: Enviada
- travelLanded: F. entrega
- travelReceived: Recibida
- buys: Compras
- stickers: Etiquetas
- package: Embalaje
- packing: Pack.
- grouping: Group.
- buyingValue: Coste
- import: Importe
- pvp: PVP
- basicData:
- travel: Envío
- currency: Moneda
- observation: Observación
- commission: Comisión
- booked: Asentado
- excludedFromAvailable: Inventario
- buys:
- observations: Observaciónes
- packagingFk: Embalaje
- color: Color
- printedStickers: Etiquetas impresas
- notes:
- observationType: Tipo de observación
- latestBuys:
- tableVisibleColumns:
- image: Foto
- itemFk: Id Artículo
- weightByPiece: Peso (gramos)/tallo
- isActive: Activo
- family: Familia
- entryFk: Entrada
- freightValue: Porte
- comissionValue: Comisión
- packageValue: Embalaje
- isIgnored: Ignorado
- price2: Grouping
- price3: Packing
- minPrice: Min
- ektFk: Ekt
- packingOut: Embalaje envíos
- landing: Llegada
- isExcludedFromAvailable: Es inventario
ticket:
+ params:
+ ticketFk: ID de ticket
+ weekDay: Salida
+ agencyModeFk: Agencia
+ id: Comercial
+ created: Creado
+ state: Estado
+ externalId: ID externo
+ counter: Contador
+ freightItemName: Nombre
+ packageItemName: Embalaje
+ longName: Descripción
card:
customerId: ID cliente
customerCard: Ficha del cliente
@@ -534,30 +489,6 @@ invoiceOut:
comercial: Comercial
errors:
downloadCsvFailed: Error al descargar CSV
-order:
- field:
- salesPersonFk: Comercial
- form:
- clientFk: Cliente
- addressFk: Dirección
- agencyModeFk: Agencia
- list:
- newOrder: Nuevo Pedido
- summary:
- basket: Cesta
- notConfirmed: No confirmada
- created: Creado
- createdFrom: Creado desde
- address: Dirección
- total: Total
- vat: IVA
- state: Estado
- alias: Alias
- items: Artículos
- orderTicketList: Tickets del pedido
- amount: Monto
- confirm: Confirmar
- confirmLines: Confirmar lineas
shelving:
list:
parking: Parking
@@ -598,6 +529,15 @@ worker:
role: Rol
sipExtension: Extensión
locker: Taquilla
+ fiDueDate: F. caducidad DNI
+ sex: Sexo
+ seniority: Antigüedad
+ fi: DNI/NIE/NIF
+ birth: F. nacimiento
+ isFreelance: Autónomo
+ isSsDiscounted: Bonificación SS
+ hasMachineryAuthorized: Autorizado para maquinaria
+ isDisable: Deshabilitado
notificationsManager:
activeNotifications: Notificaciones activas
availableNotifications: Notificaciones disponibles
@@ -681,6 +621,11 @@ wagon:
minHeightBetweenTrays: 'La distancia mínima entre bandejas es '
maxWagonHeight: 'La altura máxima del vagón es '
uncompleteTrays: Hay bandejas sin completar
+ params:
+ label: Etiqueta
+ plate: Matrícula
+ volume: Volumen
+ name: Nombre
supplier:
list:
payMethod: Método de pago
@@ -726,7 +671,6 @@ supplier:
sageTransactionTypeFk: Tipo de transacción sage
supplierActivityFk: Actividad proveedor
isTrucker: Transportista
- isVies: Vies
billingData:
payMethodFk: Forma de pago
payDemFk: Plazo de pago
@@ -756,6 +700,7 @@ travel:
totalEntries: ∑
totalEntriesTooltip: Entradas totales
daysOnward: Días de llegada en adelante
+ awb: AWB
summary:
entryId: Id entrada
freight: Porte
@@ -840,13 +785,19 @@ components:
value: Valor
# ItemFixedPriceFilter
buyerFk: Comprador
+ warehouseFk: Almacen
started: Desde
ended: Hasta
mine: Para mi
hasMinPrice: Precio mínimo
+ wareHouseFk: Almacén
# LatestBuysFilter
salesPersonFk: Comprador
+ supplierFk: Proveedor
+ visible: Visible
active: Activo
+ from: Desde
+ to: Hasta
floramondo: Floramondo
showBadDates: Ver items a futuro
userPanel:
diff --git a/src/layouts/OutLayout.vue b/src/layouts/OutLayout.vue
index 0eb1329a4..4ccc6bf9e 100644
--- a/src/layouts/OutLayout.vue
+++ b/src/layouts/OutLayout.vue
@@ -2,6 +2,8 @@
import { Dark, Quasar } from 'quasar';
import { computed } from 'vue';
import { useI18n } from 'vue-i18n';
+import { localeEquivalence } from 'src/i18n/index';
+import quasarLang from 'src/utils/quasarLang';
const { t, locale } = useI18n();
@@ -12,18 +14,9 @@ const userLocale = computed({
set(value) {
locale.value = value;
- if (value === 'en') value = 'en-GB';
+ value = localeEquivalence[value] ?? value;
- // FIXME: Dynamic imports from absolute paths are not compatible with vite:
- // https://github.com/rollup/plugins/tree/master/packages/dynamic-import-vars#limitations
- try {
- const langList = import.meta.glob('../../node_modules/quasar/lang/*.mjs');
- langList[`../../node_modules/quasar/lang/${value}.mjs`]().then((lang) => {
- Quasar.lang.set(lang.default);
- });
- } catch (error) {
- //
- }
+ quasarLang(value);
},
});
diff --git a/src/pages/Account/AccountAcls.vue b/src/pages/Account/AccountAcls.vue
index d80f835ec..6d3571661 100644
--- a/src/pages/Account/AccountAcls.vue
+++ b/src/pages/Account/AccountAcls.vue
@@ -1,16 +1,15 @@
-
-
-
(roles = data)"
/>
-
+ prefix="acls"
+ :array-data-props="{
+ url: 'ACLs',
+ order: 'id DESC',
+ exprBuilder,
+ }"
+ >
+
+
+
+
diff --git a/src/pages/Account/AccountAliasList.vue b/src/pages/Account/AccountAliasList.vue
index c67283297..f6016fb6c 100644
--- a/src/pages/Account/AccountAliasList.vue
+++ b/src/pages/Account/AccountAliasList.vue
@@ -2,21 +2,12 @@
import { useI18n } from 'vue-i18n';
import { ref, computed } from 'vue';
import VnTable from 'components/VnTable/VnTable.vue';
-import VnSearchbar from 'components/ui/VnSearchbar.vue';
-import { useStateStore } from 'stores/useStateStore';
+import VnSection from 'src/components/common/VnSection.vue';
const tableRef = ref();
const { t } = useI18n();
-const stateStore = useStateStore();
+const dataKey = 'AccountAliasList';
-const exprBuilder = (param, value) => {
- switch (param) {
- case 'search':
- return /^\d+$/.test(value)
- ? { id: value }
- : { alias: { like: `%${value}%` } };
- }
-};
const columns = computed(() => [
{
align: 'left',
@@ -40,40 +31,45 @@ const columns = computed(() => [
create: true,
},
]);
+
+const exprBuilder = (param, value) => {
+ switch (param) {
+ case 'search':
+ return /^\d+$/.test(value)
+ ? { id: value }
+ : { alias: { like: `%${value}%` } };
+ }
+};
-
-
-
-
-
-
+ prefix="mailAlias"
+ :array-data-props="{ url: 'MailAliases', order: 'id DESC', exprBuilder }"
+ >
+
+
+
+
-
es:
Id: Id
diff --git a/src/pages/Account/AccountCreate.vue b/src/pages/Account/AccountCreate.vue
index 6b7c049c8..b925ff06a 100644
--- a/src/pages/Account/AccountCreate.vue
+++ b/src/pages/Account/AccountCreate.vue
@@ -6,6 +6,7 @@ import FormModelPopup from 'components/FormModelPopup.vue';
import VnSelect from 'src/components/common/VnSelect.vue';
import FetchData from 'components/FetchData.vue';
import VnInput from 'src/components/common/VnInput.vue';
+import VnInputPassword from 'src/components/common/VnInputPassword.vue';
const { t } = useI18n();
const router = useRouter();
@@ -61,10 +62,10 @@ const redirectToAccountBasicData = (_, { id }) => {
hide-selected
:rules="validate('VnUser.roleFk')"
/>
-
await getInitialLdapConfig());
:required="true"
:rules="validate('LdapConfig.rdn')"
/>
-
import { useI18n } from 'vue-i18n';
-import { ref, computed } from 'vue';
+import { computed, ref } from 'vue';
import VnTable from 'components/VnTable/VnTable.vue';
-import VnSearchbar from 'components/ui/VnSearchbar.vue';
import AccountSummary from './Card/AccountSummary.vue';
import { useSummaryDialog } from 'src/composables/useSummaryDialog';
-import AccountFilter from './AccountFilter.vue';
-import RightMenu from 'src/components/common/RightMenu.vue';
-import VnInput from 'src/components/common/VnInput.vue';
+import VnSection from 'src/components/common/VnSection.vue';
+import FetchData from 'src/components/FetchData.vue';
+import VnInputPassword from 'src/components/common/VnInputPassword.vue';
+
const { t } = useI18n();
const { viewSummary } = useSummaryDialog();
-const tableRef = ref();
const filter = {
include: { relation: 'role', scope: { fields: ['id', 'name'] } },
};
+const dataKey = 'AccountList';
+const roles = ref([]);
const columns = computed(() => [
{
align: 'left',
@@ -48,7 +49,7 @@ const columns = computed(() => [
component: 'select',
name: 'roleFk',
attrs: {
- url: 'VnRoles',
+ options: roles,
optionValue: 'id',
optionLabel: 'name',
},
@@ -116,7 +117,8 @@ const columns = computed(() => [
],
},
]);
-const exprBuilder = (param, value) => {
+
+function exprBuilder(param, value) {
switch (param) {
case 'search':
return /^\d+$/.test(value)
@@ -133,52 +135,50 @@ const exprBuilder = (param, value) => {
case 'roleFk':
return { [param]: value };
}
-};
+}
-
-
-
-
-
-
- (roles = data)" auto-load />
+
-
-
-
-
+
+
+
+
+
+
+
+
-
+
diff --git a/src/pages/Account/AccountSamba.vue b/src/pages/Account/AccountSamba.vue
index 699a638eb..7b36de85f 100644
--- a/src/pages/Account/AccountSamba.vue
+++ b/src/pages/Account/AccountSamba.vue
@@ -8,6 +8,7 @@ import VnSubToolbar from 'src/components/ui/VnSubToolbar.vue';
import { useArrayData } from 'src/composables/useArrayData';
import useNotify from 'src/composables/useNotify.js';
import axios from 'axios';
+import VnInputPassword from 'src/components/common/VnInputPassword.vue';
const { t } = useI18n();
const { notify } = useNotify();
@@ -143,10 +144,9 @@ onMounted(async () => await getInitialSambaConfig());
v-model="data.adUser"
:rules="validate('SambaConfigs.adUser')"
/>
-
import { useI18n } from 'vue-i18n';
-import VnCard from 'components/common/VnCard.vue';
+import VnCardBeta from 'components/common/VnCardBeta.vue';
import AliasDescriptor from './AliasDescriptor.vue';
const { t } = useI18n();
-
-import { useI18n } from 'vue-i18n';
-import VnCard from 'components/common/VnCard.vue';
+import VnCardBeta from 'components/common/VnCardBeta.vue';
import AccountDescriptor from './AccountDescriptor.vue';
-
-const { t } = useI18n();
-
+
diff --git a/src/pages/Account/Card/AccountDescriptor.vue b/src/pages/Account/Card/AccountDescriptor.vue
index 3156f8e1e..4e5328de6 100644
--- a/src/pages/Account/Card/AccountDescriptor.vue
+++ b/src/pages/Account/Card/AccountDescriptor.vue
@@ -1,13 +1,13 @@
- (hasAccount = data.exists)"
- />
-
+
-
import axios from 'axios';
-import { computed, ref, toRefs } from 'vue';
+import { computed, onMounted, ref, toRefs } from 'vue';
import { useI18n } from 'vue-i18n';
import { useVnConfirm } from 'composables/useVnConfirm';
import { useRoute } from 'vue-router';
import { useAcl } from 'src/composables/useAcl';
import { useArrayData } from 'src/composables/useArrayData';
+import { useState } from 'src/composables/useState';
import VnConfirm from 'src/components/ui/VnConfirm.vue';
+import VnInputPassword from 'src/components/common/VnInputPassword.vue';
import VnChangePassword from 'src/components/common/VnChangePassword.vue';
import { useQuasar } from 'quasar';
+import { useRouter } from 'vue-router';
const $props = defineProps({
hasAccount: {
@@ -17,14 +20,20 @@ const $props = defineProps({
required: true,
},
});
+
const { t } = useI18n();
const { hasAccount } = toRefs($props);
const { openConfirmationModal } = useVnConfirm();
const route = useRoute();
+const router = useRouter();
+const state = useState();
+const user = state.getUser();
const { notify } = useQuasar();
const account = computed(() => useArrayData('AccountId').store.data[0]);
account.value.hasAccount = hasAccount.value;
const entityId = computed(() => +route.params.id);
+const hasitManagementAccess = ref();
+const hasSysadminAccess = ref();
async function updateStatusAccount(active) {
if (active) {
@@ -36,7 +45,7 @@ async function updateStatusAccount(active) {
account.value.hasAccount = active;
const status = active ? 'enable' : 'disable';
notify({
- message: t(`account.card.${status}Account.success`),
+ message: t(`account.card.actions.${status}Account.success`),
type: 'positive',
});
}
@@ -49,6 +58,17 @@ async function updateStatusUser(active) {
type: 'positive',
});
}
+
+async function deleteAccount() {
+ const { data } = await axios.delete(`VnUsers/${entityId.value}`);
+ if (data) {
+ notify({
+ message: t('account.card.actions.delete.success'),
+ type: 'positive',
+ });
+ router.push({ name: 'AccountList' });
+ }
+}
const showSyncDialog = ref(false);
const syncPassword = ref(null);
const shouldSyncPassword = ref(false);
@@ -63,11 +83,27 @@ async function sync() {
type: 'positive',
});
}
+const askOldPass = ref(false);
+const changePassRef = ref();
+
+const onChangePass = (oldPass) => {
+ askOldPass.value = oldPass;
+ changePassRef.value.show();
+};
+
+onMounted(() => {
+ hasitManagementAccess.value = useAcl().hasAny([
+ { model: 'VnUser', props: 'higherPrivileges', accessType: 'WRITE' },
+ ]);
+ hasSysadminAccess.value = useAcl().hasAny([
+ { model: 'VnUser', props: 'adminUser', accessType: 'WRITE' },
+ ]);
+});
deleteAccount()
+ )
+ "
>
- {{ t('globals.changePass') }}
+ {{ t('globals.delete') }}
+
+ {{ t('globals.changePass') }}
+
+ {{ t('globals.setPass') }}
+
+ updateStatusAccount(true)
+ )
+ "
+ >
+ {{ t('account.card.actions.enableAccount.name') }}
+
+
{{ t('account.card.actions.activateUser.name') }}
{{ t('account.card.actions.deactivateUser.name') }}
-
+
{{ t('account.card.actions.sync.name') }}
diff --git a/src/pages/Account/Card/AccountMailAlias.vue b/src/pages/Account/Card/AccountMailAlias.vue
index 8d3bd3b67..efd2b481b 100644
--- a/src/pages/Account/Card/AccountMailAlias.vue
+++ b/src/pages/Account/Card/AccountMailAlias.vue
@@ -9,6 +9,7 @@ import AccountMailAliasCreateForm from './AccountMailAliasCreateForm.vue';
import { useVnConfirm } from 'composables/useVnConfirm';
import { useArrayData } from 'composables/useArrayData';
import useNotify from 'src/composables/useNotify.js';
+import useHasAccount from 'src/composables/useHasAccount.js';
import axios from 'axios';
const { t } = useI18n();
@@ -50,16 +51,6 @@ const columns = computed(() => [
},
]);
-const fetchAccountExistence = async () => {
- try {
- const { data } = await axios.get(`Accounts/${route.params.id}/exists`);
- return data.exists;
- } catch (error) {
- console.error('Error fetching account existence', error);
- return false;
- }
-};
-
const deleteMailAlias = async (row) => {
await axios.delete(`${urlPath}/${row.id}`);
fetchMailAliases();
@@ -79,7 +70,7 @@ const fetchMailAliases = async () => {
const getAccountData = async (reload = true) => {
loading.value = true;
- hasAccount.value = await fetchAccountExistence();
+ hasAccount.value = await useHasAccount(route.params.id);
if (!hasAccount.value) {
loading.value = false;
store.data = [];
diff --git a/src/pages/Account/Card/AccountMailForwarding.vue b/src/pages/Account/Card/AccountMailForwarding.vue
index 30849d44a..0e5ae3122 100644
--- a/src/pages/Account/Card/AccountMailForwarding.vue
+++ b/src/pages/Account/Card/AccountMailForwarding.vue
@@ -9,6 +9,7 @@ import VnRow from 'components/ui/VnRow.vue';
import axios from 'axios';
import { useStateStore } from 'stores/useStateStore';
import useNotify from 'src/composables/useNotify.js';
+import useHasAccount from 'src/composables/useHasAccount';
const { t } = useI18n();
const route = useRoute();
@@ -30,23 +31,9 @@ const hasDataChanged = computed(
initialData.value.hasData !== hasData.value
);
-const fetchAccountExistence = async () => {
- try {
- const { data } = await axios.get(`Accounts/${route.params.id}/exists`);
- return data.exists;
- } catch (error) {
- console.error('Error fetching account existence', error);
- return false;
- }
-};
-
const fetchMailForwards = async () => {
- try {
- const response = await axios.get(`MailForwards/${route.params.id}`);
- return response.data;
- } catch {
- return null;
- }
+ const response = await axios.get(`MailForwards/${route.params.id}`);
+ return response.data;
};
const deleteMailForward = async () => {
@@ -72,7 +59,7 @@ const setInitialData = async () => {
loading.value = true;
initialData.value.account = route.params.id;
formData.value.account = route.params.id;
- hasAccount.value = await fetchAccountExistence(route.params.id);
+ hasAccount.value = await useHasAccount(route.params.id);
if (!hasAccount.value) {
loading.value = false;
return;
diff --git a/src/pages/Account/Card/AccountSummary.vue b/src/pages/Account/Card/AccountSummary.vue
index 5a21e18a5..ca17c7975 100644
--- a/src/pages/Account/Card/AccountSummary.vue
+++ b/src/pages/Account/Card/AccountSummary.vue
@@ -7,6 +7,7 @@ import CardSummary from 'components/ui/CardSummary.vue';
import VnLv from 'src/components/ui/VnLv.vue';
import { useArrayData } from 'src/composables/useArrayData';
+import AccountDescriptorMenu from './AccountDescriptorMenu.vue';
const route = useRoute();
const { t } = useI18n();
@@ -30,13 +31,15 @@ const filter = {
(account = data)"
>
{{ account.id }} - {{ account.nickname }}
+
+
+
diff --git a/src/pages/Account/Role/AccountRoles.vue b/src/pages/Account/Role/AccountRoles.vue
index 5a27e2ed6..3c3d6b243 100644
--- a/src/pages/Account/Role/AccountRoles.vue
+++ b/src/pages/Account/Role/AccountRoles.vue
@@ -3,11 +3,13 @@ import { useI18n } from 'vue-i18n';
import { computed, ref } from 'vue';
import VnTable from 'components/VnTable/VnTable.vue';
import { useRoute } from 'vue-router';
-import VnSearchbar from 'components/ui/VnSearchbar.vue';
import { useSummaryDialog } from 'src/composables/useSummaryDialog';
import RoleSummary from './Card/RoleSummary.vue';
+import VnSection from 'src/components/common/VnSection.vue';
+
const route = useRoute();
const { t } = useI18n();
+const { viewSummary } = useSummaryDialog();
const $props = defineProps({
id: {
type: Number,
@@ -15,8 +17,10 @@ const $props = defineProps({
},
});
const tableRef = ref();
+const url = 'VnRoles';
+const dataKey = 'AccountRoleList';
+
const entityId = computed(() => $props.id || route.params.id);
-const { viewSummary } = useSummaryDialog();
const columns = computed(() => [
{
align: 'left',
@@ -81,30 +85,32 @@ const exprBuilder = (param, value) => {
-
-
+ prefix="role"
+ :array-data-props="{ url, exprBuilder, order: 'id ASC' }"
+ >
+
+
+
+
diff --git a/src/pages/Account/Role/Card/RoleCard.vue b/src/pages/Account/Role/Card/RoleCard.vue
index a2d5710f4..7664deca8 100644
--- a/src/pages/Account/Role/Card/RoleCard.vue
+++ b/src/pages/Account/Role/Card/RoleCard.vue
@@ -1,20 +1,7 @@
-
+
diff --git a/src/pages/Account/Role/Card/RoleDescriptor.vue b/src/pages/Account/Role/Card/RoleDescriptor.vue
index 693fcdf48..0a555346d 100644
--- a/src/pages/Account/Role/Card/RoleDescriptor.vue
+++ b/src/pages/Account/Role/Card/RoleDescriptor.vue
@@ -43,14 +43,14 @@ const removeRole = async () => {
:filter="filter"
module="Role"
@on-fetch="setData"
- data-key="accountData"
+ data-key="Role"
:title="data.title"
:subtitle="data.subtitle"
:summary="$props.summary"
>
- {{ t('Delete') }}
+ {{ t('globals.delete') }}
diff --git a/src/pages/Account/Role/Card/RoleSummary.vue b/src/pages/Account/Role/Card/RoleSummary.vue
index fef85f919..f0daa77fb 100644
--- a/src/pages/Account/Role/Card/RoleSummary.vue
+++ b/src/pages/Account/Role/Card/RoleSummary.vue
@@ -27,10 +27,10 @@ const filter = {
(role = data)"
- data-key="RoleSummary"
+ data-key="Role"
>
{{ role.id }} - {{ role.name }}
diff --git a/src/pages/Account/locale/en.yml b/src/pages/Account/locale/en.yml
index f2f563923..1826250fd 100644
--- a/src/pages/Account/locale/en.yml
+++ b/src/pages/Account/locale/en.yml
@@ -1,4 +1,18 @@
account:
+ params:
+ id: Id
+ name: Name
+ roleFk: Role
+ nickname: Nickname
+ password: Password
+ active: Active
+ search: Id
+ description: Description
+ alias: Alias
+ model: Model
+ principalId: Role
+ property: Property
+ accessType: Access
card:
nickname: User
role: Role
@@ -66,7 +80,7 @@ account:
mailInputInfo: All emails will be forwarded to the specified address.
role:
newRole: New role
- searchRoles: Search role
+ search: Search role
searchInfo: Search role by id or name
description: Description
id: Id
diff --git a/src/pages/Account/locale/es.yml b/src/pages/Account/locale/es.yml
index ba559f2c3..941a9948f 100644
--- a/src/pages/Account/locale/es.yml
+++ b/src/pages/Account/locale/es.yml
@@ -1,4 +1,20 @@
+accessType: Acceso
+property: Propiedad
account:
+ params:
+ id: Id
+ name: Nombre
+ roleFk: Rol
+ nickname: Nickname
+ password: Contraseña
+ active: Activo
+ search: Id
+ description: Descripción
+ alias: Alias
+ model: Modelo
+ principalId: Rol
+ property: Propiedad
+ accessType: Acceso
card:
nickname: Usuario
role: Rol
diff --git a/src/pages/Claim/Card/ClaimCard.vue b/src/pages/Claim/Card/ClaimCard.vue
index 3642dc0d0..e1e000815 100644
--- a/src/pages/Claim/Card/ClaimCard.vue
+++ b/src/pages/Claim/Card/ClaimCard.vue
@@ -1,21 +1,13 @@
-
diff --git a/src/pages/Claim/Card/ClaimDevelopment.vue b/src/pages/Claim/Card/ClaimDevelopment.vue
index e288d8614..d17c6b4e6 100644
--- a/src/pages/Claim/Card/ClaimDevelopment.vue
+++ b/src/pages/Claim/Card/ClaimDevelopment.vue
@@ -164,19 +164,7 @@ const columns = computed(() => [
:autofocus="col.tabIndex == 1"
input-debounce="0"
hide-selected
- >
-
-
-
- {{ scope.opt?.name }}
-
- {{ scope.opt?.nickname }}
- {{ scope.opt?.code }}
-
-
-
-
-
+ />
-
+
-
+
{{ value }}
-
+
{{ value }}
-
+
-
+
{{ column.value }}
diff --git a/src/pages/Claim/Card/ClaimSummary.vue b/src/pages/Claim/Card/ClaimSummary.vue
index 200ab4bea..66fb151e5 100644
--- a/src/pages/Claim/Card/ClaimSummary.vue
+++ b/src/pages/Claim/Card/ClaimSummary.vue
@@ -19,6 +19,7 @@ import ClaimNotes from 'src/pages/Claim/Card/ClaimNotes.vue';
import ItemDescriptorProxy from 'src/pages/Item/Card/ItemDescriptorProxy.vue';
import CustomerDescriptorProxy from 'src/pages/Customer/Card/CustomerDescriptorProxy.vue';
import WorkerDescriptorProxy from 'src/pages/Worker/Card/WorkerDescriptorProxy.vue';
+import ClaimDescriptorMenu from './ClaimDescriptorMenu.vue';
const route = useRoute();
const router = useRouter();
@@ -228,6 +229,9 @@ function claimUrl(section) {
+
+
+
{{
t(col.value)
}}
- {{ col.value }}
+ {{
+ t(col.value)
+ }}
{{ formatFn(tag.value) }}
-
+
-
-
-
- #{{ scope.opt?.id }}
- {{ scope.opt?.name }}
-
-
-
-
+ />
+
@@ -153,6 +137,7 @@ en:
created: Created
myTeam: My team
itemFk: Item
+ zoneFk: Zone
es:
params:
search: Contiene
@@ -165,6 +150,7 @@ es:
created: Creada
myTeam: Mi equipo
itemFk: Artículo
+ zoneFk: Zona
Client Name: Nombre del cliente
Salesperson: Comercial
Item: Artículo
diff --git a/src/pages/Claim/ClaimList.vue b/src/pages/Claim/ClaimList.vue
index d561a69f7..35b051cdc 100644
--- a/src/pages/Claim/ClaimList.vue
+++ b/src/pages/Claim/ClaimList.vue
@@ -2,17 +2,18 @@
import { ref, computed } from 'vue';
import { useI18n } from 'vue-i18n';
import { toDate } from 'filters/index';
-import VnSearchbar from 'components/ui/VnSearchbar.vue';
import ClaimFilter from './ClaimFilter.vue';
import CustomerDescriptorProxy from 'src/pages/Customer/Card/CustomerDescriptorProxy.vue';
import VnUserLink from 'src/components/ui/VnUserLink.vue';
import ClaimSummary from './Card/ClaimSummary.vue';
import { useSummaryDialog } from 'src/composables/useSummaryDialog';
-import RightMenu from 'src/components/common/RightMenu.vue';
import VnTable from 'src/components/VnTable/VnTable.vue';
+import ZoneDescriptorProxy from '../Zone/Card/ZoneDescriptorProxy.vue';
+import VnSection from 'src/components/common/VnSection.vue';
const { t } = useI18n();
const { viewSummary } = useSummaryDialog();
+const dataKey = 'ClaimList';
const claimFilterRef = ref();
const columns = computed(() => [
@@ -95,7 +96,12 @@ const columns = computed(() => [
optionLabel: 'description',
},
},
- orderBy: 'priority',
+ orderBy: 'cs.priority',
+ },
+ {
+ align: 'left',
+ label: t('claim.zone'),
+ name: 'zoneFk',
},
{
align: 'right',
@@ -105,6 +111,7 @@ const columns = computed(() => [
title: t('components.smartCard.viewSummary'),
icon: 'preview',
action: (row) => viewSummary(row.id, ClaimSummary),
+ isPrimary: true,
},
],
},
@@ -118,43 +125,50 @@ const STATE_COLOR = {
-
-
-
+
+
-
-
-
-
- {{ row.clientName }}
-
-
+
+
+
+
+ {{ row.clientName }}
+
+
+
+
+
+
+
+
+
+
+ {{ row.zoneName }}
+
+
+
+
-
-
-
-
-
-
+
es:
- Search claim: Buscar reclamación
- You can search by claim id or customer name: Puedes buscar por id de la reclamación o nombre del cliente
params:
stateCode: Estado
en:
diff --git a/src/pages/Claim/locale/en.yml b/src/pages/Claim/locale/en.yml
index ffcb44df6..11b4a2ca4 100644
--- a/src/pages/Claim/locale/en.yml
+++ b/src/pages/Claim/locale/en.yml
@@ -44,3 +44,5 @@ claim:
fileDescription: 'Claim id {claimId} from client {clientName} id {clientId}'
noData: 'There are no images/videos, click here or drag and drop the file'
dragDrop: Drag and drop it here
+ search: Search claims
+ searchInfo: You can search by claim id or customer name
diff --git a/src/pages/Claim/locale/es.yml b/src/pages/Claim/locale/es.yml
index 052416aa7..d35d2c8e7 100644
--- a/src/pages/Claim/locale/es.yml
+++ b/src/pages/Claim/locale/es.yml
@@ -1,5 +1,3 @@
-Search claim: Buscar reclamación
-You can search by claim id or customer name: Puedes buscar por id de la reclamación o nombre del cliente
claim:
customer: Cliente
code: Código
@@ -46,3 +44,5 @@ claim:
fileDescription: 'ID de reclamación {claimId} del cliente {clientName} con ID {clientId}'
noData: 'No hay imágenes/videos, haz clic aquí o arrastra y suelta el archivo'
dragDrop: Arrastra y suelta aquí
+ search: Buscar reclamación
+ searchInfo: Puedes buscar por ID de la reclamación o nombre del cliente
diff --git a/src/pages/Customer/Card/CustomerBalance.vue b/src/pages/Customer/Card/CustomerBalance.vue
index 712be5e09..04ef5f882 100644
--- a/src/pages/Customer/Card/CustomerBalance.vue
+++ b/src/pages/Customer/Card/CustomerBalance.vue
@@ -84,6 +84,7 @@ const columns = computed(() => [
label: t('Creation date'),
format: ({ created }) => toDateHourMin(created),
cardVisible: true,
+ style: 'color: var(--vn-label-color)',
},
{
align: 'left',
diff --git a/src/pages/Customer/Card/CustomerBasicData.vue b/src/pages/Customer/Card/CustomerBasicData.vue
index 768c66f32..e9a349e0b 100644
--- a/src/pages/Customer/Card/CustomerBasicData.vue
+++ b/src/pages/Customer/Card/CustomerBasicData.vue
@@ -16,14 +16,17 @@ const { t } = useI18n();
const businessTypes = ref([]);
const contactChannels = ref([]);
-const handleSalesModelValue = (val) => ({
- or: [
- { id: val },
- { name: val },
- { nickname: { like: '%' + val + '%' } },
- { code: { like: `${val}%` } },
- ],
-});
+const handleSalesModelValue = (val) => {
+ if (!val) val = '';
+ return {
+ or: [
+ { id: val },
+ { name: val },
+ { nickname: { like: '%' + val + '%' } },
+ { code: { like: `${val}%` } },
+ ],
+ };
+};
const exprBuilder = (param, value) => {
return {
diff --git a/src/pages/Customer/Card/CustomerBillingData.vue b/src/pages/Customer/Card/CustomerBillingData.vue
index 48f729e29..29394ceec 100644
--- a/src/pages/Customer/Card/CustomerBillingData.vue
+++ b/src/pages/Customer/Card/CustomerBillingData.vue
@@ -38,7 +38,7 @@ const getBankEntities = (data, formData) => {
hide-selected
option-label="name"
option-value="id"
- v-model="data.payMethod"
+ v-model="data.payMethodFk"
/>
diff --git a/src/pages/Customer/Card/CustomerConsumption.vue b/src/pages/Customer/Card/CustomerConsumption.vue
index 35f366e47..640e37ed3 100644
--- a/src/pages/Customer/Card/CustomerConsumption.vue
+++ b/src/pages/Customer/Card/CustomerConsumption.vue
@@ -2,7 +2,7 @@
import { ref, computed, onBeforeMount } from 'vue';
import axios from 'axios';
import { useI18n } from 'vue-i18n';
-import { toDate } from 'src/filters/index';
+import { dateRange, toDate } from 'src/filters/index';
import { useRoute } from 'vue-router';
import VnTable from 'components/VnTable/VnTable.vue';
@@ -104,18 +104,12 @@ function getParams() {
};
}
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 {
- campaign: campaignList.value[0]?.id,
- from: minDate,
- to: maxDate,
+ const campaign = campaignList.value[0]?.id;
+ const userParams = {
+ campaign,
+ ...updateDateParams(campaign, { from: Date.vnNew(), to: Date.vnNew() }),
};
+ return userParams;
});
const openReportPdf = () => {
openReport(`Clients/${route.params.id}/campaign-metrics-pdf`, getParams());
@@ -134,6 +128,23 @@ const sendCampaignMetricsEmail = ({ address }) => {
...getParams(),
});
};
+
+const updateDateParams = (value, params) => {
+ if (!value) {
+ params.from = null;
+ params.to = null;
+ return;
+ }
+ const campaign = campaignList.value.find((c) => c.id === value);
+ if (!campaign) return;
+
+ const { dated, previousDays, scopeDays } = campaign;
+ const _date = new Date(dated);
+ const [from, to] = dateRange(_date);
+ params.from = new Date(from.setDate(from.getDate() - previousDays)).toISOString();
+ params.to = new Date(to.setDate(to.getDate() + scopeDays)).toISOString();
+ return params;
+};
@@ -144,7 +155,6 @@ const sendCampaignMetricsEmail = ({ address }) => {
:order="['itemTypeFk', 'itemName', 'itemSize', 'description']"
:columns="columns"
search-url="consumption"
- :filter="filter"
:user-params="userParams"
:default-remove="false"
:default-reset="false"
@@ -201,6 +211,7 @@ const sendCampaignMetricsEmail = ({ address }) => {
class="q-px-sm q-pt-none fit"
dense
option-label="code"
+ @update:model-value="(data) => updateDateParams(data, params)"
>
diff --git a/src/pages/Customer/Card/CustomerCredits.vue b/src/pages/Customer/Card/CustomerCredits.vue
index 1fa7047e5..d6e4be89e 100644
--- a/src/pages/Customer/Card/CustomerCredits.vue
+++ b/src/pages/Customer/Card/CustomerCredits.vue
@@ -59,6 +59,7 @@ const columns = computed(() => [
state.get('customer'));
+const customerDebt = ref();
+const customerCredit = ref();
const $props = defineProps({
id: {
type: Number,
@@ -37,11 +35,12 @@ const entityId = computed(() => {
const data = ref(useCardDescription());
const setData = (entity) => {
+ customerDebt.value = entity?.debt;
+ customerCredit.value = entity?.credit;
data.value = useCardDescription(entity?.name, entity?.id);
- if (customer.value) customer.value.webAccess = data.value?.account?.isActive;
};
const debtWarning = computed(() => {
- return customer.value?.debt > customer.value?.credit ? 'negative' : 'primary';
+ return customerDebt.value > customerCredit.value ? 'negative' : 'primary';
});
@@ -93,26 +92,21 @@ const debtWarning = computed(() => {
:value="entity.businessType.description"
/>
-
-
+
+
{{ t('customer.card.isDisabled') }}
-
+
{{ t('customer.card.isFrozen') }}
{
{{ t('customer.card.webAccountInactive') }}
{
{{ t('customer.card.hasDebt') }}
{
{{ t('customer.card.notChecked') }}
diff --git a/src/pages/Customer/Card/CustomerGreuges.vue b/src/pages/Customer/Card/CustomerGreuges.vue
index dcf297d12..47a589aaa 100644
--- a/src/pages/Customer/Card/CustomerGreuges.vue
+++ b/src/pages/Customer/Card/CustomerGreuges.vue
@@ -84,6 +84,7 @@ const columns = computed(() => [
component: 'number',
autofocus: true,
required: true,
+ positive: false,
},
format: ({ amount }) => toCurrency(amount),
create: true,
diff --git a/src/pages/Customer/Card/CustomerMandates.vue b/src/pages/Customer/Card/CustomerMandates.vue
index 248515b4a..66cb44bc2 100644
--- a/src/pages/Customer/Card/CustomerMandates.vue
+++ b/src/pages/Customer/Card/CustomerMandates.vue
@@ -63,9 +63,10 @@ const columns = computed(() => [
{
data-key="CustomerSummary"
module-name="Customer"
>
+
+
+
{
:phone-number="entity.mobile"
:channel="entity.country?.saySimpleCountry?.channel"
class="q-ml-xs"
- :country="entity.country?.code"
/>
{{ t('globals.params.email') }}
-
({
- or: [
- { id: val },
- { name: val },
- { nickname: { like: '%' + val + '%' } },
- { code: { like: `${val}%` } },
- ],
-});
+const handleSalesModelValue = (val) => {
+ if (!val) val = '';
+ return {
+ or: [
+ { id: val },
+ { name: val },
+ { nickname: { like: '%' + val + '%' } },
+ { code: { like: `${val}%` } },
+ ],
+ };
+};
const exprBuilder = (param, value) => {
return {
@@ -170,6 +173,8 @@ en:
phone: Phone
email: Email
zoneFk: Zone
+ socialName : Social name
+ name: Name
postcode: Postcode
es:
params:
@@ -181,6 +186,8 @@ es:
phone: Teléfono
email: Email
zoneFk: Zona
+ socialName : Razón social
+ name: Nombre
postcode: CP
FI: NIF
Salesperson: Comercial
diff --git a/src/pages/Customer/CustomerList.vue b/src/pages/Customer/CustomerList.vue
index e86e35966..bd2947cfc 100644
--- a/src/pages/Customer/CustomerList.vue
+++ b/src/pages/Customer/CustomerList.vue
@@ -2,22 +2,21 @@
import { ref, computed, markRaw } from 'vue';
import { useI18n } from 'vue-i18n';
import { useRouter } from 'vue-router';
+import { useSummaryDialog } from 'src/composables/useSummaryDialog';
+import { toDate } from 'src/filters';
+
+import RightMenu from 'src/components/common/RightMenu.vue';
+import CustomerSummary from './Card/CustomerSummary.vue';
+import CustomerFilter from './CustomerFilter.vue';
import VnTable from 'components/VnTable/VnTable.vue';
import VnLocation from 'src/components/common/VnLocation.vue';
import VnSearchbar from 'components/ui/VnSearchbar.vue';
-import CustomerSummary from './Card/CustomerSummary.vue';
-import { useSummaryDialog } from 'src/composables/useSummaryDialog';
-import RightMenu from 'src/components/common/RightMenu.vue';
import VnLinkPhone from 'src/components/ui/VnLinkPhone.vue';
-import { toDate } from 'src/filters';
-import CustomerFilter from './CustomerFilter.vue';
import VnSelectWorker from 'src/components/common/VnSelectWorker.vue';
const { t } = useI18n();
const router = useRouter();
-
const tableRef = ref();
-
const columns = computed(() => [
{
align: 'left',
@@ -51,6 +50,14 @@ const columns = computed(() => [
isTitle: true,
create: true,
columnClass: 'expand',
+ attrs: {
+ uppercase: true,
+ },
+ columnFilter: {
+ attrs: {
+ uppercase: false,
+ },
+ },
},
{
align: 'left',
@@ -263,7 +270,7 @@ const columns = computed(() => [
},
{
align: 'left',
- label: t('customer.extendedList.tableVisibleColumns.isVies'),
+ label: t('globals.isVies'),
name: 'isVies',
columnFilter: {
inWhere: true,
@@ -405,6 +412,7 @@ function handleLocation(data, location) {
ref="tableRef"
data-key="CustomerList"
url="Clients/filter"
+ order="id DESC"
:create="{
urlCreate: 'Clients/createWithUser',
title: t('globals.pageTitles.customerCreate'),
@@ -414,24 +422,41 @@ function handleLocation(data, location) {
isEqualizated: false,
},
}"
- order="id DESC"
:columns="columns"
- redirect="customer"
:right-search="false"
- auto-load
+ redirect="customer"
>
+ >
+
+
+
+
+
+
+ {{ scope.opt?.name }}
+ {{ scope.opt?.nickname }},
+ {{ scope.opt?.code }}
+
+
+
+
es:
- Web user: Usuario Web
+ Web user: Usuario web
-
- es:
- Edit travel: Editar envío
- Travel: Envíos
- Purchase Spaces: Espacios de compra
- Buyer: Comprador
- Reserve: Reservado
- Bought: Comprado
- Date: Fecha
- View more details: Ver más detalles
- Reserve some space: Reservar espacio
- This buyer has already made a reservation for this date: Este comprador ya ha hecho una reserva para esta fecha
-
diff --git a/src/pages/Entry/EntryStockBoughtFilter.vue b/src/pages/Entry/EntryStockBoughtFilter.vue
index e59332064..136881f17 100644
--- a/src/pages/Entry/EntryStockBoughtFilter.vue
+++ b/src/pages/Entry/EntryStockBoughtFilter.vue
@@ -65,6 +65,6 @@ onMounted(async () => {
es:
Date: Fecha
params:
- dated: Date
+ dated: Fecha
workerFk: Trabajador
diff --git a/src/pages/Entry/MyEntries.vue b/src/pages/Entry/MyEntries.vue
index 91a29b190..3f7566ae0 100644
--- a/src/pages/Entry/MyEntries.vue
+++ b/src/pages/Entry/MyEntries.vue
@@ -102,7 +102,7 @@ const columns = computed(() => [
actions: [
{
title: t('myEntries.printLabels'),
- icon: 'print',
+ icon: 'move_item',
isPrimary: true,
action: (row) => printBuys(row.id),
},
@@ -123,8 +123,8 @@ const printBuys = (rowId) => {
{
chip-locale="myEntries"
/>
-
-
- You can search by entry reference: Puedes buscar por referencia de la entrada
-
diff --git a/src/pages/Entry/locale/en.yml b/src/pages/Entry/locale/en.yml
index cd5113d84..97a3be32b 100644
--- a/src/pages/Entry/locale/en.yml
+++ b/src/pages/Entry/locale/en.yml
@@ -1,8 +1,94 @@
-entryList:
+entry:
list:
+ newEntry: New entry
+ tableVisibleColumns:
+ created: Creation
+ supplierFk: Supplier
+ isBooked: Booked
+ isConfirmed: Confirmed
+ isOrdered: Ordered
+ companyFk: Company
+ travelFk: Travel
+ isExcludedFromAvailable: Inventory
+ invoiceAmount: Import
inventoryEntry: Inventory entry
+ summary:
+ commission: Commission
+ currency: Currency
+ invoiceNumber: Invoice number
+ ordered: Ordered
+ booked: Booked
+ excludedFromAvailable: Inventory
+ travelReference: Reference
+ travelAgency: Agency
+ travelShipped: Shipped
+ travelDelivered: Delivered
+ travelLanded: Landed
+ travelReceived: Received
+ buys: Buys
+ stickers: Stickers
+ package: Package
+ packing: Pack.
+ grouping: Group.
+ buyingValue: Buying value
+ import: Import
+ pvp: PVP
+ basicData:
+ travel: Travel
+ currency: Currency
+ commission: Commission
+ observation: Observation
+ booked: Booked
+ excludedFromAvailable: Inventory
+ initialTemperature: Ini °C
+ finalTemperature: Fin °C
+ buys:
+ observations: Observations
+ packagingFk: Box
+ color: Color
+ printedStickers: Printed stickers
+ notes:
+ observationType: Observation type
+ latestBuys:
+ tableVisibleColumns:
+ image: Picture
+ itemFk: Item ID
+ weightByPiece: Weight/Piece
+ isActive: Active
+ family: Family
+ entryFk: Entry
+ freightValue: Freight value
+ comissionValue: Commission value
+ packageValue: Package value
+ isIgnored: Is ignored
+ price2: Grouping
+ price3: Packing
+ minPrice: Min
+ ektFk: Ekt
+ packingOut: Package out
+ landing: Landing
+ isExcludedFromAvailable: Es inventory
+ params:
+ toShipped: To
+ fromShipped: From
+ daysOnward: Days onward
+ daysAgo: Days ago
+ warehouseInFk: Warehouse in
+ search: Search entries
+ searchInfo: You can search by entry reference
entryFilter:
- filter:
+ params:
+ invoiceNumber: Invoice number
+ travelFk: Travel
+ companyFk: Company
+ currencyFk: Currency
+ supplierFk: Supplier
+ from: From
+ to: To
+ created: Created
+ isBooked: Booked
+ isConfirmed: Confirmed
+ isOrdered: Ordered
search: General search
reference: Reference
myEntries:
@@ -17,5 +103,19 @@ myEntries:
warehouseInFk: Warehouse in
daysOnward: Days onward
daysAgo: Days ago
+ downloadCsv: Download CSV
+ search: Search entries
+ searchInfo: You can search by entry reference
+entryStockBought:
+ travel: Travel
+ editTravel: Edit travel
+ purchaseSpaces: Purchase spaces
+ buyer: Buyer
+ reserve: Reserve
+ bought: Bought
+ date: Date
+ viewMoreDetails: View more details
+ reserveSomeSpace: Reserve some space
+ thisBuyerHasReservationThisDate: This buyer has already made a reservation for this date
wasteRecalc:
recalcOk: The wastes were successfully recalculated
diff --git a/src/pages/Entry/locale/es.yml b/src/pages/Entry/locale/es.yml
index 3007c5d44..993913417 100644
--- a/src/pages/Entry/locale/es.yml
+++ b/src/pages/Entry/locale/es.yml
@@ -1,11 +1,95 @@
-Search entries: Buscar entradas
-You can search by entry reference: Puedes buscar por referencia de la entrada
-
-entryList:
+entry:
list:
+ newEntry: Nueva entrada
+ tableVisibleColumns:
+ created: Creación
+ supplierFk: Proveedor
+ isBooked: Asentado
+ isConfirmed: Confirmado
+ isOrdered: Pedida
+ companyFk: Empresa
+ travelFk: Envio
+ isExcludedFromAvailable: Inventario
+ invoiceAmount: Importe
inventoryEntry: Es inventario
+ summary:
+ commission: Comisión
+ currency: Moneda
+ invoiceNumber: Núm. factura
+ ordered: Pedida
+ booked: Contabilizada
+ excludedFromAvailable: Inventario
+ travelReference: Referencia
+ travelAgency: Agencia
+ travelShipped: F. envio
+ travelWarehouseOut: Alm. salida
+ travelDelivered: Enviada
+ travelLanded: F. entrega
+ travelReceived: Recibida
+ buys: Compras
+ stickers: Etiquetas
+ package: Embalaje
+ packing: Pack.
+ grouping: Group.
+ buyingValue: Coste
+ import: Importe
+ pvp: PVP
+ basicData:
+ travel: Envío
+ currency: Moneda
+ observation: Observación
+ commission: Comisión
+ booked: Asentado
+ excludedFromAvailable: Inventario
+ initialTemperature: Ini °C
+ finalTemperature: Fin °C
+ buys:
+ observations: Observaciónes
+ packagingFk: Embalaje
+ color: Color
+ printedStickers: Etiquetas impresas
+ notes:
+ observationType: Tipo de observación
+ latestBuys:
+ tableVisibleColumns:
+ image: Foto
+ itemFk: Id Artículo
+ weightByPiece: Peso (gramos)/tallo
+ isActive: Activo
+ family: Familia
+ entryFk: Entrada
+ freightValue: Porte
+ comissionValue: Comisión
+ packageValue: Embalaje
+ isIgnored: Ignorado
+ price2: Grouping
+ price3: Packing
+ minPrice: Min
+ ektFk: Ekt
+ packingOut: Embalaje envíos
+ landing: Llegada
+ isExcludedFromAvailable: Es inventario
+ params:
+ toShipped: Hasta
+ fromShipped: Desde
+ warehouseInFk: Alm. entrada
+ daysOnward: Días adelante
+ daysAgo: Días atras
+ search: Buscar entradas
+ searchInfo: Puedes buscar por referencia de entrada
entryFilter:
- filter:
+ params:
+ invoiceNumber: Núm. factura
+ travelFk: Envío
+ companyFk: Empresa
+ currencyFk: Moneda
+ supplierFk: Proveedor
+ from: Desde
+ to: Hasta
+ created: Fecha creación
+ isBooked: Asentado
+ isConfirmed: Confirmado
+ isOrdered: Pedida
search: Búsqueda general
reference: Referencia
myEntries:
@@ -20,5 +104,19 @@ myEntries:
warehouseInFk: Alm. entrada
daysOnward: Días adelante
daysAgo: Días atras
+ downloadCsv: Descargar CSV
+ search: Buscar entradas
+ searchInfo: Puedes buscar por referencia de la entrada
+entryStockBought:
+ travel: Envío
+ editTravel: Editar envío
+ purchaseSpaces: Espacios de compra
+ buyer: Comprador
+ reserve: Reservado
+ bought: Comprado
+ date: Fecha
+ viewMoreDetails: Ver más detalles
+ reserveSomeSpace: Reservar espacio
+ thisBuyerHasReservationThisDate: Este comprador ya ha hecho una reserva para esta fecha
wasteRecalc:
recalcOk: Se han recalculado las mermas correctamente
diff --git a/src/pages/InvoiceIn/Card/InvoiceInBasicData.vue b/src/pages/InvoiceIn/Card/InvoiceInBasicData.vue
index 209681b7c..90aa50af7 100644
--- a/src/pages/InvoiceIn/Card/InvoiceInBasicData.vue
+++ b/src/pages/InvoiceIn/Card/InvoiceInBasicData.vue
@@ -116,6 +116,7 @@ function deleteFile(dmsFk) {
-import { ref, computed } from 'vue';
-import { useRouter } from 'vue-router';
+import { ref, computed, capitalize } from 'vue';
+import { useRoute } from 'vue-router';
import { useI18n } from 'vue-i18n';
import { useArrayData } from 'src/composables/useArrayData';
-import { useCapitalize } from 'src/composables/useCapitalize';
import CrudModel from 'src/components/CrudModel.vue';
import FetchData from 'src/components/FetchData.vue';
import VnSelect from 'src/components/common/VnSelect.vue';
-const { push, currentRoute } = useRouter();
+const route = useRoute();
const { t } = useI18n();
-const invoiceId = +currentRoute.value.params.id;
const arrayData = useArrayData();
const invoiceIn = computed(() => arrayData.store.data);
const invoiceInCorrectionRef = ref();
const filter = {
include: { relation: 'invoiceIn' },
- where: { correctingFk: invoiceId },
+ where: { correctingFk: route.params.id },
};
const columns = computed(() => [
{
@@ -31,7 +29,7 @@ const columns = computed(() => [
},
{
name: 'type',
- label: useCapitalize(t('globals.type')),
+ label: capitalize(t('globals.type')),
field: (row) => row.cplusRectificationTypeFk,
options: cplusRectificationTypes.value,
model: 'cplusRectificationTypeFk',
@@ -43,10 +41,10 @@ const columns = computed(() => [
},
{
name: 'class',
- label: useCapitalize(t('globals.class')),
- field: (row) => row.siiTypeInvoiceOutFk,
- options: siiTypeInvoiceOuts.value,
- model: 'siiTypeInvoiceOutFk',
+ label: capitalize(t('globals.class')),
+ field: (row) => row.siiTypeInvoiceInFk,
+ options: siiTypeInvoiceIns.value,
+ model: 'siiTypeInvoiceInFk',
optionValue: 'id',
optionLabel: 'code',
sortable: true,
@@ -55,7 +53,7 @@ const columns = computed(() => [
},
{
name: 'reason',
- label: useCapitalize(t('globals.reason')),
+ label: capitalize(t('globals.reason')),
field: (row) => row.invoiceCorrectionTypeFk,
options: invoiceCorrectionTypes.value,
model: 'invoiceCorrectionTypeFk',
@@ -67,13 +65,10 @@ const columns = computed(() => [
},
]);
const cplusRectificationTypes = ref([]);
-const siiTypeInvoiceOuts = ref([]);
+const siiTypeInvoiceIns = ref([]);
const invoiceCorrectionTypes = ref([]);
-const rowsSelected = ref([]);
const requiredFieldRule = (val) => val || t('globals.requiredField');
-
-const onSave = (data) => data.deletes && push(`/invoice-in/${invoiceId}/summary`);
data.deletes && push(`/invoice-in/${invoiceId}/summary`
auto-load
/>
(siiTypeInvoiceOuts = data)"
+ @on-fetch="(data) => (siiTypeInvoiceIns = data)"
auto-load
/>
data.deletes && push(`/invoice-in/${invoiceId}/summary`
url="InvoiceInCorrections"
:filter="filter"
auto-load
- v-model:selected="rowsSelected"
primary-key="correctingFk"
- @save-changes="onSave"
+ :default-remove="false"
>
@@ -121,8 +113,17 @@ const onSave = (data) => data.deletes && push(`/invoice-in/${invoiceId}/summary`
:options="col.options"
:option-value="col.optionValue"
:option-label="col.optionLabel"
- :readonly="row.invoiceIn.isBooked"
- />
+ :disable="row.invoiceIn.isBooked"
+ :filter-options="['description']"
+ >
+
+
+
+ {{ opt.description }}
+
+
+
+
@@ -134,8 +135,20 @@ const onSave = (data) => data.deletes && push(`/invoice-in/${invoiceId}/summary`
:option-value="col.optionValue"
:option-label="col.optionLabel"
:rules="[requiredFieldRule]"
- :readonly="row.invoiceIn.isBooked"
- />
+ :filter-options="['code', 'description']"
+ :disable="row.invoiceIn.isBooked"
+ >
+
+
+
+ {{ opt.code }} -
+ {{ opt.description }}
+
+
+
+
@@ -147,7 +160,7 @@ const onSave = (data) => data.deletes && push(`/invoice-in/${invoiceId}/summary`
:option-value="col.optionValue"
:option-label="col.optionLabel"
:rules="[requiredFieldRule]"
- :readonly="row.invoiceIn.isBooked"
+ :disable="row.invoiceIn.isBooked"
/>
@@ -155,7 +168,6 @@ const onSave = (data) => data.deletes && push(`/invoice-in/${invoiceId}/summary`
-
es:
Original invoice: Factura origen
diff --git a/src/pages/InvoiceIn/Card/InvoiceInDescriptor.vue b/src/pages/InvoiceIn/Card/InvoiceInDescriptor.vue
index 92f3fffca..9fa3bcbcb 100644
--- a/src/pages/InvoiceIn/Card/InvoiceInDescriptor.vue
+++ b/src/pages/InvoiceIn/Card/InvoiceInDescriptor.vue
@@ -2,60 +2,21 @@
import { ref, reactive, computed, onBeforeMount } from 'vue';
import { useRouter, onBeforeRouteUpdate } from 'vue-router';
import { useI18n } from 'vue-i18n';
-import { useQuasar } from 'quasar';
import axios from 'axios';
import { toCurrency, toDate } from 'src/filters';
-import { useAcl } from 'src/composables/useAcl';
-import { downloadFile } from 'src/composables/downloadFile';
-import { useArrayData } from 'src/composables/useArrayData';
-import { usePrintService } from 'composables/usePrintService';
import VnLv from 'src/components/ui/VnLv.vue';
import CardDescriptor from 'components/ui/CardDescriptor.vue';
-import FetchData from 'src/components/FetchData.vue';
-import SendEmailDialog from 'components/common/SendEmailDialog.vue';
-import VnConfirm from 'src/components/ui/VnConfirm.vue';
-import VnSelect from 'src/components/common/VnSelect.vue';
-import { useCapitalize } from 'src/composables/useCapitalize';
import SupplierDescriptorProxy from 'src/pages/Supplier/Card/SupplierDescriptorProxy.vue';
-import InvoiceInToBook from '../InvoiceInToBook.vue';
+import InvoiceInDescriptorMenu from './InvoiceInDescriptorMenu.vue';
const $props = defineProps({ id: { type: Number, default: null } });
-
-const { push, currentRoute } = useRouter();
-
-const quasar = useQuasar();
-const { hasAny } = useAcl();
+const { currentRoute } = useRouter();
const { t } = useI18n();
-const { openReport, sendEmail } = usePrintService();
-const arrayData = useArrayData();
-const invoiceIn = computed(() => arrayData.store.data);
const cardDescriptorRef = ref();
-const correctionDialogRef = ref();
const entityId = computed(() => $props.id || +currentRoute.value.params.id);
const totalAmount = ref();
-const currentAction = ref();
-const config = ref();
-const cplusRectificationTypes = ref([]);
-const siiTypeInvoiceOuts = ref([]);
-const invoiceCorrectionTypes = ref([]);
-const actions = {
- unbook: {
- title: t('assertAction', { action: t('unbook') }),
- action: toUnbook,
- },
- delete: {
- title: t('assertAction', { action: t('delete') }),
- action: deleteInvoice,
- },
- clone: {
- title: t('assertAction', { action: t('clone') }),
- action: cloneInvoice,
- },
- showPdf: { cb: showPdfInvoice },
- sendPdf: { cb: sendPdfInvoiceConfirmation },
- correct: { cb: () => correctionDialogRef.value.show() },
-};
+
const filter = {
include: [
{
@@ -116,12 +77,6 @@ const routes = reactive({
return { name: 'EntryCard', params: { id } };
},
});
-const correctionFormData = reactive({
- invoiceReason: 2,
- invoiceType: 2,
- invoiceClass: 6,
-});
-const isNotFilled = computed(() => Object.values(correctionFormData).includes(null));
onBeforeMount(async () => {
await setInvoiceCorrection(entityId.value);
@@ -153,125 +108,8 @@ async function setInvoiceCorrection(id) {
(corrected) => corrected.correctingFk
);
}
-
-function openDialog() {
- quasar.dialog({
- component: VnConfirm,
- componentProps: {
- title: t(currentAction.value.title),
- promise: currentAction.value.action,
- },
- });
-}
-
-async function toUnbook() {
- const { data } = await axios.post(`InvoiceIns/${entityId.value}/toUnbook`);
- const { isLinked, bookEntry, accountingEntries } = data;
-
- const type = isLinked ? 'warning' : 'positive';
- const message = isLinked
- ? t('isLinked', { bookEntry, accountingEntries })
- : t('isNotLinked', { bookEntry });
-
- quasar.notify({ type, message });
- if (!isLinked) arrayData.store.data.isBooked = false;
-}
-
-async function deleteInvoice() {
- await axios.delete(`InvoiceIns/${entityId.value}`);
- quasar.notify({
- type: 'positive',
- message: t('Invoice deleted'),
- });
- push({ path: '/invoice-in' });
-}
-
-async function cloneInvoice() {
- const { data } = await axios.post(`InvoiceIns/${entityId.value}/clone`);
- quasar.notify({
- type: 'positive',
- message: t('Invoice cloned'),
- });
- push({ path: `/invoice-in/${data.id}/summary` });
-}
-
-const canEditProp = (props) =>
- hasAny([{ model: 'InvoiceIn', props, accessType: 'WRITE' }]);
-
-const isAgricultural = () => {
- if (!config.value) return false;
- return (
- invoiceIn.value?.supplier?.sageFarmerWithholdingFk ===
- config?.value[0]?.sageWithholdingFk
- );
-};
-
-function showPdfInvoice() {
- if (isAgricultural()) openReport(`InvoiceIns/${entityId.value}/invoice-in-pdf`);
-}
-
-function sendPdfInvoiceConfirmation() {
- quasar.dialog({
- component: SendEmailDialog,
- componentProps: {
- data: {
- address: invoiceIn.value.supplier.contacts[0].email,
- },
- promise: sendPdfInvoice,
- },
- });
-}
-
-function sendPdfInvoice({ address }) {
- if (!address)
- quasar.notify({
- type: 'negative',
- message: t(`The email can't be empty`),
- });
- else
- return sendEmail(`InvoiceIns/${entityId.value}/invoice-in-email`, {
- recipientId: invoiceIn.value.supplier.id,
- recipient: address,
- });
-}
-
-function triggerMenu(type) {
- currentAction.value = actions[type];
- if (currentAction.value.cb) currentAction.value.cb();
- else openDialog(type);
-}
-
-const createInvoiceInCorrection = async () => {
- const { data: correctingId } = await axios.post(
- 'InvoiceIns/corrective',
- Object.assign(correctionFormData, { id: entityId.value })
- );
- push({ path: `/invoice-in/${correctingId}/summary` });
-};
- (config = data)"
- />
- (cplusRectificationTypes = data)"
- auto-load
- />
- (siiTypeInvoiceOuts = data)"
- auto-load
- />
- (invoiceCorrectionTypes = data)"
- auto-load
- />
{
title="supplierRef"
>
-
-
-
- {{ t('To book') }}
-
-
-
-
-
- {{ t('To unbook') }}
-
-
-
- {{ t('Delete invoice') }}
-
-
- {{ t('Clone invoice') }}
-
-
- {{ t('Show agricultural receipt as PDF') }}
-
-
- {{ t('Send agricultural receipt as PDF') }}...
-
-
- {{ t('Create rectificative invoice') }}...
-
-
- {{ t('components.smartCard.downloadFile') }}
-
+
-
-
-
-
+
+
+
+
{{ entity?.supplier?.nickname }}
@@ -375,7 +145,7 @@ const createInvoiceInCorrection = async () => {
color="primary"
:to="routes.getSupplier(entity.supplierFk)"
>
- {{ t('invoiceIn.list.supplier') }}
+ {{ t('invoicein.list.supplier') }}
{
color="primary"
:to="routes.getTickets(entity.supplierFk)"
>
- {{ t('invoiceOut.card.ticketList') }}
+ {{ t('InvoiceOut.card.ticketList') }}
-
-
-
-
- {{ t('Create rectificative invoice') }}
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-en:
- isNotLinked: The entry {bookEntry} has been deleted with {accountingEntries} entries
- isLinked: The entry {bookEntry} has been linked to Sage. Please contact administration for further information
- assertAction: Are you sure you want to {action} this invoice?
-es:
- book: asentar
- unbook: desasentar
- delete: eliminar
- clone: clonar
- To book: Contabilizar
- To unbook: Descontabilizar
- Delete invoice: Eliminar factura
- Invoice deleted: Factura eliminada
- Clone invoice: Clonar factura
- Invoice cloned: Factura clonada
- Show agricultural receipt as PDF: Ver recibo agrícola como PDF
- Send agricultural receipt as PDF: Enviar recibo agrícola como PDF
- Are you sure you want to send it?: Estás seguro que quieres enviarlo?
- Send PDF invoice: Enviar factura a PDF
- Create rectificative invoice: Crear factura rectificativa
- Rectificative invoice: Factura rectificativa
- Original invoice: Factura origen
- Entry: entrada
- isNotLinked: Se ha eliminado el asiento nº {bookEntry} con {accountingEntries} apuntes
- isLinked: El asiento {bookEntry} fue enlazado a Sage, por favor contacta con administración
- assertAction: Estas seguro de querer {action} esta factura?
-
diff --git a/src/pages/InvoiceIn/Card/InvoiceInDescriptorMenu.vue b/src/pages/InvoiceIn/Card/InvoiceInDescriptorMenu.vue
new file mode 100644
index 000000000..24bf427e9
--- /dev/null
+++ b/src/pages/InvoiceIn/Card/InvoiceInDescriptorMenu.vue
@@ -0,0 +1,321 @@
+
+
+
+ (invoiceCorrectionTypes = data)"
+ auto-load
+ />
+ (cplusRectificationTypes = data)"
+ auto-load
+ />
+ (siiTypeInvoiceIns = data)"
+ auto-load
+ />
+ (config = data)"
+ />
+
+
+
+ {{ t('invoicein.descriptorMenu.toBook') }}
+
+
+
+
+
+ {{ t('invoicein.descriptorMenu.toUnbook') }}
+
+
+
+ {{ t('invoicein.descriptorMenu.deleteInvoice') }}
+
+
+ {{ t('invoicein.descriptorMenu.cloneInvoice') }}
+
+
+ {{
+ t('invoicein.descriptorMenu.showAgriculturalPdf')
+ }}
+
+
+ {{ t('invoicein.descriptorMenu.sendAgriculturalPdf') }}...
+
+
+ {{ t('invoicein.descriptorMenu.createCorrective') }}...
+
+
+ {{ t('components.smartCard.downloadFile') }}
+
+
+
+
+
+
+ {{ t('Create rectificative invoice') }}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {{ console.log('opt: ', opt) }}
+
+ {{ opt.id }} -
+ {{ opt.description }}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+en:
+ isNotLinked: The entry {bookEntry} has been deleted with {accountingEntries} entries
+ isLinked: The entry has been linked to Sage. Please contact administration for further information
+ assertAction: Are you sure you want to {action} this invoice?
+es:
+ isNotLinked: Se ha eliminado el asiento nº {bookEntry} con {accountingEntries} apuntes
+ isLinked: El asiento fue enlazado a Sage, por favor contacta con administración
+ assertAction: Estas seguro de querer {action} esta factura?
+
diff --git a/src/pages/InvoiceIn/Card/InvoiceInDueDay.vue b/src/pages/InvoiceIn/Card/InvoiceInDueDay.vue
index e8f73848b..d2c6d0a2d 100644
--- a/src/pages/InvoiceIn/Card/InvoiceInDueDay.vue
+++ b/src/pages/InvoiceIn/Card/InvoiceInDueDay.vue
@@ -25,6 +25,7 @@ const banks = ref([]);
const invoiceInFormRef = ref();
const invoiceId = +route.params.id;
const filter = { where: { invoiceInFk: invoiceId } };
+const areRows = ref(false);
const columns = computed(() => [
{
@@ -143,8 +144,6 @@ async function insert() {
}"
:disable="!isNotEuro(currency)"
v-model="row.foreignValue"
- clearable
- clear-icon="close"
/>
@@ -230,7 +229,14 @@ async function insert() {
-
+
-
en:
amount: Amount
@@ -261,7 +250,7 @@ const formatOpt = (row, { model, options }, prop) => {
country: Country
es:
Code: Código
- amount: Cantidad
+ amount: Valor mercancía
net: Neto
stems: Tallos
country: País
diff --git a/src/pages/InvoiceIn/Card/InvoiceInSummary.vue b/src/pages/InvoiceIn/Card/InvoiceInSummary.vue
index 08fc11f69..eca0c7af1 100644
--- a/src/pages/InvoiceIn/Card/InvoiceInSummary.vue
+++ b/src/pages/InvoiceIn/Card/InvoiceInSummary.vue
@@ -10,6 +10,7 @@ import VnLv from 'src/components/ui/VnLv.vue';
import SupplierDescriptorProxy from 'src/pages/Supplier/Card/SupplierDescriptorProxy.vue';
import InvoiceIntoBook from '../InvoiceInToBook.vue';
import VnTitle from 'src/components/common/VnTitle.vue';
+import InvoiceInDescriptorMenu from './InvoiceInDescriptorMenu.vue';
const props = defineProps({ id: { type: [Number, String], default: 0 } });
const { t } = useI18n();
@@ -26,14 +27,14 @@ const intrastatTotals = ref({ amount: 0, net: 0, stems: 0 });
const vatColumns = ref([
{
name: 'expense',
- label: 'invoiceIn.summary.expense',
+ label: 'invoicein.summary.expense',
field: (row) => row.expenseFk,
sortable: true,
align: 'left',
},
{
name: 'landed',
- label: 'invoiceIn.summary.taxableBase',
+ label: 'invoicein.summary.taxableBase',
field: (row) => row.taxableBase,
format: (value) => toCurrency(value),
sortable: true,
@@ -41,7 +42,7 @@ const vatColumns = ref([
},
{
name: 'vat',
- label: 'invoiceIn.summary.sageVat',
+ label: 'invoicein.summary.sageVat',
field: (row) => {
if (row.taxTypeSage) return `#${row.taxTypeSage.id} : ${row.taxTypeSage.vat}`;
},
@@ -51,7 +52,7 @@ const vatColumns = ref([
},
{
name: 'transaction',
- label: 'invoiceIn.summary.sageTransaction',
+ label: 'invoicein.summary.sageTransaction',
field: (row) => {
if (row.transactionTypeSage)
return `#${row.transactionTypeSage.id} : ${row.transactionTypeSage?.transaction}`;
@@ -62,7 +63,7 @@ const vatColumns = ref([
},
{
name: 'rate',
- label: 'invoiceIn.summary.rate',
+ label: 'invoicein.summary.rate',
field: (row) => taxRate(row.taxableBase, row.taxTypeSage?.rate),
format: (value) => toCurrency(value),
sortable: true,
@@ -70,7 +71,7 @@ const vatColumns = ref([
},
{
name: 'currency',
- label: 'invoiceIn.summary.currency',
+ label: 'invoicein.summary.currency',
field: (row) => row.foreignValue,
format: (val) => val && toCurrency(val, currency.value),
sortable: true,
@@ -81,21 +82,21 @@ const vatColumns = ref([
const dueDayColumns = ref([
{
name: 'date',
- label: 'invoiceIn.summary.dueDay',
+ label: 'invoicein.summary.dueDay',
field: (row) => toDate(row.dueDated),
sortable: true,
align: 'left',
},
{
name: 'bank',
- label: 'invoiceIn.summary.bank',
+ label: 'invoicein.summary.bank',
field: (row) => row.bank.bank,
sortable: true,
align: 'left',
},
{
name: 'amount',
- label: 'invoiceIn.list.amount',
+ label: 'invoicein.list.amount',
field: (row) => row.amount,
format: (value) => toCurrency(value),
sortable: true,
@@ -103,7 +104,7 @@ const dueDayColumns = ref([
},
{
name: 'landed',
- label: 'invoiceIn.summary.foreignValue',
+ label: 'invoicein.summary.foreignValue',
field: (row) => row.foreignValue,
format: (val) => val && toCurrency(val, currency.value),
sortable: true,
@@ -114,7 +115,7 @@ const dueDayColumns = ref([
const intrastatColumns = ref([
{
name: 'code',
- label: 'invoiceIn.summary.code',
+ label: 'invoicein.summary.code',
field: (row) => {
return `${row.intrastat.id}: ${row.intrastat?.description}`;
},
@@ -123,21 +124,21 @@ const intrastatColumns = ref([
},
{
name: 'amount',
- label: 'invoiceIn.list.amount',
+ label: 'invoicein.list.amount',
field: (row) => toCurrency(row.amount),
sortable: true,
align: 'left',
},
{
name: 'net',
- label: 'invoiceIn.summary.net',
+ label: 'invoicein.summary.net',
field: (row) => row.net,
sortable: true,
align: 'left',
},
{
name: 'stems',
- label: 'invoiceIn.summary.stems',
+ label: 'invoicein.summary.stems',
field: (row) => row.stems,
format: (value) => value,
sortable: true,
@@ -145,7 +146,7 @@ const intrastatColumns = ref([
},
{
name: 'landed',
- label: 'invoiceIn.summary.country',
+ label: 'invoicein.summary.country',
field: (row) => row.country?.code,
format: (value) => value,
sortable: true,
@@ -200,6 +201,9 @@ const getLink = (param) => `#/invoice-in/${entityId.value}/${param}`;
+
+
+
@@ -210,7 +214,7 @@ const getLink = (param) => `#/invoice-in/${entityId.value}/${param}`;
/>
@@ -221,14 +225,18 @@ const getLink = (param) => `#/invoice-in/${entityId.value}/${param}`;
-
+
+
@@ -239,21 +247,22 @@ const getLink = (param) => `#/invoice-in/${entityId.value}/${param}`;
+
@@ -263,18 +272,18 @@ const getLink = (param) => `#/invoice-in/${entityId.value}/${param}`;
/>
-
+
@@ -285,11 +294,11 @@ const getLink = (param) => `#/invoice-in/${entityId.value}/${param}`;
-
+
`#/invoice-in/${entityId.value}/${param}`;
:color="amountsNotMatch ? 'negative' : 'transparent'"
:title="
amountsNotMatch
- ? t('invoiceIn.summary.noMatch')
- : t('invoiceIn.summary.dueTotal')
+ ? t('invoicein.summary.noMatch')
+ : t('invoicein.summary.dueTotal')
"
>
{{ toCurrency(entity.totals.totalDueDay) }}
@@ -309,7 +318,7 @@ const getLink = (param) => `#/invoice-in/${entityId.value}/${param}`;
-
+
`#/invoice-in/${entityId.value}/${param}`;
-
+
@@ -395,7 +404,7 @@ const getLink = (param) => `#/invoice-in/${entityId.value}/${param}`;
arrayData.store.data);
-const invoiceId = +useRoute().params.id;
const currency = computed(() => invoiceIn.value?.currency?.code);
const expenses = ref([]);
const sageTaxTypes = ref([]);
const sageTransactionTypes = ref([]);
const rowsSelected = ref([]);
const invoiceInFormRef = ref();
+const expenseRef = ref();
defineProps({
actionIcon: {
@@ -39,9 +42,8 @@ const columns = computed(() => [
options: expenses.value,
model: 'expenseFk',
optionValue: 'id',
- optionLabel: 'id',
+ optionLabel: (row) => `${row.id}: ${row.name}`,
sortable: true,
- tabIndex: 1,
align: 'left',
},
{
@@ -50,7 +52,6 @@ const columns = computed(() => [
field: (row) => row.taxableBase,
model: 'taxableBase',
sortable: true,
- tabIndex: 2,
align: 'left',
},
{
@@ -60,9 +61,8 @@ const columns = computed(() => [
options: sageTaxTypes.value,
model: 'taxTypeSageFk',
optionValue: 'id',
- optionLabel: 'id',
+ optionLabel: (row) => `${row.id}: ${row.vat}`,
sortable: true,
- tabindex: 3,
align: 'left',
},
{
@@ -72,16 +72,14 @@ const columns = computed(() => [
options: sageTransactionTypes.value,
model: 'transactionTypeSageFk',
optionValue: 'id',
- optionLabel: 'id',
+ optionLabel: (row) => `${row.id}: ${row.transaction}`,
sortable: true,
- tabIndex: 4,
align: 'left',
},
{
name: 'rate',
label: t('Rate'),
sortable: true,
- tabIndex: 5,
field: (row) => taxRate(row, row.taxTypeSageFk),
align: 'left',
},
@@ -89,10 +87,14 @@ const columns = computed(() => [
name: 'foreignvalue',
label: t('Foreign value'),
sortable: true,
- tabIndex: 6,
field: (row) => row.foreignValue,
align: 'left',
},
+ {
+ name: 'total',
+ label: 'Total',
+ align: 'left',
+ },
]);
const filter = {
@@ -106,7 +108,7 @@ const filter = {
'transactionTypeSageFk',
],
where: {
- invoiceInFk: invoiceId,
+ invoiceInFk: route.params.id,
},
};
@@ -120,14 +122,38 @@ function taxRate(invoiceInTax) {
const taxTypeSage = taxRateSelection?.rate ?? 0;
const taxableBase = invoiceInTax?.taxableBase ?? 0;
- return (taxTypeSage / 100) * taxableBase;
+ return ((taxTypeSage / 100) * taxableBase).toFixed(2);
}
-const formatOpt = (row, { model, options }, prop) => {
- const obj = row[model];
- const option = options.find(({ id }) => id == obj);
- return option ? `${obj}:${option[prop]}` : '';
-};
+function autocompleteExpense(evt, row, col) {
+ 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)
+ );
+
+ expenseRef.value.vnSelectDialogRef.vnSelectRef.toggleOption(lookup);
+}
+
+const taxableBaseTotal = computed(() => {
+ return getTotal(invoiceInFormRef.value.formData, 'taxableBase', );
+});
+
+const taxRateTotal = computed(() => {
+ return getTotal(invoiceInFormRef.value.formData, null, {
+ cb: taxRate,
+ });
+});
+
+
+const combinedTotal = computed(() => {
+ return +taxableBaseTotal.value + +taxRateTotal.value;
+});
+
+
+
{
data-key="InvoiceInTaxes"
url="InvoiceInTaxes"
:filter="filter"
- :data-required="{ invoiceInFk: invoiceId }"
+ :data-required="{ invoiceInFk: $route.params.id }"
auto-load
v-model:selected="rowsSelected"
- :go-to="`/invoice-in/${invoiceId}/due-day`"
+ :go-to="`/invoice-in/${$route.params.id}/due-day`"
>
{
@@ -187,13 +215,7 @@ const formatOpt = (row, { model, options }, prop) => {
- {{ currency }}
{
:option-value="col.optionValue"
:option-label="col.optionLabel"
:filter-options="['id', 'vat']"
- :hide-selected="false"
- :fill-input="false"
- :display-value="formatOpt(row, col, 'vat')"
+ data-cy="vat-sageiva"
>
@@ -233,11 +253,6 @@ const formatOpt = (row, { model, options }, prop) => {
:option-value="col.optionValue"
:option-label="col.optionLabel"
:filter-options="['id', 'transaction']"
- :autofocus="col.tabIndex == 1"
- input-debounce="0"
- :hide-selected="false"
- :fill-input="false"
- :display-value="formatOpt(row, col, 'transaction')"
>
@@ -262,6 +277,16 @@ const formatOpt = (row, { model, options }, prop) => {
}"
: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
+ );
+ }
+ "
/>
@@ -270,26 +295,20 @@ const formatOpt = (row, { model, options }, prop) => {
- {{ getTotal(rows, 'taxableBase', { currency: 'default' }) }}
+ {{ toCurrency(taxableBaseTotal) }}
- {{
- getTotal(rows, null, { cb: taxRate, currency: 'default' })
- }}
+ {{ toCurrency(taxRateTotal) }}
+
+
-
- {{
- getTotal(rows, 'foreignValue', {
- currency: invoiceIn.currency.code,
- })
- }}
-
+ {{ toCurrency(combinedTotal) }}
+
@@ -305,7 +324,7 @@ const formatOpt = (row, { model, options }, prop) => {
v-model="props.row['expenseFk']"
:options="expenses"
option-value="id"
- option-label="name"
+ :option-label="(row) => `${row.id}:${row.name}`"
:filter-options="['id', 'name']"
:tooltip="t('Create a new expense')"
>
@@ -339,7 +358,7 @@ const formatOpt = (row, { model, options }, prop) => {
v-model="props.row['taxTypeSageFk']"
:options="sageTaxTypes"
option-value="id"
- option-label="vat"
+ :option-label="(row) => `${row.id}:${row.vat}`"
:filter-options="['id', 'vat']"
>
@@ -362,7 +381,9 @@ const formatOpt = (row, { model, options }, prop) => {
v-model="props.row['transactionTypeSageFk']"
:options="sageTransactionTypes"
option-value="id"
- option-label="transaction"
+ :option-label="
+ (row) => `${row.id}:${row.transaction}`
+ "
:filter-options="['id', 'transaction']"
>
@@ -418,11 +439,6 @@ const formatOpt = (row, { model, options }, prop) => {
.bg {
background-color: var(--vn-light-gray);
}
-
-:deep(.q-table tr td:nth-child(n + 4):nth-child(-n + 5) input) {
- display: none;
-}
-
@media (max-width: $breakpoint-xs) {
.q-dialog {
.q-card {
diff --git a/src/pages/InvoiceIn/InvoiceInCreate.vue b/src/pages/InvoiceIn/InvoiceInCreate.vue
index c809e032b..f180410aa 100644
--- a/src/pages/InvoiceIn/InvoiceInCreate.vue
+++ b/src/pages/InvoiceIn/InvoiceInCreate.vue
@@ -83,7 +83,7 @@ const redirectToInvoiceInBasicData = (__, { id }) => {
@@ -97,10 +97,10 @@ const redirectToInvoiceInBasicData = (__, { id }) => {
map-options
hide-selected
:required="true"
- :rules="validate('invoiceIn.companyFk')"
+ :rules="validate('invoicein.companyFk')"
/>
diff --git a/src/pages/InvoiceIn/InvoiceInFilter.vue b/src/pages/InvoiceIn/InvoiceInFilter.vue
index 130a77960..31a611936 100644
--- a/src/pages/InvoiceIn/InvoiceInFilter.vue
+++ b/src/pages/InvoiceIn/InvoiceInFilter.vue
@@ -1,41 +1,66 @@
- (activities = data)"
- />
-
-
+
+
- {{ t(`params.${tag.label}`) }}:
+ {{ getLocale(tag.label) }}:
{{ formatFn(tag.value) }}
-
+
-
+
-
+
+
+
+
+
+ handleDaysAgo(params, val)"
+ @remove="(val) => handleDaysAgo(params, val)"
+ />
@@ -43,21 +68,32 @@ const activities = ref([]);
+ >
+
+
+
+
+ {{ scope.opt?.name}}
+
+
+ {{ `#${scope.opt?.id } , ${ scope.opt?.nickname}` }}
+
+
+
+
+
+
+
+
+
+
-
-
-
-
-en:
- params:
- search: Id or supplier name
- supplierRef: Supplier ref.
- supplierFk: Supplier
- fi: Supplier fiscal id
- clientFk: Customer
- amount: Amount
- created: Created
- awb: AWB
- dued: Dued
- serialNumber: Serial Number
- serial: Serial
- account: Ledger account
- isBooked: is booked
- correctedFk: Rectified
- issued: Issued
- to: To
- from: From
- awbCode: AWB
- correctingFk: Rectificative
- supplierActivityFk: Supplier activity
-es:
- params:
- search: Id o nombre proveedor
- supplierRef: Ref. proveedor
- supplierFk: Proveedor
- clientFk: Cliente
- fi: CIF proveedor
- serialNumber: Num. serie
- serial: Serie
- awb: AWB
- amount: Importe
- issued: Emitida
- isBooked: Contabilizada
- account: Cuenta contable
- created: Creada
- dued: Vencida
- correctedFk: Rectificada
- correctingFk: Rectificativa
- supplierActivityFk: Actividad proveedor
- from: Desde
- to: Hasta
- From: Desde
- To: Hasta
- Amount: Importe
- Issued: Fecha factura
- Id or supplier: Id o proveedor
-
diff --git a/src/pages/InvoiceIn/InvoiceInList.vue b/src/pages/InvoiceIn/InvoiceInList.vue
index 8d658bee3..5e80ae652 100644
--- a/src/pages/InvoiceIn/InvoiceInList.vue
+++ b/src/pages/InvoiceIn/InvoiceInList.vue
@@ -1,7 +1,7 @@
+ (companies = data)" auto-load />
@@ -116,7 +147,7 @@ const cols = computed(() => [
urlCreate: 'InvoiceIns',
title: t('globals.createInvoiceIn'),
onDataSaved: ({ id }) => tableRef.redirect(id),
- formInitialData: {},
+ formInitialData: { companyFk: user.companyFk, issued: Date.vnNew() },
}"
redirect="invoice-in"
:columns="cols"
@@ -134,24 +165,24 @@ const cols = computed(() => [
{{ scope.opt?.nickname }}
- #{{ scope.opt?.id }}
+ #{{ scope.opt?.id }}, {{ scope.opt?.name }}
[
option-label="code"
:required="true"
/>
-
+
diff --git a/src/pages/InvoiceIn/Serial/InvoiceInSerial.vue b/src/pages/InvoiceIn/Serial/InvoiceInSerial.vue
index 4eb9fa69d..a8fb3b0c8 100644
--- a/src/pages/InvoiceIn/Serial/InvoiceInSerial.vue
+++ b/src/pages/InvoiceIn/Serial/InvoiceInSerial.vue
@@ -58,6 +58,14 @@ onBeforeMount(async () => {
:right-search="false"
:user-params="{ daysAgo }"
:disable-option="{ card: true }"
+ :row-click="
+ (row) => {
+ $router.push({
+ name: 'InvoiceInList',
+ query: { table: JSON.stringify({ serial: row.serial }) },
+ });
+ }
+ "
auto-load
/>
diff --git a/src/pages/InvoiceIn/Serial/InvoiceInSerialFilter.vue b/src/pages/InvoiceIn/Serial/InvoiceInSerialFilter.vue
index 4f8c9d70b..19ed73e50 100644
--- a/src/pages/InvoiceIn/Serial/InvoiceInSerialFilter.vue
+++ b/src/pages/InvoiceIn/Serial/InvoiceInSerialFilter.vue
@@ -8,7 +8,11 @@ defineProps({ dataKey: { type: String, required: true } });
const { t } = useI18n();
-
+
{{ t(`params.${tag.label}`) }}:
diff --git a/src/pages/InvoiceIn/locale/en.yml b/src/pages/InvoiceIn/locale/en.yml
index b39511f29..94db50066 100644
--- a/src/pages/InvoiceIn/locale/en.yml
+++ b/src/pages/InvoiceIn/locale/en.yml
@@ -1,4 +1,4 @@
-invoiceIn:
+invoicein:
serial: Serial
isBooked: Is booked
list:
@@ -7,8 +7,31 @@ invoiceIn:
supplierRef: Supplier ref.
file: File
issued: Issued
+ dueDated: Due dated
awb: AWB
amount: Amount
+ descriptor:
+ ticketList: Ticket list
+ descriptorMenu:
+ book: Book
+ unbook: Unbook
+ delete: Delete
+ clone: Clone
+ toBook: To book
+ toUnbook: To unbook
+ deleteInvoice: Delete invoice
+ invoiceDeleted: invoice deleted
+ cloneInvoice: Clone invoice
+ invoiceCloned: Invoice cloned
+ showAgriculturalPdf: Show agricultural receipt as PDF
+ sendAgriculturalPdf: Send agricultural receipt as PDF
+ checkSendInvoice: Are you sure you want to send it?
+ sendPdfInvoice: Send PDF invoice
+ createCorrective: Create rectificative invoice
+ correctiveInvoice: Rectificative invoice
+ originalInvoice: Original invoice
+ entry: Entry
+ emailEmpty: The email can't be empty
card:
client: Client
company: Company
@@ -39,3 +62,10 @@ invoiceIn:
net: Net
stems: Stems
country: Country
+ params:
+ search: Id or supplier name
+ correctedFk: Corrected
+ isBooked: Is booked
+ account: Ledger account
+ correctingFk: Rectificative
+
\ No newline at end of file
diff --git a/src/pages/InvoiceIn/locale/es.yml b/src/pages/InvoiceIn/locale/es.yml
index 5f483dd08..bcb9c0551 100644
--- a/src/pages/InvoiceIn/locale/es.yml
+++ b/src/pages/InvoiceIn/locale/es.yml
@@ -1,15 +1,37 @@
-invoiceIn:
+invoicein:
serial: Serie
isBooked: Contabilizada
list:
ref: Referencia
supplier: Proveedor
supplierRef: Ref. proveedor
- shortIssued: F. emisión
+ issued: F. emisión
+ dueDated: F. vencimiento
file: Fichero
- issued: Fecha emisión
awb: AWB
amount: Importe
+ descriptor:
+ ticketList: Listado de tickets
+ descriptorMenu:
+ book: Asentar
+ unbook: Desasentar
+ delete: Eliminar
+ clone: Clonar
+ toBook: Contabilizar
+ toUnbook: Descontabilizar
+ deleteInvoice: Eliminar factura
+ invoiceDeleted: Factura eliminada
+ cloneInvoice: Clonar factura
+ invoiceCloned: Factura clonada
+ showAgriculturalPdf: Ver recibo agrícola como PDF
+ sendAgriculturalPdf: Enviar recibo agrícola como PDF
+ checkSendInvoice: ¿Estás seguro que quieres enviarlo?
+ sendPdfInvoice: Enviar factura a PDF
+ createCorrective: Crear factura rectificativa
+ correctiveInvoice: Factura rectificativa
+ originalInvoice: Factura origen
+ entry: Entrada
+ emailEmpty: El email no puede estar vacío
card:
client: Cliente
company: Empresa
@@ -38,3 +60,9 @@ invoiceIn:
net: Neto
stems: Tallos
country: País
+ params:
+ search: Id o nombre proveedor
+ correctedFk: Rectificada
+ account: Cuenta contable
+ correctingFk: Rectificativa
+
diff --git a/src/pages/InvoiceOut/Card/InvoiceOutSummary.vue b/src/pages/InvoiceOut/Card/InvoiceOutSummary.vue
index 81b3e7c41..3ceb447dd 100644
--- a/src/pages/InvoiceOut/Card/InvoiceOutSummary.vue
+++ b/src/pages/InvoiceOut/Card/InvoiceOutSummary.vue
@@ -10,6 +10,7 @@ import { getUrl } from 'src/composables/getUrl';
import TicketDescriptorProxy from 'src/pages/Ticket/Card/TicketDescriptorProxy.vue';
import CustomerDescriptorProxy from 'src/pages/Customer/Card/CustomerDescriptorProxy.vue';
import VnTitle from 'src/components/common/VnTitle.vue';
+import InvoiceOutDescriptorMenu from './InvoiceOutDescriptorMenu.vue';
onMounted(async () => {
fetch();
@@ -113,6 +114,9 @@ const ticketsColumns = ref([
{{ invoiceOut.ref }} - {{ invoiceOut.client?.socialName }}
+
+
+
diff --git a/src/pages/InvoiceOut/InvoiceOutFilter.vue b/src/pages/InvoiceOut/InvoiceOutFilter.vue
index dc1d833a2..cdc9f037a 100644
--- a/src/pages/InvoiceOut/InvoiceOutFilter.vue
+++ b/src/pages/InvoiceOut/InvoiceOutFilter.vue
@@ -47,6 +47,7 @@ const states = ref();
:label="t('Amount')"
v-model="params.amount"
is-outlined
+ data-cy="InvoiceOutFilterAmountBtn"
/>
diff --git a/src/pages/InvoiceOut/InvoiceOutGlobalForm.vue b/src/pages/InvoiceOut/InvoiceOutGlobalForm.vue
index 3fd3104bf..392256473 100644
--- a/src/pages/InvoiceOut/InvoiceOutGlobalForm.vue
+++ b/src/pages/InvoiceOut/InvoiceOutGlobalForm.vue
@@ -101,6 +101,7 @@ onMounted(async () => {
dense
outlined
rounded
+ data-cy="InvoiceOutGlobalClientSelect"
>
@@ -115,6 +116,9 @@ onMounted(async () => {
{
dense
outlined
rounded
+ data-cy="InvoiceOutGlobalSerialSelect"
/>
{
v-model="formData.maxShipped"
:label="t('maxShipped')"
is-outlined
+ data-cy="InvoiceOutGlobalMaxShippedDate"
/>
{
dense
outlined
rounded
+ data-cy="InvoiceOutGlobalCompanySelect"
/>
{
dense
outlined
rounded
+ data-cy="InvoiceOutGlobalPrinterSelect"
/>
-import { onMounted, onUnmounted, ref, computed, watchEffect } from 'vue';
+import { ref, computed, watchEffect } from 'vue';
import { useI18n } from 'vue-i18n';
import VnSelect from 'src/components/common/VnSelect.vue';
import VnInputDate from 'src/components/common/VnInputDate.vue';
@@ -10,7 +10,6 @@ import { usePrintService } from 'src/composables/usePrintService';
import VnTable from 'src/components/VnTable/VnTable.vue';
import InvoiceOutSummary from './Card/InvoiceOutSummary.vue';
import { toCurrency, toDate } from 'src/filters/index';
-import { useStateStore } from 'stores/useStateStore';
import { QBtn } from 'quasar';
import axios from 'axios';
import RightMenu from 'src/components/common/RightMenu.vue';
@@ -21,7 +20,6 @@ import VnInput from 'src/components/common/VnInput.vue';
import CustomerDescriptorProxy from '../Customer/Card/CustomerDescriptorProxy.vue';
const { t } = useI18n();
-const stateStore = useStateStore();
const { viewSummary } = useSummaryDialog();
const tableRef = ref();
const invoiceOutSerialsOptions = ref([]);
@@ -128,6 +126,13 @@ const columns = computed(() => [
columnField: { component: null },
format: (row) => toDate(row.dued),
},
+ {
+ align: 'left',
+ name: 'customsAgentFk',
+ label: t('invoiceOutList.tableVisibleColumns.customsAgent'),
+ cardVisible: true,
+ format: (row, dashIfEmpty) => dashIfEmpty(row.customsAgentName),
+ },
{
align: 'right',
name: 'tableActions',
@@ -147,8 +152,6 @@ const columns = computed(() => [
],
},
]);
-onMounted(() => (stateStore.rightDrawer = true));
-onUnmounted(() => (stateStore.rightDrawer = false));
function openPdf(id) {
openReport(`${MODEL}/${id}/download`);
@@ -194,6 +197,7 @@ watchEffect(selectedRows);
icon-right="cloud_download"
@click="downloadPdf()"
:disable="!hasSelectedCards"
+ data-cy="InvoiceOutDownloadPdfBtn"
>
{{ t('downloadPdf') }}
@@ -214,7 +218,6 @@ watchEffect(selectedRows);
order="id DESC"
:columns="columns"
redirect="invoice-out"
- auto-load
:table="{
'row-key': 'id',
selection: 'multiple',
@@ -243,6 +246,7 @@ watchEffect(selectedRows);
v-model="data.ticketFk"
:label="t('globals.ticket')"
style="flex: 1"
+ data-cy="InvoiceOutCreateTicketinput"
/>
diff --git a/src/pages/InvoiceOut/locale/en.yml b/src/pages/InvoiceOut/locale/en.yml
index 8cefe8bdc..f31e5a07c 100644
--- a/src/pages/InvoiceOut/locale/en.yml
+++ b/src/pages/InvoiceOut/locale/en.yml
@@ -13,6 +13,7 @@ invoiceOutList:
invoiceOutSerial: Serial
ticket: Ticket
taxArea: Tax area
+ customsAgent: Custom Agent
DownloadPdf: Download PDF
InvoiceOutSummary: Summary
negativeBases:
@@ -24,3 +25,15 @@ negativeBases:
hasToInvoice: Has to invoice
verifiedData: Verified data
commercial: Commercial
+invoiceout:
+ params:
+ company: Company
+ country: Country
+ clientId: Client ID
+ clientSocialName: Client
+ taxableBase: Base
+ ticketFk: Ticket
+ isActive: Active
+ hasToInvoice: Has to invoice
+ hasVerifiedData: Verified data
+ workerName: Worker
\ No newline at end of file
diff --git a/src/pages/InvoiceOut/locale/es.yml b/src/pages/InvoiceOut/locale/es.yml
index 106168a5d..deca8bdea 100644
--- a/src/pages/InvoiceOut/locale/es.yml
+++ b/src/pages/InvoiceOut/locale/es.yml
@@ -15,6 +15,7 @@ invoiceOutList:
invoiceOutSerial: Serial
ticket: Ticket
taxArea: Area
+ customsAgent: Agente de aduanas
DownloadPdf: Descargar PDF
InvoiceOutSummary: Resumen
negativeBases:
@@ -27,3 +28,15 @@ negativeBases:
hasToInvoice: Debe facturar
verifiedData: Datos verificados
commercial: Comercial
+invoiceout:
+ params:
+ company: Empresa
+ country: País
+ clientId: ID del cliente
+ clientSocialName: Cliente
+ taxableBase: Base
+ ticketFk: Ticket
+ isActive: Activo
+ hasToInvoice: Debe facturar
+ hasVerifiedData: Datos verificados
+ workerName: Comercial
\ No newline at end of file
diff --git a/src/pages/Item/Card/ItemBasicData.vue b/src/pages/Item/Card/ItemBasicData.vue
index a1788617f..4c96401f3 100644
--- a/src/pages/Item/Card/ItemBasicData.vue
+++ b/src/pages/Item/Card/ItemBasicData.vue
@@ -203,6 +203,12 @@ const onIntrastatCreated = (response, formData) => {
v-model="data.hasKgPrice"
:label="t('item.basicData.hasKgPrice')"
/>
+
+
+
{
:fields="['id', 'name']"
sort-by="name ASC"
hide-selected
+ data-cy="AddGenusSelectDialog"
>
{
:fields="['id', 'name']"
sort-by="name ASC"
hide-selected
+ data-cy="AddSpeciesSelectDialog"
>
{
return $props.id || route.params.id;
});
-const regularizeStockFormDialog = ref(null);
const mounted = ref();
const arrayDataStock = useArrayData('descriptorStock', {
@@ -61,14 +58,14 @@ onMounted(async () => {
const data = ref(useCardDescription());
const setData = async (entity) => {
if (!entity) return;
- data.value = useCardDescription(entity?.name, entity?.id);
+ data.value = useCardDescription(entity.name, entity.id);
await updateStock();
};
const getItemConfigs = async () => {
const { data } = await axios.get('ItemConfigs/findOne');
if (!data) return;
- return (warehouseConfig.value = data.warehouseFk);
+ warehouseConfig.value = data.warehouseFk;
};
const updateStock = async () => {
if (!mounted.value) return;
@@ -89,10 +86,6 @@ const updateStock = async () => {
if (storeData?.itemFk == entityId.value) return;
await stock.fetch({});
};
-
-const openRegularizeStockForm = () => {
- regularizeStockFormDialog.value.show();
-};
@@ -105,24 +98,12 @@ const openRegularizeStockForm = () => {
:url="`Items/${entityId}/getCard`"
@on-fetch="setData"
>
-
-
-
- {{ t('Regularize stock') }}
-
-
-
-
-
-
-
- {{ t('globals.clone') }}
-
-
+
+
{
es:
- Regularize stock: Regularizar stock
Inactive article: Artículo inactivo
diff --git a/src/pages/Item/Card/ItemDescriptorImage.vue b/src/pages/Item/Card/ItemDescriptorImage.vue
index 05185c589..a887964e9 100644
--- a/src/pages/Item/Card/ItemDescriptorImage.vue
+++ b/src/pages/Item/Card/ItemDescriptorImage.vue
@@ -131,7 +131,6 @@ const handlePhotoUpdated = (evt = false) => {
es:
- Regularize stock: Regularizar stock
All it's properties will be copied: Todas sus propiedades serán copiadas
Do you want to clone this item?: ¿Desea clonar este artículo?
warehouseText: Calculado sobre el almacén de { warehouseName }
diff --git a/src/pages/Item/Card/ItemDescriptorMenu.vue b/src/pages/Item/Card/ItemDescriptorMenu.vue
new file mode 100644
index 000000000..3e9c6f2d4
--- /dev/null
+++ b/src/pages/Item/Card/ItemDescriptorMenu.vue
@@ -0,0 +1,44 @@
+
+
+
+
+ {{ $t('item.regularizeStock') }}
+
+
+
+
+
+
+
+ {{ $t('globals.clone') }}
+
+
+
+
+
diff --git a/src/pages/Item/Card/ItemDiary.vue b/src/pages/Item/Card/ItemDiary.vue
index b94ff9255..c2f2c19a0 100644
--- a/src/pages/Item/Card/ItemDiary.vue
+++ b/src/pages/Item/Card/ItemDiary.vue
@@ -1,7 +1,7 @@
- (itemBalances = data)"
- />
fetchItemBalances() && updateWarehouse(value)
+ (val) => fetchItemBalances() && updateWarehouse(val)
"
class="q-mr-lg"
+ :is-clearable="false"
/>
{
+ if (!val) where.date = null;
+ else where.date = inventoriedDate;
+ await fetchItemBalances();
+ }
+ "
class="q-mr-lg"
/>
-
+
{
switch (param) {
@@ -45,22 +36,7 @@ const exprBuilder = (param, value) => {
}
};
-const where = {
- itemFk: route.params.id,
-};
-
-if (hideInventory.value) {
- where.supplierFk = { neq: inventorySupplierFk };
-}
-
-const arrayData = useArrayData('ItemLastEntries', {
- url: 'Items/lastEntriesFilter',
- order: ['landed DESC', 'buyFk DESC'],
- exprBuilder: exprBuilder,
- userFilter: {
- where: where,
- },
-});
+let arrayData = useArrayData('ItemLastEntries');
const itemLastEntries = ref([]);
const columns = computed(() => [
@@ -110,7 +86,7 @@ const columns = computed(() => [
format: (val) => dashIfEmpty(val),
},
{
- label: t('shelvings.packing'),
+ label: 'Packing',
name: 'packing',
field: 'packing',
align: 'center',
@@ -174,38 +150,64 @@ const getDate = (date, type) => {
};
const updateFilter = async () => {
- let filter;
- if (!from.value && to.value) filter = { lte: to.value };
- else if (from.value && !to.value) filter = { gte: from.value };
- else if (from.value && to.value) filter = { between: [from.value, to.value] };
-
- const userFilter = arrayData.store.userFilter.where;
-
- userFilter.landed = filter;
- if (hideInventory.value) userFilter.supplierFk = { neq: inventorySupplierFk };
- else delete userFilter.supplierFk;
+ let landed;
+ if (!from.value && to.value) landed = { lte: to.value };
+ else if (from.value && !to.value) landed = { gte: from.value };
+ else if (from.value && to.value) landed = { between: [from.value, to.value] };
+ arrayData.store.filter.where.landed = landed;
await fetchItemLastEntries();
};
onMounted(async () => {
- await getInventorySupplier();
+ const landed = arrayData.store.filter.where?.landed;
+ arrayData = useArrayData('ItemLastEntries', {
+ url: 'Items/lastEntriesFilter',
+ order: ['landed DESC', 'buyFk DESC'],
+ exprBuilder: exprBuilder,
+ filter: {
+ where: {
+ itemFk: route.params.id,
+ landed,
+ },
+ },
+ });
- const _from = Date.vnNew();
- _from.setDate(_from.getDate() - 75);
- from.value = getDate(_from, 'from');
- const _to = Date.vnNew();
- _to.setDate(_to.getDate() + 10);
- to.value = getDate(_to, 'to');
+ if (landed) {
+ const key = Object.keys(landed)[0];
+ switch (key) {
+ case 'gte':
+ from.value = landed.gte;
+ break;
+ case 'lte':
+ to.value = landed.lte;
+ break;
+ case 'between':
+ from.value = landed.between[0];
+ to.value = landed.between[1];
+ break;
+ }
+ } else {
+ const _from = Date.vnNew();
+ _from.setDate(_from.getDate() - 75);
+ from.value = getDate(_from, 'from');
+ const _to = Date.vnNew();
+ _to.setDate(_to.getDate() + 10);
+ to.value = getDate(_to, 'to');
+ }
updateFilter();
- watch([from, to, hideInventory], ([nFrom, nTo], [oFrom, oTo]) => {
+ watch([from, to], ([nFrom, nTo], [oFrom, oTo]) => {
if (nFrom && nFrom != oFrom) nFrom = getDate(new Date(nFrom), 'from');
if (nTo && nTo != oTo) nTo = getDate(new Date(nTo), 'to');
updateFilter();
});
});
+
+function getBadgeClass(groupingMode, expectedGrouping) {
+ return groupingMode === expectedGrouping ? 'accent-badge' : 'simple-badge';
+}
@@ -224,13 +226,6 @@ onMounted(async () => {
class="q-mr-lg"
data-cy="to"
/>
-
@@ -249,6 +244,11 @@ onMounted(async () => {
/>
+
+
+ {{ row.warehouse }}
+
+
@@ -262,32 +262,37 @@ onMounted(async () => {
+
+
+ {{ value }}
+ {{ t('lastEntries.grouping') }}/Packing
+
+
+
+
+ {{ row.printedStickers }}
+
+
{{ dashIfEmpty(row.packing) }}
- {{ t('lastEntries.packing') }}
+ Packing
-
-
- {{ value }}
-
- {{ t('lastEntries.grouping') }}/{{ t('lastEntries.packing') }}
-
-
{{ dashIfEmpty(row.grouping) }}
{{ t('lastEntries.grouping') }}
@@ -315,13 +320,16 @@ onMounted(async () => {
-
-
+
- {{ row.supplier }}
+ >
+
+ {{ row.supplier }}
+
@@ -349,4 +357,13 @@ onMounted(async () => {
background-color: red;
}
}
+.accent-badge {
+ background-color: var(--vn-label-color);
+ color: var(--vn-text-color-contrast);
+}
+.simple-badge {
+ background-color: transparent;
+ color: var(--vn-text-color);
+ font-size: 14px;
+}
diff --git a/src/pages/Item/Card/ItemSummary.vue b/src/pages/Item/Card/ItemSummary.vue
index e1b97d7c9..bc828bbf6 100644
--- a/src/pages/Item/Card/ItemSummary.vue
+++ b/src/pages/Item/Card/ItemSummary.vue
@@ -8,6 +8,7 @@ import VnLv from 'src/components/ui/VnLv.vue';
import ItemDescriptorImage from 'src/pages/Item/Card/ItemDescriptorImage.vue';
import VnUserLink from 'src/components/ui/VnUserLink.vue';
import VnTitle from 'src/components/common/VnTitle.vue';
+import ItemDescriptorMenu from './ItemDescriptorMenu.vue';
const $props = defineProps({
id: {
@@ -43,10 +44,13 @@ const getUrl = (id, param) => `#/Item/${id}/${param}`;
{{ item.id }} - {{ item.name }}
+
+
+
`#/Item/${id}/${param}`;
{
@on-fetch="onItemTagsFetched"
>
-
+
{
rowsSelected.value.length > 0);
const rowsSelected = ref([]);
const itemFixedPriceFilterRef = ref();
@@ -53,7 +54,6 @@ const columns = computed(() => [
name: 'itemFk',
...defaultColumnAttrs,
isId: true,
- cardVisible: true,
columnField: {
component: 'input',
type: 'number',
@@ -65,14 +65,12 @@ const columns = computed(() => [
name: 'name',
...defaultColumnAttrs,
create: true,
- cardVisible: true,
},
{
label: t('item.fixedPrice.groupingPrice'),
field: 'rate2',
name: 'rate2',
...defaultColumnAttrs,
- cardVisible: true,
component: 'input',
type: 'number',
},
@@ -81,7 +79,6 @@ const columns = computed(() => [
field: 'rate3',
name: 'rate3',
...defaultColumnAttrs,
- cardVisible: true,
component: 'input',
type: 'number',
},
@@ -91,7 +88,6 @@ const columns = computed(() => [
field: 'minPrice',
name: 'minPrice',
...defaultColumnAttrs,
- cardVisible: true,
component: 'input',
type: 'number',
},
@@ -100,7 +96,6 @@ const columns = computed(() => [
field: 'started',
name: 'started',
format: ({ started }) => toDate(started),
- cardVisible: true,
...defaultColumnAttrs,
columnField: {
component: 'date',
@@ -116,7 +111,6 @@ const columns = computed(() => [
field: 'ended',
name: 'ended',
...defaultColumnAttrs,
- cardVisible: true,
columnField: {
component: 'date',
class: 'shrink',
@@ -251,11 +245,14 @@ const upsertPrice = async (props, resetMinPrice = false) => {
}
if (!changes.updates && !changes.creates) return;
const data = await upsertFixedPrice(row);
- tableRef.value.CrudModelRef.formData[props.rowIndex] = data;
+ Object.assign(tableRef.value.CrudModelRef.formData[props.rowIndex], data);
+ notify(t('globals.dataSaved'), 'positive');
+ tableRef.value.reload();
};
async function upsertFixedPrice(row) {
const { data } = await axios.patch('FixedPrices/upsertFixedPrice', row);
+ data.hasMinPrice = data.hasMinPrice ? 1 : 0;
return data;
}
@@ -361,7 +358,7 @@ function handleOnDataSave({ CrudModelRef }) {
@on-fetch="(data) => (warehousesOptions = data)"
auto-load
url="Warehouses"
- :filter="{ fields: ['id', 'name'], order: 'name ASC', limit: 30 }"
+ :filter="{ fields: ['id', 'name'], order: 'name ASC' }"
/>
@@ -372,9 +369,9 @@ function handleOnDataSave({ CrudModelRef }) {
-
+
confirmRemove(row, true)"
:title="t('globals.remove')"
- v-if="rowsSelected.length"
/>
-
-
- data.forEach((item) => {
- item.hasMinPrice = `${item.hasMinPrice !== 0}`;
- })
- "
- :default-remove="false"
- :default-reset="false"
- :default-save="false"
- data-key="ItemFixedPrices"
- url="FixedPrices/filter"
- :order="['itemFk DESC', 'name DESC']"
- save-url="FixedPrices/crud"
- ref="tableRef"
- dense
- :filter="{
- where: {
- warehouseFk: user.warehouseFk,
- },
- }"
- :columns="columns"
- default-mode="table"
- auto-load
- :is-editable="true"
- :right-search="false"
- :table="{
- 'row-key': 'id',
- selection: 'multiple',
- }"
- :crud-model="{
- disableInfiniteScroll: true,
- }"
- v-model:selected="rowsSelected"
- :create-as-dialog="false"
- :create="{
- onDataSaved: handleOnDataSave,
- }"
- :use-model="true"
- :disable-option="{ card: true }"
- >
-
-
-
-
- {{ scope }}
-
-
+
+
+
+
+
+ {{ scope }}
+
+
-
-
+
+
+
+
+ #{{ scope.opt?.id }}
+ {{ scope.opt?.name }}
+
+
+
+
+
+
+
+ {{ row.name }}
+
+ {{ row.subName }}
+
+
+
+
+
+
-
-
-
- #{{ scope.opt?.id }}
- {{ scope.opt?.name }}
-
-
-
-
-
-
-
- {{ row.name }}
-
- {{ row.subName }}
-
-
-
-
-
-
- €
-
-
-
-
-
-
- €
-
-
-
-
-
-
-
-
- €
-
-
-
-
-
-
-
-
-
-
-
-
- €
+
+
+
+
+
+
+ €
+
+
+
+
+
+
+
-
-
-
- removePrice(row.id, rowIndex)
- )
- "
- >
-
- {{ t('globals.delete') }}
-
-
-
-
-
-
-
+ €
+
+
+
+
+
+
-
-
+
+
+
+
+
+
+
+
+
+
+ removePrice(row.id, rowIndex)
+ )
+ "
+ >
+
+ {{ t('globals.delete') }}
+
+
+
+
+
+
+
+
es:
New item: Nuevo artículo
+ Create Item: Crear artículo
+ You can search by id: Puedes buscar por id
Preview: Vista previa
- Regularize stock: Regularizar stock
diff --git a/src/pages/Item/ItemListFilter.vue b/src/pages/Item/ItemListFilter.vue
index 484265b49..a8349c935 100644
--- a/src/pages/Item/ItemListFilter.vue
+++ b/src/pages/Item/ItemListFilter.vue
@@ -199,17 +199,7 @@ onMounted(async () => {
dense
outlined
rounded
- >
-
-
-
- {{
- t(`params.${scope.opt?.name}`)
- }}
-
-
-
-
+ />
@@ -265,6 +255,7 @@ onMounted(async () => {
option-value="id"
option-label="name"
:fields="['id', 'name', 'nickname']"
+ :filter-options="['id', 'name', 'nickname']"
sort-by="name ASC"
hide-selected
dense
@@ -274,9 +265,12 @@ onMounted(async () => {
- {{
- scope.opt?.name + ': ' + scope.opt?.nickname
- }}
+
+ {{ scope.opt?.name}}
+
+
+ {{ `#${scope.opt?.id } , ${ scope.opt?.nickname}` }}
+
@@ -375,6 +369,7 @@ onMounted(async () => {
:model-value="fieldFilter.selectedField"
:options="moreFields"
option-label="label"
+ option-value="label"
dense
outlined
rounded
diff --git a/src/pages/Item/ItemRequest.vue b/src/pages/Item/ItemRequest.vue
index 4447d1bcf..d96fbca2f 100644
--- a/src/pages/Item/ItemRequest.vue
+++ b/src/pages/Item/ItemRequest.vue
@@ -172,24 +172,22 @@ const changeQuantity = async (request) => {
};
await axios.patch(`Sales/${request.saleFk}`, params);
- notify(t('globals.dataSaved'), 'positive');
- confirmRequest(request);
- } else confirmRequest(request);
+ }
+ await confirmRequest(request);
+ notify(t('globals.dataSaved'), 'positive');
};
const confirmRequest = async (request) => {
- if (request.itemFk && request.saleQuantity) {
- const params = {
- itemFk: request.itemFk,
- quantity: request.saleQuantity,
- attenderFk: request.attenderFk,
- };
+ if (!request.itemFk || !request.saleQuantity) return;
+ const params = {
+ itemFk: request.itemFk,
+ quantity: request.saleQuantity,
+ attenderFk: request.attenderFk,
+ };
- const { data } = await axios.post(`TicketRequests/${request.id}/confirm`, params);
- request.itemDescription = data.concept;
- request.isOk = true;
- notify(t('globals.dataSaved'), 'positive');
- }
+ const { data } = await axios.post(`TicketRequests/${request.id}/confirm`, params);
+ request.itemDescription = data.concept;
+ request.isOk = true;
};
const getState = (isOk) => {
diff --git a/src/pages/Item/ItemRequestFilter.vue b/src/pages/Item/ItemRequestFilter.vue
index 4e8ae0d42..af48f7f5c 100644
--- a/src/pages/Item/ItemRequestFilter.vue
+++ b/src/pages/Item/ItemRequestFilter.vue
@@ -149,7 +149,6 @@ onMounted(async () => {
:label="t('params.requesterFk')"
v-model="params.requesterFk"
@update:model-value="searchFn()"
- :fields="['id', 'name']"
:params="{ departmentCodes: ['VT'] }"
hide-selected
dense
@@ -201,6 +200,7 @@ en:
to: To
mine: For me
state: State
+ daysOnward: Days onward
myTeam: My team
dateFiltersTooltip: Cannot choose a range of dates and days onward at the same time
denied: Denied
@@ -218,6 +218,7 @@ es:
to: Hasta
mine: Para mi
state: Estado
+ daysOnward: Días en adelante
myTeam: Mi equipo
dateFiltersTooltip: No se puede seleccionar un rango de fechas y días en adelante a la vez
denied: Denegada
diff --git a/src/pages/Item/ItemType/Card/ItemTypeDescriptor.vue b/src/pages/Item/ItemType/Card/ItemTypeDescriptor.vue
index cd12fc238..936e95d2f 100644
--- a/src/pages/Item/ItemType/Card/ItemTypeDescriptor.vue
+++ b/src/pages/Item/ItemType/Card/ItemTypeDescriptor.vue
@@ -6,13 +6,11 @@ import { useI18n } from 'vue-i18n';
import CardDescriptor from 'components/ui/CardDescriptor.vue';
import VnLv from 'src/components/ui/VnLv.vue';
import WorkerDescriptorProxy from 'src/pages/Worker/Card/WorkerDescriptorProxy.vue';
-
import useCardDescription from 'src/composables/useCardDescription';
const $props = defineProps({
id: {
type: Number,
- required: false,
default: null,
},
summary: {
@@ -24,6 +22,10 @@ const $props = defineProps({
const route = useRoute();
const { t } = useI18n();
+const entityId = computed(() => {
+ return $props.id || route.params.id;
+});
+
const itemTypeFilter = {
include: [
{ relation: 'worker' },
@@ -33,10 +35,6 @@ const itemTypeFilter = {
],
};
-const entityId = computed(() => {
- return $props.id || route.params.id;
-});
-
const data = ref(useCardDescription());
const setData = (entity) => (data.value = useCardDescription(entity.code, entity.id));
@@ -48,8 +46,8 @@ const setData = (entity) => (data.value = useCardDescription(entity.code, entity
:filter="itemTypeFilter"
:title="data.title"
:subtitle="data.subtitle"
+ data-key="itemTypeDescriptor"
@on-fetch="setData"
- data-key="entry"
>
diff --git a/src/pages/Item/ItemType/Card/ItemTypeDescriptorProxy.vue b/src/pages/Item/ItemType/Card/ItemTypeDescriptorProxy.vue
new file mode 100644
index 000000000..7cde9aef8
--- /dev/null
+++ b/src/pages/Item/ItemType/Card/ItemTypeDescriptorProxy.vue
@@ -0,0 +1,17 @@
+
+
+
+
+
+
+
diff --git a/src/pages/Item/locale/en.yml b/src/pages/Item/locale/en.yml
index bd91ef745..52722198b 100644
--- a/src/pages/Item/locale/en.yml
+++ b/src/pages/Item/locale/en.yml
@@ -58,6 +58,7 @@ lastEntries:
pvp: PVP
label: Label
grouping: Grouping
+ packing: Packing
quantity: Quantity
cost: Cost
kg: Kg.
@@ -107,6 +108,7 @@ item:
scopeDays: Scope days
searchbar:
label: Search item
+ info: You can search by id
descriptor:
item: Item
buyer: Buyer
@@ -135,10 +137,11 @@ item:
origin: Orig.
userName: Buyer
weight: Weight
- weightByPiece: Weight/Piece
+ weightByPiece: Weight/stem
stemMultiplier: Multiplier
producer: Producer
landed: Landed
+ newItem: New item
basicData:
type: Type
reference: Reference
@@ -158,6 +161,7 @@ item:
isFragileTooltip: Is shown at website, app that this item cannot travel (wreath, palms, ...)
isPhotoRequested: Do photo
isPhotoRequestedTooltip: This item does need a photo
+ isCustomInspectionRequired: Needs physical inspection (PIF)
description: Description
fixedPrice:
itemFk: Item ID
@@ -216,3 +220,4 @@ item:
minSalesQuantity: 'Cantidad mínima de venta'
genus: 'Genus'
specie: 'Specie'
+ regularizeStock: Regularize stock
diff --git a/src/pages/Item/locale/es.yml b/src/pages/Item/locale/es.yml
index b821d276a..29af8dc5c 100644
--- a/src/pages/Item/locale/es.yml
+++ b/src/pages/Item/locale/es.yml
@@ -58,6 +58,7 @@ lastEntries:
pvp: PVP
label: Eti.
grouping: Grouping
+ packing: Packing
quantity: Cantidad
cost: Coste
kg: Kg.
@@ -109,6 +110,7 @@ item:
scopeDays: Días en adelante
searchbar:
label: Buscar artículo
+ info: Puedes buscar por id
descriptor:
item: Artículo
buyer: Comprador
@@ -136,11 +138,12 @@ item:
size: Medida
origin: Orig.
weight: Peso
- weightByPiece: Peso (gramos)/tallo
+ weightByPiece: Peso/tallo
userName: Comprador
stemMultiplier: Multiplicador
producer: Productor
landed: F. entrega
+ newItem: Nuevo artículo
basicData:
type: Tipo
reference: Referencia
@@ -160,6 +163,7 @@ item:
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
+ isCustomInspectionRequired: Necesita inspección física (PIF)
description: Descripción
fixedPrice:
itemFk: ID Artículo
@@ -207,6 +211,7 @@ item:
minSalesQuantity: 'Cantidad mínima de venta'
genus: 'Genus'
specie: 'Specie'
+ regularizeStock: Regularizar stock
buyRequest:
ticketId: 'ID Ticket'
shipped: 'F. envío'
diff --git a/src/pages/Login/LoginMain.vue b/src/pages/Login/LoginMain.vue
index 44b868ebd..a4c3566a9 100644
--- a/src/pages/Login/LoginMain.vue
+++ b/src/pages/Login/LoginMain.vue
@@ -3,7 +3,7 @@ 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';
@@ -63,11 +63,10 @@ async function onSubmit() {
:rules="[(val) => (val && val.length > 0) || t('login.fieldRequired')]"
color="primary"
/>
-
diff --git a/src/pages/Login/ResetPassword.vue b/src/pages/Login/ResetPassword.vue
index 2751f1ceb..081801e0e 100644
--- a/src/pages/Login/ResetPassword.vue
+++ b/src/pages/Login/ResetPassword.vue
@@ -7,6 +7,7 @@ import axios from 'axios';
import VnInput from 'components/common/VnInput.vue';
import VnOutForm from 'components/ui/VnOutForm.vue';
+import VnInputPassword from 'src/components/common/VnInputPassword.vue';
const quasar = useQuasar();
const router = useRouter();
@@ -54,8 +55,7 @@ async function onSubmit() {
-
-
-
+
-
+
[
name: 'salesPersonFk',
field: 'userName',
align: 'left',
- optionFilter: 'firstName',
columnFilter: {
component: 'select',
attrs: {
- url: 'Workers/activeWithInheritedRole',
- fields: ['id', 'name'],
+ url: 'Workers/search?departmentCodes=["VT"]',
+ fields: ['id', 'name', 'nickname', 'code'],
sortBy: 'nickname ASC',
- where: { role: 'salesPerson' },
- useLike: false,
+ optionLabel: 'nickname',
},
},
},
@@ -223,7 +222,16 @@ const columns = computed(() => [
label: t('salesTicketsTable.payMethod'),
name: 'payMethod',
align: 'left',
- columnFilter: false,
+ columnFilter: {
+ component: 'select',
+ url: 'PayMethods',
+ attrs: {
+ options: PayMethodOpts.value,
+ optionValue: 'id',
+ optionLabel: 'name',
+ dense: true,
+ },
+ },
},
{
label: t('salesTicketsTable.total'),
@@ -244,11 +252,8 @@ const columns = computed(() => [
align: 'left',
columnFilter: {
component: 'select',
- url: 'Departments',
attrs: {
options: DepartmentOpts.value,
- optionValue: 'name',
- optionLabel: 'name',
dense: true,
},
},
@@ -364,6 +369,15 @@ const openTab = (id) =>
auto-load
@on-fetch="(data) => (DepartmentOpts = data)"
/>
+ (PayMethodOpts = data)"
+ />
@@ -383,7 +397,7 @@ const openTab = (id) =>
auto-load
:row-click="({ id }) => openTab(id)"
:disable-option="{ card: true }"
- :user-params="{ from, to, scopeDays: 0, packing }"
+ :user-params="{ from, to, scopeDays: 0 }"
>
-import { computed } from 'vue';
-import { useRoute } from 'vue-router';
-import VnCard from 'components/common/VnCard.vue';
+import VnCardBeta from 'components/common/VnCardBeta.vue';
import OrderDescriptor from 'pages/Order/Card/OrderDescriptor.vue';
-import OrderFilter from './OrderFilter.vue';
-import OrderSearchbar from './OrderSearchbar.vue';
-import OrderCatalogFilter from './OrderCatalogFilter.vue';
-const config = {
- OrderCatalog: OrderCatalogFilter,
-};
-const route = useRoute();
-
-const routeName = computed(() => route.name);
-const customRouteRedirectName = computed(() => {
- const route = config[routeName.value];
- if (route) return null;
- return 'OrderList';
-});
-const customFilterPanel = computed(() => {
- const filterPanel = config[routeName.value] ?? OrderFilter;
- return filterPanel;
-});
-
-
-
-
-
+ />
diff --git a/src/pages/Order/Card/OrderCatalog.vue b/src/pages/Order/Card/OrderCatalog.vue
index 4ad009133..186f216fb 100644
--- a/src/pages/Order/Card/OrderCatalog.vue
+++ b/src/pages/Order/Card/OrderCatalog.vue
@@ -15,15 +15,18 @@ const router = useRouter();
const stateStore = useStateStore();
const { t } = useI18n();
const dataKey = 'OrderCatalogList';
-const arrayData = useArrayData(dataKey);
-const store = arrayData.store;
-const tags = ref([]);
-const itemRefs = ref({});
-
-let catalogParams = {
+const catalogParams = {
orderFk: route.params.id,
orderBy: JSON.stringify({ field: 'relevancy DESC, name', way: 'ASC', isTag: false }),
};
+const arrayData = useArrayData(dataKey, {
+ url: 'Orders/CatalogFilter',
+ limit: 50,
+ userParams: catalogParams,
+});
+const store = arrayData.store;
+const tags = ref([]);
+const itemRefs = ref({});
onMounted(() => {
stateStore.rightDrawer = true;
@@ -66,7 +69,6 @@ function extractValueTags(items) {
);
tagValue.value = resultValueTags;
}
-const autoLoad = computed(() => !!JSON.parse(route?.query.table ?? '{}')?.categoryFk);
watch(
() => store.data,
@@ -78,15 +80,15 @@ watch(
-
+
+
+
-
+
diff --git a/src/pages/Order/Card/OrderCatalogItemDialog.vue b/src/pages/Order/Card/OrderCatalogItemDialog.vue
index 0d55b7de1..163b036eb 100644
--- a/src/pages/Order/Card/OrderCatalogItemDialog.vue
+++ b/src/pages/Order/Card/OrderCatalogItemDialog.vue
@@ -1,6 +1,6 @@
-
-
-
-
-
-
-
-es:
- Search order: Buscar orden
- Search orders by ticket id: Buscar pedido por id ticket
-
diff --git a/src/pages/Order/Card/OrderSummary.vue b/src/pages/Order/Card/OrderSummary.vue
index b8016abac..a289688e4 100644
--- a/src/pages/Order/Card/OrderSummary.vue
+++ b/src/pages/Order/Card/OrderSummary.vue
@@ -12,6 +12,7 @@ import CustomerDescriptorProxy from 'pages/Customer/Card/CustomerDescriptorProxy
import FetchedTags from 'components/ui/FetchedTags.vue';
import VnTitle from 'src/components/common/VnTitle.vue';
import ItemDescriptorProxy from 'src/pages/Item/Card/ItemDescriptorProxy.vue';
+import OrderDescriptorMenu from 'pages/Order/Card/OrderDescriptorMenu.vue';
const { t } = useI18n();
const route = useRoute();
@@ -91,6 +92,9 @@ async function handleConfirm() {
{{ t('order.summary.confirmLines') }}
+
+
+
-
+
{{ props.row.quantity }}
diff --git a/src/pages/Order/Card/OrderVolume.vue b/src/pages/Order/Card/OrderVolume.vue
index 27ee24197..fb104157e 100644
--- a/src/pages/Order/Card/OrderVolume.vue
+++ b/src/pages/Order/Card/OrderVolume.vue
@@ -71,9 +71,11 @@ onMounted(async () => (stateStore.rightDrawer = false));
auto-load
/>
-
+
@@ -111,12 +113,12 @@ onMounted(async () => (stateStore.rightDrawer = false));
-