email da inviare ai clienti ...

This commit is contained in:
Surya Paolo
2024-01-09 15:32:21 +01:00
parent 1021331f7c
commit 6dc74b5826
34 changed files with 1318 additions and 486 deletions

View File

@@ -0,0 +1,8 @@
$heightBtn: 100%;
.card .product-image {
height: 300px;
}
.insert{
cursor:pointer;
}

267
src/components/CCart/CCart.ts Executable file
View File

@@ -0,0 +1,267 @@
import { defineComponent, onMounted, ref, computed } from 'vue'
import { tools } from '@store/Modules/tools'
import { useUserStore } from '@store/UserStore'
import { useRouter } from 'vue-router'
import { useGlobalStore } from '@store/globalStore'
import { useProducts } from '@store/Products'
import { useI18n } from '@/boot/i18n'
import { toolsext } from '@store/Modules/toolsext'
import { useQuasar } from 'quasar'
import { costanti } from '@costanti'
import { ICart, IOrder, IOrderCart, IProduct, IShareWithUs } from '@src/model/Products'
import { shared_consts } from '@src/common/shared_vuejs'
import { CSingleCart } from '../CSingleCart'
import { CTitleBanner } from '@components'
export default defineComponent({
name: 'CCart',
props: {
iscash: {
type: Boolean,
required: false,
default: false,
},
idOrdersCart: {
type: String,
required: false,
default: null,
},
},
components: { CSingleCart, CTitleBanner },
setup(props) {
const userStore = useUserStore()
const globalStore = useGlobalStore()
const productStore = useProducts()
const $router = useRouter()
const $q = useQuasar()
const { t } = useI18n();
const mycart = ref(<ICart>{})
const myrec = ref(<any[string]>[])
const oldrec = ref(<any[string]>[])
const note = ref('')
const endload = ref(false)
const recOrderCart = ref(<IOrderCart>{})
const search = ref('')
const statusnow = computed(() => (): number => {
if (recOrderCart.value) {
return recOrderCart.value.status
}
return 0
})
function mounted() {
// Inizializza
load()
}
function getOrdersCart() {
if (props.iscash) {
return productStore.getOrdersCartById(props.idOrdersCart)
} else {
return productStore.getCart()
}
}
function getItemsCart() {
const cart = getOrdersCart()
return cart.items || null
}
function getNumItems(): number {
const cart = getOrdersCart()
if (!!cart.items)
return cart.items.length || 0
else
return 0
}
function getCart(): ICart {
return getOrdersCart()
}
function getNote() {
const cart = getOrdersCart()
return cart.note
}
function change_field(fieldname: string) {
if (myrec.value[fieldname] !== oldrec.value[fieldname]) {
myrec.value[fieldname] = oldrec.value[fieldname]
const mydata = {
[fieldname]: myrec.value[fieldname]
}
const aggiorna = fieldname !== 'status'
tools.saveFieldToServer($q, 'carts', mycart.value._id, mydata, aggiorna)
oldrec.value[fieldname] = myrec.value[fieldname]
}
}
function myTotalPrice(): string {
if (productStore.cart && productStore.cart.totalPrice) {
return productStore.cart.totalPrice.toFixed(2)
} else {
return '0'
}
}
function myTotalQty(): number {
if (productStore.cart) {
return productStore.cart.totalQty!
} else {
return 0
}
}
async function load() {
mycart.value = getCart()
myrec.value = Object.keys(mycart)
oldrec.value = myrec.value
note.value = mycart.value.note!
let options = {};
if (mycart.value) {
recOrderCart.value = await productStore.CreateOrdersCart({ cart_id: mycart.value._id, status: 0, note: note.value })
}
console.log('myrec', myrec.value)
endload.value = true
}
function CanBeShipped() {
return productStore.cart.items ? productStore.cart.items.filter((rec: any) => rec.order.product.canBeShipped).length : false
}
function CanBeBuyOnline() {
return productStore.cart.items ? productStore.cart.items.filter((rec: any) => rec.order.product.canBeBuyOnline).length : false
}
function getnumsteps() {
let numsteps = 1
if (CanBeShipped())
numsteps++
if (CanBeBuyOnline())
numsteps++
return numsteps
}
function docheckout() {
// Può essere spedito?
if (CanBeShipped()) {
// mostra form di spedizione
}
if (CanBeBuyOnline()) {
// mostra form di acquisto Online
}
}
function completeOrder() {
$q.dialog({
message: t('ecomm.conferma_acq', { qty: myTotalQty() }),
ok: {
label: t('dialog.yes'),
push: true
},
cancel: {
label: t('dialog.cancel')
},
title: t('ecomm.order')
}).onOk(async () => {
const status = shared_consts.OrderStatus.CHECKOUT_SENT
recOrderCart.value = await productStore.CreateOrdersCart({ cart_id: mycart.value._id, status, note: note.value })
// statusnow.value = myordercart ? myordercart.status : 0
if (recOrderCart.value.status === status) {
tools.showPositiveNotif($q, t('ecomm.ord_confirmed'))
setTimeout(() => {
$router.push('/orderinfo')
}, 2000)
} else {
tools.showNegativeNotif($q, t('ecomm.ord_not_confirmed'))
}
// change_field('status')
// change_field('status')
})
}
function getActualIdStorehouse(myprod: IProduct) {
// Ottieni il negozio attualmente selezionato:
// Se ce n'è solo 1 allora prendi quello !
if (myprod.storehouses.length === 1) {
return myprod.storehouses[0]._id
} else {
// Ottieni il negozio attualmente scelto !
return ''
}
}
function getActualGasordine(myprod: IProduct) {
// Ottieni il negozio attualmente selezionato:
// Se ce n'è solo 1 allora prendi quello !
if (myprod.gasordines.length === 1) {
return myprod.gasordines[0]._id
} else {
// Ottieni il gasordine attualmente scelto !
return ''
}
}
async function insertArticolo() {
let lowerSearchText = search.value.trim();
const myprod = productStore.getProductByCode(lowerSearchText);
if (myprod && myprod.active) {
let myorder: IOrder = {
quantity: 1, quantitypreordered: 0,
TotalPriceProduct: 0, price: 0,
idStorehouse: getActualIdStorehouse(myprod),
idGasordine: getActualGasordine(myprod),
}
await productStore.addtoCartBase({ $q, t, id: myprod._id, order: myorder, addqty: true })
search.value = ''
load()
}
}
onMounted(mounted)
return {
userStore,
costanti,
tools,
toolsext,
completeOrder,
getNumItems,
myTotalPrice,
getItemsCart,
getNote,
change_field,
note,
statusnow,
shared_consts,
myTotalQty,
recOrderCart,
mycart,
endload,
search,
insertArticolo,
}
}
})

52
src/components/CCart/CCart.vue Executable file
View File

@@ -0,0 +1,52 @@
<template>
<q-spinner v-if="!endload" color="primary" size="3em" :thickness="2" />
<div v-if="endload">
<div v-if="recOrderCart" class="panel">
<div>
<div class="container">
<div class="q-pa-sm col items-start q-gutter-xs" v-for="(itemorder, index) in getItemsCart()" :key="index">
<CSingleCart :order="itemorder.order" :showall="true" />
</div>
</div>
<q-separator></q-separator>
<div class="col-6 q-mr-sm" style="text-align: right">
<span class="text-grey q-mr-xs">{{ $t('ecomm.totale') }}:</span>
<span class="text-subtitle1 q-mr-sm"> {{ myTotalPrice() }}</span>
</div>
<q-input v-if="getNumItems() > 0" v-model="note" style="max-width: 400px" :label="$t('ecomm.note')" filled dense
debounce="1000" autogrow @input="change_field('note')">
</q-input>
<br />
</div>
<div class="text-center">
<q-btn v-if="recOrderCart &&
recOrderCart.status < shared_consts.OrderStatus.CHECKOUT_SENT
" rounded icon="fas fa-shopping-cart" color="green" :label="$t('ecomm.completa_ord')" class="q-mb-sm"
:disabled="myTotalQty() < 1" @click="completeOrder()"></q-btn>
</div>
</div>
<div v-else style="text-align: center" class="text-grey">
{{ $t('ecomm.carrello_vuoto') }}
</div>
<br>
<div class="q-gutter-y-md column text-center q-mx-auto" style="width: 350px; max-width: 100%">
<q-input filled stack-label dense :label="$t('ecomm.code_add_to_cart')" v-model="search" class="q-ml-md"
@keyup.enter="insertArticolo()">
<template v-slot:append>
<q-icon class="insert" name="fas fa-shopping-cart" color="green" @click="insertArticolo()" />
</template>
</q-input>
</div>
</div>
</template>
<script lang="ts" src="./CCart.ts">
</script>
<style lang="scss" scoped>
@import './CCart';
</style>

1
src/components/CCart/index.ts Executable file
View File

@@ -0,0 +1 @@
export {default as CCart} from './CCart.vue'

View File

@@ -0,0 +1,12 @@
$heightBtn: 100%;
.card .product-image {
height: 300px;
}
.insert{
cursor:pointer;
}
.numorder{
font-weight: bold;
}

View File

@@ -0,0 +1,206 @@
import { defineComponent, onMounted, ref, computed } from 'vue'
import { tools } from '@store/Modules/tools'
import { useUserStore } from '@store/UserStore'
import { useRouter } from 'vue-router'
import { useGlobalStore } from '@store/globalStore'
import { useProducts } from '@store/Products'
import { useI18n } from '@/boot/i18n'
import { toolsext } from '@store/Modules/toolsext'
import { useQuasar } from 'quasar'
import { costanti } from '@costanti'
import { IBaseOrder, ICart, IOrder, IOrderCart, IProduct, IShareWithUs } from '@src/model/Products'
import { shared_consts } from '@src/common/shared_vuejs'
import { CSingleCart } from '../CSingleCart'
import { CTitleBanner } from '@components'
export default defineComponent({
name: 'COrdersCart',
props: {
iscash: {
type: Boolean,
required: false,
default: false,
},
idOrdersCart: {
type: String,
required: false,
default: null,
},
},
components: { CSingleCart, CTitleBanner },
setup(props) {
const userStore = useUserStore()
const globalStore = useGlobalStore()
const productStore = useProducts()
const $router = useRouter()
const $q = useQuasar()
const { t } = useI18n();
const myrec = ref(<any[string]>[])
const oldrec = ref(<any[string]>[])
const note = ref('')
const endload = ref(false)
const recOrderCart = ref(<IOrderCart>{})
const search = ref('')
const statusnow = computed(() => (): number => {
if (recOrderCart.value) {
return recOrderCart.value.status
}
return 0
})
function mounted() {
// Inizializza
load()
}
function getItems(): IBaseOrder[] | [] {
return recOrderCart.value.items ?? []
}
function getNumItems(): number {
const itemsord = getItems()
if (itemsord)
return itemsord.length || 0
else
return 0
}
function change_field(fieldname: string) {
if (myrec.value[fieldname] !== oldrec.value[fieldname]) {
myrec.value[fieldname] = oldrec.value[fieldname]
const mydata = {
[fieldname]: myrec.value[fieldname]
}
const aggiorna = false
tools.saveFieldToServer($q, 'orderscarts', recOrderCart.value._id, mydata, aggiorna)
oldrec.value[fieldname] = myrec.value[fieldname]
}
}
function myTotalPrice(): string {
if (recOrderCart.value) {
return recOrderCart.value.totalPrice.toFixed(2)
} else {
return '0'
}
}
function myTotalQty(): number {
if (recOrderCart.value) {
return recOrderCart.value.totalQty
} else {
return 0
}
}
function load() {
recOrderCart.value = productStore.getOrdersCartById(props.idOrdersCart)
if (recOrderCart.value) {
oldrec.value = myrec.value
note.value = recOrderCart.value.note!
}
endload.value = true
}
function CanBeShipped() {
return recOrderCart.value.items ? recOrderCart.value.items.filter((rec: any) => rec.order.product.canBeShipped).length : false
}
function CanBeBuyOnline() {
return recOrderCart.value.items ? recOrderCart.value.items.filter((rec: any) => rec.order.product.canBeBuyOnline).length : false
}
function getnumsteps() {
let numsteps = 1
if (CanBeShipped())
numsteps++
if (CanBeBuyOnline())
numsteps++
return numsteps
}
function docheckout() {
// Può essere spedito?
if (CanBeShipped()) {
// mostra form di spedizione
}
if (CanBeBuyOnline()) {
// mostra form di acquisto Online
}
}
function getActualIdStorehouse(myprod: IProduct) {
// Ottieni il negozio attualmente selezionato:
// Se ce n'è solo 1 allora prendi quello !
if (myprod.storehouses.length === 1) {
return myprod.storehouses[0]._id
} else {
// Ottieni il negozio attualmente scelto !
return ''
}
}
function getActualGasordine(myprod: IProduct) {
// Ottieni il negozio attualmente selezionato:
// Se ce n'è solo 1 allora prendi quello !
if (myprod.gasordines.length === 1) {
return myprod.gasordines[0]._id
} else {
// Ottieni il gasordine attualmente scelto !
return ''
}
}
async function insertArticolo() {
let lowerSearchText = search.value.trim();
const myprod = productStore.getProductByCode(lowerSearchText);
if (myprod && myprod.active) {
let myorder: IOrder = {
quantity: 1, quantitypreordered: 0,
TotalPriceProduct: 0, price: 0,
idStorehouse: getActualIdStorehouse(myprod),
idGasordine: getActualGasordine(myprod),
}
await productStore.addtoCartBase({ $q, t, id: myprod._id, order: myorder, addqty: true })
search.value = ''
load()
}
}
onMounted(mounted)
return {
userStore,
costanti,
tools,
toolsext,
getNumItems,
myTotalPrice,
getItems,
change_field,
note,
statusnow,
shared_consts,
myTotalQty,
recOrderCart,
endload,
search,
insertArticolo,
t,
}
}
})

View File

@@ -0,0 +1,93 @@
<template>
<q-spinner v-if="!endload" color="primary" size="3em" :thickness="2" />
<div v-if="endload && recOrderCart.numorder > 0">
<div v-if="recOrderCart" class="panel">
<div class="numorder">
{{ t('orderscart.numero_ordine') }}: {{ recOrderCart.numorder }}
</div>
<div class="user">
{{ t('orderscart.nome') }}:
{{
recOrderCart.user
? tools.getNomeUtenteByRecUser(recOrderCart.user)
: ''
}}
</div>
<div
v-if="recOrderCart.items && recOrderCart.items.length > 0"
class="container"
>
<div
class="q-pa-sm col items-start q-gutter-xs"
v-for="(itemorder, index) in recOrderCart.items"
:key="index"
>
<CSingleCart
:order="itemorder.order"
:showall="false"
:idOrdersCart="recOrderCart._id"
:editmode="tools.isManager()"
:nomodif="true"
/>
</div>
</div>
<q-separator></q-separator>
<div class="col-6 q-mr-sm" style="text-align: right">
<span class="text-grey q-mr-xs">{{ t('ecomm.totale') }}:</span>
<span class="text-subtitle1 q-mr-sm"> {{ myTotalPrice() }}</span>
</div>
<q-input
v-if="tools.isManager() && getNumItems() > 0"
v-model="note"
style="max-width: 400px"
:label="t('ecomm.note')"
filled
dense
debounce="1000"
autogrow
@input="change_field('note')"
>
</q-input>
<q-label v-else> Note: {{ note }} </q-label>
<br />
</div>
</div>
<div v-else style="text-align: center" class="text-grey">
{{ t('ecomm.carrello_vuoto') }}
</div>
<br />
<div
v-if="tools.isManager()"
class="q-gutter-y-md column text-center q-mx-auto"
style="width: 350px; max-width: 100%"
>
<q-input
filled
stack-label
dense
:label="t('ecomm.code_add_to_cart')"
v-model="search"
class="q-ml-md"
@keyup.enter="insertArticolo()"
>
<template v-slot:append>
<q-icon
class="insert"
name="fas fa-shopping-cart"
color="green"
@click="insertArticolo()"
/>
</template>
</q-input>
</div>
</template>
<script lang="ts" src="./COrdersCart.ts">
</script>
<style lang="scss" scoped>
@import './COrdersCart';
</style>

View File

@@ -0,0 +1 @@
export {default as COrdersCart} from './COrdersCart.vue'

View File

@@ -9,7 +9,6 @@ import { useProducts } from '@store/Products'
import { useI18n } from '@src/boot/i18n' import { useI18n } from '@src/boot/i18n'
import { useQuasar } from 'quasar' import { useQuasar } from 'quasar'
export default defineComponent({ export default defineComponent({
name: 'CSingleCart', name: 'CSingleCart',
props: { props: {
@@ -17,11 +16,21 @@ export default defineComponent({
type: Object as PropType<IOrder>, type: Object as PropType<IOrder>,
required: true, required: true,
}, },
editmode: {
type: Boolean,
required: false,
default: false,
},
showall: { showall: {
type: Boolean, type: Boolean,
required: false, required: false,
default: false, default: false,
}, },
idOrdersCart: {
type: String,
required: false,
default: '',
},
nomodif: { nomodif: {
type: Boolean, type: Boolean,
required: false, required: false,
@@ -93,7 +102,12 @@ export default defineComponent({
} }
function removeFromCard() { function removeFromCard() {
products.removeFromCart({ order: order.value }) if (props.idOrdersCart) {
//
} else {
products.removeFromCart({ order: order.value })
}
} }
function getRisparmio(): string { function getRisparmio(): string {

View File

@@ -41,7 +41,27 @@
}) })
" "
></q-btn> ></q-btn>
<div v-if="showall" :class="`q-mx-sm text-blue-14 qta` "> <div v-if="editmode">
<q-input
v-model="order.quantity"
autofocus
debounce="500"
borderless
rounded
dense
:label="$t('products.quantity')"
></q-input>
<q-input
v-model="order.quantitypreordered"
autofocus
debounce="500"
borderless
rounded
dense
:label="$t('ecomm.preord')"
></q-input>
</div>
<div v-else-if="showall" :class="`q-mx-sm text-blue-14 qta` ">
{{ order.quantity + order.quantitypreordered }} {{ order.quantity + order.quantitypreordered }}
</div> </div>
@@ -99,7 +119,7 @@
<q-item-label> <q-item-label>
<div class="col-1"> <div class="col-1">
<q-btn <q-btn
v-if="!nomodif" v-if="!nomodif && editmode"
icon="fas fa-trash" icon="fas fa-trash"
color="negative" color="negative"
round round

View File

@@ -212,7 +212,7 @@ export interface IOrderCart {
numorder: number numorder: number
numord_pers: number numord_pers: number
userId: string userId: string
user: IUserFields, user: IUserFields | null,
totalQty: number totalQty: number
totalPrice: number totalPrice: number
department?: string department?: string
@@ -230,7 +230,7 @@ export interface IOrderCart {
date_spedito?: Date date_spedito?: Date
ricevuto: boolean ricevuto: boolean
date_ricevuto?: Date date_ricevuto?: Date
created_at: Date created_at?: Date
note: string note: string
} }

View File

@@ -1,24 +0,0 @@
import { defineComponent } from 'vue'
import { CImgText } from '../../../components/CImgText/index'
import { CCard } from '@/components/CCard'
import { CMyPage } from '@/components/CMyPage'
import { CTitleBanner } from '@/components/CTitleBanner'
import { CGridTableRec } from '@/components/CGridTableRec'
import { colTableCash } from '@src/store/Modules/fieldsTable'
import MixinMetaTags from '@/mixins/mixin-metatags'
export default defineComponent({
name: 'Cash',
components: { CImgText, CCard, CMyPage, CTitleBanner, CGridTableRec },
setup() {
const { setmeta } = MixinMetaTags()
return {
colTableCash,
setmeta,
}
}
})

View File

@@ -1,32 +0,0 @@
<template>
<CMyPage title="Cassa" imgbackground="images/prodotti.jpg" sizes="max-height: 120px">
<span>{{
setmeta({
title: 'Cassa',
description: '',
keywords: '',
})
}}
</span>
<div class="q-ma-sm q-gutter-sm q-pa-xs">
<CTitleBanner title="Cassa"></CTitleBanner>
<CGridTableRec
prop_mytable="cashs"
prop_mytitle="Cassa"
:prop_mycolumns="colTableCash"
prop_colkey="name"
nodataLabel="Nessuna Cassa"
noresultLabel="Il filtro selezionato non ha trovato nessun risultato">
</CGridTableRec>
</div>
</CMyPage>
</template>
<script lang="ts" src="./cash.ts">
</script>
<style lang="scss" scoped>
@import 'cash.scss';
</style>

View File

@@ -109,14 +109,8 @@ export default defineComponent({
async function load() { async function load() {
console.log('Newsletter load') console.log('Newsletter load')
myloadingload.value = true myloadingload.value = true
const mydata = { const myris = await userStore.newsletterload(true)
locale: tools.getLocale()
}
const myris = await userStore.newsletterload(mydata)
newsstate.value = myris.newsstate newsstate.value = myris.newsstate
globalStore.serv_settings = myris.serv_settings
globalStore.templemail = myris.templemail
globalStore.opzemail = myris.opzemail
// console.log('newsstate') // console.log('newsstate')
// console.table('globalStore.serv_settings', globalStore.serv_settings) // console.table('globalStore.serv_settings', globalStore.serv_settings)

View File

@@ -72,10 +72,10 @@ function getRoutesEcomm(site: ISites) {
{ {
active: true, active: true,
order: 30, order: 30,
path: '/admin/ecommerce/productInfos', path: '/admin/ecommerce/cash',
materialIcon: 'fas fa-lemon', materialIcon: 'fas fa-cash-register',
name: 'pages.productInfos', name: 'pages.cash',
component: () => import('@/rootgen/admin/productInfos/productInfos.vue'), component: () => import('@/views/ecommerce/cash/cash.vue'),
inmenu: true, inmenu: true,
submenu: true, submenu: true,
level_parent: 0, level_parent: 0,
@@ -86,10 +86,10 @@ function getRoutesEcomm(site: ISites) {
{ {
active: true, active: true,
order: 30, order: 30,
path: '/admin/ecommerce/cash', path: '/admin/ecommerce/productInfos',
materialIcon: 'fas fa-cash-register', materialIcon: 'fas fa-lemon',
name: 'pages.cash', name: 'pages.productInfos',
component: () => import('@/rootgen/admin/cash/cash.vue'), component: () => import('@/rootgen/admin/productInfos/productInfos.vue'),
inmenu: true, inmenu: true,
submenu: true, submenu: true,
level_parent: 0, level_parent: 0,
@@ -245,15 +245,6 @@ function getRoutesEcomm(site: ISites) {
inmenu: false, inmenu: false,
infooter: false, infooter: false,
}, },
{
active: true,
order: 30,
path: '/admin/ecommerce/cash',
name: 'pages.cash',
component: () => import('@/rootgen/admin/cash/cash.vue'),
inmenu: false,
infooter: false,
},
{ {
active: true, active: true,
order: 31, order: 31,
@@ -354,6 +345,16 @@ function getRoutesEcomm(site: ISites) {
inmenu: false, inmenu: false,
infooter: false infooter: false
}, },
{
active: true,
order: 1000,
path: '/orderscart/:idorderscart',
materialIcon: 'event',
name: 'otherpages.orderscart',
component: () => import('@/views/ecommerce/orderscart/orderscart.vue'),
inmenu: false,
infooter: false
},
] ]

View File

@@ -112,6 +112,7 @@ const msg_it = {
myactivities: 'Attività', myactivities: 'Attività',
myactivities2: 'Mie Attività', myactivities2: 'Mie Attività',
product: 'Prodotto', product: 'Prodotto',
orderscart: 'Ordini',
sito_offline: 'Sito in Aggiornamento', sito_offline: 'Sito in Aggiornamento',
modifprof: 'Modifica', modifprof: 'Modifica',
modifgrp: 'Modifica Gruppo', modifgrp: 'Modifica Gruppo',
@@ -1711,6 +1712,7 @@ const msg_it = {
offerta_gas: 'Offerta valida al raggiungimento di {qta} {unit}', offerta_gas: 'Offerta valida al raggiungimento di {qta} {unit}',
offerta_gas_raggiunta: 'Complimenti! Gli ordini hanno superato il minimo quantitativo di {qta} {unit}', offerta_gas_raggiunta: 'Complimenti! Gli ordini hanno superato il minimo quantitativo di {qta} {unit}',
note: 'Note', note: 'Note',
apriordine: 'Vedi Ordine',
}, },
gas: { gas: {
name: 'Ordine Gas', name: 'Ordine Gas',
@@ -1727,6 +1729,12 @@ const msg_it = {
numorder: 'Ordine', numorder: 'Ordine',
totalQty: 'totalQty', totalQty: 'totalQty',
totalQtyPreordered: 'totalQty PreOrd', totalQtyPreordered: 'totalQty PreOrd',
numero_ordine: 'Numero d\'Ordine',
nome: 'Nominativo',
sendmail: 'Invia Email a Tutti',
sendmail_test: 'Invia Email TEST',
email_sent: '{inviate} email inviate !',
email_not_send: 'Email non inviata',
}, },
cash: { cash: {
creatorUserId: 'Creatore', creatorUserId: 'Creatore',

View File

@@ -2395,36 +2395,6 @@ const colTableEvents = [
AddCol(DuplicateRec), AddCol(DuplicateRec),
] ]
export const colTableCash = [
AddCol({ name: '_id', label_trans: 'event._id' }),
AddCol({ name: 'creatorUserId', label_trans: 'order.users', fieldtype: costanti.FieldType.select, jointable: 'users' }),
AddCol({
name: 'idCashCategory',
label_trans: 'Category.idCashCategory',
fieldtype: costanti.FieldType.select,
jointable: 'cashcategory',
}),
AddCol({ name: 'fromUsername', label_trans: 'cash.fromUsername', fieldtype: costanti.FieldType.string }),
AddCol({ name: 'toUsername', label_trans: 'cash.toUsername', fieldtype: costanti.FieldType.string }),
AddCol({ name: 'idOrdersCart', label_trans: 'cash.orderscart', fieldtype: costanti.FieldType.select, jointable: 'orderscart' }),
AddCol({ name: 'type', label_trans: 'cash.type', fieldtype: costanti.FieldType.select, jointable: toolsext.TABTYPECASH }),
AddCol({
name: 'date_payment', label_trans: 'cash.date_payment', fieldtype: costanti.FieldType.onlydate,
sortable: true,
}),
AddCol({ name: 'price', label_trans: 'products.price', fieldtype: costanti.FieldType.number }),
AddCol({ name: 'causale', label_trans: 'cash.causale' }),
AddCol({ name: 'note', label_trans: 'cash.note' }),
AddCol({ name: 'internal', label_trans: 'cash.internal', fieldtype: costanti.FieldType.boolean }),
AddCol({ name: 'extra', label_trans: 'cash.extra', fieldtype: costanti.FieldType.boolean }),
AddCol({ name: 'confirmed', label_trans: 'cash.confirmed', fieldtype: costanti.FieldType.boolean }),
AddCol({
name: 'date_created', label_trans: 'reg.pub_created', fieldtype: costanti.FieldType.onlydate,
sortable: true,
}),
AddCol(DeleteRec),
AddCol(DuplicateRec),
]
export const fields = { export const fields = {
colSettings: [ colSettings: [
@@ -3703,7 +3673,7 @@ export const fieldsTable = {
collabel: '_id', collabel: '_id',
}, },
{ {
value: 'orderscart', value: 'orderscarts',
label: 'Ordini', label: 'Ordini',
columns: colTableOrdersCart, columns: colTableOrdersCart,
colkey: '_id', colkey: '_id',
@@ -3723,13 +3693,6 @@ export const fieldsTable = {
colkey: '_id', colkey: '_id',
collabel: 'name', collabel: 'name',
}, },
{
value: 'cashs',
label: 'Cassa',
columns: colTableCash,
colkey: '_id',
collabel: 'causale',
},
{ {
value: 'departments', value: 'departments',
label: 'Uffici', label: 'Uffici',

View File

@@ -14,6 +14,24 @@ import { ref } from 'vue'
import translate from '@src/globalroutines/util' import translate from '@src/globalroutines/util'
function getRecordOrdersCartEmpty(): IOrderCart {
return {
numorder: 0,
numord_pers: 0,
userId: '',
user: null,
totalQty: 0,
totalPrice: 0,
status: 0,
confermato: false,
consegnato: false,
pagato: false,
spedito: false,
ricevuto: false,
note: '',
}
}
function getRecordProductInfoEmpty(): IProductInfo { function getRecordProductInfoEmpty(): IProductInfo {
return { return {
code: '', code: '',
@@ -228,6 +246,14 @@ export const useProducts = defineStore('Products', {
return null return null
}, },
getOrdersCartById: (state: IProductsState) => (idordercart: string): IOrderCart => {
if (state.orders) {
const orderscart = state.orders.find((rec: IOrderCart) => rec._id === idordercart)
return orderscart ?? getRecordOrdersCartEmpty()
}
return getRecordOrdersCartEmpty()
},
getSumQtyPreOrderInOrdersCart: (state: IProductsState) => (idproduct: string): number => { getSumQtyPreOrderInOrdersCart: (state: IProductsState) => (idproduct: string): number => {
let totalQuantity = 0; let totalQuantity = 0;
@@ -900,8 +926,18 @@ export const useProducts = defineStore('Products', {
getNumQtaBottega() { getNumQtaBottega() {
const arrprod = this.getProducts(shared_consts.PROD.BOTTEGA) const arrprod = this.getProducts(shared_consts.PROD.BOTTEGA)
return arrprod.length return arrprod.length
} },
async sendMailToTheBuyer(idOrdersCart: string, templemail_id: string, test: boolean) {
return await Api.SendReq('/orders/sendmail', 'POST', { templemail_id, idOrdersCart, previewonly: tools.isDebug(), test })
.then((res) => {
console.log('res', res)
if (res)
return res.data
else
return null
})
},
}, },

View File

@@ -15,6 +15,7 @@ import {
IColGridTable, IColGridTable,
ISignupIscrizioneConacreisOptions, ISignupIscrizioneConacreisOptions,
ISignupIscrizioneArcadeiOptions, ISignupIscrizioneArcadeiOptions,
ISettings,
} from '@src/model' } from '@src/model'
import { tools } from '@store/Modules/tools' import { tools } from '@store/Modules/tools'
import translate from '@src/globalroutines/util' import translate from '@src/globalroutines/util'
@@ -1021,11 +1022,26 @@ export const useUserStore = defineStore('UserStore', {
} }
}, },
async newsletterload(paramquery: any) { async newsletterload(force: boolean) {
return Api.SendReq('/news/load', 'POST', paramquery) const globalStore = useGlobalStore()
.then((res) => {
const mydata = {
locale: tools.getLocale()
}
if ((globalStore.serv_settings.length > 0) && !force)
return null;
return Api.SendReq('/news/load', 'POST', mydata)
.then((res: any) => {
// console.log('res', res) // console.log('res', res)
if (res.data) {
globalStore.serv_settings = res.data.serv_settings
globalStore.templemail = res.data.templemail
globalStore.opzemail = res.data.opzemail
}
return res.data return res.data
}).catch((error) => { }).catch((error) => {
return null return null
@@ -1117,10 +1133,10 @@ export const useUserStore = defineStore('UserStore', {
this.usersList = [...usersList] this.usersList = [...usersList]
}, },
setlang($q: any, $router: Router, newstr: string) { setlang($q: any, router: Router, newstr: string) {
console.log('SETLANG', newstr) console.log('SETLANG', newstr)
this.lang = newstr this.lang = newstr
toolsext.setLangAtt($q, $router, newstr) toolsext.setLangAtt($q, router, newstr)
tools.localStSetItem(toolsext.localStorage.lang, this.lang) tools.localStSetItem(toolsext.localStorage.lang, this.lang)
}, },
@@ -1258,7 +1274,7 @@ export const useUserStore = defineStore('UserStore', {
}, },
async signin($router: Router, authData: ISigninOptions) { async signin(router: Router, authData: ISigninOptions) {
console.log('LOGIN signin') console.log('LOGIN signin')
const globalStore = useGlobalStore() const globalStore = useGlobalStore()
@@ -1321,7 +1337,7 @@ export const useUserStore = defineStore('UserStore', {
}).then((code) => { }).then((code) => {
if (code === tools.OK) { if (code === tools.OK) {
return this.setGlobal($router, true) return this.setGlobal(router, true)
.then(() => { .then(() => {
return code return code
}) })
@@ -1338,7 +1354,7 @@ export const useUserStore = defineStore('UserStore', {
async logout() { async logout() {
const globalStore = useGlobalStore() const globalStore = useGlobalStore()
// const $router = useRouter()
console.log('logout') console.log('logout')
@@ -1375,7 +1391,7 @@ export const useUserStore = defineStore('UserStore', {
}) })
}, },
async setGlobal($router: Router, isLogged: boolean) { async setGlobal(router: Router, isLogged: boolean) {
console.log('setGlobal', isLogged) console.log('setGlobal', isLogged)
const globalStore = useGlobalStore() const globalStore = useGlobalStore()
@@ -1405,7 +1421,7 @@ export const useUserStore = defineStore('UserStore', {
if (globalStore.site.confpages.enableProj) if (globalStore.site.confpages.enableProj)
await projects.dbLoad({ checkPending: true, onlyiffirsttime: true }) await projects.dbLoad({ checkPending: true, onlyiffirsttime: true })
globalStore.addDynamicPages($router) globalStore.addDynamicPages(router)
static_data.lang_available = globalStore.getLangAvailable() static_data.lang_available = globalStore.getLangAvailable()
@@ -1426,7 +1442,7 @@ export const useUserStore = defineStore('UserStore', {
// console.log('setGlobal: END') // console.log('setGlobal: END')
}, },
async autologin_FromLocalStorage($router: Router, $q: any) { async autologin_FromLocalStorage(router: Router, $q: any) {
try { try {
const globalStore = useGlobalStore() const globalStore = useGlobalStore()
@@ -1454,7 +1470,7 @@ export const useUserStore = defineStore('UserStore', {
isLogged = tools.isLogged() isLogged = tools.isLogged()
} }
return await this.setGlobal($router, isLogged) return await this.setGlobal(router, isLogged)
.then((loadstorage: any) => { .then((loadstorage: any) => {
// console.log('RISULT setGlobal:', loadstorage) // console.log('RISULT setGlobal:', loadstorage)
if (loadstorage) { if (loadstorage) {
@@ -1760,13 +1776,13 @@ export const useUserStore = defineStore('UserStore', {
let msg = '' let msg = ''
if (res.data.imported) { if (res.data.imported) {
msg += ' ' + t('db.records_imported', {num: res.data.imported}) msg += ' ' + t('db.records_imported', { num: res.data.imported })
} }
if (res.data.errors) { if (res.data.errors) {
msg += ' ' + t('db.records_errors', {num: res.data.errors}) msg += ' ' + t('db.records_errors', { num: res.data.errors })
} }
if (res.data.updated) { if (res.data.updated) {
msg += ' ' + t('db.records_updated', {num: res.data.updated}) msg += ' ' + t('db.records_updated', { num: res.data.updated })
} }
if (!msg) { if (!msg) {
msg = t('db.recupdated') msg = t('db.recupdated')
@@ -1931,7 +1947,7 @@ export const useUserStore = defineStore('UserStore', {
const globalStore = useGlobalStore() const globalStore = useGlobalStore()
if (globalStore.site && (!globalStore.site.confpages.showCoins && !globalStore.site.confpages.showRIS)) { if (globalStore.site && (!globalStore.site.confpages.showCoins && !globalStore.site.confpages.showRIS)) {
return false return false
} }

View File

@@ -1,3 +1,4 @@
import { createPinia } from 'pinia'; import { createPinia } from 'pinia';
export default createPinia(); export default createPinia();

View File

@@ -0,0 +1,14 @@
$heightBtn: 100%;
.card .product-image {
height: 300px;
}
.container{
margin-top: 4px;
margin-bottom: 4px;
}
.prod_trov{
font-style: italic;
}

116
src/views/ecommerce/cash/cash.ts Executable file
View File

@@ -0,0 +1,116 @@
import { defineComponent, onMounted, ref, watch, computed } from 'vue'
import { tools } from '@store/Modules/tools'
import { useUserStore } from '@store/UserStore'
import { useRouter } from 'vue-router'
import { useGlobalStore } from '@store/globalStore'
import { useProducts } from '@store/Products'
import { useI18n } from '@/boot/i18n'
import { toolsext } from '@store/Modules/toolsext'
import { useQuasar } from 'quasar'
import { costanti } from '@costanti'
import { shared_consts } from '@/common/shared_vuejs'
import { CProductCard } from '@src/components/CProductCard'
import { IProduct } from '@src/model'
export default defineComponent({
name: 'cash',
components: { CProductCard },
props: {},
setup() {
const userStore = useUserStore()
const globalStore = useGlobalStore()
const productStore = useProducts()
const $router = useRouter()
const $q = useQuasar()
const { t } = useI18n()
const search = ref('')
const cosa = ref(0)
const cat = ref('')
const loadpage = ref(false)
watch(() => cosa.value, (newval, oldval) => {
tools.setCookie(tools.COOK_COSA_PRODOTTI, cosa.value.toString())
})
const getArrProducts = computed(() => {
let arrprod = productStore.getProducts(cosa.value)
let catstr = cat.value;
let lowerSearchText = search.value.toLowerCase().trim();
if ((!lowerSearchText || (lowerSearchText && lowerSearchText.length < 2)) && !catstr) {
return arrprod
}
return arrprod.filter((product: IProduct) => {
let lowerName = product.productInfo.name!.toLowerCase();
let hasCategoria = !catstr || (catstr && product.productInfo.idCatProds?.includes(catstr));
// Use a regular expression to match whole words
let codeMatch = new RegExp(`\\b${lowerSearchText}\\b`, 'i');
let nameMatch = new RegExp(`\\b${lowerSearchText}`, 'i');
// Check if any word in lowerName starts with lowerSearchText
let anyWordStartsWithSearch = lowerName.split(/\s+/).some(word => nameMatch.test(word));
return (codeMatch.test(product.productInfo.code!) || anyWordStartsWithSearch) && hasCategoria;
});
})
/*function getProducts() {
let arrprod = productStore.getProducts(cosa.value)
if (!search.value) {
return arrprod
}
let lowerSearchText = search.value.toLowerCase();
let catstr = cat.value;
return arrprod.filter((product: IProduct) => {
let lowerName = product.productInfo.name!.toLowerCase();
const hasCategoria = !catstr || (catstr && product.productInfo.idCatProds?.includes(catstr));
return (product.productInfo.code!.includes(search.value) || lowerName.includes(lowerSearchText)) && hasCategoria
});
}*/
async function mounted() {
loadpage.value = false
await productStore.loadProducts()
cosa.value = tools.getCookie(tools.COOK_COSA_PRODOTTI, shared_consts.PROD.BOTTEGA, true)
// Inizializza
loadpage.value = true
}
function getCatProds() {
let arrcat = productStore.getCatProds()
let riscat: any = [{ label: 'Tutti', value: '', icon: undefined, color: undefined }]
for (const rec of arrcat) {
riscat.push({ label: rec.name, value: rec._id, icon: rec.icon, color: rec.color })
}
return riscat
}
onMounted(mounted)
return {
userStore,
costanti,
tools,
toolsext,
getArrProducts,
search,
cosa,
shared_consts,
getCatProds,
cat,
productStore,
t,
loadpage,
}
}
})

116
src/views/ecommerce/cash/cash.vue Executable file
View File

@@ -0,0 +1,116 @@
<template>
<q-page>
<div class="text-center">
<q-spinner v-if="!loadpage" color="primary" size="3em" :thickness="2" />
</div>
<div v-if="loadpage" class="panel">
<div>
<div class="text-center">
<q-btn-toggle
v-model="cosa"
push
:size="tools.isMobile() ? '0.75rem' : '1rem'"
rounded
glossy
dense
toggle-color="purple"
:options="[
{ value: shared_consts.PROD.BOTTEGA, slot: 'bottega' },
{ value: shared_consts.PROD.GAS, slot: 'gas' },
]"
>
<template v-slot:gas>
<div class="row items-center no-wrap">
<div class="text-center">
{{ t('gas.ordina_sul_gas') }}
<br />
{{
t('gas.x_prodotti_gas', {
qta: productStore.getNumQtaGas(),
})
}}
</div>
<q-icon right name="fas fa-user-friends" />
</div>
</template>
<template v-slot:bottega>
<div class="row items-center no-wrap">
<div class="text-center">
{{ t('gas.bottega') }}
<br />
{{
t('gas.x_prodotti_bottega', {
qta: productStore.getNumQtaBottega(),
})
}}
</div>
<q-icon right name="fas fa-store" />
</div>
</template>
</q-btn-toggle>
</div>
</div>
<div class="container">
<div
class="column text-center q-mx-auto q-py-sm q-mb-sm"
style="width: 350px; max-width: 100%"
>
<q-input
filled
stack-label
:dense="tools.isMobile() ? true : false"
:label="t('ecomm.code_o_text_search')"
v-model="search"
debounce="500"
class="q-ml-md"
>
<template v-slot:append>
<q-icon name="search" />
</template>
</q-input>
</div>
<div class="row q-gutter-xs justify-center q-mx-auto">
<div v-for="(reccat, index) in getCatProds()" :key="index">
<q-btn
:push="cat === reccat.value"
dense
:size="tools.isMobile() ? '0.70rem' : '1rem'"
:icon="reccat.icon ? reccat.icon : undefined"
:color="cat === reccat.value ? 'primary' : undefined"
:text-color="cat === reccat.value ? 'white' : 'black'"
rounded
:label="reccat.label"
@click="cat = reccat.value"
>
</q-btn>
</div>
</div>
<div class="text-center q-py-sm prod_trov">
{{
t('ecomm.prodotti_trovati', {
qta: getArrProducts.length,
qtatot: productStore.getNumProdTot(),
})
}}{{}}
</div>
<div class="row justify-around">
<div
class="q-pa-xs row items-start"
v-for="(product, index) in getArrProducts"
:key="index"
>
<CProductCard :id="product._id" :complete="false" :cosa="cosa" />
</div>
</div>
</div>
</div>
</q-page>
</template>
<script lang="ts" src="./cash.ts">
</script>
<style lang="scss" scoped>
@import './cash';
</style>

View File

@@ -0,0 +1 @@
export {default as ProductsList} from './cash.vue'

View File

@@ -13,209 +13,19 @@ import { ICart, IOrder, IOrderCart, IProduct, IShareWithUs } from '@src/model/Pr
import { shared_consts } from '@src/common/shared_vuejs' import { shared_consts } from '@src/common/shared_vuejs'
import { CSingleCart } from '../../../components/CSingleCart' import { CSingleCart } from '../../../components/CSingleCart'
import { CCart } from '../../../components/CCart'
import { CTitleBanner } from '@components' import { CTitleBanner } from '@components'
export default defineComponent({ export default defineComponent({
name: 'checkOut', name: 'checkOut',
components: { CSingleCart, CTitleBanner }, components: { CSingleCart, CTitleBanner, CCart },
props: {}, props: {},
setup() { setup() {
const userStore = useUserStore() const userStore = useUserStore()
const globalStore = useGlobalStore()
const productStore = useProducts()
const $router = useRouter()
const $q = useQuasar()
const { t } = useI18n(); const { t } = useI18n();
const mycart = ref(<ICart>{})
const myrec = ref(<any[string]>[])
const oldrec = ref(<any[string]>[])
const note = ref('')
const endload = ref(false)
const recOrderCart = ref(<IOrderCart>{})
const search = ref('')
const statusnow = computed(() => (): number => {
if (recOrderCart.value) {
return recOrderCart.value.status
}
return 0
})
function mounted() { function mounted() {
// Inizializza // Inizializza
load()
}
function getItemsCart() {
const cart = productStore.getCart()
return cart.items || null
}
function getNumItems(): number {
const cart = productStore.getCart()
if (!!cart.items)
return cart.items.length || 0
else
return 0
}
function getCart(): ICart {
return productStore.getCart()
}
function getNote() {
const cart = productStore.getCart()
return cart.note
}
function change_field(fieldname: string) {
if (myrec.value[fieldname] !== oldrec.value[fieldname]) {
myrec.value[fieldname] = oldrec.value[fieldname]
const mydata = {
[fieldname]: myrec.value[fieldname]
}
const aggiorna = fieldname !== 'status'
tools.saveFieldToServer($q, 'carts', mycart.value._id, mydata, aggiorna)
oldrec.value[fieldname] = myrec.value[fieldname]
}
}
function myTotalPrice(): string {
if (productStore.cart && productStore.cart.totalPrice) {
return productStore.cart.totalPrice.toFixed(2)
} else {
return '0'
}
}
function myTotalQty(): number {
if (productStore.cart) {
return productStore.cart.totalQty!
} else {
return 0
}
}
async function load() {
mycart.value = getCart()
myrec.value = Object.keys(mycart)
oldrec.value = myrec.value
note.value = mycart.value.note!
let options = {};
if (mycart.value) {
recOrderCart.value = await productStore.CreateOrdersCart({ cart_id: mycart.value._id, status: 0, note: note.value })
}
console.log('myrec', myrec.value)
endload.value = true
}
function CanBeShipped() {
return productStore.cart.items ? productStore.cart.items.filter((rec: any) => rec.order.product.canBeShipped).length : false
}
function CanBeBuyOnline() {
return productStore.cart.items ? productStore.cart.items.filter((rec: any) => rec.order.product.canBeBuyOnline).length : false
}
function getnumsteps() {
let numsteps = 1
if (CanBeShipped())
numsteps++
if (CanBeBuyOnline())
numsteps++
return numsteps
}
function docheckout() {
// Può essere spedito?
if (CanBeShipped()) {
// mostra form di spedizione
}
if (CanBeBuyOnline()) {
// mostra form di acquisto Online
}
}
function completeOrder() {
$q.dialog({
message: t('ecomm.conferma_acq', { qty: myTotalQty() }),
ok: {
label: t('dialog.yes'),
push: true
},
cancel: {
label: t('dialog.cancel')
},
title: t('ecomm.order')
}).onOk(async () => {
const status = shared_consts.OrderStatus.CHECKOUT_SENT
recOrderCart.value = await productStore.CreateOrdersCart({ cart_id: mycart.value._id, status, note: note.value })
// statusnow.value = myordercart ? myordercart.status : 0
if (recOrderCart.value.status === status) {
tools.showPositiveNotif($q, t('ecomm.ord_confirmed'))
setTimeout(() => {
$router.push('/orderinfo')
}, 2000)
} else {
tools.showNegativeNotif($q, t('ecomm.ord_not_confirmed'))
}
// change_field('status')
// change_field('status')
})
}
function getActualIdStorehouse(myprod: IProduct) {
// Ottieni il negozio attualmente selezionato:
// Se ce n'è solo 1 allora prendi quello !
if (myprod.storehouses.length === 1) {
return myprod.storehouses[0]._id
} else {
// Ottieni il negozio attualmente scelto !
return ''
}
}
function getActualGasordine(myprod: IProduct) {
// Ottieni il negozio attualmente selezionato:
// Se ce n'è solo 1 allora prendi quello !
if (myprod.gasordines.length === 1) {
return myprod.gasordines[0]._id
} else {
// Ottieni il gasordine attualmente scelto !
return ''
}
}
async function insertArticolo() {
let lowerSearchText = search.value.trim();
const myprod = productStore.getProductByCode(lowerSearchText);
if (myprod && myprod.active) {
let myorder: IOrder = { quantity: 1, quantitypreordered: 0,
TotalPriceProduct: 0, price: 0,
idStorehouse: getActualIdStorehouse(myprod),
idGasordine: getActualGasordine(myprod),
}
await productStore.addtoCartBase({ $q, t, id: myprod._id, order: myorder, addqty: true })
search.value = ''
load()
}
} }
onMounted(mounted) onMounted(mounted)
@@ -225,21 +35,8 @@ export default defineComponent({
costanti, costanti,
tools, tools,
toolsext, toolsext,
completeOrder,
getNumItems,
myTotalPrice,
getItemsCart,
getNote,
change_field,
note,
statusnow,
shared_consts, shared_consts,
myTotalQty, t,
recOrderCart,
mycart,
endload,
search,
insertArticolo,
} }
} }
}) })

View File

@@ -1,82 +1,8 @@
<template> <template>
<q-page> <q-page>
<CTitleBanner :title="$t('ecomm.carrello')"></CTitleBanner> <CTitleBanner :title="t('ecomm.carrello')"></CTitleBanner>
<q-spinner v-if="!endload" color="primary" size="3em" :thickness="2" /> <CCart>
<div v-if="endload"> </CCart>
<div v-if="recOrderCart" class="panel">
<div>
<div class="container">
<div
class="q-pa-sm col items-start q-gutter-xs"
v-for="(itemorder, index) in getItemsCart()"
:key="index"
>
<CSingleCart :order="itemorder.order" :showall="true" />
</div>
</div>
<q-separator></q-separator>
<div class="col-6 q-mr-sm" style="text-align: right">
<span class="text-grey q-mr-xs">{{ $t('ecomm.totale') }}:</span>
<span class="text-subtitle1 q-mr-sm"> {{ myTotalPrice() }}</span>
</div>
<q-input
v-if="getNumItems() > 0"
v-model="note"
style="max-width: 400px"
:label="$t('ecomm.note')"
filled
dense
debounce="1000"
autogrow
@input="change_field('note')"
>
</q-input>
<br />
</div>
<div class="text-center">
<q-btn
v-if="
recOrderCart &&
recOrderCart.status < shared_consts.OrderStatus.CHECKOUT_SENT
"
rounded
icon="fas fa-shopping-cart"
color="green"
:label="$t('ecomm.completa_ord')"
class="q-mb-sm"
:disabled="myTotalQty() < 1"
@click="completeOrder()"
></q-btn>
</div>
</div>
<div v-else style="text-align: center" class="text-grey">
{{ $t('ecomm.carrello_vuoto') }}
</div>
<br >
<div
class="q-gutter-y-md column text-center q-mx-auto"
style="width: 350px; max-width: 100%"
>
<q-input
filled
stack-label
dense
:label="$t('ecomm.code_add_to_cart')"
v-model="search"
class="q-ml-md"
@keyup.enter="insertArticolo()"
>
<template v-slot:append>
<q-icon class="insert" name="fas fa-shopping-cart" color="green" @click="insertArticolo()"/>
</template>
</q-input>
</div>
</div>
</q-page> </q-page>
</template> </template>

View File

@@ -10,14 +10,16 @@ import { useQuasar } from 'quasar'
import { costanti } from '@costanti' import { costanti } from '@costanti'
import { shared_consts } from '@src/common/shared_vuejs' import { shared_consts } from '@src/common/shared_vuejs'
// import MixinBase from '@src/mixins/mixin-base' // import MixinBase from '@src/mixins/mixin-base'
import { serv_constants } from '@store/Modules/serv_constants'
import { fieldsTable } from '@store/Modules/fieldsTable'
import { CSingleCart } from '../../../components/CSingleCart' import { CSingleCart } from '../../../components/CSingleCart'
import { CTitleBanner } from '@components' import { CTitleBanner, CMyFieldDb } from '@components'
import { ICart, IOrder, IOrderCart } from '@src/model' import { ICart, IOrder, IOrderCart } from '@src/model'
export default defineComponent({ export default defineComponent({
name: 'OrderInfo', name: 'OrderInfo',
components: { CSingleCart, CTitleBanner }, components: { CSingleCart, CTitleBanner, CMyFieldDb },
props: {}, props: {},
setup() { setup() {
const userStore = useUserStore() const userStore = useUserStore()
@@ -30,6 +32,7 @@ export default defineComponent({
const myorderscart = ref(<IOrderCart[] | undefined>[]) const myorderscart = ref(<IOrderCart[] | undefined>[])
const myarrrec = ref(<any>{}) const myarrrec = ref(<any>{})
const myoldrec = ref(<any>{}) const myoldrec = ref(<any>{})
const templemail = ref('')
const cosa = ref(0) const cosa = ref(0)
@@ -48,6 +51,14 @@ export default defineComponent({
const statusnow = ref(0) const statusnow = ref(0)
const arrnumstatus = ref(<any[]>[]) const arrnumstatus = ref(<any[]>[])
const columns = ref(<any>[ const columns = ref(<any>[
{
name: 'apri',
align: 'center',
required: false,
label: 'Apri',
field: 'apri',
sortable: false
},
{ {
name: 'numorder', name: 'numorder',
required: true, required: true,
@@ -89,6 +100,14 @@ export default defineComponent({
]) ])
const columns_Admin = ref(<any>[ const columns_Admin = ref(<any>[
{
name: 'apri',
align: 'center',
required: false,
label: 'Apri',
field: 'apri',
sortable: false
},
{ {
name: 'numorder', name: 'numorder',
required: true, required: true,
@@ -170,9 +189,10 @@ export default defineComponent({
const totals = { const totals = {
created_at: new Date(), created_at: new Date(),
items: null, items: null,
user:{ user: {
name: 'TOTALI', name: 'TOTALI',
surname: '', surname: '',
email: '',
}, },
status: 0, status: 0,
// Add other properties as needed // Add other properties as needed
@@ -227,6 +247,7 @@ export default defineComponent({
async function mounted() { async function mounted() {
await userStore.newsletterload(false)
await productStore.loadProducts() await productStore.loadProducts()
taborders.value = -1 taborders.value = -1
@@ -312,6 +333,41 @@ export default defineComponent({
}) })
} }
async function sendMailToAll() {
const orders = getOrdersCartWithTotals()
let res = null
let inviate = 0
for (const ord of orders) {
res = await productStore.sendMailToTheBuyer(ord._id, templemail.value, false)
if (res && res.emailsend)
inviate++
}
if (inviate > 0) {
tools.showPositiveNotif($q, t('orderscart.email_sent', { inviate }))
} else {
tools.showNegativeNotif($q, t('orderscart.email_not_send'))
}
}
async function sendMailTest() {
const orders = getOrdersCartWithTotals()
if (orders && orders.length > 0) {
const res = await productStore.sendMailToTheBuyer(orders[0]._id, templemail.value, true)
if (res && res.emailsend) {
tools.showPositiveNotif($q, t('reset.email_sent'))
} else {
tools.showNegativeNotif($q, t('orderscart.email_not_send'))
}
}
}
onMounted(mounted) onMounted(mounted)
return { return {
@@ -320,6 +376,7 @@ export default defineComponent({
tools, tools,
toolsext, toolsext,
shared_consts, shared_consts,
globalStore,
columns, columns,
taborders, taborders,
arrnumstatus, arrnumstatus,
@@ -334,6 +391,10 @@ export default defineComponent({
t, t,
initialPagination, initialPagination,
cosa, cosa,
sendMailToAll,
sendMailTest,
templemail,
fieldsTable,
} }
} }
}) })

View File

@@ -4,54 +4,64 @@
<q-spinner v-if="!endload" color="primary" size="3em" :thickness="2" /> <q-spinner v-if="!endload" color="primary" size="3em" :thickness="2" />
<div class="q-gutter-md text-center"> <div class="q-gutter-md text-center">
<q-btn-toggle <q-btn-toggle
v-model="cosa" v-model="cosa"
push push
rounded rounded
glossy glossy
toggle-color="purple" toggle-color="purple"
:options="[ :options="[
{ value: shared_consts.PROD.TUTTI, slot: 'tutti' }, { value: shared_consts.PROD.TUTTI, slot: 'tutti' },
{ value: shared_consts.PROD.BOTTEGA, slot: 'bottega' }, { value: shared_consts.PROD.BOTTEGA, slot: 'bottega' },
{ value: shared_consts.PROD.GAS, slot: 'gas' }, { value: shared_consts.PROD.GAS, slot: 'gas' },
]" ]"
> >
<template v-slot:tutti> <template v-slot:tutti>
<div class="row items-center no-wrap"> <div class="row items-center no-wrap">
<div class="text-center"> <div class="text-center">
{{ t('gas.tutti') }} {{ t('gas.tutti') }}
<br /> <br />
{{ t('gas.x_prodotti_gas', { qta: productStore.getNumQtaGas()+productStore.getNumQtaBottega() }) }} {{
</div> t('gas.x_prodotti_gas', {
<q-icon right name="fas fa-user-friends" /> qta:
</div> productStore.getNumQtaGas() +
</template> productStore.getNumQtaBottega(),
<template v-slot:gas> })
<div class="row items-center no-wrap"> }}
<div class="text-center"> </div>
{{ t('gas.ordina_sul_gas') }} <q-icon right name="fas fa-user-friends" />
<br /> </div>
{{ t('gas.x_prodotti_gas', { qta: productStore.getNumQtaGas() }) }} </template>
</div> <template v-slot:gas>
<q-icon right name="fas fa-user-friends" /> <div class="row items-center no-wrap">
</div> <div class="text-center">
</template> {{ t('gas.ordina_sul_gas') }}
<br />
{{
t('gas.x_prodotti_gas', { qta: productStore.getNumQtaGas() })
}}
</div>
<q-icon right name="fas fa-user-friends" />
</div>
</template>
<template v-slot:bottega> <template v-slot:bottega>
<div class="row items-center no-wrap"> <div class="row items-center no-wrap">
<div class="text-center"> <div class="text-center">
{{ t('gas.bottega') }} {{ t('gas.bottega') }}
<br /> <br />
{{ {{
t('gas.x_prodotti_bottega', { qta: productStore.getNumQtaBottega() }) t('gas.x_prodotti_bottega', {
}} qta: productStore.getNumQtaBottega(),
</div> })
<q-icon right name="fas fa-store" /> }}
</div> </div>
</template> <q-icon right name="fas fa-store" />
</q-btn-toggle> </div>
</div> </template>
˚ </q-btn-toggle>
</div>
˚
<div v-if="endload" class="panel"> <div v-if="endload" class="panel">
<q-tabs v-model="taborders" inline-label class="text-blue"> <q-tabs v-model="taborders" inline-label class="text-blue">
<span v-for="(stat, index) of shared_consts.OrderStat" :key="index"> <span v-for="(stat, index) of shared_consts.OrderStat" :key="index">
@@ -105,7 +115,12 @@
:key="index" :key="index"
> >
<div <div
v-if="!!item && item.order && item.order.product && item.order.product.productInfo" v-if="
!!item &&
item.order &&
item.order.product &&
item.order.product.productInfo
"
> >
{{ item.order.product.productInfo.name }} ({{ {{ item.order.product.productInfo.name }} ({{
productStore.getQuantityByOrder(t, item.order) productStore.getQuantityByOrder(t, item.order)
@@ -156,6 +171,17 @@
</q-btn-dropdown> </q-btn-dropdown>
</div> </div>
</q-item-label> </q-item-label>
<q-item-label v-else-if="col.name === 'apri'" caption>
<div class="q-pa-sm">
<q-btn
size="sm"
dense
icon="fas fa-filter"
:label="t('ecomm.apriordine')"
:to="`/orderscart/{$idOrdersCart}`"
></q-btn>
</div>
</q-item-label>
<q-item-label v-else caption>{{ <q-item-label v-else caption>{{
col.value col.value
}}</q-item-label> }}</q-item-label>
@@ -167,6 +193,18 @@
</template> </template>
<template v-else v-slot:body="props"> <template v-else v-slot:body="props">
<q-tr :props="props"> <q-tr :props="props">
<q-td key="apri" :props="props">
<div class="q-pa-sm">
<q-btn
color="primary"
size="sm"
dense
icon="far fa-file-alt"
:label="t('ecomm.apriordine')"
:to="`/orderscart/${props.row._id}`"
></q-btn>
</div>
</q-td>
<q-td key="numorder" :props="props"> <q-td key="numorder" :props="props">
<span v-if="props.row.numorder"> <span v-if="props.row.numorder">
&nbsp; n. {{ props.row.numorder }}</span &nbsp; n. {{ props.row.numorder }}</span
@@ -190,7 +228,13 @@
</q-td> </q-td>
<q-td key="items" :props="props"> <q-td key="items" :props="props">
<div v-for="(item, index) of props.row.items" :key="index"> <div v-for="(item, index) of props.row.items" :key="index">
<div v-if="!!item.order && item.order.product && item.order.product.productInfo"> <div
v-if="
!!item.order &&
item.order.product &&
item.order.product.productInfo
"
>
{{ item.order.product.productInfo.name }} ({{ {{ item.order.product.productInfo.name }} ({{
productStore.getQuantityByOrder($t, item.order) productStore.getQuantityByOrder($t, item.order)
}})<br /> }})<br />
@@ -212,7 +256,9 @@
<br /> <br />
<div v-if="props.row.confermato" class="ordstat"> <div v-if="props.row.confermato" class="ordstat">
{{ tools.getstrDateTime(props.row.date_confermato) }}: {{ tools.getstrDateTime(props.row.date_confermato) }}:
<span class="ordstat confermato">{{ $t('ecomm.confermato') }}</span> <span class="ordstat confermato">{{
$t('ecomm.confermato')
}}</span>
</div> </div>
<div v-if="props.row.pagato" class="ordstat"> <div v-if="props.row.pagato" class="ordstat">
{{ tools.getstrDateTime(props.row.date_pagato) }}: {{ tools.getstrDateTime(props.row.date_pagato) }}:
@@ -265,6 +311,45 @@
</q-table> </q-table>
</div> </div>
<!-- Emails -->
<div v-if="tools.isManager()" class="q-ma-sm q-pa-sm row">
<q-select
:behavior="$q.platform.is.ios === true ? 'dialog' : 'menu'"
rounded
style="width: 300px"
outlined
v-model="templemail"
:options="globalStore.templemail"
:option-value="fieldsTable.getKeyByTable('templemail')"
:option-label="fieldsTable.getLabelByTable('templemail')"
label="Scegli il tipo di Email:"
emit-value
map-options
>
</q-select>
<CMyFieldDb
title="Email di Test"
mykey="EMAIL_TEST"
:serv="true"
:type="costanti.FieldType.string"
>
</CMyFieldDb>
<q-btn
color="primary"
icon="fas fa-check"
:label="t('orderscart.sendmail_test')"
@click="sendMailTest"
></q-btn>
<q-btn
color="positive"
icon="mail"
:label="t('orderscart.sendmail')"
@click="sendMailToAll"
></q-btn>
</div>
<!-- <!--
<div v-for="(ordercart, index) in getOrdersCart" :key="index"> <div v-for="(ordercart, index) in getOrdersCart" :key="index">

View File

@@ -0,0 +1 @@
export {default as orderscart} from './orderscart.vue'

View File

@@ -0,0 +1,5 @@
$heightBtn: 100%;
.card .product-image {
height: 300px;
}

View File

@@ -0,0 +1,55 @@
import { defineComponent, onMounted, ref } from 'vue'
import { tools } from '@store/Modules/tools'
import { useUserStore } from '@store/UserStore'
import { useRouter } from 'vue-router'
import { useRoute } from 'vue-router'
import { useGlobalStore } from '@store/globalStore'
import { useProducts } from '@store/Products'
import { useI18n } from '@/boot/i18n'
import { toolsext } from '@store/Modules/toolsext'
import { useQuasar } from 'quasar'
import { costanti } from '@costanti'
import { shared_consts } from '@src/common/shared_vuejs'
// import MixinBase from '@src/mixins/mixin-base'
import { CProductCard } from '@src/components/CProductCard'
import { COrdersCart } from '@src/components/COrdersCart'
export default defineComponent({
name: 'orderscart',
components: { CProductCard, COrdersCart },
props: {},
setup() {
const userStore = useUserStore()
const globalStore = useGlobalStore()
const productStore = useProducts()
const $router = useRouter()
const $route = useRoute()
const $q = useQuasar()
const { t } = useI18n();
const idOrdersCart = ref('')
const cosa = ref(0)
// const { setValDb, getValDb } = MixinBase()
function mounted() {
// Inizializza
if (!!$route.params.idorderscart) {
idOrdersCart.value = $route.params.idorderscart.toString()
}
}
onMounted(mounted)
return {
userStore,
costanti,
tools,
toolsext,
shared_consts,
idOrdersCart,
cosa,
}
}
})

View File

@@ -0,0 +1,18 @@
<template>
<q-page class="q-pa-md">
<div class="panel">
<div class="container">
<div v-if="!!idOrdersCart" class="row justify-center">
<COrdersCart :iscash="false" :idOrdersCart="idOrdersCart"/>
</div>
</div>
</div>
</q-page>
</template>
<script lang="ts" src="./orderscart.ts">
</script>
<style lang="scss" scoped>
@import './orderscart';
</style>

View File

@@ -22,7 +22,7 @@ export default defineComponent({
const userStore = useUserStore() const userStore = useUserStore()
const globalStore = useGlobalStore() const globalStore = useGlobalStore()
const productStore = useProducts() const productStore = useProducts()
const $router = useRouter() const router = useRouter()
const $q = useQuasar() const $q = useQuasar()
const { t } = useI18n() const { t } = useI18n()