Merge branch 'dev' into 7136_vnselectFilter_paginate

This commit is contained in:
Javier Segarra 2024-06-27 09:14:19 +02:00
commit b8e6ae409a
21 changed files with 5958 additions and 8820 deletions

View File

@ -6,6 +6,7 @@
"author": "Verdnatura",
"private": true,
"packageManager": "pnpm@8.15.1",
"type": "module",
"scripts": {
"lint": "eslint --ext .js,.vue ./",
"format": "prettier --write \"**/*.{js,vue,scss,html,md,json}\" --ignore-path .gitignore",
@ -22,7 +23,7 @@
"chromium": "^3.0.3",
"croppie": "^2.6.5",
"pinia": "^2.1.3",
"quasar": "^2.14.5",
"quasar": "^2.16.4",
"validator": "^13.9.0",
"vue": "^3.3.4",
"vue-i18n": "^9.2.2",
@ -31,7 +32,7 @@
"devDependencies": {
"@intlify/unplugin-vue-i18n": "^0.8.1",
"@pinia/testing": "^0.1.2",
"@quasar/app-vite": "^1.7.3",
"@quasar/app-vite": "^1.9.3",
"@quasar/quasar-app-extension-qcalendar": "4.0.0-beta.15",
"@quasar/quasar-app-extension-testing-unit-vitest": "^0.4.0",
"@vue/test-utils": "^2.4.4",
@ -43,7 +44,8 @@
"eslint-plugin-vue": "^9.14.1",
"postcss": "^8.4.23",
"prettier": "^2.8.8",
"vitest": "^0.31.1"
"vite": "^2.5.10",
"vitest": "^0.34.0"
},
"engines": {
"node": "^20 || ^18 || ^16",

File diff suppressed because it is too large Load Diff

104
quasar.config.cjs Normal file
View File

@ -0,0 +1,104 @@
/* eslint-env node */
/*
* This file runs in a Node context (it's NOT transpiled by Babel), so use only
* the ES6 features that are supported by your Node version. https://node.green/
*/
const { configure } = require('quasar/wrappers');
const VueI18nPlugin = require('@intlify/unplugin-vue-i18n/vite');
const path = require('path');
module.exports = configure(function (/* ctx */) {
return {
eslint: {
warnings: true,
errors: true,
},
boot: ['i18n', 'axios', 'vnDate', 'validations', 'quasar', 'quasar.defaults'],
css: ['app.scss'],
extras: ['roboto-font', 'material-icons-outlined', 'material-symbols-outlined'],
build: {
target: {
browser: ['es2022', 'edge88', 'firefox78', 'chrome87', 'safari13.1'],
node: 'node18',
},
vueRouterMode: 'hash',
rawDefine: {
'process.env.NODE_ENV': JSON.stringify(process.env.NODE_ENV),
},
extendViteConf(viteConf) {
delete viteConf.build.polyfillModulePreload;
viteConf.build.modulePreload = {
polyfill: false,
};
},
alias: {
composables: path.join(__dirname, './src/composables'),
filters: path.join(__dirname, './src/filters'),
},
vitePlugins: [
[
VueI18nPlugin({
runtimeOnly: false,
include: [
path.resolve(__dirname, './src/i18n/locale/**'),
path.resolve(__dirname, './src/pages/**/locale/**'),
],
}),
],
],
},
devServer: {
server: {
type: 'http',
},
proxy: {
'/api': {
target: 'http://0.0.0.0:3000',
logLevel: 'debug',
changeOrigin: true,
secure: false,
},
},
open: false,
},
framework: {
config: {
dark: 'auto',
},
lang: 'en-GB',
plugins: ['Notify', 'Dialog'],
all: 'auto',
autoImportComponentCase: 'pascal',
},
animations: [],
ssr: {
pwa: false,
prodPort: 3000,
middlewares: ['render'],
},
pwa: {
workboxMode: 'generateSW',
injectPwaMetaTags: true,
swFilename: 'sw.js',
manifestFilename: 'manifest.json',
useCredentialsForManifestTag: false,
},
cordova: {},
capacitor: {
hideSplashscreen: true,
},
electron: {
inspectPort: 5858,
bundler: 'packager',
packager: {},
builder: {
appId: 'salix-frontend',
},
},
bex: {
contentScripts: ['my-content-script'],
},
};
});

View File

@ -1,242 +0,0 @@
/* eslint-env node */
/*
* This file runs in a Node context (it's NOT transpiled by Babel), so use only
* the ES6 features that are supported by your Node version. https://node.green/
*/
// Configuration for your app
// https://v2.quasar.dev/quasar-cli-vite/quasar-config-js
const { configure } = require('quasar/wrappers');
const VueI18nPlugin = require('@intlify/unplugin-vue-i18n/vite');
const path = require('path');
module.exports = configure(function (/* ctx */) {
return {
eslint: {
// fix: true,
// include = [],
// exclude = [],
// rawOptions = {},
warnings: true,
errors: true,
},
// https://v2.quasar.dev/quasar-cli/prefetch-feature
// preFetch: true,
// app boot file (/src/boot)
// --> boot files are part of "main.js"
// https://v2.quasar.dev/quasar-cli/boot-files
boot: ['i18n', 'axios', 'vnDate', 'validations', 'quasar', 'quasar.defaults'],
// https://v2.quasar.dev/quasar-cli-vite/quasar-config-js#css
css: ['app.scss'],
// https://github.com/quasarframework/quasar/tree/dev/extras
extras: [
// 'ionicons-v4',
// 'mdi-v5',
// 'fontawesome-v6',
// 'eva-icons',
// 'themify',
// 'line-awesome',
// 'roboto-font-latin-ext', // this or either 'roboto-font', NEVER both!
'roboto-font',
'material-icons-outlined',
'material-symbols-outlined',
],
// Full list of options: https://v2.quasar.dev/quasar-cli-vite/quasar-config-js#build
build: {
target: {
browser: ['es2022', 'edge88', 'firefox78', 'chrome87', 'safari13.1'],
node: 'node18',
},
vueRouterMode: 'hash', // available values: 'hash', 'history'
// vueRouterBase,
// vueDevtools,
// vueOptionsAPI: false,
// rebuildCache: true, // rebuilds Vite/linter/etc cache on startup
// publicPath: '/',
// analyze: true,
// env: {},
rawDefine: {
'process.env.NODE_ENV': JSON.stringify(process.env.NODE_ENV),
},
// ignorePublicFolder: true,
// minify: false,
// polyfillModulePreload: true,
// distDir
extendViteConf(viteConf) {
// FIXME: Delete deprecated property polyfillModulePreload
// that is set by Quasar by default
delete viteConf.build.polyfillModulePreload;
viteConf.build.modulePreload = {
polyfill: false,
};
},
// viteVuePluginOptions: {},
alias: {
composables: path.join(__dirname, './src/composables'),
filters: path.join(__dirname, './src/filters'),
},
vitePlugins: [
[
VueI18nPlugin({
runtimeOnly: false,
include: [
path.resolve(__dirname, './src/i18n/locale/**'),
path.resolve(__dirname, './src/pages/**/locale/**'),
],
}),
],
],
},
// Full list of options: https://v2.quasar.dev/quasar-cli-vite/quasar-config-js#devServer
devServer: {
server: {
type: 'http',
},
proxy: {
'/api': {
target: 'http://0.0.0.0:3000',
logLevel: 'debug',
changeOrigin: true,
secure: false,
},
},
open: false,
},
// https://v2.quasar.dev/quasar-cli-vite/quasar-config-js#framework
framework: {
config: {
config: {
dark: 'auto',
},
},
lang: 'en-GB',
// iconSet: 'material-icons', // Quasar icon set
// lang: 'en-US', // Quasar language pack
// For special cases outside of where the auto-import strategy can have an impact
// (like functional components as one of the examples),
// you can manually specify Quasar components/directives to be available everywhere:
//
// components: [],
// directives: [],
// Quasar plugins
plugins: ['Notify', 'Dialog'],
all: 'auto',
autoImportComponentCase: 'pascal',
},
// animations: 'all', // --- includes all animations
// https://v2.quasar.dev/options/animations
animations: [],
// https://v2.quasar.dev/quasar-cli-vite/quasar-config-js#property-sourcefiles
// sourceFiles: {
// rootComponent: 'src/App.vue',
// router: 'src/router/index',
// store: 'src/store/index',
// registerServiceWorker: 'src-pwa/register-service-worker',
// serviceWorker: 'src-pwa/custom-service-worker',
// pwaManifestFile: 'src-pwa/manifest.json',
// electronMain: 'src-electron/electron-main',
// electronPreload: 'src-electron/electron-preload'
// },
// https://v2.quasar.dev/quasar-cli/developing-ssr/configuring-ssr
ssr: {
// ssrPwaHtmlFilename: 'offline.html', // do NOT use index.html as name!
// will mess up SSR
// extendSSRWebserverConf (esbuildConf) {},
// extendPackageJson (json) {},
pwa: false,
// manualStoreHydration: true,
// manualPostHydrationTrigger: true,
prodPort: 3000, // The default port that the production server should use
// (gets superseded if process.env.PORT is specified at runtime)
middlewares: [
'render', // keep this as last one
],
},
// https://v2.quasar.dev/quasar-cli/developing-pwa/configuring-pwa
pwa: {
workboxMode: 'generateSW', // or 'injectManifest'
injectPwaMetaTags: true,
swFilename: 'sw.js',
manifestFilename: 'manifest.json',
useCredentialsForManifestTag: false,
// useFilenameHashes: true,
// extendGenerateSWOptions (cfg) {}
// extendInjectManifestOptions (cfg) {},
// extendManifestJson (json) {}
// extendPWACustomSWConf (esbuildConf) {}
},
// Full list of options: https://v2.quasar.dev/quasar-cli/developing-cordova-apps/configuring-cordova
cordova: {
// noIosLegacyBuildFlag: true, // uncomment only if you know what you are doing
},
// Full list of options: https://v2.quasar.dev/quasar-cli/developing-capacitor-apps/configuring-capacitor
capacitor: {
hideSplashscreen: true,
},
// Full list of options: https://v2.quasar.dev/quasar-cli/developing-electron-apps/configuring-electron
electron: {
// extendElectronMainConf (esbuildConf)
// extendElectronPreloadConf (esbuildConf)
inspectPort: 5858,
bundler: 'packager', // 'packager' or 'builder'
packager: {
// https://github.com/electron-userland/electron-packager/blob/master/docs/api.md#options
// OS X / Mac App Store
// appBundleId: '',
// appCategoryType: '',
// osxSign: '',
// protocol: 'myapp://path',
// Windows only
// win32metadata: { ... }
},
builder: {
// https://www.electron.build/configuration/configuration
appId: 'salix-frontend',
},
},
// Full list of options: https://v2.quasar.dev/quasar-cli-vite/developing-browser-extensions/configuring-bex
bex: {
contentScripts: ['my-content-script'],
// extendBexScriptsConf (esbuildConf) {}
// extendBexManifestJson (json) {}
},
};
});

View File

@ -60,7 +60,7 @@ const emit = defineEmits(['refresh', 'clear', 'search', 'init', 'remove']);
const arrayData = useArrayData($props.dataKey, {
exprBuilder: $props.exprBuilder,
searchUrl: $props.searchUrl,
navigate: {},
navigate: $props.redirect ? {} : null,
});
const route = useRoute();
const store = arrayData.store;

View File

@ -21,7 +21,7 @@ const currentUser = ref(state.getUser());
const newNote = ref('');
const vnPaginateRef = ref();
function handleKeyUp(event) {
if (event.key === 'Enter') {
if (event.key === 'Enter') {
event.preventDefault();
if (!event.shiftKey) insert();
}
@ -78,6 +78,7 @@ async function insert() {
ref="vnPaginateRef"
class="show"
v-bind="$attrs"
search-url="notes"
>
<template #body="{ rows }">
<TransitionGroup name="list" tag="div" class="column items-center full-width">

View File

@ -71,7 +71,6 @@ export function useArrayData(key = useRoute().meta.moduleName, userOptions) {
const filter = {
order: store.order,
limit: store.limit,
skip: store.skip,
};
let exprFilter;
@ -86,7 +85,7 @@ export function useArrayData(key = useRoute().meta.moduleName, userOptions) {
}
Object.assign(filter, store.userFilter, exprFilter);
Object.assign(store.filter, filter);
Object.assign(store.filter, { ...filter, skip: store.skip });
const params = {
filter: JSON.stringify(store.filter),
};

View File

@ -849,6 +849,7 @@ worker:
calendar: Calendar
timeControl: Time control
locker: Locker
balance: Balance
formation: Formation
list:
name: Name
@ -930,6 +931,13 @@ worker:
remark: Bonficado
hasDiploma: Diploma
imageNotFound: Image not found
balance:
tableVisibleColumns:
paymentDate: Date
incomeType: Type
debit: Debt
credit: Have
concept: Concept
wagon:
pageTitles:
wagons: Wagons

View File

@ -845,6 +845,7 @@ worker:
calendar: Calendario
timeControl: Control de horario
locker: Taquilla
balance: Balance
formation: Formación
list:
name: Nombre
@ -917,6 +918,13 @@ worker:
remark: Bonficado
hasDiploma: Diploma
imageNotFound: No se ha encontrado la imagen
balance:
tableVisibleColumns:
paymentDate: Fecha
incomeType: Tipo
debit: Debe
credit: Haber
concept: Concepto
wagon:
pageTitles:
wagons: Vagones

View File

@ -219,6 +219,7 @@ const useLang = (values) => {
:expr-builder="exprBuilder"
:custom-tags="['tagGroups']"
@remove="clearFilter"
:redirect="false"
>
<template #tags="{ tag, formatFn }">
<strong v-if="tag.label === 'categoryFk'">

View File

@ -104,10 +104,14 @@ const totalEntryPrice = (rows) => {
for (const row of rows) {
let total = 0;
let quantity = 0;
for (const buy of row.buys) {
total = total + buy.total;
quantity = quantity + buy.quantity;
if (row.buys) {
for (const buy of row.buys) {
total = total + buy.total;
quantity = quantity + buy.quantity;
}
}
row.total = total;
row.quantity = quantity;
totalPrice = totalPrice + total;

View File

@ -50,7 +50,7 @@ const itemCategoriesOptions = ref([]);
@on-fetch="(data) => (itemCategoriesOptions = data)"
auto-load
/>
<VnFilterPanel :data-key="props.dataKey" :search-button="true">
<VnFilterPanel :data-key="props.dataKey" :search-button="true" :redirect="false">
<template #tags="{ tag, formatFn }">
<div class="q-gutter-x-xs">
<strong>{{ t(`params.${tag.label}`) }}: </strong>

View File

@ -0,0 +1,91 @@
<script setup>
import { ref, computed } from 'vue';
import { useI18n } from 'vue-i18n';
import { useRoute } from 'vue-router';
import VnTable from 'components/VnTable/VnTable.vue';
const tableRef = ref();
const { t } = useI18n();
const route = useRoute();
const entityId = computed(() => route.params.id);
const columns = computed(() => [
{
align: 'left',
name: 'paymentDate',
label: t('worker.balance.tableVisibleColumns.paymentDate'),
create: true,
component: 'date',
field: 'paymentDate',
cardVisible: true,
},
{
align: 'left',
name: 'incomeTypeFk',
label: t('worker.balance.tableVisibleColumns.incomeType'),
create: true,
component: 'select',
attrs: {
url: 'payrollComponents',
fields: ['id', 'name'],
},
cardVisible: true,
},
{
align: 'left',
name: 'debit',
label: t('worker.balance.tableVisibleColumns.debit'),
create: true,
component: 'input',
field: 'debit',
cardVisible: true,
},
{
align: 'left',
name: 'credit',
label: t('worker.balance.tableVisibleColumns.credit'),
create: true,
component: 'input',
field: 'credit',
cardVisible: true,
},
{
align: 'left',
name: 'concept',
label: t('worker.balance.tableVisibleColumns.concept'),
create: true,
component: 'input',
field: 'concept',
cardVisible: true,
},
]);
</script>
<template>
<VnTable
ref="tableRef"
data-key="WorkerBalance"
:url="`Workers/${entityId}/incomes`"
:url-create="`Workers/${entityId}/incomes`"
save-url="WorkerIncomes/crud"
:create="{
urlCreate: 'workerIncomes',
title: t('Create workerBalance'),
onDataSaved: () => tableRef.reload(),
formInitialData: {
workerFk: entityId,
},
}"
order="paymentDate DESC"
:columns="columns"
default-mode="table"
auto-load
:right-search="false"
:is-editable="true"
:use-model="true"
/>
</template>
<i18n>
es:
Create workerBalance: Crear balance
</i18n>

View File

@ -35,6 +35,7 @@ const columns = computed(() => [
url: 'TrainingCourseTypes',
fields: ['id', 'name'],
},
cardVisible: true,
},
{
align: 'left',
@ -52,6 +53,7 @@ const columns = computed(() => [
component: 'date',
field: 'ended',
create: true,
cardVisible: true,
},
{
align: 'left',
@ -63,6 +65,7 @@ const columns = computed(() => [
url: 'TrainingCenters',
fields: ['id', 'name'],
},
cardVisible: true,
},
{
align: 'left',
@ -78,6 +81,7 @@ const columns = computed(() => [
component: 'input',
field: 'amount',
create: true,
cardVisible: true,
},
{
align: 'left',

View File

@ -274,7 +274,7 @@ export default {
name: 'CustomerBalance',
meta: {
title: 'balance',
icon: 'vn:invoice',
icon: 'balance',
},
component: () =>
import('src/pages/Customer/Card/CustomerBalance.vue'),

View File

@ -23,6 +23,7 @@ export default {
'WorkerDms',
'WorkerTimeControl',
'WorkerLocker',
'WorkerBalance',
'WorkerFormation',
],
},
@ -177,6 +178,15 @@ export default {
},
component: () => import('src/pages/Worker/Card/WorkerLocker.vue'),
},
{
name: 'WorkerBalance',
path: 'balance',
meta: {
title: 'balance',
icon: 'balance',
},
component: () => import('src/pages/Worker/Card/WorkerBalance.vue'),
},
{
name: 'WorkerFormation',
path: 'formation',

View File

@ -6,15 +6,14 @@ describe('InvoiceInCorrective', () => {
const saveDialog = '.q-card > .q-card__actions > .q-btn--standard ';
it('should create a correcting invoice', () => {
cy.viewport(1280, 720);
cy.login('developer');
cy.visit(`/#/invoice-in/1/summary?limit=10`);
cy.openLeftMenu();
cy.openActionsDescriptor();
cy.get(createRectificative).click();
cy.get(saveDialog).click();
cy.openLeftMenu();
cy.get(rectificativeSection).click();
cy.get('tbody > tr:visible').should('have.length', 1);
});

View File

@ -5,18 +5,15 @@ describe('InvoiceInDescriptor', () => {
'.q-card:nth-child(3) .vn-label-value:nth-child(5) > .value > span';
it('should booking and unbooking the invoice properly', () => {
cy.viewport(1280, 720);
cy.login('developer');
cy.visit(`/#/invoice-in/1/summary?limit=10`);
cy.visit('/#/invoice-in/1/summary');
cy.openLeftMenu();
cy.openActionsDescriptor();
cy.get(firstDescritorOpt).click();
cy.get(dialogBtns).eq(1).click();
cy.get('.fullscreen').first().click();
cy.get(isBookedField).should('have.attr', 'title', 'true');
cy.openLeftMenu();
cy.openActionsDescriptor();
cy.get(firstDescritorOpt).click();
cy.get(dialogBtns).eq(1).click();
cy.get(isBookedField).should('have.attr', 'title', 'false');

View File

@ -5,14 +5,11 @@ import jsconfigPaths from 'vite-jsconfig-paths';
import VueI18nPlugin from '@intlify/unplugin-vue-i18n/vite';
import path from 'path';
// https://vitejs.dev/config/
export default defineConfig({
test: {
environment: 'happy-dom',
setupFiles: 'test/vitest/setup-file.js',
include: [
// Matches vitest tests in any subfolder of 'src' or into 'test/vitest/__tests__'
// Matches all files with extension 'js', 'jsx', 'ts' and 'tsx'
'test/vitest/__tests__/**/*.{test,spec}.{js,mjs,cjs,ts,mts,cts,jsx,tsx}',
],
},