@@ -15,7 +18,9 @@
}
@media screen and (max-width: 800px) {
.vn-row {
- flex-direction: column;
+ &:not(.wrap) {
+ flex-direction: column;
+ }
}
}
diff --git a/src/components/ui/VnUserLink.vue b/src/components/ui/VnUserLink.vue
index b04ea7476..00c50ee34 100644
--- a/src/components/ui/VnUserLink.vue
+++ b/src/components/ui/VnUserLink.vue
@@ -1,20 +1,18 @@
-
- {{ $props.defaultName ? $props.name ?? t('globals.system') : $props.name }}
+
+ {{ defaultName ? name ?? $t('globals.system') : name }}
-
+
diff --git a/src/composables/getTotal.js b/src/composables/getTotal.js
new file mode 100644
index 000000000..41c4330c4
--- /dev/null
+++ b/src/composables/getTotal.js
@@ -0,0 +1,10 @@
+import { toCurrency } from 'src/filters';
+
+export function getTotal(rows, key, opts = {}) {
+ const { currency, cb } = opts;
+ const total = rows.reduce((acc, row) => acc + +(cb ? cb(row) : row[key] || 0), 0);
+
+ return currency
+ ? toCurrency(total, currency == 'default' ? undefined : currency)
+ : total;
+}
diff --git a/src/composables/useAcl.js b/src/composables/useAcl.js
index 46aaa3c25..ede359186 100644
--- a/src/composables/useAcl.js
+++ b/src/composables/useAcl.js
@@ -16,13 +16,18 @@ export function useAcl() {
state.setAcls(acls);
}
- function hasAny(model, prop, accessType) {
- const acls = state.getAcls().value[model];
- if (acls)
- return ['*', prop].some((key) => {
- const acl = acls[key];
- return acl && (acl['*'] || acl[accessType]);
- });
+ function hasAny(acls) {
+ for (const acl of acls) {
+ let { model, props, accessType } = acl;
+ const modelAcls = state.getAcls().value[model];
+ Array.isArray(props) || (props = [props]);
+ if (modelAcls)
+ return ['*', ...props].some((key) => {
+ const acl = modelAcls[key];
+ return acl && (acl['*'] || acl[accessType]);
+ });
+ }
+ return false;
}
return {
diff --git a/src/composables/usePrintService.js b/src/composables/usePrintService.js
index edf9598b2..ff43c65a1 100644
--- a/src/composables/usePrintService.js
+++ b/src/composables/usePrintService.js
@@ -17,6 +17,7 @@ export function usePrintService() {
}
function openReport(path, params) {
+ if (typeof params === 'string') params = JSON.parse(params);
params = Object.assign(
{
access_token: getTokenMultimedia(),
diff --git a/src/css/app.scss b/src/css/app.scss
index 357c9ecdb..3c51dc8af 100644
--- a/src/css/app.scss
+++ b/src/css/app.scss
@@ -37,6 +37,10 @@ a {
.link {
color: $color-link;
cursor: pointer;
+
+ &--white {
+ color: white;
+ }
}
.tx-color-link {
@@ -271,3 +275,8 @@ input::-webkit-inner-spin-button {
z-index: 1;
cursor: pointer;
}
+
+.subName {
+ color: var(--vn-label-color);
+ text-transform: uppercase;
+}
diff --git a/src/i18n/locale/en.yml b/src/i18n/locale/en.yml
index 548981de1..d29b864b9 100644
--- a/src/i18n/locale/en.yml
+++ b/src/i18n/locale/en.yml
@@ -2,6 +2,7 @@ globals:
lang:
es: Spanish
en: English
+ quantity: Quantity
language: Language
entity: Entity
user: User
@@ -40,6 +41,8 @@ globals:
noChanges: No changes to save
changesToSave: You have changes pending to save
confirmRemove: You are about to delete this row. Are you sure?
+ rowWillBeRemoved: This row will be removed
+ sureToContinue: Are you sure you want to continue?
rowAdded: Row added
rowRemoved: Row removed
pleaseWait: Please wait...
@@ -84,7 +87,7 @@ globals:
description: Description
id: Id
order: Order
- original: Original
+ original: Phys. Doc
file: File
selectFile: Select a file
copyClipboard: Copy on clipboard
@@ -96,6 +99,10 @@ globals:
to: To
notes: Notes
refresh: Refresh
+ item: Item
+ ticket: Ticket
+ campaign: Campaign
+ weight: Weight
pageTitles:
logIn: Login
summary: Summary
@@ -122,6 +129,7 @@ globals:
notifications: Notifications
defaulter: Defaulter
customerCreate: New customer
+ createOrder: New order
fiscalData: Fiscal data
billingData: Billing data
consignees: Consignees
@@ -261,6 +269,7 @@ globals:
clientsActionsMonitor: Clients and actions
serial: Serial
medical: Mutual
+ supplier: Supplier
created: Created
worker: Worker
now: Now
@@ -311,135 +320,6 @@ resetPassword:
repeatPassword: Repeat password
passwordNotMatch: Passwords don't match
passwordChanged: Password changed
-customer:
- list:
- phone: Phone
- email: Email
- customerOrders: Display customer orders
- moreOptions: More options
- card:
- customerList: Customer list
- customerId: Claim ID
- salesPerson: Sales person
- credit: Credit
- risk: Risk
- securedCredit: Secured credit
- payMethod: Pay method
- debt: Debt
- isFrozen: Customer frozen
- hasDebt: Customer has debt
- isDisabled: Customer inactive
- notChecked: Customer no checked
- webAccountInactive: Web account inactive
- noWebAccess: Web access is disabled
- businessType: Business type
- passwordRequirements: 'The password must have at least { length } length characters, {nAlpha} alphabetic characters, {nUpper} capital letters, {nDigits} digits and {nPunct} symbols (Ex: $%&.)\n'
- businessTypeFk: Business type
- summary:
- basicData: Basic data
- fiscalAddress: Fiscal address
- fiscalData: Fiscal data
- billingData: Billing data
- consignee: Default consignee
- businessData: Business data
- financialData: Financial data
- customerId: Customer ID
- name: Name
- contact: Contact
- phone: Phone
- mobile: Mobile
- email: Email
- salesPerson: Sales person
- contactChannel: Contact channel
- socialName: Social name
- fiscalId: Fiscal ID
- postcode: Postcode
- province: Province
- country: Country
- street: Address
- isEqualizated: Is equalizated
- isActive: Is active
- invoiceByAddress: Invoice by address
- verifiedData: Verified data
- hasToInvoice: Has to invoice
- notifyByEmail: Notify by email
- vies: VIES
- payMethod: Pay method
- bankAccount: Bank account
- dueDay: Due day
- hasLcr: Has LCR
- hasCoreVnl: Has core VNL
- hasB2BVnl: Has B2B VNL
- addressName: Address name
- addressCity: City
- addressStreet: Street
- username: Username
- webAccess: Web access
- totalGreuge: Total greuge
- mana: Mana
- priceIncreasingRate: Price increasing rate
- averageInvoiced: Average invoiced
- claimRate: Claming rate
- risk: Risk
- riskInfo: Invoices minus payments plus orders not yet invoiced
- credit: Credit
- creditInfo: Company's maximum risk
- securedCredit: Secured credit
- securedCreditInfo: Solunion's maximum risk
- balance: Balance
- balanceInfo: Invoices minus payments
- balanceDue: Balance due
- balanceDueInfo: Deviated invoices minus payments
- recoverySince: Recovery since
- businessType: Business Type
- city: City
- descriptorInfo: Invoices minus payments plus orders not yet
- rating: Rating
- recommendCredit: Recommended credit
- basicData:
- socialName: Fiscal name
- businessType: Business type
- contact: Contact
- youCanSaveMultipleEmails: You can save multiple emails
- email: Email
- phone: Phone
- mobile: Mobile
- salesPerson: Sales person
- contactChannel: Contact channel
- previousClient: Previous client
- extendedList:
- tableVisibleColumns:
- id: Identifier
- name: Name
- socialName: Social name
- fi: Tax number
- salesPersonFk: Salesperson
- credit: Credit
- creditInsurance: Credit insurance
- phone: Phone
- mobile: Mobile
- street: Street
- countryFk: Country
- provinceFk: Province
- city: City
- postcode: Postcode
- email: Email
- created: Created
- businessTypeFk: Business type
- payMethodFk: Billing data
- sageTaxTypeFk: Sage tax type
- sageTransactionTypeFk: Sage tr. type
- isActive: Active
- isVies: Vies
- isTaxDataChecked: Verified data
- isEqualizated: Is equalizated
- isFreezed: Freezed
- hasToInvoice: Invoice
- hasToInvoiceByAddress: Invoice by address
- isToBeMailed: Mailing
- hasLcr: Received LCR
- hasCoreVnl: VNL core received
- hasSepaVnl: VNL B2B received
entry:
list:
newEntry: New entry
@@ -753,56 +633,6 @@ parking:
searchBar:
info: You can search by parking code
label: Search parking...
-invoiceIn:
- list:
- ref: Reference
- supplier: Supplier
- supplierRef: Supplier ref.
- serialNumber: Serial number
- serial: Serial
- file: File
- issued: Issued
- isBooked: Is booked
- awb: AWB
- amount: Amount
- card:
- issued: Issued
- amount: Amount
- client: Client
- company: Company
- customerCard: Customer card
- ticketList: Ticket List
- vat: Vat
- dueDay: Due day
- intrastat: Intrastat
- summary:
- supplier: Supplier
- supplierRef: Supplier ref.
- currency: Currency
- docNumber: Doc number
- issued: Expedition date
- operated: Operation date
- bookEntried: Entry date
- bookedDate: Booked date
- sage: Sage withholding
- vat: Undeductible VAT
- company: Company
- booked: Booked
- expense: Expense
- taxableBase: Taxable base
- rate: Rate
- sageVat: Sage vat
- sageTransaction: Sage transaction
- dueDay: Date
- bank: Bank
- amount: Amount
- foreignValue: Foreign value
- dueTotal: Due day
- noMatch: Do not match
- code: Code
- net: Net
- stems: Stems
- country: Country
order:
field:
salesPersonFk: Sales Person
@@ -1298,6 +1128,7 @@ components:
active: Is active
visible: Is visible
floramondo: Is floramondo
+ showBadDates: Show future items
userPanel:
copyToken: Token copied to clipboard
settings: Settings
diff --git a/src/i18n/locale/es.yml b/src/i18n/locale/es.yml
index 697e6c38c..3d905509d 100644
--- a/src/i18n/locale/es.yml
+++ b/src/i18n/locale/es.yml
@@ -3,6 +3,7 @@ globals:
es: Español
en: Inglés
language: Idioma
+ quantity: Cantidad
entity: Entidad
user: Usuario
details: Detalles
@@ -39,6 +40,8 @@ globals:
noChanges: Sin cambios que guardar
changesToSave: Tienes cambios pendientes de guardar
confirmRemove: Vas a eliminar este registro. ¿Continuar?
+ rowWillBeRemoved: Esta linea se eliminará
+ sureToContinue: ¿Seguro que quieres continuar?
rowAdded: Fila añadida
rowRemoved: Fila eliminada
pleaseWait: Por favor espera...
@@ -86,7 +89,7 @@ globals:
description: Descripción
id: Id
order: Orden
- original: Original
+ original: Doc. física
file: Fichero
selectFile: Seleccione un fichero
copyClipboard: Copiar en portapapeles
@@ -98,6 +101,10 @@ globals:
to: Hasta
notes: Notas
refresh: Actualizar
+ item: Artículo
+ ticket: Ticket
+ campaign: Campaña
+ weight: Peso
pageTitles:
logIn: Inicio de sesión
summary: Resumen
@@ -119,6 +126,7 @@ globals:
inheritedRoles: Roles heredados
customers: Clientes
customerCreate: Nuevo cliente
+ createOrder: Nuevo pedido
list: Listado
webPayments: Pagos Web
extendedList: Listado extendido
@@ -265,6 +273,7 @@ globals:
clientsActionsMonitor: Clientes y acciones
serial: Facturas por serie
medical: Mutua
+ supplier: Proveedor
created: Fecha creación
worker: Trabajador
now: Ahora
@@ -313,134 +322,6 @@ resetPassword:
repeatPassword: Repetir contraseña
passwordNotMatch: Las contraseñas no coinciden
passwordChanged: Contraseña cambiada
-customer:
- list:
- phone: Teléfono
- email: Email
- customerOrders: Mostrar órdenes del cliente
- moreOptions: Más opciones
- card:
- customerId: ID cliente
- salesPerson: Comercial
- credit: Crédito
- risk: Riesgo
- securedCredit: Crédito asegurado
- payMethod: Método de pago
- debt: Riesgo
- isFrozen: Cliente congelado
- hasDebt: Cliente con riesgo
- isDisabled: Cliente inactivo
- notChecked: Cliente no comprobado
- webAccountInactive: Sin acceso web
- noWebAccess: El acceso web está desactivado
- businessType: Tipo de negocio
- passwordRequirements: 'La contraseña debe tener al menos { length } caracteres de longitud, {nAlpha} caracteres alfabéticos, {nUpper} letras mayúsculas, {nDigits} dígitos y {nPunct} símbolos (Ej: $%&.)'
- businessTypeFk: Tipo de negocio
- summary:
- basicData: Datos básicos
- fiscalAddress: Dirección fiscal
- fiscalData: Datos fiscales
- billingData: Datos de facturación
- consignee: Consignatario pred.
- businessData: Datos comerciales
- financialData: Datos financieros
- customerId: ID cliente
- name: Nombre
- contact: Contacto
- phone: Teléfono
- mobile: Móvil
- email: Email
- salesPerson: Comercial
- contactChannel: Canal de contacto
- socialName: Razón social
- fiscalId: NIF/CIF
- postcode: Código postal
- province: Provincia
- country: País
- street: Calle
- isEqualizated: Recargo de equivalencia
- isActive: Activo
- invoiceByAddress: Facturar por consignatario
- verifiedData: Datos verificados
- hasToInvoice: Facturar
- notifyByEmail: Notificar por email
- vies: VIES
- payMethod: Método de pago
- bankAccount: Cuenta bancaria
- dueDay: Día de pago
- hasLcr: Recibido LCR
- hasCoreVnl: Recibido core VNL
- hasB2BVnl: Recibido B2B VNL
- addressName: Nombre de la dirección
- addressCity: Ciudad
- addressStreet: Calle
- username: Usuario
- webAccess: Acceso web
- totalGreuge: Greuge total
- mana: Maná
- priceIncreasingRate: Ratio de incremento de precio
- averageInvoiced: Facturación media
- claimRate: Ratio de reclamaciones
- risk: Riesgo
- riskInfo: Facturas menos recibos mas pedidos sin facturar
- credit: Crédito
- creditInfo: Riesgo máximo asumido por la empresa
- securedCredit: Crédito asegurado
- securedCreditInfo: Riesgo máximo asumido por Solunion
- balance: Balance
- balanceInfo: Facturas menos recibos
- balanceDue: Saldo vencido
- balanceDueInfo: Facturas fuera de plazo menos recibos
- recoverySince: Recobro desde
- businessType: Tipo de negocio
- city: Población
- descriptorInfo: Facturas menos recibos mas pedidos sin facturar
- rating: Clasificación
- recommendCredit: Crédito recomendado
- basicData:
- socialName: Nombre fiscal
- businessType: Tipo de negocio
- contact: Contacto
- youCanSaveMultipleEmails: Puede guardar varios correos electrónicos encadenándolos mediante comas sin espacios{','} ejemplo{':'} user{'@'}dominio{'.'}com, user2{'@'}dominio{'.'}com siendo el primer correo electrónico el principal
- email: Email
- phone: Teléfono
- mobile: Móvil
- salesPerson: Comercial
- contactChannel: Canal de contacto
- previousClient: Cliente anterior
- extendedList:
- tableVisibleColumns:
- id: Identificador
- name: Nombre
- socialName: Razón social
- fi: NIF / CIF
- salesPersonFk: Comercial
- credit: Crédito
- creditInsurance: Crédito asegurado
- phone: Teléfono
- mobile: Móvil
- street: Dirección fiscal
- countryFk: País
- provinceFk: Provincia
- city: Población
- postcode: Código postal
- email: Email
- created: Fecha creación
- businessTypeFk: Tipo de negocio
- payMethodFk: Forma de pago
- sageTaxTypeFk: Tipo de impuesto Sage
- sageTransactionTypeFk: Tipo tr. sage
- isActive: Activo
- isVies: Vies
- isTaxDataChecked: Datos comprobados
- isEqualizated: Recargo de equivalencias
- isFreezed: Congelado
- hasToInvoice: Factura
- hasToInvoiceByAddress: Factura por consigna
- isToBeMailed: Env. emails
- hasLcr: Recibido LCR
- hasCoreVnl: Recibido core VNL
- hasSepaVnl: Recibido B2B VNL
entry:
list:
newEntry: Nueva entrada
@@ -799,54 +680,6 @@ parking:
searchBar:
info: Puedes buscar por código de parking
label: Buscar parking...
-invoiceIn:
- list:
- ref: Referencia
- supplier: Proveedor
- supplierRef: Ref. proveedor
- serialNumber: Num. serie
- shortIssued: F. emisión
- serial: Serie
- file: Fichero
- issued: Fecha emisión
- isBooked: Conciliada
- awb: AWB
- amount: Importe
- card:
- issued: Fecha emisión
- amount: Importe
- client: Cliente
- company: Empresa
- customerCard: Ficha del cliente
- ticketList: Listado de tickets
- vat: Iva
- dueDay: Fecha de vencimiento
- summary:
- supplier: Proveedor
- supplierRef: Ref. proveedor
- currency: Divisa
- docNumber: Número documento
- issued: Fecha de expedición
- operated: Fecha operación
- bookEntried: Fecha asiento
- bookedDate: Fecha contable
- sage: Retención sage
- vat: Iva no deducible
- company: Empresa
- booked: Contabilizada
- expense: Gasto
- taxableBase: Base imp.
- rate: Tasa
- sageTransaction: Sage transación
- dueDay: Fecha
- bank: Caja
- amount: Importe
- foreignValue: Divisa
- dueTotal: Vencimiento
- code: Código
- net: Neto
- stems: Tallos
- country: País
department:
pageTitles:
basicData: Basic data
@@ -1278,6 +1111,7 @@ components:
active: Activo
visible: Visible
floramondo: Floramondo
+ showBadDates: Ver items a futuro
userPanel:
copyToken: Token copiado al portapapeles
settings: Configuración
diff --git a/src/pages/Account/AccountConnections.vue b/src/pages/Account/AccountConnections.vue
index 4d3450665..057745831 100644
--- a/src/pages/Account/AccountConnections.vue
+++ b/src/pages/Account/AccountConnections.vue
@@ -27,15 +27,15 @@ const filter = {
order: 'created DESC',
};
-const urlPath = 'AccessTokens';
+const urlPath = 'VnTokens';
const refresh = () => paginateRef.value.fetch();
const navigate = (id) => router.push({ name: 'AccountSummary', params: { id } });
-const killSession = async (id) => {
+const killSession = async ({ userId, created }) => {
try {
- await axios.delete(`${urlPath}/${id}`);
+ await axios.post(`${urlPath}/killSession`, { userId, created });
paginateRef.value.fetch();
notify(t('Session killed'), 'positive');
} catch (error) {
@@ -84,7 +84,7 @@ const killSession = async (id) => {
openConfirmationModal(
t('Session will be killed'),
t('Are you sure you want to continue?'),
- () => killSession(row.id)
+ () => killSession(row)
)
"
outline
diff --git a/src/pages/Account/Card/AccountPrivileges.vue b/src/pages/Account/Card/AccountPrivileges.vue
index 0574e08d2..fea57105b 100644
--- a/src/pages/Account/Card/AccountPrivileges.vue
+++ b/src/pages/Account/Card/AccountPrivileges.vue
@@ -19,7 +19,15 @@ watch(
(rolesOptions = data)" />
-
+
@@ -211,7 +211,7 @@ async function saveWhenHasChanges() {
- toCurrency(sale.quantity * sale.price * ((100 - sale.discount) / 100)),
+ field: (row) =>
+ toCurrency(row.quantity * row.sale.price * ((100 - row.sale.discount) / 100)),
sortable: true,
},
]);
diff --git a/src/pages/Customer/Card/CustomerBalance.vue b/src/pages/Customer/Card/CustomerBalance.vue
index 548a67b0b..70747bb3f 100644
--- a/src/pages/Customer/Card/CustomerBalance.vue
+++ b/src/pages/Customer/Card/CustomerBalance.vue
@@ -2,7 +2,7 @@
import { computed, onBeforeMount, ref } from 'vue';
import { useI18n } from 'vue-i18n';
import { useRoute } from 'vue-router';
-import { useRole } from 'src/composables/useRole';
+import { useAcl } from 'src/composables/useAcl';
import axios from 'axios';
import { useQuasar } from 'quasar';
@@ -24,7 +24,7 @@ import InvoiceOutDescriptorProxy from 'src/pages/InvoiceOut/Card/InvoiceOutDescr
const { openConfirmationModal } = useVnConfirm();
const { sendEmail } = usePrintService();
const { t } = useI18n();
-const { hasAny } = useRole();
+const { hasAny } = useAcl();
const session = useSession();
const tokenMultimedia = session.getTokenMultimedia();
@@ -95,12 +95,7 @@ const columns = computed(() => [
label: t('Employee'),
columnField: {
component: 'userLink',
- attrs: ({ row }) => {
- return {
- workerId: row.workerFk,
- name: row.userName,
- };
- },
+ attrs: ({ row }) => ({ workerId: row.workerFk, tag: row.userName }),
},
cardVisible: true,
},
@@ -259,6 +254,7 @@ const showBalancePdf = ({ id }) => {
:is-editable="false"
:column-search="false"
@on-fetch="onFetch"
+ :disable-option="{ card: true }"
auto-load
>
@@ -284,7 +280,9 @@ const showBalancePdf = ({ id }) => {
>
diff --git a/src/pages/Customer/Card/CustomerBasicData.vue b/src/pages/Customer/Card/CustomerBasicData.vue
index a6150bb3f..8cc59ef3c 100644
--- a/src/pages/Customer/Card/CustomerBasicData.vue
+++ b/src/pages/Customer/Card/CustomerBasicData.vue
@@ -25,6 +25,7 @@ const title = ref();
/>
(businessTypes = data)"
auto-load
/>
@@ -38,7 +39,7 @@ const title = ref();
clearable
v-model="data.name"
/>
-
{
- title = val?.nickname;
- data.salesPersonFk = val?.id;
- }
- "
+ emit-value
+ auto-load
>
+
+
+
+ {{ scope.opt?.name }}
+ {{ scope.opt?.nickname }},
+ {{ scope.opt?.code }}
+
+
+
-
-
@@ -145,7 +159,7 @@ const title = ref();
}}
-
+
diff --git a/src/pages/Customer/Card/CustomerBillingData.vue b/src/pages/Customer/Card/CustomerBillingData.vue
index b01dc4523..5eeaea50b 100644
--- a/src/pages/Customer/Card/CustomerBillingData.vue
+++ b/src/pages/Customer/Card/CustomerBillingData.vue
@@ -31,8 +31,8 @@ const getBankEntities = (data, formData) => {
- (payMethods = data)" auto-load url="PayMethods" />
- (payMethods = data)" auto-load url="PayMethods" />
+ (bankEntitiesOptions = data)"
:filter="filter"
@@ -70,7 +70,7 @@ const getBankEntities = (data, formData) => {
{
- {{ scope.opt.bic }} {{ scope.opt.name }}
+ {{ scope.opt.bic }}
+ {{ scope.opt.name }}
diff --git a/src/pages/Customer/Card/CustomerCard.vue b/src/pages/Customer/Card/CustomerCard.vue
index 229946ea2..139917d05 100644
--- a/src/pages/Customer/Card/CustomerCard.vue
+++ b/src/pages/Customer/Card/CustomerCard.vue
@@ -1,17 +1,23 @@
-import CustomerConsumptionFilter from './CustomerConsumptionFilter.vue';
-import { useStateStore } from 'src/stores/useStateStore';
+import { ref, computed, onBeforeMount } from 'vue';
+import axios from 'axios';
+import { useI18n } from 'vue-i18n';
+import { toDate } from 'src/filters/index';
+import { useRoute } from 'vue-router';
+
+import VnTable from 'components/VnTable/VnTable.vue';
+import FetchedTags from 'components/ui/FetchedTags.vue';
+import { useArrayData } from 'src/composables/useArrayData';
+import { usePrintService } from 'src/composables/usePrintService';
+import { useVnConfirm } from 'src/composables/useVnConfirm';
+
+const { openConfirmationModal } = useVnConfirm();
+const { openReport, sendEmail } = usePrintService();
+import TicketDescriptorProxy from 'src/pages/Ticket/Card/TicketDescriptorProxy.vue';
+import ItemDescriptorProxy from 'src/pages/Item/Card/ItemDescriptorProxy.vue';
+import VnSelect from 'components/common/VnSelect.vue';
+import VnInputDate from 'components/common/VnInputDate.vue';
+
+const arrayData = useArrayData('Client');
+const { t } = useI18n();
+const route = useRoute();
+const campaignList = ref();
+const showActionBtns = computed(() => handleQueryParams());
+function handleQueryParams() {
+ const query = getQueryParams();
+ return query.from && query.to;
+}
+const columns = computed(() => [
+ {
+ name: 'search',
+ align: 'left',
+ label: t('globals.search'),
+ visible: false,
+ },
+ {
+ name: 'itemFk',
+ align: 'left',
+ label: t('globals.item'),
+ columnClass: 'shrink',
+ cardVisible: true,
+ columnFilter: {
+ name: 'itemId',
+ },
+ },
+ {
+ name: 'ticketFk',
+ align: 'left',
+ label: t('globals.ticket'),
+ cardVisible: true,
+ columnFilter: {
+ inWhere: true,
+ },
+ },
+ {
+ name: 'shipped',
+ align: 'left',
+ label: t('globals.shipped'),
+ format: ({ shipped }) => toDate(shipped),
+ columnFilter: false,
+ cardVisible: true,
+ },
+ {
+ name: 'description',
+ align: 'left',
+ label: t('globals.description'),
+ columnClass: 'expand',
+ columnFilter: {
+ inWhere: true,
+ },
+ },
+ {
+ name: 'quantity',
+ label: t('globals.quantity'),
+ cardVisible: true,
+ columnFilter: {
+ inWhere: true,
+ },
+ },
+ {
+ name: 'grouped',
+ label: t('Group by items'),
+ component: 'checkbox',
+ visible: false,
+ orderBy: false,
+ },
+]);
+
+onBeforeMount(async () => {
+ campaignList.value = (await axios('Campaigns/latest')).data;
+});
+
+function getQueryParams() {
+ return JSON.parse(route.query.consumption ?? '{}');
+}
+function getParams() {
+ const query = getQueryParams();
+ return {
+ from: query.from,
+ to: query.to,
+ recipient: arrayData.store.data.email,
+ recipientId: arrayData.store.data.id,
+ };
+}
+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 openReportPdf = () => {
+ openReport(`Clients/${route.params.id}/campaign-metrics-pdf`, getParams());
+};
+
+const openSendEmailDialog = async () => {
+ openConfirmationModal(
+ t('The consumption report will be sent'),
+ t('Please, confirm'),
+ () => sendCampaignMetricsEmail({ address: arrayData.store.data.email })
+ );
+};
+const sendCampaignMetricsEmail = ({ address }) => {
+ sendEmail(`Clients/${route.params.id}/campaign-metrics-email`, {
+ recipient: address,
+ ...getParams(),
+ });
+};
-
-
-
+
+
+
+ {{ t('globals.downloadPdf') }}
+
+
+ {{ t('Send to email') }}
+
+
+
+
+ {{ row.itemFk }}
+
+
+
+
+
+ {{ row.ticketFk }}
+
+
+
+
+ {{ row.concept }}
+
+ {{ row.subName }}
+
+
+
+
+
+
+
+
+
+
+ {{ scope.opt?.code }}
+ {{
+ new Date(scope.opt?.dated).getFullYear()
+ }}
+
+
+
+
+
+
+
+
+
es:
Enter a new search: Introduce una nueva búsqueda
+ Group by items: Agrupar por artículos
diff --git a/src/pages/Customer/Card/CustomerConsumptionFilter.vue b/src/pages/Customer/Card/CustomerConsumptionFilter.vue
deleted file mode 100644
index 4d2c5ff3c..000000000
--- a/src/pages/Customer/Card/CustomerConsumptionFilter.vue
+++ /dev/null
@@ -1,91 +0,0 @@
-
-
-
-
-
- {{ t(`params.${tag.label}`) }}:
- {{ formatFn(tag.value) }}
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-en:
- params:
- item: Item id
- buyer: Buyer
- type: Type
- category: Category
-es:
- params:
- item: Id artículo
- buyer: Comprador
- type: Tipo
- category: Categoría
-
diff --git a/src/pages/Customer/Card/CustomerCreditContracts.vue b/src/pages/Customer/Card/CustomerCreditContracts.vue
index 12719b2cf..0ff074793 100644
--- a/src/pages/Customer/Card/CustomerCreditContracts.vue
+++ b/src/pages/Customer/Card/CustomerCreditContracts.vue
@@ -53,6 +53,8 @@ const openDialog = (item) => {
promise: updateData,
},
});
+ updateData();
+ showQPageSticky.value = true;
};
const openViewCredit = (credit) => {
diff --git a/src/pages/Customer/Card/CustomerCreditOpinion.vue b/src/pages/Customer/Card/CustomerCreditOpinion.vue
index 9c060b1a5..6a839ff3f 100644
--- a/src/pages/Customer/Card/CustomerCreditOpinion.vue
+++ b/src/pages/Customer/Card/CustomerCreditOpinion.vue
@@ -1,23 +1,17 @@
- (rows = data)"
- auto-load
- ref="clientInformasRef"
+
-
-
-
-
-
-
-
-
-
-
-
+
+ {{ row.worker.user.nickname }}
+
-
-
-
-
+
diff --git a/src/pages/Customer/Card/CustomerDescriptor.vue b/src/pages/Customer/Card/CustomerDescriptor.vue
index 0e76bcfed..b18f90d20 100644
--- a/src/pages/Customer/Card/CustomerDescriptor.vue
+++ b/src/pages/Customer/Card/CustomerDescriptor.vue
@@ -3,7 +3,7 @@ import { ref, computed } from 'vue';
import { useRoute } from 'vue-router';
import { useI18n } from 'vue-i18n';
-import { toCurrency, toDate } from 'src/filters';
+import { dashIfEmpty, toCurrency, toDate } from 'src/filters';
import useCardDescription from 'src/composables/useCardDescription';
@@ -11,6 +11,10 @@ import CardDescriptor from 'components/ui/CardDescriptor.vue';
import VnLv from 'src/components/ui/VnLv.vue';
import VnUserLink from 'src/components/ui/VnUserLink.vue';
import CustomerDescriptorMenu from './CustomerDescriptorMenu.vue';
+import { useState } from 'src/composables/useState';
+const state = useState();
+
+const customer = computed(() => state.get('customer'));
const $props = defineProps({
id: {
@@ -43,7 +47,7 @@ const setData = (entity) => (data.value = useCardDescription(entity?.name, entit
:subtitle="data.subtitle"
@on-fetch="setData"
:summary="$props.summary"
- data-key="customerData"
+ data-key="customer"
>
@@ -57,35 +61,46 @@ const setData = (entity) => (data.value = useCardDescription(entity?.name, entit
:value="toCurrency(entity.creditInsurance)"
/>
-
-
+
+
+ {{ dashIfEmpty(entity.salesPersonUser) }}
-
-
+
+
{{ t('customer.card.isDisabled') }}
-
+
{{ t('customer.card.isFrozen') }}
(data.value = useCardDescription(entity?.name, entit
{{ t('customer.card.webAccountInactive') }}
(data.value = useCardDescription(entity?.name, entit
{{ t('customer.card.hasDebt') }}
(data.value = useCardDescription(entity?.name, entit
{{ t('customer.card.notChecked') }}
(data.value = useCardDescription(entity?.name, entit
{{
t('unpaidDated', {
- dated: toDate(entity.unpaid.dated),
+ dated: toDate(customer.unpaid.dated),
})
}}
{{
t('unpaidAmount', {
- amount: toCurrency(entity.unpaid.amount),
+ amount: toCurrency(customer.unpaid.amount),
})
}}
@@ -139,7 +154,13 @@ const setData = (entity) => (data.value = useCardDescription(entity?.name, entit
(data.value = useCardDescription(entity?.name, entit
- {{ t('New order') }}
-
- {
notify(error.message, 'positive');
}
};
+
+const ticketCreateFormDialog = ref(null);
+const openTicketCreateForm = () => {
+ ticketCreateFormDialog.value.show();
+};
+const orderCreateFormDialog = ref(null);
+const openOrderCreateForm = () => {
+ orderCreateFormDialog.value.show();
+};
-
+
-
- {{ t('Simple ticket') }}
-
+ {{ t('globals.pageTitles.createTicket') }}
+
+
+
+
+
+
+
+ {{ t('globals.pageTitles.createOrder') }}
+
+
+
diff --git a/src/pages/Customer/Card/CustomerFiscalData.vue b/src/pages/Customer/Card/CustomerFiscalData.vue
index 5cc656bb3..c2adace5e 100644
--- a/src/pages/Customer/Card/CustomerFiscalData.vue
+++ b/src/pages/Customer/Card/CustomerFiscalData.vue
@@ -93,7 +93,7 @@ function handleLocation(data, location) {
handleLocation(data, location)"
/>
diff --git a/src/pages/Customer/Card/CustomerGreuges.vue b/src/pages/Customer/Card/CustomerGreuges.vue
index 12173727f..1c78392e7 100644
--- a/src/pages/Customer/Card/CustomerGreuges.vue
+++ b/src/pages/Customer/Card/CustomerGreuges.vue
@@ -47,7 +47,6 @@ const columns = computed(() => [
},
{
align: 'left',
- name: 'userFk',
label: t('Created by'),
component: 'userLink',
attrs: ({ row }) => {
@@ -73,6 +72,7 @@ const columns = computed(() => [
columnCreate: {
component: 'select',
url: 'greugeTypes',
+ sortBy: 'name ASC ',
limit: 0,
},
},
@@ -105,9 +105,10 @@ const setRows = (data) => {
:use-model="true"
:column-search="false"
@on-fetch="(data) => setRows(data)"
+ :disable-option="{ card: true }"
:create="{
urlCreate: `Greuges`,
- title: t('New credit'),
+ title: t('New greuge'),
onDataSaved: () => tableRef.reload(),
formInitialData: { shipped: new Date(), clientFk: route.params.id },
}"
diff --git a/src/pages/Customer/Card/CustomerRecoveries.vue b/src/pages/Customer/Card/CustomerRecoveries.vue
index 8d3d05702..3ea8998e9 100644
--- a/src/pages/Customer/Card/CustomerRecoveries.vue
+++ b/src/pages/Customer/Card/CustomerRecoveries.vue
@@ -89,6 +89,7 @@ function setFinished(id) {
:columns="columns"
:use-model="true"
:right-search="false"
+ :disable-option="{ card: true }"
:create="{
urlCreate: 'Recoveries',
title: 'New recovery',
diff --git a/src/pages/Customer/Card/CustomerSamples.vue b/src/pages/Customer/Card/CustomerSamples.vue
index de998d8d3..49697aab7 100644
--- a/src/pages/Customer/Card/CustomerSamples.vue
+++ b/src/pages/Customer/Card/CustomerSamples.vue
@@ -3,18 +3,18 @@ import { ref, computed } from 'vue';
import { useI18n } from 'vue-i18n';
import { useRoute, useRouter } from 'vue-router';
-import { QBtn } from 'quasar';
+import { QBtn, useQuasar } from 'quasar';
-import FetchData from 'components/FetchData.vue';
import WorkerDescriptorProxy from 'src/pages/Worker/Card/WorkerDescriptorProxy.vue';
import { toDateTimeFormat } from 'src/filters/date';
+import VnTable from 'src/components/VnTable/VnTable.vue';
+import { dashIfEmpty } from 'src/filters';
+import CustomerSamplesCreate from '../components/CustomerSamplesCreate.vue';
const { t } = useI18n();
const route = useRoute();
const router = useRouter();
-const rows = ref([]);
-
const filter = {
include: [
{ relation: 'type', scope: { fields: ['code', 'description'] } },
@@ -26,105 +26,67 @@ const filter = {
limit: 20,
};
-const tableColumnComponents = {
- sent: {
- component: 'span',
- props: () => {},
- event: () => {},
- },
- description: {
- component: 'span',
- props: () => {},
- event: () => {},
- },
- worker: {
- component: QBtn,
- props: () => ({ flat: true, color: 'blue', noCaps: true }),
- event: () => {},
- },
- company: {
- component: 'span',
- props: () => {},
- event: () => {},
- },
-};
-
const columns = computed(() => [
{
align: 'left',
- field: 'created',
+ name: 'created',
label: t('Sent'),
- name: 'sent',
- format: (value) => toDateTimeFormat(value),
+ format: ({ created }) => toDateTimeFormat(created),
},
{
align: 'left',
- field: (value) => value.type.description,
+ format: (row) => row.type.description,
label: t('Description'),
name: 'description',
},
{
align: 'left',
- field: (value) => value.user.name,
label: t('Worker'),
name: 'worker',
},
{
align: 'left',
- field: (value) => value.company?.code,
+ format: ({ company }) => company?.code ?? dashIfEmpty(company),
label: t('Company'),
name: 'company',
},
]);
+const quasar = useQuasar();
const toCustomerSamplesCreate = () => {
- router.push({ name: 'CustomerSamplesCreate' });
+ quasar
+ .dialog({
+ component: CustomerSamplesCreate,
+ })
+ .onOk(() => tableRef.value.reload());
};
+const tableRef = ref();
- (rows = data)"
+
-
-
-
-
-
-
-
-
- {{ props.value }}
-
-
-
-
-
-
-
-
+ :columns="columns"
+ :pagination="{ rowsPerPage: 12 }"
+ :disable-option="{ card: true }"
+ :rows="rows"
+ class="full-width q-mt-md"
+ row-key="id"
+ :create="false"
+ :no-data-label="t('globals.noResults')"
+ >
+
+
+ {{ row.user?.name }}
+
+ {{ dashIfEmpty(row.user) }}
+
+
diff --git a/src/pages/Customer/Card/CustomerSummary.vue b/src/pages/Customer/Card/CustomerSummary.vue
index da50ba239..f049426e2 100644
--- a/src/pages/Customer/Card/CustomerSummary.vue
+++ b/src/pages/Customer/Card/CustomerSummary.vue
@@ -1,10 +1,11 @@
@@ -91,7 +92,13 @@ const creditWarning = computed(() => {
+ >
+
+
{
:url="`#/customer/${entityId}/fiscal-data`"
:text="t('customer.summary.fiscalData')"
/>
-
+
{
:label="t('customer.summary.isActive')"
:value="entity.isActive"
/>
-
-
{
:label="t('customer.summary.hasToInvoice')"
:value="entity.hasToInvoice"
/>
-
-
{
{
/>
-
+
{
{
@@ -231,7 +234,6 @@ const creditWarning = computed(() => {
:value="toCurrency(entity?.mana?.mana)"
/>
@@ -240,15 +242,14 @@ const creditWarning = computed(() => {
:value="toCurrency(entity?.averageInvoiced?.invoiced)"
/>
{
/>
-
@@ -301,7 +300,7 @@ const creditWarning = computed(() => {
:value="entity.recommendedCredit"
/>
-
+
diff --git a/src/pages/Customer/Card/CustomerUnpaid.vue b/src/pages/Customer/Card/CustomerUnpaid.vue
index 5b9a6cde2..ad00cbf59 100644
--- a/src/pages/Customer/Card/CustomerUnpaid.vue
+++ b/src/pages/Customer/Card/CustomerUnpaid.vue
@@ -151,7 +151,10 @@ watch(
clearable
type="number"
v-model="amount"
- />
+ autofocus
+ >
+ €
diff --git a/src/pages/Customer/CustomerCreate.vue b/src/pages/Customer/CustomerCreate.vue
index 041c92d17..79da63283 100644
--- a/src/pages/Customer/CustomerCreate.vue
+++ b/src/pages/Customer/CustomerCreate.vue
@@ -86,7 +86,7 @@ function handleLocation(data, location) {
handleLocation(data, location)"
>
diff --git a/src/pages/Customer/CustomerList.vue b/src/pages/Customer/CustomerList.vue
index 0dc7f09be..f6758bf4e 100644
--- a/src/pages/Customer/CustomerList.vue
+++ b/src/pages/Customer/CustomerList.vue
@@ -2,6 +2,7 @@
import { ref, computed, markRaw } from 'vue';
import { useI18n } from 'vue-i18n';
import { useRouter } from 'vue-router';
+import VnSelect from 'src/components/common/VnSelect.vue';
import VnTable from 'components/VnTable/VnTable.vue';
import VnLocation from 'src/components/common/VnLocation.vue';
import VnSearchbar from 'components/ui/VnSearchbar.vue';
@@ -69,7 +70,7 @@ const columns = computed(() => [
optionFilter: 'firstName',
useLike: false,
},
- create: true,
+ create: false,
columnField: {
component: null,
},
@@ -195,6 +196,8 @@ const columns = computed(() => [
component: 'select',
attrs: {
url: 'BusinessTypes',
+ fields: ['code', 'description'],
+ sortBy: 'description ASC ',
optionLabel: 'description',
optionValue: 'code',
},
@@ -353,12 +356,13 @@ const columns = computed(() => [
{
title: t('Client ticket list'),
icon: 'vn:ticket',
- action: redirectToCreateView,
+ action: redirectToTicketsList,
isPrimary: true,
},
{
title: t('components.smartCard.viewSummary'),
icon: 'preview',
+ isPrimary: true,
action: (row) => viewSummary(row.id, CustomerSummary),
},
],
@@ -366,11 +370,12 @@ const columns = computed(() => [
]);
const { viewSummary } = useSummaryDialog();
-const redirectToCreateView = (row) => {
+const redirectToTicketsList = (row) => {
router.push({
name: 'TicketList',
+
query: {
- params: JSON.stringify({
+ table: JSON.stringify({
clientFk: row.id,
}),
},
@@ -395,10 +400,10 @@ function handleLocation(data, location) {
+
+
+
+
+
+
+
+ {{ scope.opt?.name }}
+ {{ scope.opt?.nickname }},
+ {{ scope.opt?.code }}
+
+
+
+
+
handleLocation(data, location)"
/>
diff --git a/src/pages/Customer/components/CustomerAddressCreate.vue b/src/pages/Customer/components/CustomerAddressCreate.vue
index 30e4b21d0..7826c3579 100644
--- a/src/pages/Customer/components/CustomerAddressCreate.vue
+++ b/src/pages/Customer/components/CustomerAddressCreate.vue
@@ -57,12 +57,12 @@ function handleLocation(data, location) {
- (agencyModes = data)"
auto-load
url="AgencyModes/isActive"
/>
- (incoterms = data)" auto-load url="Incoterms" />
+ (incoterms = data)" auto-load url="Incoterms" />
handleLocation(data, location)"
/>
diff --git a/src/pages/Customer/components/CustomerAddressEdit.vue b/src/pages/Customer/components/CustomerAddressEdit.vue
index 7a4c44014..0aa46f85d 100644
--- a/src/pages/Customer/components/CustomerAddressEdit.vue
+++ b/src/pages/Customer/components/CustomerAddressEdit.vue
@@ -113,18 +113,18 @@ function handleLocation(data, location) {
- (agencyModes = data)"
auto-load
url="AgencyModes/isActive"
/>
- (incoterms = data)" auto-load url="Incoterms" />
- (incoterms = data)" auto-load url="Incoterms" />
+ (customsAgents = data)"
auto-load
url="CustomsAgents"
/>
-
+
handleLocation(data, location)"
>
diff --git a/src/pages/Customer/components/CustomerCreditContractsCreate.vue b/src/pages/Customer/components/CustomerCreditContractsCreate.vue
index c4434e870..c25e59e1a 100644
--- a/src/pages/Customer/components/CustomerCreditContractsCreate.vue
+++ b/src/pages/Customer/components/CustomerCreditContractsCreate.vue
@@ -1,5 +1,5 @@
- (rows = data)"
- auto-load
+
-
-
-
-
-
-
-
- {{ props.value }}
-
-
-
-
-
-
-
-
- {{ t('globals.noResults') }}
-
+ ref="tableRef"
+ data-key="creditInsurances"
+ :filter="filter"
+ :columns="columns"
+ :right-search="false"
+ :is-editable="false"
+ :use-model="true"
+ :column-search="false"
+ :disable-option="{ card: true }"
+ auto-load
+ >
diff --git a/src/pages/Customer/components/CustomerFileManagementCreate.vue b/src/pages/Customer/components/CustomerFileManagementCreate.vue
index 7c15e0b71..f33a47bcc 100644
--- a/src/pages/Customer/components/CustomerFileManagementCreate.vue
+++ b/src/pages/Customer/components/CustomerFileManagementCreate.vue
@@ -83,35 +83,35 @@ const toCustomerFileManagement = () => {
- (client = data)"
auto-load
:url="`Clients/${route.params.id}/getCard`"
/>
- (findOne = data)"
auto-load
url="DmsTypes/findOne"
/>
- (allowedContentTypes = data)"
auto-load
url="DmsContainers/allowedContentTypes"
/>
- (optionsCompanies = data)"
auto-load
url="Companies"
/>
- (optionsWarehouses = data)"
auto-load
url="Warehouses"
/>
- (optionsDmsTypes = data)"
auto-load
diff --git a/src/pages/Customer/components/CustomerFileManagementEdit.vue b/src/pages/Customer/components/CustomerFileManagementEdit.vue
index 80eaa44f9..107f41330 100644
--- a/src/pages/Customer/components/CustomerFileManagementEdit.vue
+++ b/src/pages/Customer/components/CustomerFileManagementEdit.vue
@@ -69,25 +69,25 @@ const toCustomerFileManagement = () => {
-
-
+ (allowedContentTypes = data)"
auto-load
url="DmsContainers/allowedContentTypes"
/>
- (optionsCompanies = data)"
auto-load
url="Companies"
/>
- (optionsWarehouses = data)"
auto-load
url="Warehouses"
/>
- (optionsDmsTypes = data)"
auto-load
diff --git a/src/pages/Customer/components/CustomerSamplesCreate.vue b/src/pages/Customer/components/CustomerSamplesCreate.vue
index 0470dc176..3c9eb856b 100644
--- a/src/pages/Customer/components/CustomerSamplesCreate.vue
+++ b/src/pages/Customer/components/CustomerSamplesCreate.vue
@@ -1,10 +1,11 @@
-
-
- (optionsCompanies = data)"
+ @on-fetch="(data) => (companies = data)"
auto-load
url="Companies"
/>
- (optionsSamplesVisible = data)"
auto-load
url="Samples/visible"
/>
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
{
{
{
required="true"
v-model="initialData.from"
/>
-
-
-
-
-
+
+
+
es:
+ New sample: Crear plantilla
Sample: Plantilla
Recipient: Destinatario
Reply to: Responder a
diff --git a/src/pages/Customer/components/CustomerSummaryTable.vue b/src/pages/Customer/components/CustomerSummaryTable.vue
index dc9969b61..374769a57 100644
--- a/src/pages/Customer/components/CustomerSummaryTable.vue
+++ b/src/pages/Customer/components/CustomerSummaryTable.vue
@@ -1,22 +1,25 @@
- (rows = data)"
- auto-load
+ :right-search="false"
+ :column-search="false"
url="Tickets"
- />
-
-
-
-
-
-
-
-
- {{ props.value }}
-
-
-
-
- {{ props.value }}
-
-
-
-
- {{ props.value }}
-
-
-
-
- {{ toCurrency(props.value) }}
-
- {{ toCurrency(props.value) }}
-
-
-
-
-
-
-
-
-
+ :columns="columns"
+ search-url="tickets"
+ :without-header="true"
+ auto-load
+ order="shipped DESC, id"
+ :disable-option="{ card: true, table: true }"
+ limit="5"
+ class="full-width"
+ :disable-infinite-scroll="true"
+ >
+
+
+ {{ row.nickname }}
+
+
+
+
+
+
+ {{ row.routeFk }}
+
+
+
+
+
+ {{ toCurrency(row.totalWithVat) }}
+
+ {{ toCurrency(row.totalWithVat) }}
+
+
+
+
+ {{ row.invoiceOut.ref }}
+
+
+
+
+ {{ row?.ticketState?.state.name }}
+
+ {{ row?.ticketState?.state.name }}
+
+
+
+ {{ toDateFormat(row.shipped) }}
+
+ {{ toDateFormat(row.shipped) }}
+
+
diff --git a/src/pages/Customer/components/CustomerSummaryTableActions.vue b/src/pages/Customer/components/CustomerSummaryTableActions.vue
deleted file mode 100644
index 6e9038374..000000000
--- a/src/pages/Customer/components/CustomerSummaryTableActions.vue
+++ /dev/null
@@ -1,44 +0,0 @@
-
-
-
-
-
-
- {{ t('Go to lines') }}
-
-
-
-
- {{ t('Preview') }}
-
-
-
-
-
-
-es:
- Go to lines: Ir a lineas
- Preview: Vista previa
-
diff --git a/src/pages/Customer/locale/en.yml b/src/pages/Customer/locale/en.yml
index 6eb7cfa85..545c3f274 100644
--- a/src/pages/Customer/locale/en.yml
+++ b/src/pages/Customer/locale/en.yml
@@ -2,3 +2,135 @@ customerFilter:
filter:
name: Name
socialName: Social name
+customer:
+ list:
+ phone: Phone
+ email: Email
+ customerOrders: Display customer orders
+ moreOptions: More options
+ card:
+ customerList: Customer list
+ customerId: Claim ID
+ salesPerson: Sales person
+ credit: Credit
+ risk: Risk
+ securedCredit: Secured credit
+ payMethod: Pay method
+ debt: Debt
+ isFrozen: Customer frozen
+ hasDebt: Customer has debt
+ isDisabled: Customer inactive
+ notChecked: Customer no checked
+ webAccountInactive: Web account inactive
+ noWebAccess: Web access is disabled
+ businessType: Business type
+ passwordRequirements: 'The password must have at least { length } length characters, {nAlpha} alphabetic characters, {nUpper} capital letters, {nDigits} digits and {nPunct} symbols (Ex: $%&.)\n'
+ businessTypeFk: Business type
+ summary:
+ basicData: Basic data
+ fiscalAddress: Fiscal address
+ fiscalData: Fiscal data
+ billingData: Billing data
+ consignee: Default consignee
+ businessData: Business data
+ financialData: Financial data
+ customerId: Customer ID
+ name: Name
+ contact: Contact
+ phone: Phone
+ mobile: Mobile
+ email: Email
+ salesPerson: Sales person
+ contactChannel: Contact channel
+ socialName: Social name
+ fiscalId: Fiscal ID
+ postcode: Postcode
+ province: Province
+ country: Country
+ street: Address
+ isEqualizated: Is equalizated
+ isActive: Is active
+ invoiceByAddress: Invoice by address
+ verifiedData: Verified data
+ hasToInvoice: Has to invoice
+ notifyByEmail: Notify by email
+ vies: VIES
+ payMethod: Pay method
+ bankAccount: Bank account
+ dueDay: Due day
+ hasLcr: Has LCR
+ hasCoreVnl: Has core VNL
+ hasB2BVnl: Has B2B VNL
+ addressName: Address name
+ addressCity: City
+ addressStreet: Street
+ username: Username
+ webAccess: Web access
+ totalGreuge: Total greuge
+ mana: Mana
+ priceIncreasingRate: Price increasing rate
+ averageInvoiced: Average invoiced
+ claimRate: Claming rate
+ payMethodFk: Billing data
+ risk: Risk
+ maximumRisk: Solunion's maximum risk
+ riskInfo: Invoices minus payments plus orders not yet invoiced
+ credit: Credit
+ creditInfo: Company's maximum risk
+ securedCredit: Secured credit
+ securedCreditInfo: Solunion's maximum risk
+ balance: Balance
+ balanceInfo: Invoices minus payments
+ balanceDue: Balance due
+ balanceDueInfo: Deviated invoices minus payments
+ recoverySince: Recovery since
+ businessType: Business Type
+ city: City
+ descriptorInfo: Invoices minus payments plus orders not yet
+ rating: Rating
+ recommendCredit: Recommended credit
+ goToLines: Go to lines
+ basicData:
+ socialName: Fiscal name
+ businessType: Business type
+ contact: Contact
+ youCanSaveMultipleEmails: You can save multiple emails
+ email: Email
+ phone: Phone
+ mobile: Mobile
+ salesPerson: Sales person
+ contactChannel: Contact channel
+ previousClient: Previous client
+ extendedList:
+ tableVisibleColumns:
+ id: Identifier
+ name: Name
+ socialName: Social name
+ fi: Tax number
+ salesPersonFk: Salesperson
+ credit: Credit
+ creditInsurance: Credit insurance
+ phone: Phone
+ mobile: Mobile
+ street: Street
+ countryFk: Country
+ provinceFk: Province
+ city: City
+ postcode: Postcode
+ email: Email
+ created: Created
+ businessTypeFk: Business type
+ payMethodFk: Billing data
+ sageTaxTypeFk: Sage tax type
+ sageTransactionTypeFk: Sage tr. type
+ isActive: Active
+ isVies: Vies
+ isTaxDataChecked: Verified data
+ isEqualizated: Is equalizated
+ isFreezed: Freezed
+ hasToInvoice: Invoice
+ hasToInvoiceByAddress: Invoice by address
+ isToBeMailed: Mailing
+ hasLcr: Received LCR
+ hasCoreVnl: VNL core received
+ hasSepaVnl: VNL B2B received
diff --git a/src/pages/Customer/locale/es.yml b/src/pages/Customer/locale/es.yml
index 111696f21..4fcbe3fa2 100644
--- a/src/pages/Customer/locale/es.yml
+++ b/src/pages/Customer/locale/es.yml
@@ -4,3 +4,134 @@ customerFilter:
filter:
name: Nombre
socialName: Razón Social
+customer:
+ list:
+ phone: Teléfono
+ email: Email
+ customerOrders: Mostrar órdenes del cliente
+ moreOptions: Más opciones
+ card:
+ customerId: ID cliente
+ salesPerson: Comercial
+ credit: Crédito
+ risk: Riesgo
+ securedCredit: Crédito asegurado
+ payMethod: Método de pago
+ debt: Riesgo
+ isFrozen: Cliente congelado
+ hasDebt: Cliente con riesgo
+ isDisabled: Cliente inactivo
+ notChecked: Cliente no comprobado
+ webAccountInactive: Sin acceso web
+ noWebAccess: El acceso web está desactivado
+ businessType: Tipo de negocio
+ passwordRequirements: 'La contraseña debe tener al menos { length } caracteres de longitud, {nAlpha} caracteres alfabéticos, {nUpper} letras mayúsculas, {nDigits} dígitos y {nPunct} símbolos (Ej: $%&.)'
+ businessTypeFk: Tipo de negocio
+ summary:
+ basicData: Datos básicos
+ fiscalAddress: Dirección fiscal
+ fiscalData: Datos fiscales
+ billingData: Datos de facturación
+ consignee: Consignatario pred.
+ businessData: Datos comerciales
+ financialData: Datos financieros
+ customerId: ID cliente
+ name: Nombre
+ contact: Contacto
+ phone: Teléfono
+ mobile: Móvil
+ email: Email
+ salesPerson: Comercial
+ contactChannel: Canal de contacto
+ socialName: Razón social
+ fiscalId: NIF/CIF
+ postcode: Código postal
+ province: Provincia
+ country: País
+ street: Calle
+ isEqualizated: Recargo de equivalencia
+ isActive: Activo
+ invoiceByAddress: Facturar por consignatario
+ verifiedData: Datos verificados
+ hasToInvoice: Facturar
+ notifyByEmail: Notificar por email
+ vies: VIES
+ payMethod: Método de pago
+ bankAccount: Cuenta bancaria
+ dueDay: Día de pago
+ hasLcr: Recibido LCR
+ hasCoreVnl: Recibido core VNL
+ hasB2BVnl: Recibido B2B VNL
+ addressName: Nombre de la dirección
+ addressCity: Ciudad
+ addressStreet: Calle
+ username: Usuario
+ webAccess: Acceso web
+ totalGreuge: Greuge total
+ mana: Maná
+ priceIncreasingRate: Ratio de incremento de precio
+ averageInvoiced: Facturación media
+ claimRate: Ratio de reclamaciones
+ maximumRisk: Riesgo máximo asumido por Solunion
+ payMethodFk: Forma de pago
+ risk: Riesgo
+ riskInfo: Facturas menos recibos mas pedidos sin facturar
+ credit: Crédito
+ creditInfo: Riesgo máximo asumido por la empresa
+ securedCredit: Crédito asegurado
+ securedCreditInfo: Riesgo máximo asumido por Solunion
+ balance: Balance
+ balanceInfo: Facturas menos recibos
+ balanceDue: Saldo vencido
+ balanceDueInfo: Facturas fuera de plazo menos recibos
+ recoverySince: Recobro desde
+ businessType: Tipo de negocio
+ city: Población
+ descriptorInfo: Facturas menos recibos mas pedidos sin facturar
+ rating: Clasificación
+ recommendCredit: Crédito recomendado
+ goToLines: Ir a líneas
+ basicData:
+ socialName: Nombre fiscal
+ businessType: Tipo de negocio
+ contact: Contacto
+ youCanSaveMultipleEmails: Puede guardar varios correos electrónicos encadenándolos mediante comas sin espacios{','} ejemplo{':'} user{'@'}dominio{'.'}com, user2{'@'}dominio{'.'}com siendo el primer correo electrónico el principal
+ email: Email
+ phone: Teléfono
+ mobile: Móvil
+ salesPerson: Comercial
+ contactChannel: Canal de contacto
+ previousClient: Cliente anterior
+ extendedList:
+ tableVisibleColumns:
+ id: Identificador
+ name: Nombre
+ socialName: Razón social
+ fi: NIF / CIF
+ salesPersonFk: Comercial
+ credit: Crédito
+ creditInsurance: Crédito asegurado
+ phone: Teléfono
+ mobile: Móvil
+ street: Dirección fiscal
+ countryFk: País
+ provinceFk: Provincia
+ city: Población
+ postcode: Código postal
+ email: Email
+ created: Fecha creación
+ businessTypeFk: Tipo de negocio
+ payMethodFk: Forma de pago
+ sageTaxTypeFk: Tipo de impuesto Sage
+ sageTransactionTypeFk: Tipo tr. sage
+ isActive: Activo
+ isVies: Vies
+ isTaxDataChecked: Datos comprobados
+ isEqualizated: Recargo de equivalencias
+ isFreezed: Congelado
+ hasToInvoice: Factura
+ hasToInvoiceByAddress: Factura por consigna
+ isToBeMailed: Env. emails
+ hasLcr: Recibido LCR
+ hasCoreVnl: Recibido core VNL
+ hasSepaVnl: Recibido B2B VNL
diff --git a/src/pages/Dashboard/DashboardMain.vue b/src/pages/Dashboard/DashboardMain.vue
index 6da39ce25..56054156a 100644
--- a/src/pages/Dashboard/DashboardMain.vue
+++ b/src/pages/Dashboard/DashboardMain.vue
@@ -55,6 +55,15 @@ const pinnedModules = computed(() => navigation.getPinnedModules());
>
{{ t(item.title) }}
+
+ {{ '(' + item.keyBinding + ')' }}
+
+ {{
+ 'Ctrl + Alt + ' +
+ item?.keyBinding?.toUpperCase()
+ }}
+
+
diff --git a/src/pages/Department/Card/DepartmentBasicData.vue b/src/pages/Department/Card/DepartmentBasicData.vue
index 4573f7b66..98abfd6b9 100644
--- a/src/pages/Department/Card/DepartmentBasicData.vue
+++ b/src/pages/Department/Card/DepartmentBasicData.vue
@@ -16,12 +16,12 @@ const workersOptions = ref([]);
const clientsOptions = ref([]);
- (workersOptions = data)"
auto-load
/>
- (clientsOptions = data)" auto-load />
+ (clientsOptions = data)" auto-load />
{
@@ -66,7 +65,10 @@ const tableColumnComponents = computed(() => ({
'map-options': true,
'use-input': true,
'hide-selected': true,
- options: packagingsOptions.value,
+ url: 'Packagings',
+ fields: ['id'],
+ where: { freightItemFk: true },
+ 'sort-by': 'id ASC',
dense: true,
},
event: getInputEvents,
@@ -304,13 +306,6 @@ const lockIconType = (groupingMode, mode) => {
- (packagingsOptions = data)"
- />
diff --git a/src/pages/InvoiceIn/Card/InvoiceInBasicData.vue b/src/pages/InvoiceIn/Card/InvoiceInBasicData.vue
index ede9af825..045517a3f 100644
--- a/src/pages/InvoiceIn/Card/InvoiceInBasicData.vue
+++ b/src/pages/InvoiceIn/Card/InvoiceInBasicData.vue
@@ -223,6 +223,10 @@ async function onSubmit() {
autofocus
/>
+
+
+
+
-
-
-
-
await setRectificative(to));
hasAny(['administrative']);
+const canEditProp = (props) =>
+ hasAny([{ model: 'InvoiceIn', props, accessType: 'WRITE' }]);
const isAgricultural = () => {
if (!config.value) return false;
@@ -283,7 +284,7 @@ const createInvoiceInCorrection = async () => {
{
{
{
{{ t('Delete invoice') }}
{
-
+
diff --git a/src/pages/InvoiceIn/Card/InvoiceInDueDay.vue b/src/pages/InvoiceIn/Card/InvoiceInDueDay.vue
index 62beb88ad..1593ea1be 100644
--- a/src/pages/InvoiceIn/Card/InvoiceInDueDay.vue
+++ b/src/pages/InvoiceIn/Card/InvoiceInDueDay.vue
@@ -5,10 +5,10 @@ import { useI18n } from 'vue-i18n';
import axios from 'axios';
import { toDate } from 'src/filters';
import { useArrayData } from 'src/composables/useArrayData';
+import { getTotal } from 'src/composables/getTotal';
import CrudModel from 'src/components/CrudModel.vue';
import FetchData from 'src/components/FetchData.vue';
import VnSelect from 'src/components/common/VnSelect.vue';
-import { toCurrency } from 'src/filters';
import useNotify from 'src/composables/useNotify.js';
import VnInputDate from 'src/components/common/VnInputDate.vue';
import VnInputNumber from 'src/components/common/VnInputNumber.vue';
@@ -72,7 +72,6 @@ async function insert() {
await invoiceInFormRef.value.reload();
notify(t('globals.dataSaved'), 'positive');
}
-const getTotalAmount = (rows) => rows.reduce((acc, { amount }) => acc + +amount, 0);
rows.reduce((acc, { amount }) => acc + +amount,
- {{ toCurrency(getTotalAmount(rows), currency) }}
+ {{ getTotal(rows, 'amount', { currency: 'default' }) }}
+
+
+
+ {{
+ getTotal(rows, 'foreignValue', {
+ currency: invoiceIn.currency.code,
+ })
+ }}
+
-
diff --git a/src/pages/InvoiceIn/Card/InvoiceInIntrastat.vue b/src/pages/InvoiceIn/Card/InvoiceInIntrastat.vue
index 481698832..717f30b7f 100644
--- a/src/pages/InvoiceIn/Card/InvoiceInIntrastat.vue
+++ b/src/pages/InvoiceIn/Card/InvoiceInIntrastat.vue
@@ -2,18 +2,15 @@
import { computed, ref } from 'vue';
import { useRoute } from 'vue-router';
import { useI18n } from 'vue-i18n';
-import { toCurrency } from 'src/filters';
+import { getTotal } from 'src/composables/getTotal';
import CrudModel from 'src/components/CrudModel.vue';
import FetchData from 'src/components/FetchData.vue';
import VnSelect from 'src/components/common/VnSelect.vue';
-import { useArrayData } from 'src/composables/useArrayData';
import VnInputNumber from 'src/components/common/VnInputNumber.vue';
const { t } = useI18n();
const route = useRoute();
-const arrayData = useArrayData();
-const currency = computed(() => arrayData.store.data?.currency?.code);
const invoceInIntrastat = ref([]);
const rowsSelected = ref([]);
const countries = ref([]);
@@ -72,9 +69,6 @@ const columns = computed(() => [
},
]);
-const getTotal = (data, key) =>
- data.reduce((acc, cur) => acc + +String(cur[key] || 0).replace(',', '.'), 0);
-
const formatOpt = (row, { model, options }, prop) => {
const obj = row[model];
const option = options.find(({ id }) => id == obj);
@@ -154,7 +148,7 @@ const formatOpt = (row, { model, options }, prop) => {
- {{ toCurrency(getTotal(rows, 'amount'), currency) }}
+ {{ getTotal(rows, 'amount', { currency: 'default' }) }}
{{ getTotal(rows, 'net') }}
diff --git a/src/pages/InvoiceIn/Card/InvoiceInSummary.vue b/src/pages/InvoiceIn/Card/InvoiceInSummary.vue
index 644b472e2..bf2e7db48 100644
--- a/src/pages/InvoiceIn/Card/InvoiceInSummary.vue
+++ b/src/pages/InvoiceIn/Card/InvoiceInSummary.vue
@@ -35,7 +35,7 @@ const vatColumns = ref([
name: 'landed',
label: 'invoiceIn.summary.taxableBase',
field: (row) => row.taxableBase,
- format: (value) => toCurrency(value, currency.value),
+ format: (value) => toCurrency(value),
sortable: true,
align: 'left',
},
@@ -64,7 +64,7 @@ const vatColumns = ref([
name: 'rate',
label: 'invoiceIn.summary.rate',
field: (row) => taxRate(row.taxableBase, row.taxTypeSage?.rate),
- format: (value) => toCurrency(value, currency.value),
+ format: (value) => toCurrency(value),
sortable: true,
align: 'left',
},
@@ -72,7 +72,7 @@ const vatColumns = ref([
name: 'currency',
label: 'invoiceIn.summary.currency',
field: (row) => row.foreignValue,
- format: (value) => value,
+ format: (val) => val && toCurrency(val, currency.value),
sortable: true,
align: 'left',
},
@@ -97,7 +97,7 @@ const dueDayColumns = ref([
name: 'amount',
label: 'invoiceIn.summary.amount',
field: (row) => row.amount,
- format: (value) => toCurrency(value, currency.value),
+ format: (value) => toCurrency(value),
sortable: true,
align: 'left',
},
@@ -105,7 +105,7 @@ const dueDayColumns = ref([
name: 'landed',
label: 'invoiceIn.summary.foreignValue',
field: (row) => row.foreignValue,
- format: (value) => value,
+ format: (val) => val && toCurrency(val, currency.value),
sortable: true,
align: 'left',
},
@@ -124,7 +124,7 @@ const intrastatColumns = ref([
{
name: 'amount',
label: 'invoiceIn.summary.amount',
- field: (row) => toCurrency(row.amount, currency.value),
+ field: (row) => toCurrency(row.amount),
sortable: true,
align: 'left',
},
@@ -179,7 +179,6 @@ const getTotalTax = (tax) =>
const getLink = (param) => `#/invoice-in/${entityId.value}/${param}`;
-
`#/invoice-in/${entityId.value}/${param}`;
:label="t('invoiceIn.summary.currency')"
:value="entity.currency?.code"
/>
-
+
@@ -293,12 +289,9 @@ const getLink = (param) => `#/invoice-in/${entityId.value}/${param}`;
-
+
`#/invoice-in/${entityId.value}/${param}`;
: t('invoiceIn.summary.dueTotal')
"
>
- {{ toCurrency(entity.totals.totalDueDay, currency) }}
+ {{ toCurrency(entity.totals.totalDueDay) }}
@@ -350,15 +343,17 @@ const getLink = (param) => `#/invoice-in/${entityId.value}/${param}`;
+ {{ toCurrency(entity.totals.totalTaxableBase) }}
+
+
+ {{ toCurrency(getTotalTax(entity.invoiceInTax)) }}
{{
- toCurrency(entity.totals.totalTaxableBase, currency)
+ entity.totals.totalTaxableBaseForeignValue &&
+ toCurrency(
+ entity.totals.totalTaxableBaseForeignValue,
+ currency
+ )
}}
-
-
- {{
- toCurrency(getTotalTax(entity.invoiceInTax, currency))
- }}
-
@@ -384,9 +379,17 @@ const getLink = (param) => `#/invoice-in/${entityId.value}/${param}`;
- {{ toCurrency(entity.totals.totalDueDay, currency) }}
+ {{ toCurrency(entity.totals.totalDueDay) }}
+
+
+ {{
+ entity.totals.totalDueDayForeignValue &&
+ toCurrency(
+ entity.totals.totalDueDayForeignValue,
+ currency
+ )
+ }}
-
@@ -421,7 +424,7 @@ const getLink = (param) => `#/invoice-in/${entityId.value}/${param}`;
- {{ toCurrency(intrastatTotals.amount, currency) }}
+ {{ toCurrency(intrastatTotals.amount) }}
{{ intrastatTotals.net }}
{{ intrastatTotals.stems }}
diff --git a/src/pages/InvoiceIn/Card/InvoiceInVat.vue b/src/pages/InvoiceIn/Card/InvoiceInVat.vue
index 34b0b64bd..d44880937 100644
--- a/src/pages/InvoiceIn/Card/InvoiceInVat.vue
+++ b/src/pages/InvoiceIn/Card/InvoiceInVat.vue
@@ -2,18 +2,17 @@
import { ref, computed } from 'vue';
import { useRoute } from 'vue-router';
import { useI18n } from 'vue-i18n';
-import { useQuasar } from 'quasar';
-import axios from 'axios';
import { useArrayData } from 'src/composables/useArrayData';
+import { getTotal } from 'src/composables/getTotal';
import { toCurrency } from 'src/filters';
import FetchData from 'src/components/FetchData.vue';
import VnSelect from 'src/components/common/VnSelect.vue';
import CrudModel from 'src/components/CrudModel.vue';
-import VnInput from 'src/components/common/VnInput.vue';
import VnInputNumber from 'src/components/common/VnInputNumber.vue';
+import VnSelectDialog from 'src/components/common/VnSelectDialog.vue';
+import CreateNewExpenseForm from 'src/components/CreateNewExpenseForm.vue';
const { t } = useI18n();
-const quasar = useQuasar();
const arrayData = useArrayData();
const invoiceIn = computed(() => arrayData.store.data);
@@ -23,15 +22,7 @@ const expenses = ref([]);
const sageTaxTypes = ref([]);
const sageTransactionTypes = ref([]);
const rowsSelected = ref([]);
-const newExpense = ref({
- code: undefined,
- isWithheld: false,
- description: undefined,
-});
-
const invoiceInFormRef = ref();
-const expensesRef = ref();
-const newExpenseRef = ref();
defineProps({
actionIcon: {
@@ -56,7 +47,7 @@ const columns = computed(() => [
{
name: 'taxablebase',
label: t('Taxable base'),
- field: (row) => toCurrency(row.taxableBase, currency.value),
+ field: (row) => row.taxableBase,
model: 'taxableBase',
sortable: true,
tabIndex: 2,
@@ -91,7 +82,7 @@ const columns = computed(() => [
label: t('Rate'),
sortable: true,
tabIndex: 5,
- field: (row) => toCurrency(taxRate(row, row.taxTypeSageFk), currency.value),
+ field: (row) => taxRate(row, row.taxTypeSageFk),
align: 'left',
},
{
@@ -132,40 +123,6 @@ function taxRate(invoiceInTax) {
return (taxTypeSage / 100) * taxableBase;
}
-async function addExpense() {
- try {
- if (!newExpense.value.code) throw new Error(t(`The code can't be empty`));
- if (isNaN(newExpense.value.code))
- throw new Error(t(`The code have to be a number`));
- if (!newExpense.value.description)
- throw new Error(t(`The description can't be empty`));
-
- const data = [
- {
- id: newExpense.value.code,
- isWithheld: newExpense.value.isWithheld,
- name: newExpense.value.description,
- },
- ];
-
- await axios.post(`Expenses`, data);
- await expensesRef.value.fetch();
- quasar.notify({
- type: 'positive',
- message: t('globals.dataSaved'),
- });
- newExpenseRef.value.hide();
- } catch (error) {
- quasar.notify({
- type: 'negative',
- message: t(`${error.message}`),
- });
- }
-}
-const getTotalTaxableBase = (rows) =>
- rows.reduce((acc, { taxableBase }) => acc + +(taxableBase || 0), 0);
-const getTotalRate = (rows) => rows.reduce((acc, cur) => acc + +taxRate(cur), 0);
-
const formatOpt = (row, { model, options }, prop) => {
const obj = row[model];
const option = options.find(({ id }) => id == obj);
@@ -207,37 +164,25 @@ const formatOpt = (row, { model, options }, prop) => {
>
-
{{ `${scope.opt.id}: ${scope.opt.name}` }}
-
-
+
-
-
- {{ t('Create expense') }}
-
-
-
+
@@ -325,12 +270,24 @@ const formatOpt = (row, { model, options }, prop) => {
- {{ toCurrency(getTotalTaxableBase(rows), currency) }}
+ {{ getTotal(rows, 'taxableBase', { currency: 'default' }) }}
- {{ toCurrency(getTotalRate(rows), currency) }}
-
+
+ {{
+ getTotal(rows, null, { cb: taxRate, currency: 'default' })
+ }}
+
+
+ {{
+ getTotal(rows, 'foreignValue', {
+ currency: invoiceIn.currency.code,
+ })
+ }}
+
+
@@ -342,7 +299,7 @@ const formatOpt = (row, { model, options }, prop) => {
- {
option-value="id"
option-label="name"
:filter-options="['id', 'name']"
+ :tooltip="t('Create a new expense')"
>
{{ `${scope.opt.id}: ${scope.opt.name}` }}
-
+
+
+
+
{
-
-
-
-
-
-
- {{ t('New expense') }}
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
{
size="lg"
round
@click="invoiceInFormRef.insert()"
- />
+ >
+ {{ t('Add tax') }}
+
@@ -524,18 +449,11 @@ const formatOpt = (row, { model, options }, prop) => {
es:
Expense: Gasto
- Create expense: Crear gasto
+ Create a new expense: Crear nuevo gasto
Add tax: Crear gasto
Taxable base: Base imp.
Sage tax: Sage iva
Sage transaction: Sage transacción
Rate: Tasa
Foreign value: Divisa
- New expense: Nuevo gasto
- Code: Código
- It's a withholding: Es una retención
- Descripction: Descripción
- The code can't be empty: El código no puede estar vacío
- The description can't be empty: La descripción no puede estar vacía
- The code have to be a number: El código debe ser un número.
diff --git a/src/pages/InvoiceIn/InvoiceInFilter.vue b/src/pages/InvoiceIn/InvoiceInFilter.vue
index 2f87c2b2e..bf4e023a9 100644
--- a/src/pages/InvoiceIn/InvoiceInFilter.vue
+++ b/src/pages/InvoiceIn/InvoiceInFilter.vue
@@ -28,6 +28,16 @@ const activities = ref([]);
+
+
+
+
+
+
+
+
+
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
@@ -179,6 +154,7 @@ en:
correctedFk: Rectified
issued: Issued
to: To
+ from: From
awbCode: AWB
correctingFk: Rectificative
supplierActivityFk: Supplier activity
@@ -201,6 +177,8 @@ es:
correctedFk: Rectificada
correctingFk: Rectificativa
supplierActivityFk: Actividad proveedor
+ from: Desde
+ to: Hasta
From: Desde
To: Hasta
Amount: Importe
diff --git a/src/pages/InvoiceIn/InvoiceInList.vue b/src/pages/InvoiceIn/InvoiceInList.vue
index 234cfb50f..0cad09378 100644
--- a/src/pages/InvoiceIn/InvoiceInList.vue
+++ b/src/pages/InvoiceIn/InvoiceInList.vue
@@ -47,12 +47,6 @@ const cols = computed(() => [
name: 'supplierRef',
label: t('invoiceIn.list.supplierRef'),
},
-
- {
- align: 'left',
- name: 'serialNumber',
- label: t('invoiceIn.list.serialNumber'),
- },
{
align: 'left',
name: 'serial',
@@ -141,7 +135,7 @@ const cols = computed(() => [
v-model="data.supplierFk"
url="Suppliers"
:fields="['id', 'nickname']"
- :label="t('Supplier')"
+ :label="t('globals.supplier')"
option-value="id"
option-label="nickname"
:filter-options="['id', 'name']"
@@ -162,7 +156,7 @@ const cols = computed(() => [
/>
route.name === 'InvoiceInCard');
+ const corrective = card.children.find(
+ (route) => route.name === 'InvoiceInCorrective'
+ );
+
+ corrective.meta.hidden = !(
+ await axios.get('InvoiceInCorrections', {
+ params: { filter: { where: { correctingFk: route.params.id } } },
+ })
+ ).data.length;
+}
diff --git a/src/pages/InvoiceIn/locale/en.yml b/src/pages/InvoiceIn/locale/en.yml
new file mode 100644
index 000000000..824fd6e12
--- /dev/null
+++ b/src/pages/InvoiceIn/locale/en.yml
@@ -0,0 +1,49 @@
+invoiceIn:
+ serial: Serial
+ list:
+ ref: Reference
+ supplier: Supplier
+ supplierRef: Supplier ref.
+ serial: Serial
+ file: File
+ issued: Issued
+ isBooked: Is booked
+ awb: AWB
+ amount: Amount
+ card:
+ issued: Issued
+ amount: Amount
+ client: Client
+ company: Company
+ customerCard: Customer card
+ ticketList: Ticket List
+ vat: Vat
+ dueDay: Due day
+ intrastat: Intrastat
+ summary:
+ supplier: Supplier
+ supplierRef: Supplier ref.
+ currency: Currency
+ issued: Expedition date
+ operated: Operation date
+ bookEntried: Entry date
+ bookedDate: Booked date
+ sage: Sage withholding
+ vat: Undeductible VAT
+ company: Company
+ booked: Booked
+ expense: Expense
+ taxableBase: Taxable base
+ rate: Rate
+ sageVat: Sage vat
+ sageTransaction: Sage transaction
+ dueDay: Date
+ bank: Bank
+ amount: Amount
+ foreignValue: Foreign value
+ dueTotal: Due day
+ noMatch: Do not match
+ code: Code
+ net: Net
+ stems: Stems
+ country: Country
diff --git a/src/pages/InvoiceIn/locale/es.yml b/src/pages/InvoiceIn/locale/es.yml
new file mode 100644
index 000000000..944708364
--- /dev/null
+++ b/src/pages/InvoiceIn/locale/es.yml
@@ -0,0 +1,47 @@
+invoiceIn:
+ serial: Serie
+ list:
+ ref: Referencia
+ supplier: Proveedor
+ supplierRef: Ref. proveedor
+ shortIssued: F. emisión
+ file: Fichero
+ issued: Fecha emisión
+ isBooked: Conciliada
+ awb: AWB
+ amount: Importe
+ card:
+ issued: Fecha emisión
+ amount: Importe
+ client: Cliente
+ company: Empresa
+ customerCard: Ficha del cliente
+ ticketList: Listado de tickets
+ vat: Iva
+ dueDay: Fecha de vencimiento
+ summary:
+ supplier: Proveedor
+ supplierRef: Ref. proveedor
+ currency: Divisa
+ docNumber: Número documento
+ issued: Fecha de expedición
+ operated: Fecha operación
+ bookEntried: Fecha asiento
+ bookedDate: Fecha contable
+ sage: Retención sage
+ vat: Iva no deducible
+ company: Empresa
+ booked: Contabilizada
+ expense: Gasto
+ taxableBase: Base imp.
+ rate: Tasa
+ sageTransaction: Sage transación
+ dueDay: Fecha
+ bank: Caja
+ amount: Importe
+ foreignValue: Divisa
+ dueTotal: Vencimiento
+ code: Código
+ net: Neto
+ stems: Tallos
+ country: País
diff --git a/src/pages/Item/Card/ItemDescriptor.vue b/src/pages/Item/Card/ItemDescriptor.vue
index 8381f0624..baac0c608 100644
--- a/src/pages/Item/Card/ItemDescriptor.vue
+++ b/src/pages/Item/Card/ItemDescriptor.vue
@@ -10,8 +10,6 @@ import WorkerDescriptorProxy from 'src/pages/Worker/Card/WorkerDescriptorProxy.v
import VnConfirm from 'components/ui/VnConfirm.vue';
import RegularizeStockForm from 'components/RegularizeStockForm.vue';
import ItemDescriptorImage from 'src/pages/Item/Card/ItemDescriptorImage.vue';
-
-import { useState } from 'src/composables/useState';
import useCardDescription from 'src/composables/useCardDescription';
import { getUrl } from 'src/composables/getUrl';
import axios from 'axios';
@@ -35,58 +33,69 @@ const $props = defineProps({
type: Number,
default: null,
},
+ warehouseFk: {
+ type: Number,
+ default: null,
+ },
});
const quasar = useQuasar();
const route = useRoute();
const router = useRouter();
const { t } = useI18n();
-const state = useState();
-const user = state.getUser();
-
+const warehouseConfig = ref(null);
const entityId = computed(() => {
return $props.id || route.params.id;
});
+
const regularizeStockFormDialog = ref(null);
const available = ref(null);
const visible = ref(null);
-const _warehouseFk = ref(null);
const salixUrl = ref();
-const warehouseFk = computed({
- get() {
- return _warehouseFk.value;
- },
- set(val) {
- _warehouseFk.value = val;
- if (val) updateStock();
- },
-});
onMounted(async () => {
- warehouseFk.value = user.value.warehouseFk;
salixUrl.value = await getUrl('');
+ await getItemConfigs();
+ await updateStock();
});
const data = ref(useCardDescription());
-const setData = (entity) => {
- if (!entity) return;
- data.value = useCardDescription(entity.name, entity.id);
+const setData = async (entity) => {
+ try {
+ if (!entity) return;
+ data.value = useCardDescription(entity.name, entity.id);
+ await updateStock();
+ } catch (err) {
+ console.error('Error item');
+ }
};
+const getItemConfigs = async () => {
+ try {
+ const { data } = await axios.get('ItemConfigs/findOne');
+ if (!data) return;
+ return (warehouseConfig.value = data.warehouseFk);
+ } catch (err) {
+ console.error('Error item');
+ }
+};
const updateStock = async () => {
try {
available.value = null;
visible.value = null;
const params = {
- warehouseFk: warehouseFk.value,
+ warehouseFk: $props.warehouseFk,
dated: $props.dated,
};
+ await getItemConfigs();
+ if (!params.warehouseFk) {
+ params.warehouseFk = warehouseConfig.value;
+ }
const { data } = await axios.get(`Items/${entityId.value}/getVisibleAvailable`, {
params,
});
-
available.value = data.available;
visible.value = data.visible;
} catch (err) {
diff --git a/src/pages/Item/Card/ItemDescriptorImage.vue b/src/pages/Item/Card/ItemDescriptorImage.vue
index d83f534b8..a4ef22ce3 100644
--- a/src/pages/Item/Card/ItemDescriptorImage.vue
+++ b/src/pages/Item/Card/ItemDescriptorImage.vue
@@ -47,8 +47,11 @@ const getWarehouseName = async (warehouseFk) => {
const filter = {
where: { id: warehouseFk },
};
-
- const { data } = await axios.get('Warehouses/findOne', { filter });
+ const { data } = await axios.get('Warehouses/findOne', {
+ params: {
+ filter: JSON.stringify(filter),
+ },
+ });
if (!data) return;
warehouseName.value = data.name;
};
diff --git a/src/pages/Item/Card/ItemDescriptorProxy.vue b/src/pages/Item/Card/ItemDescriptorProxy.vue
index 2b7b39a65..2ffc9080f 100644
--- a/src/pages/Item/Card/ItemDescriptorProxy.vue
+++ b/src/pages/Item/Card/ItemDescriptorProxy.vue
@@ -15,6 +15,10 @@ const $props = defineProps({
type: Number,
default: null,
},
+ warehouseFk: {
+ type: Number,
+ default: null,
+ },
});
@@ -26,6 +30,7 @@ const $props = defineProps({
:summary="ItemSummary"
:dated="dated"
:sale-fk="saleFk"
+ :warehouse-fk="warehouseFk"
/>
diff --git a/src/pages/Item/Card/ItemSummary.vue b/src/pages/Item/Card/ItemSummary.vue
index 7af3e0fa0..7b6015c30 100644
--- a/src/pages/Item/Card/ItemSummary.vue
+++ b/src/pages/Item/Card/ItemSummary.vue
@@ -7,8 +7,7 @@ import CardSummary from 'components/ui/CardSummary.vue';
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 { useRole } from 'src/composables/useRole';
+import VnTitle from 'src/components/common/VnTitle.vue';
const $props = defineProps({
id: {
@@ -19,23 +18,10 @@ const $props = defineProps({
const route = useRoute();
const { t } = useI18n();
-const roleState = useRole();
const entityId = computed(() => $props.id || route.params.id);
-
-const isBuyer = computed(() => {
- return roleState.hasAny(['buyer']);
-});
-
-const isReplenisher = computed(() => {
- return roleState.hasAny(['replenisher']);
-});
-
-const isAdministrative = computed(() => {
- return roleState.hasAny(['administrative']);
-});
+const getUrl = (id, param) => `#/Item/${id}/${param}`;
-
{
data-key="ItemSummary"
>
-
+ class="header link--white"
+ icon="open_in_new"
+ flat
+ dense
+ round
+ />
{{ item.id }} - {{ item.name }}
@@ -65,15 +53,10 @@ const isAdministrative = computed(() => {
/>
-
+
@@ -104,15 +87,10 @@ const isAdministrative = computed(() => {
-
+
{
/>
-
+
{
/>
-
-
- {{ item.description }}
-
+
+
-
+
{
/>
-
+
{
/>
-
-
- {{ barcode.code }}
-
+
+
-
en:
Este artículo necesita una foto: Este artículo necesita una foto
diff --git a/src/pages/Item/ItemFixedPrice.vue b/src/pages/Item/ItemFixedPrice.vue
index 6b469d13a..d91b5189e 100644
--- a/src/pages/Item/ItemFixedPrice.vue
+++ b/src/pages/Item/ItemFixedPrice.vue
@@ -1,196 +1,190 @@
(warehousesOptions = data)"
auto-load
- @on-fetch="(data) => onWarehousesFetched(data)"
+ url="Warehouses"
+ :filter="{ fields: ['id', 'name'], order: 'name ASC', limit: 30 }"
/>
-
-
+
+
+
+ {{ t('Edit fixed price(s)') }}
+
+
+ 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 ASC']"
+ save-url="FixedPrices/crud"
+ :user-params="{ warehouseFk: user.warehouseFk }"
+ ref="tableRef"
+ dense
:columns="columns"
- row-key="id"
- selection="multiple"
+ default-mode="table"
+ auto-load
+ :is-editable="true"
+ :right-search="false"
+ :table="{
+ 'row-key': 'id',
+ selection: 'multiple',
+ }"
+ :crud-model="{
+ paginate: false,
+ }"
v-model:selected="rowsSelected"
- :pagination="{ rowsPerPage: 0 }"
- class="full-width q-mt-md"
- :no-data-label="t('globals.noResults')"
+ :row-click="saveOnRowChange"
+ :create-as-dialog="false"
+ :create="{
+ onDataSaved: handleOnDataSave,
+ }"
+ :use-model="true"
+ :disable-option="{ card: true }"
>
-
-
-
-
-
-
-
+
+
+
+
+ {{ scope }}
+
-
-
-
-
-
-
- #{{ scope.opt?.id }}
- {{ scope.opt?.name }}
-
-
-
-
-
+
+
+
+
+
+ #{{ scope.opt?.id }}
+ {{ scope.opt?.name }}
+
+
+
+
-
-
-
- {{ row.name }}
-
-
-
-
+
+
+ {{ row.name }}
+
+ {{ row.subName }}
+
+
-
-
-
- €
-
-
+
+
+ €
+
-
-
-
- €
-
-
+
+
+ €
+
-
+
-
+
+ >
+ €
+
-
-
-
-
+
+
-
-
-
-
+
+
-
-
-
-
+
+
-
-
- removePrice(row.id, rowIndex)
- )
- "
- >
-
- {{ t('Delete') }}
-
-
-
+
+ removePrice(row.id, rowIndex)
+ )
+ "
+ >
+
+ {{ t('globals.delete') }}
+
+
-
-
-
-
- {{ t('Add fixed price') }}
-
-
-
-
-
-
-
-
- {{ t('Edit fixed price(s)') }}
-
-
+
+
(stateStore.rightDrawer = false));
+
es:
Add fixed price: Añadir precio fijado
Edit fixed price(s): Editar precio(s) fijado(s)
- This row will be removed: Esta linea se eliminará
- Are you sure you want to continue?: ¿Seguro que quieres continuar?
- Delete: Eliminar
diff --git a/src/pages/Item/ItemFixedPriceFilter.vue b/src/pages/Item/ItemFixedPriceFilter.vue
index 6c847ece8..84eefaed3 100644
--- a/src/pages/Item/ItemFixedPriceFilter.vue
+++ b/src/pages/Item/ItemFixedPriceFilter.vue
@@ -9,18 +9,29 @@ import ItemsFilterPanel from 'src/components/ItemsFilterPanel.vue';
const { t } = useI18n();
-defineProps({
+const props = defineProps({
dataKey: {
type: String,
required: true,
},
- warehousesOptions: {
- type: Array,
- default: () => [],
- },
});
const itemTypeWorkersOptions = ref([]);
+const exprBuilder = (param, value) => {
+ switch (param) {
+ case 'name':
+ return { 'i.name': { like: `%${value}%` } };
+ case 'itemFk':
+ case 'warehouseFk':
+ case 'rate2':
+ case 'rate3':
+ param = `fp.${param}`;
+ return { [param]: value };
+ case 'minPrice':
+ param = `i.${param}`;
+ return { [param]: value };
+ }
+};
@@ -31,7 +42,7 @@ const itemTypeWorkersOptions = ref([]);
:filter="{ fields: ['id', 'nickname'], order: 'nickname ASC', limit: 30 }"
@on-fetch="(data) => (itemTypeWorkersOptions = data)"
/>
-
+
@@ -52,9 +63,11 @@ const itemTypeWorkersOptions = ref([]);
-
-
+
+
+
+
+import { useRoute, useRouter } from 'vue-router';
+import { onMounted, ref } from 'vue';
+import { useI18n } from 'vue-i18n';
+import axios from 'axios';
+import { useState } from 'composables/useState';
+import FormModelPopup from 'components/FormModelPopup.vue';
+import VnRow from 'components/ui/VnRow.vue';
+import VnSelect from 'components/common/VnSelect.vue';
+import VnInputDate from 'components/common/VnInputDate.vue';
+import { useDialogPluginComponent } from 'quasar';
+import { reactive } from 'vue';
+import FetchData from 'components/FetchData.vue';
+
+const { t } = useI18n();
+const route = useRoute();
+const state = useState();
+const ORDER_MODEL = 'order';
+
+const router = useRouter();
+const clientList = ref([]);
+const agencyList = ref([]);
+const addressList = ref([]);
+defineEmits(['confirm', ...useDialogPluginComponent.emits]);
+
+const fetchAddressList = async (addressId) => {
+ try {
+ const { data } = await axios.get('addresses', {
+ params: {
+ filter: JSON.stringify({
+ fields: ['id', 'nickname', 'street', 'city'],
+ where: { id: addressId },
+ }),
+ },
+ });
+ addressList.value = data;
+ if (addressList.value?.length === 1) {
+ state.get(ORDER_MODEL).addressId = addressList.value[0].id;
+ }
+ } catch (err) {
+ console.error(`Error fetching addresses`, err);
+ return err.response;
+ }
+};
+
+const fetchAgencyList = async (landed, addressFk) => {
+ if (!landed || !addressFk) {
+ return;
+ }
+ try {
+ const { data } = await axios.get('Agencies/landsThatDay', {
+ params: {
+ addressFk,
+ landed: new Date(landed).toISOString(),
+ },
+ });
+ agencyList.value = data;
+ } catch (err) {
+ console.error(`Error fetching agencies`, err);
+ return err.response;
+ }
+};
+
+// const fetchOrderDetails = (order) => {
+// fetchAddressList(order?.addressFk);
+// fetchAgencyList(order?.landed, order?.addressFk);
+// };
+const $props = defineProps({
+ clientFk: {
+ type: Number,
+ default: null,
+ },
+});
+const initialFormState = reactive({
+ active: true,
+ addressId: null,
+ clientFk: $props.clientFk,
+});
+// const orderMapper = (order) => {
+// return {
+// addressId: order.addressFk,
+// agencyModeId: order.agencyModeFk,
+// landed: new Date(order.landed).toISOString(),
+// };
+// };
+// const orderFilter = {
+// include: [
+// { relation: 'agencyMode', scope: { fields: ['name'] } },
+// {
+// relation: 'address',
+// scope: { fields: ['nickname'] },
+// },
+// { relation: 'rows', scope: { fields: ['id'] } },
+// {
+// relation: 'client',
+// scope: {
+// fields: [
+// 'salesPersonFk',
+// 'name',
+// 'isActive',
+// 'isFreezed',
+// 'isTaxDataChecked',
+// ],
+// include: {
+// relation: 'salesPersonUser',
+// scope: { fields: ['id', 'name'] },
+// },
+// },
+// },
+// ],
+// };
+
+const onClientChange = async (clientId = $props.clientFk) => {
+ try {
+ const { data } = await axios.get(`Clients/${clientId}`);
+ await fetchAddressList(data.defaultAddressFk);
+ } catch (error) {
+ console.error('Error al cambiar el cliente:', error);
+ }
+};
+
+async function onDataSaved(_, id) {
+ await router.push({ path: `/order/${id}/catalog` });
+}
+onMounted(async () => {
+ await onClientChange();
+});
+
+
+
+ (clientOptions = data)"
+ :filter="{ fields: ['id', 'name', 'defaultAddressFk'], order: 'id' }"
+ auto-load
+ />
+
+
+
+
+
+
+
+
+ {{ `${scope.opt.id}: ${scope.opt.name}` }}
+
+
+
+
+
+
+
+
+
+
+ {{
+ `${scope.opt.nickname}: ${scope.opt.street},${scope.opt.city}`
+ }}
+
+
+
+
+
+
+
+ fetchAgencyList(data.landed, data.addressId)
+ "
+ />
+
+
+
+
+
+
+
+
+
+
+ es:
+ No default address found for the client: No hay ninguna dirección asociada a este cliente.
+
diff --git a/src/pages/Order/Card/OrderDescriptorMenu.vue b/src/pages/Order/Card/OrderDescriptorMenu.vue
index 2e36aa3c5..2695da4e5 100644
--- a/src/pages/Order/Card/OrderDescriptorMenu.vue
+++ b/src/pages/Order/Card/OrderDescriptorMenu.vue
@@ -23,7 +23,7 @@ function confirmRemove() {
.dialog({
component: VnConfirm,
componentProps: {
- title: t('confirmDeletion'),
+ title: t('globals.confirmDeletion'),
message: t('confirmDeletionMessage'),
promise: remove,
},
@@ -52,12 +52,10 @@ async function remove() {
en:
deleteOrder: Delete order
- confirmDeletion: Confirm deletion
confirmDeletionMessage: Are you sure you want to delete this order?
es:
deleteOrder: Eliminar pedido
- confirmDeletion: Confirmar eliminación
confirmDeletionMessage: Seguro que quieres eliminar este pedido?
diff --git a/src/pages/Supplier/Card/SupplierAddressesCreate.vue b/src/pages/Supplier/Card/SupplierAddressesCreate.vue
index da6549a24..6e51ee94e 100644
--- a/src/pages/Supplier/Card/SupplierAddressesCreate.vue
+++ b/src/pages/Supplier/Card/SupplierAddressesCreate.vue
@@ -83,7 +83,7 @@ function handleLocation(data, location) {
handleLocation(data, location)"
>
diff --git a/src/pages/Supplier/Card/SupplierConsumptionFilter.vue b/src/pages/Supplier/Card/SupplierConsumptionFilter.vue
index 3fc61b15e..401bde8fa 100644
--- a/src/pages/Supplier/Card/SupplierConsumptionFilter.vue
+++ b/src/pages/Supplier/Card/SupplierConsumptionFilter.vue
@@ -1,56 +1,21 @@
- (buyersOptions = data)"
- auto-load
- />
- (itemTypesOptions = data)"
- auto-load
- />
- (itemCategoriesOptions = data)"
- auto-load
- />
-
+
{{ t(`params.${tag.label}`) }}:
@@ -82,7 +47,9 @@ const itemCategoriesOptions = ref([]);
:label="t('params.buyerId')"
v-model="params.buyerId"
@update:model-value="searchFn()"
- :options="buyersOptions"
+ url="TicketRequests/getItemTypeWorker"
+ :fields="['id', 'nickname']"
+ sort-by="nickname ASC"
option-value="id"
option-label="nickname"
hide-selected
@@ -98,7 +65,10 @@ const itemCategoriesOptions = ref([]);
:label="t('params.typeId')"
v-model="params.typeId"
@update:model-value="searchFn()"
- :options="itemTypesOptions"
+ url="ItemTypes"
+ :include="['category']"
+ :fields="['id', 'name', 'categoryFk']"
+ sort-by="name ASC"
option-value="id"
option-label="name"
hide-selected
@@ -125,7 +95,9 @@ const itemCategoriesOptions = ref([]);
:label="t('params.categoryId')"
v-model="params.categoryId"
@update:model-value="searchFn()"
- :options="itemCategoriesOptions"
+ url="ItemCategories"
+ :fields="['id', 'name']"
+ sort-by="name ASC"
option-value="id"
option-label="name"
hide-selected
diff --git a/src/pages/Supplier/Card/SupplierFiscalData.vue b/src/pages/Supplier/Card/SupplierFiscalData.vue
index fd9667112..65c34c4ed 100644
--- a/src/pages/Supplier/Card/SupplierFiscalData.vue
+++ b/src/pages/Supplier/Card/SupplierFiscalData.vue
@@ -129,7 +129,7 @@ function handleLocation(data, location) {
handleLocation(data, location)"
>
diff --git a/src/pages/Supplier/Card/SupplierSummary.vue b/src/pages/Supplier/Card/SupplierSummary.vue
index 822586b47..5791db1eb 100644
--- a/src/pages/Supplier/Card/SupplierSummary.vue
+++ b/src/pages/Supplier/Card/SupplierSummary.vue
@@ -4,13 +4,11 @@ import { useRoute } from 'vue-router';
import { useI18n } from 'vue-i18n';
import CardSummary from 'components/ui/CardSummary.vue';
import VnLv from 'src/components/ui/VnLv.vue';
-import { useRole } from 'src/composables/useRole';
import { dashIfEmpty } from 'src/filters';
import VnUserLink from 'src/components/ui/VnUserLink.vue';
import VnTitle from 'src/components/common/VnTitle.vue';
const route = useRoute();
-const roleState = useRole();
const { t } = useI18n();
const $props = defineProps({
@@ -32,13 +30,7 @@ async function setData(data) {
}
}
-const isAdministrative = computed(() => {
- return roleState.hasAny(['administrative']);
-});
-
-function getUrl(section) {
- return isAdministrative.value && `#/supplier/${entityId.value}/${section}`;
-}
+const getUrl = (section) => `#/supplier/${entityId.value}/${section}`;
diff --git a/src/pages/Ticket/Card/TicketCard.vue b/src/pages/Ticket/Card/TicketCard.vue
index cf15cb7fa..73b6f5543 100644
--- a/src/pages/Ticket/Card/TicketCard.vue
+++ b/src/pages/Ticket/Card/TicketCard.vue
@@ -1,17 +1,11 @@
routeName.value);
:descriptor="TicketDescriptor"
search-data-key="TicketList"
:searchbar-props="{
- customRouteRedirectName,
+ url: 'Tickets/filter',
label: t('card.search'),
info: t('card.searchInfo'),
}"
diff --git a/src/pages/Ticket/Card/TicketDescriptorMenu.vue b/src/pages/Ticket/Card/TicketDescriptorMenu.vue
index 9a50288a0..4cf4e633f 100644
--- a/src/pages/Ticket/Card/TicketDescriptorMenu.vue
+++ b/src/pages/Ticket/Card/TicketDescriptorMenu.vue
@@ -9,6 +9,8 @@ import SendEmailDialog from 'components/common/SendEmailDialog.vue';
import VnConfirm from 'components/ui/VnConfirm.vue';
import VnSmsDialog from 'components/common/VnSmsDialog.vue';
import toDate from 'filters/toDate';
+import VnInputNumber from 'src/components/common/VnInputNumber.vue';
+import { useArrayData } from 'src/composables/useArrayData';
const props = defineProps({
ticket: {
@@ -21,9 +23,10 @@ const { push, currentRoute } = useRouter();
const { dialog, notify } = useQuasar();
const { t } = useI18n();
const { openReport, sendEmail } = usePrintService();
-
+const ticketSummary = useArrayData('TicketSummary');
const ticket = ref(props.ticket);
const ticketId = currentRoute.value.params.id;
+const weight = ref();
const actions = {
clone: async () => {
const opts = { message: t('Ticket cloned'), type: 'positive' };
@@ -46,6 +49,25 @@ const actions = {
push({ name: 'TicketSummary', params: { id: clonedTicketId } });
}
},
+ setWeight: async () => {
+ try {
+ const invoiceIds = (
+ await axios.post(`Tickets/${ticketId}/setWeight`, {
+ weight: weight.value,
+ })
+ ).data;
+
+ notify({ message: t('Weight set'), type: 'positive' });
+ if (invoiceIds.length)
+ notify({
+ message: t('invoiceIds', { invoiceIds: invoiceIds.join() }),
+ type: 'positive',
+ });
+ await ticketSummary.fetch({ updateRouter: false });
+ } catch (e) {
+ notify({ message: e.message, type: 'negative' });
+ }
+ },
remove: async () => {
try {
await axios.post(`Tickets/${ticketId}/setDeleted`);
@@ -255,6 +277,12 @@ function openConfirmDialog(callback) {
{{ t('To clone ticket') }}
+
+
+
+
+ {{ t('Set weight') }}
+
@@ -264,9 +292,25 @@ function openConfirmDialog(callback) {
{{ t('Delete ticket') }}
+
+
+
+
+
-
+en:
+ invoiceIds: "Invoices have been generated with the following ids: {invoiceIds}"
+
es:
Open Delivery Note...: Abrir albarán...
Send Delivery Note...: Enviar albarán...
@@ -284,4 +328,8 @@ es:
To clone ticket: Clonar ticket
Ticket cloned: Ticked clonado
It was not able to clone the ticket: No se pudo clonar el ticket
+ Set weight: Establecer peso
+ Weight set: Peso establecido
+ This ticket may be invoiced, do you want to continue?: Es posible que se facture este ticket, desea continuar?
+ invoiceIds: "Se han generado las facturas con los siguientes ids: {invoiceIds}"
diff --git a/src/pages/Ticket/Card/TicketSummary.vue b/src/pages/Ticket/Card/TicketSummary.vue
index bc160846a..6af782173 100644
--- a/src/pages/Ticket/Card/TicketSummary.vue
+++ b/src/pages/Ticket/Card/TicketSummary.vue
@@ -31,8 +31,7 @@ const $props = defineProps({
const entityId = computed(() => $props.id || route.params.id);
const summaryRef = ref();
-const ticket = ref();
-const salesLines = ref(null);
+const ticket = computed(() => summaryRef.value?.entity);
const editableStates = ref([]);
const ticketUrl = ref();
const grafanaUrl = 'https://grafana.verdnatura.es';
@@ -40,12 +39,6 @@ const grafanaUrl = 'https://grafana.verdnatura.es';
onMounted(async () => {
ticketUrl.value = (await getUrl('ticket/')) + entityId.value + '/';
});
-async function setData(data) {
- if (data) {
- ticket.value = data;
- salesLines.value = data.sales;
- }
-}
function formattedAddress() {
if (!ticket.value) return '';
@@ -89,7 +82,6 @@ async function changeState(value) {
setData(data)"
data-key="TicketSummary"
>
@@ -131,7 +123,7 @@ async function changeState(value) {
-
+
-
- {{ ticket.ticketState?.state?.name }}
+
+ {{ entity.ticketState?.state?.name }}
-
+
- {{ ticket.ticketCollections[0]?.collectionFk }}
+ {{ entity.ticketCollections[0]?.collectionFk }}
-
+
-
- {{ dashIfEmpty(ticket.refFk) }}
+
+ {{ dashIfEmpty(entity.refFk) }}
@@ -199,35 +192,35 @@ async function changeState(value) {
/>
-
-
+
+
{{ t('ticket.summary.consigneePhone') }}
-
+
-
+
{{ t('ticket.summary.consigneeMobile') }}
-
+
-
+
{{ t('ticket.summary.clientPhone') }}
-
+
-
+
{{ t('ticket.summary.clientMobile') }}
-
+
-
+
@@ -279,7 +272,7 @@ async function changeState(value) {
:url="ticketUrl + 'sale'"
:text="t('ticket.summary.saleLines')"
/>
-
+
{{ value }}
@@ -383,7 +376,11 @@ async function changeState(value) {
{{ props.row.itemFk }}
-
+
{{ props.row.visible }}
@@ -419,10 +416,10 @@ async function changeState(value) {
-
+
{{ t('ticket.summary.created') }}
@@ -442,7 +439,7 @@ async function changeState(value) {
:url="ticketUrl + 'service'"
:text="t('ticket.summary.service')"
/>
-
+
{{ t('ticket.summary.quantity') }}
diff --git a/src/pages/Ticket/Card/TicketTransfer.vue b/src/pages/Ticket/Card/TicketTransfer.vue
index 9a22c764c..1944b80f4 100644
--- a/src/pages/Ticket/Card/TicketTransfer.vue
+++ b/src/pages/Ticket/Card/TicketTransfer.vue
@@ -4,6 +4,7 @@ import { useI18n } from 'vue-i18n';
import { useRouter } from 'vue-router';
import VnInput from 'src/components/common/VnInput.vue';
+import TicketTransferForm from './TicketTransferForm.vue';
import { toDateFormat } from 'src/filters/date.js';
import axios from 'axios';
@@ -135,9 +136,7 @@ onMounted(() => (_transfer.value = $props.transfer));
:columns="destinationTicketColumns"
:title="t('Destination ticket')"
row-key="id"
- :pagination="{ rowsPerPage: 0 }"
class="full-width q-mt-md"
- :no-data-label="t('globals.noResults')"
>
@@ -158,29 +157,11 @@ onMounted(() => (_transfer.value = $props.transfer));
+
+
+
-
-
-
-
-
-
-
-
+
diff --git a/src/pages/Ticket/Card/TicketTransferForm.vue b/src/pages/Ticket/Card/TicketTransferForm.vue
new file mode 100644
index 000000000..9507429e6
--- /dev/null
+++ b/src/pages/Ticket/Card/TicketTransferForm.vue
@@ -0,0 +1,86 @@
+
+
+
+ {{ _transfer }}
+
+
+
+
+
+
+
+
+
+
+
+es:
+ Sales to transfer: Líneas a transferir
+ Destination ticket: Ticket destinatario
+ Transfer to ticket: Transferir a ticket
+ New ticket: Nuevo ticket
+
diff --git a/src/pages/Ticket/TicketAdvance.vue b/src/pages/Ticket/TicketAdvance.vue
index 45bd8fd39..177b3a29b 100644
--- a/src/pages/Ticket/TicketAdvance.vue
+++ b/src/pages/Ticket/TicketAdvance.vue
@@ -133,6 +133,14 @@ const ticketColumns = computed(() => [
sortable: true,
columnFilter: null,
},
+ {
+ label: t('advanceTickets.preparation'),
+ name: 'preparation',
+ field: 'preparation',
+ align: 'left',
+ sortable: true,
+ columnFilter: null,
+ },
{
label: t('advanceTickets.liters'),
name: 'liters',
@@ -624,6 +632,7 @@ onMounted(async () => {
+
@@ -635,6 +644,7 @@ onMounted(async () => {
{
>
{{ row.state }}
+ {{ dashIfEmpty(row.state) }}
diff --git a/src/pages/Ticket/TicketAdvanceFilter.vue b/src/pages/Ticket/TicketAdvanceFilter.vue
index ed61d9447..209a1a307 100644
--- a/src/pages/Ticket/TicketAdvanceFilter.vue
+++ b/src/pages/Ticket/TicketAdvanceFilter.vue
@@ -55,7 +55,7 @@ onMounted(async () => await getItemPackingTypes());
:data-key="props.dataKey"
:search-button="true"
:hidden-tags="['search']"
- :un-removable-params="['warehouseFk', 'dateFuture', 'dateToAdvance']"
+ :unremovable-params="['warehouseFk', 'dateFuture', 'dateToAdvance']"
>
@@ -119,10 +119,9 @@ onMounted(async () => await getItemPackingTypes());
@@ -155,7 +154,7 @@ en:
dateToAdvance: Destination date
futureIpt: Origin IPT
ipt: Destination IPT
- itemPackingTypes: 100% movable
+ isFullMovable: 100% movable
warehouseFk: Warehouse
es:
Horizontal: Horizontal
@@ -166,6 +165,6 @@ es:
dateToAdvance: Fecha destino
futureIpt: IPT Origen
ipt: IPT destino
- itemPackingTypes: 100% movible
+ isFullMovable: 100% movible
warehouseFk: Almacén
diff --git a/src/pages/Ticket/TicketCreateDialog.vue b/src/pages/Ticket/TicketCreateDialog.vue
new file mode 100644
index 000000000..1493adc53
--- /dev/null
+++ b/src/pages/Ticket/TicketCreateDialog.vue
@@ -0,0 +1,226 @@
+
+
+
+ (clientOptions = data)"
+ :filter="{ fields: ['id', 'name', 'defaultAddressFk'], order: 'id' }"
+ auto-load
+ />
+ (warehousesOptions = data)"
+ order="name"
+ auto-load
+ />
+
+
+
+
+
+ onClientSelected(data)"
+ >
+
+
+
+
+ {{ scope.opt.name }}
+
+
+ {{ `#${scope.opt.id}` }}
+
+
+
+
+
+
+
+
+
+ fetchAvailableAgencies(data)"
+ >
+
+
+
+
+ {{ scope.opt.nickname }}
+
+
+ {{ `${scope.opt.street}, ${scope.opt.city}` }}
+
+
+
+
+
+
+
+
+
+ fetchAvailableAgencies(data)"
+ />
+
+
+
+
+ fetchAvailableAgencies(data)"
+ />
+
+
+
+
+
+
+
+
+
+
diff --git a/src/pages/Ticket/TicketFuture.vue b/src/pages/Ticket/TicketFuture.vue
index 14a4a5ac8..2078d0595 100644
--- a/src/pages/Ticket/TicketFuture.vue
+++ b/src/pages/Ticket/TicketFuture.vue
@@ -49,8 +49,8 @@ const exprBuilder = (param, value) => {
};
const userParams = reactive({
- futureDated: Date.vnNew().toISOString(),
- originDated: Date.vnNew().toISOString(),
+ futureScopeDays: Date.vnNew().toISOString(),
+ originScopeDays: Date.vnNew().toISOString(),
warehouseFk: user.value.warehouseFk,
});
@@ -62,8 +62,8 @@ const arrayData = useArrayData('FutureTickets', {
const { store } = arrayData;
const params = reactive({
- futureDated: Date.vnNew(),
- originDated: Date.vnNew(),
+ futureScopeDays: Date.vnNew(),
+ originScopeDays: Date.vnNew(),
warehouseFk: user.value.warehouseFk,
});
@@ -172,7 +172,7 @@ const ticketColumns = computed(() => [
label: t('futureTickets.availableLines'),
name: 'lines',
field: 'lines',
- align: 'left',
+ align: 'center',
sortable: true,
columnFilter: {
component: VnInput,
@@ -234,7 +234,7 @@ const ticketColumns = computed(() => [
{
label: t('futureTickets.futureState'),
name: 'futureState',
- align: 'left',
+ align: 'right',
sortable: true,
columnFilter: null,
format: (val) => dashIfEmpty(val),
@@ -458,7 +458,7 @@ onMounted(async () => {
-
+
{
-
+
{