diff --git a/src/components/FetchData.vue b/src/components/FetchData.vue index f0d908972..b8e7c2ac3 100644 --- a/src/components/FetchData.vue +++ b/src/components/FetchData.vue @@ -27,6 +27,10 @@ const $props = defineProps({ type: String, default: '', }, + params: { + type: Object, + default: null, + } }); const emit = defineEmits(['onFetch']); @@ -46,7 +50,7 @@ async function fetch() { if ($props.limit) filter.limit = $props.limit; const { data } = await axios.get($props.url, { - params: { filter: JSON.stringify(filter) }, + params: { filter: JSON.stringify(filter), ...$props.params }, }); emit('onFetch', data); diff --git a/src/components/FormModel.vue b/src/components/FormModel.vue index dd283277d..62993ef24 100644 --- a/src/components/FormModel.vue +++ b/src/components/FormModel.vue @@ -55,6 +55,10 @@ const $props = defineProps({ description: 'Esto se usa principalmente para permitir guardar sin hacer cambios (Útil para la feature de clonar ya que en este caso queremos poder guardar de primeras)', }, + mapper: { + type: Function, + default: null, + } }); const emit = defineEmits(['onFetch', 'onDataSaved']); @@ -83,6 +87,7 @@ onUnmounted(() => { const isLoading = ref(false); // Si elegimos observar los cambios del form significa que inicialmente las actions estaran deshabilitadas +const isResetting = ref(false); const hasChanges = ref(!$props.observeFormChanges); const originalData = ref({ ...$props.formInitialData }); const formData = computed(() => state.get($props.model)); @@ -92,7 +97,10 @@ const startFormWatcher = () => { watch( () => formData.value, (val) => { - if (val) hasChanges.value = true; + if (!isResetting.value && val) { + hasChanges.value = true; + } + isResetting.value = false; }, { deep: true } ); @@ -121,11 +129,12 @@ async function save() { isLoading.value = true; try { + const body = $props.mapper ? $props.mapper(formData.value) : formData.value if ($props.urlCreate) { - await axios.post($props.urlCreate, formData.value); + await axios.post($props.urlCreate, body); notify('globals.dataCreated', 'positive'); } else { - await axios.patch($props.urlUpdate || $props.url, formData.value); + await axios.patch($props.urlUpdate || $props.url, body); } emit('onDataSaved', formData.value); } catch (err) { @@ -144,6 +153,7 @@ function reset() { emit('onFetch', state.get($props.model)); if ($props.observeFormChanges) { hasChanges.value = false; + isResetting.value = true; } } diff --git a/src/components/ui/VnFilterPanel.vue b/src/components/ui/VnFilterPanel.vue index 84893b667..6f6183224 100644 --- a/src/components/ui/VnFilterPanel.vue +++ b/src/components/ui/VnFilterPanel.vue @@ -31,11 +31,21 @@ const props = defineProps({ description: 'Algunos filtros vienen con parametros de búsqueda por default y necesitan tener si o si un valor, por eso de ser necesario, esta prop nos sirve para saber que filtros podemos remover y cuales no', }, + exprBuilder: { + type: Function, + default: null, + }, + hiddenTags: { + type: Array, + default: () => [], + }, }); -const emit = defineEmits(['refresh', 'clear', 'search']); +const emit = defineEmits(['refresh', 'clear', 'search', 'init']); -const arrayData = useArrayData(props.dataKey); +const arrayData = useArrayData(props.dataKey, { + exprBuilder: props.exprBuilder, +}); const store = arrayData.store; const userParams = ref({}); @@ -44,9 +54,11 @@ onMounted(() => { if (Object.keys(store.userParams).length > 0) { userParams.value = JSON.parse(JSON.stringify(store.userParams)); } + emit('init', { params: userParams.value }); }); const isLoading = ref(false); + async function search() { isLoading.value = true; const params = { ...userParams.value }; @@ -93,17 +105,12 @@ async function clearFilters() { } const tags = computed(() => { - const params = []; - - for (const param in userParams.value) { - if (!userParams.value[param]) continue; - params.push({ - label: param, - value: userParams.value[param], - }); - } - - return params; + return Object.entries(userParams.value) + .filter(([key, value]) => value && !(props.hiddenTags || []).includes(key)) + .map(([key, value]) => ({ + label: key, + value: value, + })); }); async function remove(key) { diff --git a/src/components/ui/VnPaginate.vue b/src/components/ui/VnPaginate.vue index c75761462..0849cebe5 100644 --- a/src/components/ui/VnPaginate.vue +++ b/src/components/ui/VnPaginate.vue @@ -31,7 +31,7 @@ const props = defineProps({ default: null, }, order: { - type: String, + type: [String, Array], default: '', }, limit: { @@ -149,7 +149,7 @@ async function onLoad(...params) { v-if="props.skeleton && props.autoLoad && !store.data" class="card-list q-gutter-y-md" > - + diff --git a/src/components/ui/VnSearchbar.vue b/src/components/ui/VnSearchbar.vue index cc6cd1971..8220aa3db 100644 --- a/src/components/ui/VnSearchbar.vue +++ b/src/components/ui/VnSearchbar.vue @@ -53,6 +53,14 @@ const props = defineProps({ type: Object, default: null, }, + staticParams: { + type: Array, + default: () => [], + }, + exprBuilder: { + type: Function, + default: null, + }, }); const router = useRouter(); @@ -69,8 +77,11 @@ onMounted(() => { }); async function search() { + const staticParams = Object.entries(store.userParams) + .filter(([key, value]) => value && (props.staticParams || []).includes(key)); await arrayData.applyFilter({ params: { + ...Object.fromEntries(staticParams), search: searchText.value, }, }); diff --git a/src/i18n/en/index.js b/src/i18n/en/index.js index 8c80c13e0..4a1eea8f4 100644 --- a/src/i18n/en/index.js +++ b/src/i18n/en/index.js @@ -549,6 +549,61 @@ export default { country: 'Country', }, }, + order: { + pageTitles: { + order: 'Orders', + orderList: 'List', + create: 'Create', + summary: 'Summary', + basicData: 'Basic Data', + catalog: 'Catalog', + }, + field: { + salesPersonFk: 'Sales Person', + clientFk: 'Client', + isConfirmed: 'Confirmed', + created: 'Created', + landed: 'Landed', + hour: 'Hour', + agency: 'Agency', + total: 'Total' + }, + form: { + clientFk: 'Client', + addressFk: 'Address', + landed: 'Landed', + agencyModeFk: 'Agency', + }, + list: { + newOrder: 'New Order' + }, + summary: { + basket: 'Basket', + nickname: 'Nickname', + company: 'Company', + confirmed: 'Confirmed', + notConfirmed: 'Not confirmed', + created: 'Created', + landed: 'Landed', + phone: 'Phone', + createdFrom: 'Created From', + address: 'Address', + notes: 'Notes', + subtotal: 'Subtotal', + total: 'Total', + vat: 'VAT', + state: 'State', + alias: 'Alias', + items: 'Items', + orderTicketList: 'Order Ticket List', + details: 'Details', + item: 'Item', + description: 'Description', + quantity: 'Quantity', + price: 'Price', + amount: 'Amount' + } + }, worker: { pageTitles: { workers: 'Workers', diff --git a/src/i18n/es/index.js b/src/i18n/es/index.js index 9cbfc6d03..3f4ac1c27 100644 --- a/src/i18n/es/index.js +++ b/src/i18n/es/index.js @@ -458,6 +458,61 @@ export default { }, }, }, + order: { + pageTitles: { + order: 'Cesta', + orderList: 'Listado', + create: 'Crear', + summary: 'Resumen', + basicData: 'Datos básicos', + catalog: 'Catálogo', + }, + field: { + salesPersonFk: 'Comercial', + clientFk: 'Cliente', + isConfirmed: 'Confirmada', + created: 'Creado', + landed: 'F. entrega', + hour: 'Hora', + agency: 'Agencia', + total: 'Total' + }, + form: { + clientFk: 'Cliente', + addressFk: 'Dirección', + landed: 'F. entrega', + agencyModeFk: 'Agencia', + }, + list: { + newOrder: 'Nuevo Pedido' + }, + summary: { + basket: 'Cesta', + nickname: 'Alias', + company: 'Empresa', + confirmed: 'Confirmada', + notConfirmed: 'No confirmada', + created: 'Creado', + landed: 'F. entrega', + phone: 'Teléfono', + createdFrom: 'Creado desde', + address: 'Dirección', + notes: 'Notas', + subtotal: 'Subtotal', + total: 'Total', + vat: 'IVA', + state: 'Estado', + alias: 'Alias', + items: 'Items', + orderTicketList: 'Tickets del pedido', + details: 'Detalles', + item: 'Item', + description: 'Descripción', + quantity: 'Cantidad', + price: 'Precio', + amount: 'Monto' + } + }, shelving: { pageTitles: { shelving: 'Carros', diff --git a/src/pages/Order/Card/OrderBasicData.vue b/src/pages/Order/Card/OrderBasicData.vue new file mode 100644 index 000000000..0611fa874 --- /dev/null +++ b/src/pages/Order/Card/OrderBasicData.vue @@ -0,0 +1,12 @@ + + + diff --git a/src/pages/Order/Card/OrderCard.vue b/src/pages/Order/Card/OrderCard.vue new file mode 100644 index 000000000..4163e22a4 --- /dev/null +++ b/src/pages/Order/Card/OrderCard.vue @@ -0,0 +1,23 @@ + + diff --git a/src/pages/Order/Card/OrderCatalogFilter.vue b/src/pages/Order/Card/OrderCatalogFilter.vue new file mode 100644 index 000000000..46de63abd --- /dev/null +++ b/src/pages/Order/Card/OrderCatalogFilter.vue @@ -0,0 +1,208 @@ + + + + + + + +en: + params: + type: Type + orderBy: Order By +es: + params: + type: Tipo + orderBy: Ordenar por + Plant: Planta + Flower: Flor + Handmade: Confección + Green: Verde + Accessories: Complemento + Fruit: Fruta + diff --git a/src/pages/Order/Card/OrderCatalogItem.vue b/src/pages/Order/Card/OrderCatalogItem.vue new file mode 100644 index 000000000..6579fc261 --- /dev/null +++ b/src/pages/Order/Card/OrderCatalogItem.vue @@ -0,0 +1,184 @@ + + + + + + + +es: + to: to + price-kg: Precio por Kg +en: + to: hasta + price-kg: Price per Kg + diff --git a/src/pages/Order/Card/OrderCatalogItemDialog.vue b/src/pages/Order/Card/OrderCatalogItemDialog.vue new file mode 100644 index 000000000..8d12824e6 --- /dev/null +++ b/src/pages/Order/Card/OrderCatalogItemDialog.vue @@ -0,0 +1,83 @@ + + + + + diff --git a/src/pages/Order/Card/OrderDescriptor.vue b/src/pages/Order/Card/OrderDescriptor.vue new file mode 100644 index 000000000..3b6d91cb4 --- /dev/null +++ b/src/pages/Order/Card/OrderDescriptor.vue @@ -0,0 +1,128 @@ + + + diff --git a/src/pages/Order/Card/OrderDescriptorMenu.vue b/src/pages/Order/Card/OrderDescriptorMenu.vue new file mode 100644 index 000000000..b432ba4d7 --- /dev/null +++ b/src/pages/Order/Card/OrderDescriptorMenu.vue @@ -0,0 +1,63 @@ + + + + +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/Order/Card/OrderFilter.vue b/src/pages/Order/Card/OrderFilter.vue new file mode 100644 index 000000000..b49f0b115 --- /dev/null +++ b/src/pages/Order/Card/OrderFilter.vue @@ -0,0 +1,265 @@ + + + + + + + +en: + params: + search: Includes + clientFk: Client + agencyModeFk: Agency + salesPersonFk: Sales Person + from: From + to: To + orderFk: Order + sourceApp: Application + myTeam: My Team + isConfirmed: Is Confirmed + showEmpty: Show Empty + customerId: Customer ID + agency: Agency + salesPerson: Sales Person + fromLanded: From Landed + toLanded: To Landed + orderId: Order ID + application: Application + myTeam: My Team + isConfirmed: Order Confirmed + showEmpty: Show Empty +es: + params: + search: Búsqueda + clientFk: Cliente + agencyModeFk: Agencia + salesPersonFk: Comercial + from: Desde + to: Hasta + orderFk: Cesta + sourceApp: Aplicación + myTeam: Mi Equipo + isConfirmed: Confirmado + showEmpty: Mostrar vacías + customerId: ID Cliente + agency: Agencia + salesPerson: Comercial + fromLanded: Desde F. entrega + toLanded: Hasta F. entrega + orderId: ID Cesta + application: Aplicación + myTeam: Mi Equipo + isConfirmed: Confirmado + showEmpty: Mostrar vacías + diff --git a/src/pages/Order/Card/OrderForm.vue b/src/pages/Order/Card/OrderForm.vue new file mode 100644 index 000000000..4c7e2c326 --- /dev/null +++ b/src/pages/Order/Card/OrderForm.vue @@ -0,0 +1,209 @@ + + + diff --git a/src/pages/Order/Card/OrderSearchbar.vue b/src/pages/Order/Card/OrderSearchbar.vue new file mode 100644 index 000000000..4d354603b --- /dev/null +++ b/src/pages/Order/Card/OrderSearchbar.vue @@ -0,0 +1,25 @@ + + + + + + +en: + search-order: Search order + search-order-info: You can search orders by reference +es: + Search shelving: Buscar orden + You can search by shelving reference: Puedes buscar por referencia de la orden + diff --git a/src/pages/Order/Card/OrderSummary.vue b/src/pages/Order/Card/OrderSummary.vue new file mode 100644 index 000000000..464ab3dfc --- /dev/null +++ b/src/pages/Order/Card/OrderSummary.vue @@ -0,0 +1,239 @@ + + + + diff --git a/src/pages/Order/Card/OrderSummaryDialog.vue b/src/pages/Order/Card/OrderSummaryDialog.vue new file mode 100644 index 000000000..ebe891f4a --- /dev/null +++ b/src/pages/Order/Card/OrderSummaryDialog.vue @@ -0,0 +1,29 @@ + + + + + diff --git a/src/pages/Order/OrderCatalog.vue b/src/pages/Order/OrderCatalog.vue new file mode 100644 index 000000000..ec81c50f1 --- /dev/null +++ b/src/pages/Order/OrderCatalog.vue @@ -0,0 +1,93 @@ + + + + + diff --git a/src/pages/Order/OrderList.vue b/src/pages/Order/OrderList.vue new file mode 100644 index 000000000..362a68b4d --- /dev/null +++ b/src/pages/Order/OrderList.vue @@ -0,0 +1,162 @@ + + + + + diff --git a/src/pages/Order/OrderMain.vue b/src/pages/Order/OrderMain.vue new file mode 100644 index 000000000..66ce78f23 --- /dev/null +++ b/src/pages/Order/OrderMain.vue @@ -0,0 +1,17 @@ + + + diff --git a/src/router/modules/index.js b/src/router/modules/index.js index 0ab5bf2b2..1eff2c180 100644 --- a/src/router/modules/index.js +++ b/src/router/modules/index.js @@ -9,6 +9,7 @@ import Wagon from './wagon'; import Route from './route'; import Supplier from './Supplier'; import Travel from './travel'; +import Order from './order'; export default [ Customer, @@ -21,5 +22,6 @@ export default [ Route, Supplier, Travel, + Order, invoiceIn, ]; diff --git a/src/router/modules/order.js b/src/router/modules/order.js new file mode 100644 index 000000000..e91e95493 --- /dev/null +++ b/src/router/modules/order.js @@ -0,0 +1,78 @@ +import { RouterView } from 'vue-router'; + +export default { + path: '/order', + name: 'Order', + meta: { + title: 'order', + icon: 'vn:basket', + }, + component: RouterView, + redirect: { name: 'OrderMain' }, + menus: { + main: ['OrderList'], + card: ['OrderBasicData', 'OrderCatalog'], + }, + children: [ + { + path: '', + name: 'OrderMain', + component: () => import('src/pages/Order/OrderMain.vue'), + redirect: { name: 'OrderList' }, + children: [ + { + path: 'list', + name: 'OrderList', + meta: { + title: 'orderList', + icon: 'view_list', + }, + component: () => import('src/pages/Order/OrderList.vue'), + }, + { + path: 'create', + name: 'OrderCreate', + meta: { + title: 'create', + }, + component: () => import('src/pages/Order/Card/OrderForm.vue'), + }, + ], + }, + { + name: 'OrderCard', + path: ':id', + component: () => import('src/pages/Order/Card/OrderCard.vue'), + redirect: { name: 'OrderSummary' }, + children: [ + { + name: 'OrderSummary', + path: 'summary', + meta: { + title: 'summary', + icon: 'launch', + }, + component: () => import('src/pages/Order/Card/OrderSummary.vue'), + }, + { + name: 'OrderBasicData', + path: 'basic-data', + meta: { + title: 'basicData', + icon: 'vn:settings', + }, + component: () => import('src/pages/Order/Card/OrderForm.vue'), + }, + { + name: 'OrderCatalog', + path: 'catalog', + meta: { + title: 'catalog', + icon: 'vn:basket', + }, + component: () => import('src/pages/Order/OrderCatalog.vue'), + }, + ], + }, + ], +}; diff --git a/src/router/routes.js b/src/router/routes.js index 550fcf64e..ee8b30d64 100644 --- a/src/router/routes.js +++ b/src/router/routes.js @@ -9,6 +9,7 @@ import supplier from './modules/Supplier'; import route from './modules/route'; import travel from './modules/travel'; import shelving from 'src/router/modules/shelving'; +import order from "src/router/modules/order"; const routes = [ { @@ -56,6 +57,7 @@ const routes = [ invoiceOut, invoiceIn, wagon, + order, route, supplier, travel, diff --git a/src/stores/useNavigationStore.js b/src/stores/useNavigationStore.js index b5947f87b..63dce6162 100644 --- a/src/stores/useNavigationStore.js +++ b/src/stores/useNavigationStore.js @@ -13,6 +13,7 @@ export const useNavigationStore = defineStore('navigationStore', () => { 'invoiceOut', 'worker', 'shelving', + 'order', 'wagon', 'route', 'supplier',