Changes in RLS and Tenants
Many Changes in Invoice Editor Page Loading Rebuilt Started Rights Management
This commit is contained in:
@@ -2,6 +2,11 @@
|
||||
import dayjs from "dayjs"
|
||||
const dataStore = useDataStore()
|
||||
const user = useSupabaseUser()
|
||||
const route = useRoute()
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
const tabItems = [
|
||||
{
|
||||
@@ -13,52 +18,46 @@ const tabItems = [
|
||||
]
|
||||
|
||||
const itemInfo = ref({
|
||||
customer: 13,
|
||||
contact: 8,
|
||||
type: "invoices",
|
||||
customer: null,
|
||||
contact: null,
|
||||
address: {
|
||||
street: null,
|
||||
special: null,
|
||||
zip: null,
|
||||
city: null,
|
||||
},
|
||||
project: 6,
|
||||
documentNumber: "RE23-1409",
|
||||
documentDate: "10.01.2024",
|
||||
deliveryDate: "10.01.2024",
|
||||
project: null,
|
||||
documentNumber: null,
|
||||
documentDate: null,
|
||||
deliveryDate: null,
|
||||
dateOfPerformance: null,
|
||||
createdBy: user.value.id,
|
||||
title: "TITEL",
|
||||
description: "BESCHREIBUNG",
|
||||
title: null,
|
||||
description: null,
|
||||
startText: "Sehr geehrte Frau Sindern,\n" +
|
||||
"wir bedanken uns für Ihr entgegengebrachtes Vertrauen und Ihren Auftrag und stellen Ihnen\n" +
|
||||
"folgende Positionen in Rechnung: ",
|
||||
endText: "Bitte überweisen Sie den Rechnungsbetrag unter Angabe der Rechnungsnummer im Verwendungszweck innerhalb von 10 Tagen auf das unten angegebene Konto. Wir bedanken uns für das entgegengebrachte Vertrauen und freuen uns auf eine weitere gute Zusammenarbeit.",
|
||||
rows: [
|
||||
{
|
||||
id: 1,
|
||||
pos: 1,
|
||||
mode: "free",
|
||||
text: "FahrtkostenFahrtkostenFahrtkostenFahrtkosten",
|
||||
quantity: 204,
|
||||
unit: 3,
|
||||
price: 0.80,
|
||||
taxPercent: 19,
|
||||
discountPercent: 0
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
pos: 2,
|
||||
mode: "free",
|
||||
text: "Test",
|
||||
quantity: 1,
|
||||
unit: 1,
|
||||
price: 10,
|
||||
taxPercent: 19,
|
||||
discountPercent: 0
|
||||
}
|
||||
|
||||
]
|
||||
})
|
||||
|
||||
const setupPage = () => {
|
||||
if(route.params) {
|
||||
if(route.params.id) itemInfo.value = dataStore.getCreatedDocumentById(Number(route.params.id))
|
||||
}
|
||||
|
||||
if(route.query) {
|
||||
if(route.query.type) itemInfo.value.type = route.query.type
|
||||
if(route.query.project) itemInfo.value.project = Number(route.query.project)
|
||||
if(route.query.customer) itemInfo.value.customer = Number(route.query.customer)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
const getRowAmount = (row) => {
|
||||
return String(Number(Number(row.quantity) * Number(row.price) * (1 - Number(row.discountPercent) /100) ).toFixed(2)).replace('.',',')
|
||||
}
|
||||
@@ -218,7 +217,6 @@ const generateDocument = async () => {
|
||||
uri.value = await useCreatePdf(getDocumentData())
|
||||
//alert(uri.value)
|
||||
showDocument.value = true
|
||||
|
||||
}
|
||||
|
||||
const onChangeTab = (index) => {
|
||||
@@ -238,20 +236,80 @@ const setPosNumbers = () => {
|
||||
})
|
||||
}
|
||||
|
||||
const saveDocument = async () => {
|
||||
let createData = {
|
||||
type: itemInfo.value.type,
|
||||
customer: itemInfo.value.customer,
|
||||
contact: itemInfo.value.contact,
|
||||
address: itemInfo.value.address,
|
||||
project: itemInfo.value.project,
|
||||
documentNumber: itemInfo.value.documentNumber,
|
||||
documentDate: itemInfo.value.documentDate,
|
||||
state: "Entwurf",
|
||||
info: {
|
||||
|
||||
},
|
||||
createdBy: itemInfo.value.createdBy,
|
||||
title: itemInfo.value.title,
|
||||
description: itemInfo.value.description,
|
||||
startText: itemInfo.value.startText,
|
||||
endText: itemInfo.value.endText,
|
||||
rows: itemInfo.value.rows
|
||||
}
|
||||
|
||||
if(route.params.id) {
|
||||
await dataStore.updateItem("createdDocuments", {...createData, id: itemInfo.value.id})
|
||||
} else {
|
||||
await dataStore.createNewItem("createdDocuments", createData)
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
const closeDocument = () => {
|
||||
generateDocument()
|
||||
console.log(uri)
|
||||
}
|
||||
|
||||
|
||||
setupPage()
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<!-- <UButton
|
||||
@click="createPdf"
|
||||
>TEST</UButton>-->
|
||||
<UCard class="h-fit">
|
||||
<InputGroup class="mb-3">
|
||||
<UButton
|
||||
icon="i-mdi-content-save"
|
||||
@click="saveDocument"
|
||||
>
|
||||
Entwurf
|
||||
</UButton>
|
||||
<UButton
|
||||
@click="closeDocument"
|
||||
>
|
||||
Fertigstellen
|
||||
</UButton>
|
||||
</InputGroup>
|
||||
<UTabs :items="tabItems" @change="onChangeTab">
|
||||
<template #item="{item}">
|
||||
<div v-if="item.label === 'Editor'">
|
||||
<InputGroup>
|
||||
<div class="flex-auto mr-5">
|
||||
<UFormGroup
|
||||
label="Dokumenttyp:"
|
||||
>
|
||||
<USelectMenu
|
||||
:options="Object.keys(dataStore.documentTypesForCreation).map(i => {return {label: dataStore.documentTypesForCreation[i].labelSingle, type: i }})"
|
||||
v-model="itemInfo.type"
|
||||
value-attribute="type"
|
||||
option-attribute="label"
|
||||
>
|
||||
<template #label>
|
||||
{{dataStore.documentTypesForCreation[itemInfo.type].labelSingle}}
|
||||
</template>
|
||||
</USelectMenu>
|
||||
</UFormGroup>
|
||||
<UFormGroup
|
||||
label="Kunde:"
|
||||
>
|
||||
@@ -324,6 +382,7 @@ const setPosNumbers = () => {
|
||||
>
|
||||
<UInput
|
||||
v-model="itemInfo.documentNumber"
|
||||
placeholder="Leer lassen für automatisch generierte Nummer"
|
||||
/>
|
||||
</UFormGroup>
|
||||
<UFormGroup
|
||||
@@ -735,27 +794,6 @@ const setPosNumbers = () => {
|
||||
|
||||
</table>
|
||||
|
||||
|
||||
|
||||
<table>
|
||||
<tr>
|
||||
<td class="font-bold">Netto:</td>
|
||||
<td>{{documentTotal.totalNet}}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="font-bold">zzgl. 19 % USt:</td>
|
||||
<td>{{documentTotal.total19}}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="font-bold">Brutto:</td>
|
||||
<td>{{documentTotal.totalGross}}</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<InputGroup>
|
||||
<UButton
|
||||
@click="addPosition('normal')"
|
||||
@@ -777,6 +815,21 @@ const setPosNumbers = () => {
|
||||
</UButton>
|
||||
</InputGroup>
|
||||
|
||||
<table>
|
||||
<tr>
|
||||
<td class="font-bold">Netto:</td>
|
||||
<td>{{documentTotal.totalNet}}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="font-bold">zzgl. 19 % USt:</td>
|
||||
<td>{{documentTotal.total19}}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="font-bold">Brutto:</td>
|
||||
<td>{{documentTotal.totalGross}}</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
|
||||
|
||||
<UDivider
|
||||
@@ -797,7 +850,6 @@ const setPosNumbers = () => {
|
||||
>
|
||||
Show
|
||||
</UButton>-->
|
||||
|
||||
<object
|
||||
:data="uri"
|
||||
v-if="showDocument"
|
||||
25
spaces/pages/createDocument/show/[id].vue
Normal file
25
spaces/pages/createDocument/show/[id].vue
Normal file
@@ -0,0 +1,25 @@
|
||||
<script setup>
|
||||
|
||||
const dataStore = useDataStore()
|
||||
const route = useRoute()
|
||||
|
||||
const itemInfo = ref({})
|
||||
|
||||
const setupPage = () => {
|
||||
if(route.params) {
|
||||
if(route.params.id) itemInfo.value = dataStore.getCreatedDocumentById(Number(route.params.id))
|
||||
}
|
||||
}
|
||||
|
||||
setupPage()
|
||||
</script>
|
||||
|
||||
<template>
|
||||
|
||||
{{itemInfo}}
|
||||
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
|
||||
</style>
|
||||
@@ -12,11 +12,24 @@ const {fetchData} = useDataStore()
|
||||
const email = ref("")
|
||||
const password = ref("")
|
||||
|
||||
const fields = [{
|
||||
name: 'email',
|
||||
type: 'text',
|
||||
label: 'Email',
|
||||
placeholder: 'E-Mail Adresse'
|
||||
}, {
|
||||
name: 'password',
|
||||
label: 'Password',
|
||||
type: 'password',
|
||||
placeholder: 'Passwort'
|
||||
}]
|
||||
|
||||
|
||||
const onSubmit = async (data) => {
|
||||
|
||||
const onSubmit = async () => {
|
||||
const { error } = await supabase.auth.signInWithPassword({
|
||||
email: email.value,
|
||||
password: password.value
|
||||
email: data.email,
|
||||
password: data.password
|
||||
})
|
||||
if(error) {
|
||||
console.log(error.toString())
|
||||
@@ -33,7 +46,7 @@ const onSubmit = async () => {
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div id="loginSite">
|
||||
<!-- <div id="loginSite">
|
||||
<div id="loginForm">
|
||||
<UFormGroup
|
||||
label="E-Mail:"
|
||||
@@ -59,7 +72,23 @@ const onSubmit = async () => {
|
||||
</UButton>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>-->
|
||||
<UCard class="max-w-sm w-full mx-auto mt-5">
|
||||
<UAuthForm
|
||||
title="Login"
|
||||
description="Geben Sie Ihre Anmeldedaten ein um Zugriff auf Ihren Account zu bekommen"
|
||||
align="bottom"
|
||||
icon="i-heroicons-user-circle"
|
||||
:fields="fields"
|
||||
:loading="false"
|
||||
@submit="onSubmit"
|
||||
>
|
||||
|
||||
</UAuthForm>
|
||||
</UCard>
|
||||
|
||||
|
||||
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
|
||||
@@ -309,11 +309,24 @@ setupPage()
|
||||
</UAccordion>
|
||||
</div>
|
||||
<div v-else-if="item.key === 'documents'" class="space-y-3">
|
||||
<UButton
|
||||
@click="uploadModalOpen = true"
|
||||
>
|
||||
Hochladen
|
||||
</UButton>
|
||||
<InputGroup>
|
||||
<UButton
|
||||
@click="uploadModalOpen = true"
|
||||
>
|
||||
Hochladen
|
||||
</UButton>
|
||||
<UButton
|
||||
@click="router.push(`/createDocument/edit?project=${currentItem.id}&type=quotes&customer=${currentItem.customer}`)"
|
||||
>
|
||||
+ Angebot
|
||||
</UButton>
|
||||
<UButton
|
||||
@click="router.push(`/createDocument/edit?project=${currentItem.id}&type=invoices&customer=${currentItem.customer}`)"
|
||||
>
|
||||
+ Rechnung
|
||||
</UButton>
|
||||
</InputGroup>
|
||||
|
||||
<UModal
|
||||
v-model="uploadModalOpen"
|
||||
>
|
||||
|
||||
@@ -94,7 +94,7 @@ const setState = async (newState) => {
|
||||
} else if(mode.value === 'edit') {
|
||||
await dataStore.updateItem('incomingInvoices',{...itemInfo.value, state: newState})
|
||||
}
|
||||
await router.push("/incominginvoices")
|
||||
await router.push("/receipts")
|
||||
}
|
||||
|
||||
|
||||
@@ -133,11 +133,11 @@ setupPage()
|
||||
Status zu Entwurf
|
||||
</UButton>
|
||||
<UButton
|
||||
@click="setState('Offen')"
|
||||
v-if="currentVendorInvoice.state !== 'Offen'"
|
||||
@click="setState('Gebucht')"
|
||||
v-if="currentVendorInvoice.state !== 'Gebucht'"
|
||||
color="rose"
|
||||
>
|
||||
Status zu Offen
|
||||
Status auf Gebucht
|
||||
</UButton>
|
||||
</InputGroup>
|
||||
|
||||
@@ -372,13 +372,13 @@ setupPage()
|
||||
>
|
||||
Position entfernen
|
||||
</UButton>
|
||||
<HistoryDisplay
|
||||
type="incomingInvoice"
|
||||
v-if="currentVendorInvoice"
|
||||
:element-id="currentVendorInvoice.id"
|
||||
/>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
<HistoryDisplay
|
||||
type="incomingInvoice"
|
||||
v-if="currentVendorInvoice"
|
||||
:element-id="currentVendorInvoice.id"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -8,6 +8,11 @@
|
||||
v-model="searchString"
|
||||
placeholder="Suche..."
|
||||
/>
|
||||
|
||||
<UCheckbox
|
||||
v-model="showDrafts"
|
||||
label="Entwürfe Anzeigen"
|
||||
/>
|
||||
</div>
|
||||
|
||||
|
||||
@@ -18,16 +23,20 @@
|
||||
@select="selectItem"
|
||||
:empty-state="{ icon: 'i-heroicons-circle-stack-20-solid', label: 'Noch keine Einträge' }"
|
||||
>
|
||||
<template #type-data="{row}">
|
||||
<span v-if="row.type === 'incomingInvoice'">Eingangsrechnung</span>
|
||||
<span v-else>{{dataStore.documentTypesForCreation[row.type].labelSingle}}</span>
|
||||
</template>
|
||||
<template #state-data="{row}">
|
||||
<span
|
||||
v-if="row.state === 'Entwurf'"
|
||||
class="text-cyan-500"
|
||||
class="text-rose-500"
|
||||
>
|
||||
{{row.state}}
|
||||
</span>
|
||||
<span
|
||||
v-if="row.state === 'Offen'"
|
||||
class="text-rose-500"
|
||||
v-if="row.state === 'Gebucht'"
|
||||
class="text-cyan-500"
|
||||
>
|
||||
{{row.state}}
|
||||
</span>
|
||||
@@ -41,6 +50,10 @@
|
||||
<template #vendor-data="{row}">
|
||||
{{dataStore.vendors.find(vendor => vendor.id === row.vendor) ? dataStore.vendors.find(vendor => vendor.id === row.vendor).name : ''}}
|
||||
</template>
|
||||
<template #reference-data="{row}">
|
||||
<span v-if="row.type === 'incomingInvoice'">{{row.reference}}</span>
|
||||
<span v-else>{{row.documentNumber}}</span>
|
||||
</template>
|
||||
<template #date-data="{row}">
|
||||
<span v-if="row.date">{{row.date ? dayjs(row.date).format("DD.MM.YY") : ''}}</span>
|
||||
</template>
|
||||
@@ -52,7 +65,12 @@
|
||||
<span v-if="!row.paid" :class="dayjs(row.dueDate).diff(dayjs()) <= 0 ? ['text-rose-500'] : ['text-cyan-500'] ">Offen</span>
|
||||
</template>
|
||||
<template #amount-data="{row}">
|
||||
<div class="text-right font-bold">{{getRowAmount(row) === 0 ? '' : `${String(getRowAmount(row).toFixed(2)).replace('.',',')} €`}}</div>
|
||||
<div
|
||||
class="text-right font-bold"
|
||||
v-if="row.type === 'incomingInvoice'"
|
||||
>
|
||||
{{getRowAmount(row) === 0 ? '' : `${String(getRowAmount(row).toFixed(2)).replace('.',',')} €`}}
|
||||
</div>
|
||||
</template>
|
||||
</UTable>
|
||||
|
||||
@@ -74,6 +92,10 @@ const mode = ref("show")
|
||||
|
||||
const itemColumns = [
|
||||
{
|
||||
key: 'type',
|
||||
label: "Typ",
|
||||
sortable: true
|
||||
},{
|
||||
key: 'state',
|
||||
label: "Status.",
|
||||
sortable: true
|
||||
@@ -113,13 +135,25 @@ const itemColumns = [
|
||||
|
||||
const selectItem = (item) => {
|
||||
console.log(item)
|
||||
if(item.state === "Entwurf") {
|
||||
console.log("ENTWURF")
|
||||
router.push(`/incominginvoices/edit/${item.id} `)
|
||||
} else if(item.state === "Offen") {
|
||||
router.push(`/incominginvoices/show/${item.id}`)
|
||||
|
||||
if(item.type === "incomingInvoice"){
|
||||
if(item.state === "Entwurf") {
|
||||
router.push(`/receipts/incominginvoices/edit/${item.id} `)
|
||||
} else if(item.state === "Gebucht") {
|
||||
router.push(`/receipts/incominginvoices/show/${item.id}`)
|
||||
}
|
||||
} else {
|
||||
if(item.state === "Entwurf"){
|
||||
router.push(`/createDocument/edit/${item.id}`)
|
||||
} else if(item.state !== "Entwurf") {
|
||||
router.push(`/createDocument/show/${item.id}`)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
const getRowAmount = (row) => {
|
||||
@@ -135,13 +169,25 @@ const getRowAmount = (row) => {
|
||||
|
||||
|
||||
const searchString = ref('')
|
||||
const showDrafts = ref(false)
|
||||
|
||||
const filteredRows = computed(() => {
|
||||
if(!searchString.value) {
|
||||
return dataStore.incomingInvoices
|
||||
let items = [...dataStore.incomingInvoices.map(i => {return {...i, type: "incomingInvoice"}}),...dataStore.createdDocuments]
|
||||
|
||||
console.log(dataStore.createdDocuments)
|
||||
|
||||
if(showDrafts.value === true) {
|
||||
items = items.filter(i => i.state === "Entwurf")
|
||||
} else {
|
||||
items = items.filter(i => i.state !== "Entwurf")
|
||||
}
|
||||
|
||||
return dataStore.incomingInvoices.filter(item => {
|
||||
|
||||
if(!searchString.value) {
|
||||
return items
|
||||
}
|
||||
|
||||
return items.filter(item => {
|
||||
return Object.values(item).some((value) => {
|
||||
return String(value).toLowerCase().includes(searchString.value.toLowerCase())
|
||||
})
|
||||
@@ -36,11 +36,13 @@ const resources = {
|
||||
},
|
||||
spaces: {
|
||||
label: "Lagerplätze"
|
||||
},
|
||||
invoices: {
|
||||
label: "Rechnungen"
|
||||
}
|
||||
}
|
||||
|
||||
const updateNumberRange = async (range) => {
|
||||
console.log(range)
|
||||
|
||||
const {data,error} = await supabase
|
||||
.from("numberRanges")
|
||||
|
||||
78
spaces/pages/settings/rights.vue
Normal file
78
spaces/pages/settings/rights.vue
Normal file
@@ -0,0 +1,78 @@
|
||||
<script setup>
|
||||
|
||||
const supabase = useSupabaseClient()
|
||||
|
||||
const data = await supabase.from("profiles").select('* , tenants (id, name)')
|
||||
console.log(data)
|
||||
|
||||
let rights = {
|
||||
createUser: {label: "Benutzer erstellen"},
|
||||
modifyUser: {label: "Benutzer bearbeiten"},
|
||||
deactivateUser: {label: "Benutzer sperren"},
|
||||
createProject: {label: "Projekt erstellen"},
|
||||
viewOwnProjects: {label: "Eigene Projekte sehen"},
|
||||
viewAllProjects: {label: "Alle Projekte sehen"},
|
||||
createTask: {label: "Aufgabe erstellen"},
|
||||
viewOwnTasks: {label:"Eigene Aufgaben sehen"},
|
||||
viewAllTasks: {label: "Alle Aufgaben sehen"},
|
||||
trackOwnTime: {label:""},
|
||||
createOwnTime: {label:""},
|
||||
createTime: {label:""},
|
||||
viewOwnTimes: {label:""},
|
||||
viewAllTimesTimes: {label:""},
|
||||
}
|
||||
|
||||
let roles = [
|
||||
{
|
||||
key: "tenantAdmin",
|
||||
label: "Firmenadministrator",
|
||||
rights: [
|
||||
...Object.keys(rights)
|
||||
]
|
||||
},
|
||||
{
|
||||
key:"worker",
|
||||
label: "Monteur",
|
||||
rights: [
|
||||
"viewOwnProjects",
|
||||
"createTasks",
|
||||
"viewOwnTasks"
|
||||
]
|
||||
},
|
||||
{
|
||||
key:"manager",
|
||||
label: "Vorarbeiter",
|
||||
rights: [
|
||||
"createProjects",
|
||||
"viewOwnProjects",
|
||||
"createTasks",
|
||||
"viewOwnTasks",
|
||||
]
|
||||
},
|
||||
{
|
||||
key:"booker",
|
||||
label: "Buchhalter",
|
||||
rights: [
|
||||
"createTasks",
|
||||
"viewOwnTasks",
|
||||
"createTime",
|
||||
"viewAllTimes"
|
||||
]
|
||||
}
|
||||
]
|
||||
|
||||
|
||||
</script>
|
||||
|
||||
<template>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
|
||||
</style>
|
||||
@@ -141,7 +141,7 @@ setupPage()
|
||||
<UTable
|
||||
:rows="dataStore.getIncomingInvoicesByVehicleId(currentItem.id)"
|
||||
:columns="incomingInvoicesColumns"
|
||||
@select="(row) => router.push('/incominginvoices/show/' + row.id)"
|
||||
@select="(row) => router.push('/receipts/show/' + row.id)"
|
||||
>
|
||||
<template #vendor-data="{row}">
|
||||
{{dataStore.getVendorById(row.vendor) ? dataStore.getVendorById(row.vendor).name : ""}}
|
||||
|
||||
Reference in New Issue
Block a user