Changes
This commit is contained in:
1
.gitignore
vendored
1
.gitignore
vendored
@@ -1,3 +1,4 @@
|
||||
.idea
|
||||
/test/csvparser/data.csv
|
||||
/test/imaps/.env
|
||||
/test/csvparser/node_modules/
|
||||
|
||||
@@ -23,6 +23,14 @@ services:
|
||||
- "traefik.http.routers.spaces-frontend-secure.entrypoints=web-secured" #
|
||||
- "traefik.http.routers.spaces-frontend-secure.tls.certresolver=mytlschallenge"
|
||||
|
||||
imapsync:
|
||||
image: registry.gitlab.com/cmykmedia/spaces:main-IMAPSYNC
|
||||
restart: always
|
||||
environment:
|
||||
SUPABASE_URL: "https://uwppvcxflrcsibuzsbil.supabase.co"
|
||||
SUPABASE_KEY: "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJzdXBhYmFzZSIsInJlZiI6InV3cHB2Y3hmbHJjc2lidXpzYmlsIiwicm9sZSI6InNlcnZpY2Vfcm9sZSIsImlhdCI6MTcwMDkzODE5NCwiZXhwIjoyMDE2NTE0MTk0fQ.6hOkD1J8XBkVJUm-swv0ngLQ74xrEYr28EEbo0rUrts"
|
||||
INTERVAL: 30
|
||||
|
||||
# backend:
|
||||
# image: registry.gitlab.com/cmykmedia/manordsonne:master-BACKEND
|
||||
# restart: always
|
||||
|
||||
1
spaces/.npmrc
Normal file
1
spaces/.npmrc
Normal file
@@ -0,0 +1 @@
|
||||
@bryntum:registry=https://npm.bryntum.com
|
||||
116
spaces/app.vue
116
spaces/app.vue
@@ -1,10 +1,99 @@
|
||||
<script setup>
|
||||
|
||||
|
||||
|
||||
const user = useSupabaseUser()
|
||||
const router = useRouter()
|
||||
const route = useRoute()
|
||||
const supabase = useSupabaseClient()
|
||||
const tenants = (await supabase.from("tenants").select()).data
|
||||
|
||||
|
||||
|
||||
|
||||
const dataStore = useDataStore()
|
||||
const {loaded} = storeToRefs(useDataStore())
|
||||
const {fetchData} = dataStore
|
||||
fetchData()
|
||||
|
||||
const navLinks = [
|
||||
{
|
||||
label: "Home",
|
||||
link: "",
|
||||
icon: 'i-heroicons-home'
|
||||
},
|
||||
{
|
||||
label: "Aufgaben",
|
||||
link: "tasks",
|
||||
icon: "i-heroicons-rectangle-stack"
|
||||
},
|
||||
{
|
||||
label: "Kunden",
|
||||
link: "customers",
|
||||
icon: "i-heroicons-user-group"
|
||||
},
|
||||
{
|
||||
label: "Projekte",
|
||||
link: "projects",
|
||||
icon: "i-heroicons-clipboard-document-check"
|
||||
},
|
||||
{
|
||||
label: "Zeiterfassung",
|
||||
link: "timetracking",
|
||||
icon: "i-heroicons-clock"
|
||||
},
|
||||
{
|
||||
label: "Artikel",
|
||||
link: "products"
|
||||
},
|
||||
{
|
||||
label: "Dokumente",
|
||||
link: "documents",
|
||||
icon: "i-heroicons-document"
|
||||
},
|
||||
{
|
||||
label: "Inventar",
|
||||
link: "inventory"
|
||||
}
|
||||
]
|
||||
|
||||
const linksForBreadcrumbs = ref([])
|
||||
|
||||
const generateLinks = () => {
|
||||
let pathSteps = route.fullPath.split("/")
|
||||
let returnArr = []
|
||||
|
||||
pathSteps.forEach((step,index) => {
|
||||
|
||||
let stepLink = navLinks.find(link => link.link == step)
|
||||
|
||||
if(stepLink) {
|
||||
returnArr[index] = {
|
||||
label: stepLink.label,
|
||||
icon: stepLink.icon,
|
||||
to: '/' + stepLink.link
|
||||
}
|
||||
}
|
||||
|
||||
linksForBreadcrumbs.value = returnArr
|
||||
|
||||
})
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
watch(
|
||||
() => route.path,
|
||||
() => {
|
||||
generateLinks()
|
||||
}
|
||||
)
|
||||
generateLinks()
|
||||
|
||||
|
||||
|
||||
|
||||
const userTenant = ref({})
|
||||
if(user) userTenant.value = tenants.find(tenant => tenant.id === user.value.app_metadata.tenant)
|
||||
const userDropdownItems = [
|
||||
@@ -33,20 +122,39 @@ const userDropdownItems = [
|
||||
<UCard id="page">
|
||||
<template #header>
|
||||
<div id="menu">
|
||||
<router-link to="/tasks" class="mr-2"><UButton>Aufgaben</UButton></router-link>
|
||||
<router-link to="/customers" class="mr-2"><UButton>Kunden</UButton></router-link>
|
||||
<router-link
|
||||
v-for="link in navLinks"
|
||||
:to="'/' + link.link"
|
||||
class="mr-2"
|
||||
>
|
||||
<UButton>{{link.label}}</UButton>
|
||||
</router-link>
|
||||
<!--<router-link to="/customers" class="mr-2"><UButton>Kunden</UButton></router-link>
|
||||
<router-link to="/projects" class="mr-2"><UButton>Projekte</UButton></router-link>
|
||||
-
|
||||
<router-link to="/vendorinvoices" class="mr-2"><UButton>Eingangsrechnungen</UButton></router-link>
|
||||
|
||||
<router-link to="/timetracking" class="mr-2"><UButton>Zeiterfassung</UButton></router-link>
|
||||
<router-link to="/products" class="mr-2"><UButton>Artikel</UButton></router-link>
|
||||
<router-link to="/documents" class="mr-2"><UButton>Dokumente</UButton></router-link>
|
||||
<router-link to="/inventory" class="mr-2"><UButton>Inventar</UButton></router-link>
|
||||
<router-link to="/inventory" class="mr-2"><UButton>Inventar</UButton></router-link>-->
|
||||
<UDropdown :items="userDropdownItems" :popper="{placement: 'bottom-start'}">
|
||||
<UButton color="white" label="Benutzer" trailing-icon="i-heroicons-chevron-down-20-solid" />
|
||||
</UDropdown>
|
||||
</div>
|
||||
<UBreadcrumb
|
||||
class="my-3"
|
||||
:links="linksForBreadcrumbs"
|
||||
/>
|
||||
</template>
|
||||
<NuxtPage/>
|
||||
<NuxtPage
|
||||
v-if="loaded"
|
||||
/>
|
||||
<div
|
||||
v-else
|
||||
>
|
||||
<UProgress animation="carousel" />
|
||||
</div>
|
||||
</UCard>
|
||||
</template>
|
||||
|
||||
|
||||
@@ -1,6 +1,9 @@
|
||||
// https://nuxt.com/docs/api/configuration/nuxt-config
|
||||
export default defineNuxtConfig({
|
||||
devtools: { enabled: true },
|
||||
imports: {
|
||||
dirs: ['stores']
|
||||
},
|
||||
modules: [
|
||||
'@pinia/nuxt',
|
||||
'@nuxt/ui',
|
||||
|
||||
7318
spaces/package-lock.json
generated
7318
spaces/package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@@ -17,21 +17,17 @@
|
||||
"vue-router": "^4.2.5"
|
||||
},
|
||||
"dependencies": {
|
||||
"@huntersofbook/naive-ui-nuxt": "^1.2.0",
|
||||
"@nuxt/ui": "^2.10.0",
|
||||
"@nuxt/ui": "^2.11.0",
|
||||
"@nuxtjs/strapi": "^1.9.3",
|
||||
"@pinia/nuxt": "^0.5.1",
|
||||
"@tato30/vue-pdf": "^1.8.1",
|
||||
"@vicons/ionicons5": "^0.12.0",
|
||||
"axios": "^1.6.2",
|
||||
"buffer": "^6.0.3",
|
||||
"csv-parser": "^3.0.0",
|
||||
"jsprintmanager": "^6.0.3",
|
||||
"neat-csv": "^7.0.0",
|
||||
"nuxt-editorjs": "^1.0.4",
|
||||
"papaparse": "^5.4.1",
|
||||
"pinia": "^2.1.7",
|
||||
"uuidv4": "^6.2.13",
|
||||
"vue-pdf-embed": "^1.2.1"
|
||||
"sass": "^1.69.5",
|
||||
"uuidv4": "^6.2.13"
|
||||
}
|
||||
}
|
||||
|
||||
18
spaces/pages/banking/[account].vue
Normal file
18
spaces/pages/banking/[account].vue
Normal file
@@ -0,0 +1,18 @@
|
||||
<script setup>
|
||||
const route = useRoute()
|
||||
const supabase = useSupabaseClient()
|
||||
console.log(route.params.account)
|
||||
|
||||
const accounts = (await supabase.from("bankAccounts").select()).data
|
||||
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div>
|
||||
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
|
||||
</style>
|
||||
103
spaces/pages/banking/index.vue
Normal file
103
spaces/pages/banking/index.vue
Normal file
@@ -0,0 +1,103 @@
|
||||
<script setup>
|
||||
import Papa from 'papaparse'
|
||||
|
||||
const supabase = useSupabaseClient()
|
||||
|
||||
const accounts = (supabase.from("bankAccounts").select()).data
|
||||
|
||||
let items = ref([])
|
||||
async function readSingleFile(evt) {
|
||||
var f = document.getElementById('fileInput').files[0];
|
||||
if (f) {
|
||||
let results = []
|
||||
let text = await f.text()
|
||||
results = Papa.parse(text).data
|
||||
console.log(results[0])
|
||||
results = results.slice(1)
|
||||
results = results.map(temp => {
|
||||
return {
|
||||
iban: temp[1],
|
||||
bank: temp[3],
|
||||
date: temp[4],
|
||||
partnerName: temp[6],
|
||||
partnerIban: temp[7],
|
||||
type: temp[9],
|
||||
text: temp[10],
|
||||
value: temp[11],
|
||||
currency: temp[12]
|
||||
}
|
||||
})
|
||||
|
||||
console.log(results)
|
||||
items.value = results
|
||||
|
||||
parseStatements()
|
||||
|
||||
} else {
|
||||
alert("Failed to load file");
|
||||
}
|
||||
}
|
||||
|
||||
const newStatements = ref([])
|
||||
|
||||
const parseStatements = async () => {
|
||||
items.value.forEach(item => {
|
||||
if(item.date) {
|
||||
let returnObj = {
|
||||
date: item.date,
|
||||
partnerIban: item.partnerIban,
|
||||
partnerName: item.partnerName,
|
||||
text: item.text,
|
||||
value: Number(item.value.replace(",",".")),
|
||||
|
||||
}
|
||||
|
||||
newStatements.value.push(returnObj)
|
||||
}
|
||||
|
||||
})
|
||||
|
||||
const {data,error} = await supabase
|
||||
.from("bankStatements")
|
||||
.insert(newStatements.value)
|
||||
.select()
|
||||
|
||||
console.log(data)
|
||||
console.log(error)
|
||||
|
||||
}
|
||||
|
||||
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div>
|
||||
<UInput
|
||||
type="file"
|
||||
id="fileInput"
|
||||
/>
|
||||
<UButton
|
||||
@click="readSingleFile"
|
||||
>Test</UButton>
|
||||
|
||||
<table>
|
||||
<tr
|
||||
v-for="temp in items"
|
||||
>
|
||||
<td>{{temp.date}}</td>
|
||||
<td>{{temp.partnerName}}</td>
|
||||
<td>{{temp.text}}</td>
|
||||
<td>{{temp.value}}</td>
|
||||
<td></td>
|
||||
<td></td>
|
||||
<td></td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
|
||||
</style>
|
||||
28
spaces/pages/calendar/planningBoard.vue
Normal file
28
spaces/pages/calendar/planningBoard.vue
Normal file
@@ -0,0 +1,28 @@
|
||||
<script setup>
|
||||
/*import '@bryntum/scheduler'
|
||||
import { BryntumScheduler } from '@bryntum/scheduler-vue-3'
|
||||
import '@bryntum/scheduler/scheduler.material.css'
|
||||
const config = reactive({
|
||||
startDate: new Date(2024,0,1,6),
|
||||
endDate: new Date(2024,0,1,20),
|
||||
viewPreset: "hourAndDay",
|
||||
rowHeight: 50,
|
||||
columns: [{text: "Name", field: "name", width: 130}]
|
||||
})*/
|
||||
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div>
|
||||
<!-- <bryntum-scheduler
|
||||
:width="800"
|
||||
:height="600"
|
||||
start-date="2023-04-16"
|
||||
end-date="2023-05-15"
|
||||
></bryntum-scheduler>-->
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
|
||||
</style>
|
||||
@@ -1,5 +1,6 @@
|
||||
<template>
|
||||
<div id="main">
|
||||
<!-- TODO: Kontakte erstellen und dem Kunden zuweisen -->
|
||||
<div id="left">
|
||||
|
||||
<UButton @click="showCreateCustomer = true">+ Kunde</UButton>
|
||||
@@ -57,7 +58,7 @@
|
||||
|
||||
|
||||
|
||||
|
||||
<!-- TODO: Scrollcontainer -->
|
||||
</UCard>
|
||||
</div>
|
||||
</div>
|
||||
@@ -70,11 +71,7 @@ definePageMeta({
|
||||
|
||||
const supabase = useSupabaseClient()
|
||||
|
||||
//const {find,create} = useStrapi4()
|
||||
//const customers = (await find('customers',{populate: "*"})).data
|
||||
|
||||
const customers = (await supabase.from("customers").select().order('customerNumber', {ascending: true})).data
|
||||
|
||||
const {customers } = storeToRefs(useDataStore())
|
||||
|
||||
|
||||
let showCreateCustomer = ref(false)
|
||||
|
||||
@@ -68,72 +68,37 @@
|
||||
v-model="showDocumentModal"
|
||||
fullscreen
|
||||
>
|
||||
<UCard>
|
||||
|
||||
<!-- <a
|
||||
v-if="selectedDocument"
|
||||
target="_blank"
|
||||
:href="`http://localhost:1337${selectedDocument.file.data.url}`"
|
||||
class="p-2"
|
||||
>
|
||||
Anzeigen
|
||||
|
||||
|
||||
</a>-->
|
||||
|
||||
{{selectedDocument}}
|
||||
<UCard class="h-full">
|
||||
|
||||
<embed
|
||||
:src="pdfSource"
|
||||
class="bigPreview mb-3"
|
||||
:src="selectedDocument.url"
|
||||
/>
|
||||
|
||||
<UBadge
|
||||
v-for="tag in selectedDocument.tags"
|
||||
>
|
||||
{{tag}}
|
||||
</UBadge>
|
||||
|
||||
|
||||
<!-- <UFormGroup
|
||||
label="Tags:"
|
||||
<UFormGroup
|
||||
label="Ordner ändern:"
|
||||
>
|
||||
<USelectMenu
|
||||
v-if="selectedDocument"
|
||||
multiple
|
||||
searchable
|
||||
searchable-placeholder="Suchen..."
|
||||
:options="tags"
|
||||
v-on:change="update('documents',selectedDocument.id, {tags: selectedDocument.tags})"
|
||||
v-model="selectedDocument.tags"
|
||||
:options="folders"
|
||||
v-on:change="changeFolder"
|
||||
v-model="newFolder"
|
||||
value-attribute="label"
|
||||
/>
|
||||
</UFormGroup>
|
||||
|
||||
<UFormGroup
|
||||
label="Status:"
|
||||
class="mb-3"
|
||||
>
|
||||
<USelectMenu
|
||||
:options="states"
|
||||
v-model="selectedDocument.state"
|
||||
v-on:change="update('documents',selectedDocument.id,{state: selectedDocument.state})"
|
||||
/>
|
||||
</UFormGroup>-->
|
||||
|
||||
<div>
|
||||
<VuePDF
|
||||
ref="vuePDFRef"
|
||||
:pdf="pdf"
|
||||
fit-parent
|
||||
:page="page"
|
||||
/>
|
||||
</div>
|
||||
<div class="mt-3">
|
||||
<UButton @click="page = page > 1 ? page - 1 : page">
|
||||
Prev
|
||||
</UButton>
|
||||
<span class="mx-3">{{ page }} / {{ pages }}</span>
|
||||
<UButton @click="page = page < pages ? page + 1 : page">
|
||||
Next
|
||||
</UButton>
|
||||
</div>
|
||||
|
||||
|
||||
</UCard>
|
||||
</USlideover>
|
||||
|
||||
<!-- TODO: Tab Height always Full -->
|
||||
<UTabs
|
||||
:items="folders"
|
||||
orientation="vertical"
|
||||
@@ -143,8 +108,8 @@
|
||||
<template #item="{item}">
|
||||
<div class="documentList">
|
||||
<div
|
||||
v-if="documentsComposed.filter(doc => doc.folder === item.label).length > 0"
|
||||
v-for="document in documentsComposed.filter(doc => doc.folder === item.label)"
|
||||
v-if="documents.filter(doc => doc.folder === item.label).length > 0"
|
||||
v-for="document in documents.filter(doc => doc.folder === item.label)"
|
||||
class="documentListItem"
|
||||
>
|
||||
<embed
|
||||
@@ -187,25 +152,14 @@
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
|
||||
definePageMeta({
|
||||
middleware: "auth"
|
||||
})
|
||||
const supabase = useSupabaseClient()
|
||||
const user = useSupabaseUser()
|
||||
|
||||
const documents = (await supabase.from("documents").select()).data
|
||||
|
||||
const documentsComposed = ref([])
|
||||
async function composeDocs () {
|
||||
for(const doc of documents){
|
||||
let fileurl = (await supabase.storage.from('documents').createSignedUrl(doc.path,60*60)).data.signedUrl
|
||||
|
||||
documentsComposed.value.push({...doc, url: fileurl})
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
await composeDocs()
|
||||
const {documents} = storeToRefs(useDataStore())
|
||||
|
||||
const tabOpen = ref(0)
|
||||
const uploadModalOpen = ref(false)
|
||||
@@ -271,10 +225,28 @@ const uploadFile = async () => {
|
||||
uploadModalOpen.value = false;
|
||||
}
|
||||
|
||||
const updateDocument = async () => {
|
||||
await update('documents', selectedDocument.id, {tags: selectedDocument.tags, state: selectedDocument.state})
|
||||
|
||||
|
||||
const changeFolder = async () => {
|
||||
console.log("Change Folder")
|
||||
console.log(selectedDocument.value.path)
|
||||
|
||||
let filename = selectedDocument.value.path.split("/")[2]
|
||||
let newPath = `${user.value.app_metadata.tenant}/${newFolder.value}/${filename}`
|
||||
console.log(newPath)
|
||||
|
||||
const { data, error } = await supabase
|
||||
.storage
|
||||
.from('documents')
|
||||
.move(selectedDocument.value.path, newPath )
|
||||
|
||||
console.log(data)
|
||||
console.log(error)
|
||||
|
||||
}
|
||||
|
||||
const newFolder = ref("")
|
||||
|
||||
const selectedDocument = ref({})
|
||||
const showDocumentModal = ref(false)
|
||||
|
||||
@@ -290,12 +262,13 @@ const openDocument = async (document) => {
|
||||
.documentList {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
|
||||
.documentListItem {
|
||||
display:block;
|
||||
width: 15vw;
|
||||
height: 25vh;
|
||||
height: 30vh;
|
||||
padding:1em;
|
||||
margin: 0.7em;
|
||||
border: 1px solid lightgrey;
|
||||
@@ -309,7 +282,7 @@ const openDocument = async (document) => {
|
||||
|
||||
.previewEmbed {
|
||||
width: 100%;
|
||||
height: 18vh;
|
||||
height: 22vh;
|
||||
overflow: hidden;
|
||||
-ms-overflow-style: none; /* IE and Edge */
|
||||
scrollbar-width: none; /* Firefox */
|
||||
@@ -318,4 +291,9 @@ const openDocument = async (document) => {
|
||||
.previewEmbed::-webkit-scrollbar {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.bigPreview {
|
||||
height: 70vh;
|
||||
width: 100%;
|
||||
}
|
||||
</style>
|
||||
88
spaces/pages/formSubmissions/[id].vue
Normal file
88
spaces/pages/formSubmissions/[id].vue
Normal file
@@ -0,0 +1,88 @@
|
||||
<script setup>
|
||||
const route = useRoute()
|
||||
const router = useRouter()
|
||||
const supabase = useSupabaseClient()
|
||||
|
||||
|
||||
const currentSubmission = (await supabase.from("formSubmits").select().eq('id',route.params.id)).data[0]
|
||||
const form = (await supabase.from("forms").select().eq('id',currentSubmission.formType)).data[0]
|
||||
|
||||
const formData = ref({})
|
||||
const submitted = ref(currentSubmission.submitted)
|
||||
|
||||
const submitForm = async () => {
|
||||
|
||||
submitted.value = true
|
||||
|
||||
console.log(formData.value)
|
||||
const {data,error} = await supabase
|
||||
.from("formSubmits")
|
||||
.update({values: formData.value, submitted: true})
|
||||
.eq('id',currentSubmission.id)
|
||||
.select()
|
||||
|
||||
if(error) {
|
||||
console.log(error)
|
||||
} else if( data) {
|
||||
formData.value = {}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div>
|
||||
<UForm
|
||||
v-if="!submitted"
|
||||
@submit="submitForm"
|
||||
@reset="formData = {}"
|
||||
>
|
||||
<div
|
||||
v-for="item in form.fields"
|
||||
>
|
||||
<p v-if="item.type === 'header'">{{item.label}}</p>
|
||||
<UFormGroup
|
||||
v-else-if="item.type.includes('Input')"
|
||||
:label="item.required ? item.label + '*' : item.label"
|
||||
>
|
||||
<UInput
|
||||
v-if="item.type === 'textInput'"
|
||||
v-model="formData[item.key]"
|
||||
:required="item.required"
|
||||
/>
|
||||
<UInput
|
||||
v-else-if="item.type === 'numberInput'"
|
||||
v-model="formData[item.key]"
|
||||
:required="item.required"
|
||||
type="number"
|
||||
inputmode="numeric"
|
||||
/>
|
||||
</UFormGroup>
|
||||
</div>
|
||||
|
||||
<UButton type="submit">
|
||||
Abschicken
|
||||
</UButton>
|
||||
<UButton
|
||||
type="reset"
|
||||
color="rose"
|
||||
class="m-2"
|
||||
>
|
||||
Zurücksetzen
|
||||
</UButton>
|
||||
|
||||
|
||||
</UForm>
|
||||
<div v-else>
|
||||
Dieses Formular wurde bereits abgeschickt. Möchten Sie erneut Daten abschicken, sprechen Sie bitte Ihren Ansprechpartner an, um das Formular freizuschalten.
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
|
||||
</style>
|
||||
@@ -1,5 +1,9 @@
|
||||
<template>
|
||||
<div>
|
||||
Offene Aufgaben: {{openTasks}}<br>
|
||||
Laufende Projekte:
|
||||
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
@@ -7,15 +11,13 @@ definePageMeta({
|
||||
middleware: "auth"
|
||||
})
|
||||
|
||||
const {getOpenTasksCount} = useDataStore()
|
||||
const openTasks = getOpenTasksCount
|
||||
|
||||
const supabase = useSupabaseClient()
|
||||
|
||||
const tasks = (await supabase.from("tasks").select()).data
|
||||
|
||||
const user = useSupabaseUser()
|
||||
console.log(user)
|
||||
|
||||
console.log(tasks)
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
|
||||
@@ -66,21 +66,17 @@ function checkSpaceId(spaceId) {
|
||||
<div id="main">
|
||||
<router-link to="/inventory/spaces"><UButton>Lagerplätze</UButton></router-link>
|
||||
|
||||
<!--<UInput
|
||||
icon="i-heroicons-magnifying-glass-20-solid"
|
||||
variant="outline"
|
||||
color="primary"
|
||||
placeholder="Barcode / Suche"
|
||||
v-model="searchinput"
|
||||
/>-->
|
||||
|
||||
<UButton @click="mode = 'incoming'" class="ml-3" >Wareneingang</UButton>
|
||||
<UButton @click="mode = 'outgoing'" class="ml-1">Warenausgang</UButton>
|
||||
<UButton @click="mode = 'change'" class="ml-1" disabled>Umlagern</UButton>
|
||||
<div class="my-3">
|
||||
<UButton @click="mode = 'incoming'" class="ml-3" >Wareneingang</UButton>
|
||||
<UButton @click="mode = 'outgoing'" class="ml-1">Warenausgang</UButton>
|
||||
<UButton @click="mode = 'change'" class="ml-1" disabled>Umlagern</UButton>
|
||||
</div>
|
||||
|
||||
|
||||
<UFormGroup
|
||||
label="Artikel:"
|
||||
class="mt-3"
|
||||
class="mt-3 w-80"
|
||||
>
|
||||
<UInput
|
||||
variant="outline"
|
||||
@@ -92,7 +88,7 @@ function checkSpaceId(spaceId) {
|
||||
|
||||
<UFormGroup
|
||||
label="Lagerplatz:"
|
||||
class="mt-3"
|
||||
class="mt-3 w-80"
|
||||
><!--.map(space => {return {id: space.id, name: space.spaceNumber}}-->
|
||||
<USelectMenu
|
||||
:options="spaces"
|
||||
@@ -106,7 +102,7 @@ function checkSpaceId(spaceId) {
|
||||
|
||||
<UFormGroup
|
||||
label="Anzahl:"
|
||||
class="mt-3"
|
||||
class="mt-3 w-80"
|
||||
>
|
||||
<UInput
|
||||
variant="outline"
|
||||
@@ -132,8 +128,9 @@ function checkSpaceId(spaceId) {
|
||||
|
||||
<style scoped>
|
||||
#main {
|
||||
/*display: flex;
|
||||
flex-direction: row;*/
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
}
|
||||
#left {
|
||||
width: 25vw;
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
<script setup>
|
||||
import {move} from "@antfu/utils";
|
||||
|
||||
definePageMeta({
|
||||
middleware: "auth"
|
||||
@@ -7,23 +6,19 @@ definePageMeta({
|
||||
|
||||
const supabase = useSupabaseClient()
|
||||
|
||||
const spaces = (await supabase.from("spaces").select()).data
|
||||
const movements = (await supabase.from("movements").select()).data
|
||||
const products = (await supabase.from("products").select()).data
|
||||
const units = (await supabase.from("units").select()).data
|
||||
|
||||
|
||||
|
||||
const {spaces,movements,products,units} = storeToRefs(useDataStore())
|
||||
const {movementsBySpace, getProductById} = useDataStore()
|
||||
|
||||
console.log(movements)
|
||||
let selectedItem = ref({})
|
||||
const showCreateSpace = ref(false)
|
||||
|
||||
const selectItem = (item) => {
|
||||
selectedItem.value = item
|
||||
spaceMovements.value = movements.filter(movement => movement.spaceId === selectedItem.value.id)
|
||||
spaceMovements.value = movementsBySpace(item.id)//movements.filter(movement => movement.spaceId === selectedItem.value.id)
|
||||
spaceProducts.value = []
|
||||
spaceMovements.value.forEach(movement => {
|
||||
if(spaceProducts.value.filter(product => product.id === movement.productId).length === 0) spaceProducts.value.push(products.find(product => product.id === movement.productId))
|
||||
if(spaceProducts.value.filter(product => product.id === movement.productId).length === 0) spaceProducts.value.push(getProductById(movement.productId))
|
||||
})
|
||||
|
||||
|
||||
@@ -31,7 +26,7 @@ const selectItem = (item) => {
|
||||
|
||||
}
|
||||
|
||||
const spaceTypes = ["Regalplatz", "Kiste", "Palettenplatz"]
|
||||
const spaceTypes = ["Regalplatz", "Kiste", "Palettenplatz","KFZ"]
|
||||
|
||||
const createSpaceData = ref({})
|
||||
const createSpace = async () => {
|
||||
@@ -112,11 +107,23 @@ function getSpaceProductCount(productId) {
|
||||
</template>
|
||||
{{selectedItem.description}}
|
||||
|
||||
|
||||
</UCard>
|
||||
<div v-if="spaceProducts.length > 0">
|
||||
<p class="mt-5">Artikel in diesem Lagerplatz</p>
|
||||
<p v-for="product in spaceProducts">{{product.name}} - {{getSpaceProductCount(product.id)}} {{units.find(unit => unit.id === product.unit).name}}</p>
|
||||
|
||||
<table>
|
||||
<tr>
|
||||
<th>Artikel</th>
|
||||
<th>Anzahl</th>
|
||||
<th>Einheit</th>
|
||||
</tr>
|
||||
<tr v-for="product in spaceProducts">
|
||||
<td>{{product.name}}</td>
|
||||
<td>{{getSpaceProductCount(product.id)}}</td>
|
||||
<td>{{units.find(unit => unit.id === product.unit).name}}</td>
|
||||
</tr>
|
||||
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -138,4 +145,9 @@ function getSpaceProductCount(productId) {
|
||||
width: 60vw;
|
||||
padding-left: 3vw;
|
||||
}
|
||||
|
||||
td, th {
|
||||
padding: 1em;
|
||||
border: 1px solid black;
|
||||
}
|
||||
</style>
|
||||
@@ -13,7 +13,8 @@ const onSubmit = async () => {
|
||||
password: password.value
|
||||
})
|
||||
if(error) {
|
||||
console.log(error)
|
||||
console.log(error.toString())
|
||||
alert(error.toString())
|
||||
} else {
|
||||
console.log("Login Successful")
|
||||
router.push("/")
|
||||
|
||||
@@ -127,13 +127,11 @@ definePageMeta({
|
||||
|
||||
const supabase = useSupabaseClient()
|
||||
|
||||
const products = (await supabase.from("products").select()).data
|
||||
const units = (await supabase.from("units").select()).data
|
||||
const {products,units} = storeToRefs(useDataStore())
|
||||
|
||||
const showCreateProduct = ref(false)
|
||||
const createProductData = ref({})
|
||||
|
||||
|
||||
let selectedItem = ref({})
|
||||
|
||||
const history = ref([
|
||||
|
||||
@@ -3,9 +3,48 @@ definePageMeta({
|
||||
middleware: "auth"
|
||||
})
|
||||
|
||||
//const {find, findOne,create, update} = useStrapi4()
|
||||
const supabase = useSupabaseClient()
|
||||
const route = useRoute()
|
||||
//let project = (await findOne('projects',route.params.id)).data
|
||||
|
||||
const {getProjectById, getFormSubmitsWithLabelProp} = useDataStore()
|
||||
const {forms, formSubmits} = storeToRefs(useDataStore())
|
||||
|
||||
const currentProject = getProjectById(Number(route.params.id))
|
||||
|
||||
|
||||
const formSubmissionsComposed = getFormSubmitsWithLabelProp
|
||||
const formModalOpen = ref(false)
|
||||
const newFormSubmissionData = ref({
|
||||
formType: "",
|
||||
values: {},
|
||||
submitted: false
|
||||
})
|
||||
|
||||
const addNewFormSubmission = async () => {
|
||||
//Add Form Submission
|
||||
const {data:insertData,error:insertError} = await supabase
|
||||
.from("formSubmits")
|
||||
.insert([newFormSubmissionData.value])
|
||||
.select()
|
||||
|
||||
console.log(insertData)
|
||||
console.log(insertError)
|
||||
|
||||
let projectForms = [...currentProject.forms, insertData[0].id ]
|
||||
console.log(projectForms)
|
||||
|
||||
//Add Form ID to project.forms
|
||||
const {data:updateData,error:updateError} = await supabase
|
||||
.from("projects")
|
||||
.update({forms: projectForms})
|
||||
.eq('id',currentProject.id)
|
||||
.select()
|
||||
|
||||
console.log(updateData)
|
||||
console.log(updateError)
|
||||
|
||||
}
|
||||
|
||||
const tabItems = [
|
||||
{
|
||||
key: "phases",
|
||||
@@ -25,6 +64,8 @@ const selectedPhase = ref({})
|
||||
const changesSaved = ref(true)
|
||||
|
||||
|
||||
|
||||
|
||||
const default_data = {
|
||||
time: 1660335428612,
|
||||
blocks: [
|
||||
@@ -43,87 +84,25 @@ const default_data = {
|
||||
text: "This is a nuxt3 plugin for editorjs.",
|
||||
},
|
||||
},
|
||||
{
|
||||
id: "R3o5BpI-r9",
|
||||
type: "paragraph",
|
||||
data: {
|
||||
text: "<b>A paragraph of text:</b> Lorem ipsum dolor sit amet consectetur adipisicing elit. Labore perspiciatis molestias neque autem cumque provident? Laudantium ad, quisquam quos nulla amet, perferendis recusandae voluptates eligendi cupiditate consectetur veniam! Ipsum, ullam?",
|
||||
},
|
||||
},
|
||||
{
|
||||
id: "b9mkw6ZO92",
|
||||
type: "header",
|
||||
data: {
|
||||
text: "Heading 1",
|
||||
level: 1,
|
||||
},
|
||||
},
|
||||
{
|
||||
id: "P2PZsHo2lq",
|
||||
type: "header",
|
||||
data: {
|
||||
text: "Heading 2",
|
||||
level: 2,
|
||||
},
|
||||
},
|
||||
{
|
||||
id: "hHJZjkW-TO",
|
||||
type: "header",
|
||||
data: {
|
||||
text: "Heading 3",
|
||||
level: 3,
|
||||
},
|
||||
},
|
||||
{
|
||||
id: "k8EDwa0oVG",
|
||||
type: "header",
|
||||
data: {
|
||||
text: "Heading 4",
|
||||
level: 4,
|
||||
},
|
||||
},
|
||||
{
|
||||
id: "62ciFnEFjZ",
|
||||
type: "header",
|
||||
data: {
|
||||
text: "Heading 5",
|
||||
level: 5,
|
||||
},
|
||||
},
|
||||
{
|
||||
id: "YCBcKhNqib",
|
||||
type: "header",
|
||||
data: {
|
||||
text: "Heading 6",
|
||||
level: 6,
|
||||
},
|
||||
},
|
||||
{
|
||||
id: "s_J3d5U8DA",
|
||||
type: "list",
|
||||
data: {
|
||||
style: "ordered",
|
||||
items: [
|
||||
"An ordered list item",
|
||||
"Another ordered list item",
|
||||
"One more",
|
||||
],
|
||||
},
|
||||
},
|
||||
{
|
||||
id: "kMyQbO156y",
|
||||
type: "list",
|
||||
data: {
|
||||
style: "unordered",
|
||||
items: ["An unordered list item!", "In italics?", "Or bold?"],
|
||||
},
|
||||
},
|
||||
|
||||
],
|
||||
version: "2.25.0",
|
||||
};
|
||||
const dat = ref(default_data);
|
||||
const save = () => {
|
||||
console.log(foo);
|
||||
const newProjectDescription = ref(currentProject.description || default_data.value);
|
||||
|
||||
const saveProjectDescription = async () => {
|
||||
//Update Project Description
|
||||
const {data:updateData,error:updateError} = await supabase
|
||||
.from("projects")
|
||||
.update({description: newProjectDescription.value})
|
||||
.eq('id',currentProject.id)
|
||||
.select()
|
||||
|
||||
console.log(updateData)
|
||||
console.log(updateError)
|
||||
|
||||
|
||||
|
||||
};
|
||||
|
||||
|
||||
@@ -182,12 +161,68 @@ const phaseInfo = ref({
|
||||
</div>
|
||||
|
||||
</div>
|
||||
<div v-else-if="item.key === 'password'" class="space-y-3">
|
||||
<div v-else-if="item.key === 'forms'" class="space-y-3">
|
||||
<UButton
|
||||
@click="formModalOpen = true"
|
||||
>
|
||||
+ Formular
|
||||
</UButton>
|
||||
<UModal
|
||||
v-model="formModalOpen"
|
||||
>
|
||||
<UCard>
|
||||
<template #header>
|
||||
Formular hinzufügen
|
||||
</template>
|
||||
<UFormGroup>
|
||||
<USelectMenu
|
||||
:options="forms"
|
||||
option-attribute="name"
|
||||
value-attribute="id"
|
||||
v-model="newFormSubmissionData.formType"
|
||||
/>
|
||||
</UFormGroup>
|
||||
<template #footer>
|
||||
<UButton
|
||||
@click="addNewFormSubmission"
|
||||
>
|
||||
Hinzufügen
|
||||
</UButton>
|
||||
</template>
|
||||
</UCard>
|
||||
</UModal>
|
||||
|
||||
|
||||
<UAccordion :items="formSubmissionsComposed">
|
||||
<template #item="{item}">
|
||||
|
||||
<p class="my-3">Formular Link: <a :href="'https://app.spaces.software/formSubmissions/' + item.id">{{'https://app.spaces.software/formSubmissions/' + item.id}}</a></p>
|
||||
|
||||
|
||||
<div v-if="Object.keys(item.values).length == 0">
|
||||
<p>Es wurden noch keine Daten über das Formular abgegeben</p>
|
||||
</div>
|
||||
|
||||
<table v-else>
|
||||
<tr v-for="key in Object.keys(item.values)">
|
||||
<td>{{key}}</td>
|
||||
<td>{{ item.values[key] }}</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
</template>
|
||||
</UAccordion>
|
||||
</div>
|
||||
<div v-else-if="item.key === 'description'" class="space-y-3">
|
||||
<client-only><editor-js v-model="dat" /></client-only>
|
||||
<UButton
|
||||
:disabled="false/*newProjectDescription.time === currentProject.description.time*/"
|
||||
@click="saveProjectDescription"
|
||||
>
|
||||
Speichern
|
||||
</UButton>
|
||||
<client-only><editor-js v-model="newProjectDescription" /></client-only>
|
||||
</div>
|
||||
{{item}}
|
||||
</template>
|
||||
</UTabs>
|
||||
<!-- <div id="left">
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
<template>
|
||||
<div id="main">
|
||||
<div id="left">
|
||||
|
||||
<!-- TODO: Projekt Auflistung überarbeiten, Rechte Seite wird nicht genutzt -->
|
||||
<UButton @click="showCreateProject = true">+ Projekt</UButton>
|
||||
<UModal v-model="showCreateProject">
|
||||
<UCard>
|
||||
@@ -89,8 +89,11 @@ definePageMeta({
|
||||
|
||||
const supabase = useSupabaseClient()
|
||||
|
||||
const projects = (await supabase.from("projects").select()).data
|
||||
const customers = (await supabase.from("customers").select()).data
|
||||
const {projects,customers} = storeToRefs(useDataStore())
|
||||
const {fetchProjects} = useDataStore()
|
||||
|
||||
//const projects = (await supabase.from("projects").select()).data
|
||||
//const customers = (await supabase.from("customers").select()).data
|
||||
|
||||
const showCreateProject = ref(false)
|
||||
const createProjectData = ref({
|
||||
@@ -114,6 +117,8 @@ const createProject = async () => {
|
||||
|
||||
showCreateProject.value = false
|
||||
createProjectData.value = {phases: []}
|
||||
fetchProjects()
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
<template>
|
||||
<div>
|
||||
<!-- TODO: Benutzer Aufgaben zuweisen und nach diesen Filtern -->
|
||||
<UModal
|
||||
v-model="showCreateTask"
|
||||
>
|
||||
@@ -112,7 +113,7 @@
|
||||
<div id="taskCatList">
|
||||
<div id="catNew">
|
||||
<h3>Neue Aufgaben</h3>
|
||||
<div class="taskScrollList">
|
||||
<div class="taskScrollList" v-if="tasks.length > 0">
|
||||
<a
|
||||
v-for="taskNew in tasks.filter(task => task.categorie == 'Neu')"
|
||||
@click="inspectTask(taskNew)"
|
||||
@@ -134,7 +135,7 @@
|
||||
</div>
|
||||
<div id="catInProgress">
|
||||
<h3>Aufgaben in Bearbeitung</h3>
|
||||
<div class="taskScrollList">
|
||||
<div class="taskScrollList" v-if="tasks.length > 0">
|
||||
<a
|
||||
v-for="taskNew in tasks.filter(task => task.categorie == 'In Bearbeitung')"
|
||||
@click="inspectTask(taskNew)"
|
||||
@@ -154,7 +155,7 @@
|
||||
</div>
|
||||
<div id="catUrgent">
|
||||
<h3>Dringende Aufgaben</h3>
|
||||
<div class="taskScrollList">
|
||||
<div class="taskScrollList" v-if="tasks.length > 0">
|
||||
<a
|
||||
v-for="taskNew in tasks.filter(task => task.categorie == 'Dringend')"
|
||||
@click="inspectTask(taskNew)"
|
||||
@@ -184,15 +185,12 @@ definePageMeta({
|
||||
|
||||
|
||||
const supabase = useSupabaseClient()
|
||||
|
||||
const tasks = (await supabase.from("tasks").select()).data
|
||||
|
||||
const {tasks} = storeToRefs(useDataStore())
|
||||
const {fetchTasks} = useDataStore()
|
||||
|
||||
let refTasks = ref([])
|
||||
|
||||
|
||||
//const users = (await find('users',{populate: "*"}))
|
||||
//const users = (await supabase.from("users").select()).data
|
||||
let usersForList = []
|
||||
//users.forEach(user => usersForList.push(user.username))
|
||||
const usersSelected = ref([])
|
||||
@@ -223,6 +221,7 @@ const createTask = async () => {
|
||||
|
||||
showCreateTask.value = false
|
||||
createTaskData.value = {}
|
||||
fetchTasks()
|
||||
}
|
||||
|
||||
const updateTask = async () => {
|
||||
@@ -260,7 +259,7 @@ const finishTask = async () => {
|
||||
showTaskModal.value = false
|
||||
}
|
||||
|
||||
filterTasks()
|
||||
//filterTasks()
|
||||
|
||||
</script>
|
||||
|
||||
|
||||
121
spaces/pages/vendorinvoices/[id].vue
Normal file
121
spaces/pages/vendorinvoices/[id].vue
Normal file
@@ -0,0 +1,121 @@
|
||||
<template>
|
||||
<div id="main">
|
||||
<div
|
||||
class="previewDoc"
|
||||
>
|
||||
<embed
|
||||
:src="fileurl"
|
||||
|
||||
>
|
||||
{{documents}}
|
||||
</div>
|
||||
<div
|
||||
class="inputData"
|
||||
>
|
||||
<UFormGroup label="Lieferant:" required>
|
||||
<UInput />
|
||||
</UFormGroup>
|
||||
|
||||
<UFormGroup label="Rechnungsreferenz:" required>
|
||||
<UInput />
|
||||
</UFormGroup>
|
||||
|
||||
<UFormGroup label="Rechnungsdatum:" required>
|
||||
<UInput />
|
||||
</UFormGroup>
|
||||
|
||||
<UButton @click="vendorInvoiceData.lineItems.push({})">+ Reihe</UButton>
|
||||
|
||||
|
||||
<div v-for="lineItem in vendorInvoiceData.lineItems" class="lineItemRow">
|
||||
<UFormGroup label="Text:" required>
|
||||
<UInput v-model="lineItem.text"/>
|
||||
</UFormGroup>
|
||||
<UFormGroup label="Produkt:" required>
|
||||
<UInput v-model="lineItem.productId"/>
|
||||
</UFormGroup>
|
||||
<UFormGroup label="Projekt:" required>
|
||||
<UInput v-model="lineItem.projectId"/>
|
||||
</UFormGroup>
|
||||
<UFormGroup label="Anzahl:" required>
|
||||
<UInput v-model="lineItem.quantity"/>
|
||||
</UFormGroup>
|
||||
<UFormGroup label="Einheit:" required>
|
||||
<UInput v-model="lineItem.unit"/>
|
||||
</UFormGroup>
|
||||
<UFormGroup label="Einzelpreis:" required>
|
||||
<UInput v-model="lineItem.unitPriceNet"/>
|
||||
</UFormGroup>
|
||||
<UFormGroup label="USt:" required>
|
||||
<UInput v-model="lineItem.vat"/>
|
||||
</UFormGroup>
|
||||
<UFormGroup label="Rabatt:" required>
|
||||
<UInput v-model="lineItem.discount"/>
|
||||
</UFormGroup>
|
||||
<UFormGroup label="Buchungskonto:" required>
|
||||
<UInput v-model="lineItem.skrAccountId"/>
|
||||
</UFormGroup>
|
||||
<UFormGroup label="Positionspreis:" required>
|
||||
<UInput disabled/>
|
||||
</UFormGroup>
|
||||
</div>
|
||||
{{vendorInvoiceData}}
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
const supabase = useSupabaseClient()
|
||||
const route = useRoute()
|
||||
|
||||
const currentVendorInvoice = (await supabase.from('vendorInvoices').select().eq('id', route.params.id)).data
|
||||
const document = (await supabase.from('documents').select().eq("id",18)).data[0]
|
||||
|
||||
console.log(currentVendorInvoice)
|
||||
console.log(document)
|
||||
|
||||
let fileurl = (await supabase.storage.from('documents').createSignedUrl(document.path,60*60)).data.signedUrl
|
||||
|
||||
|
||||
let vendorInvoiceData = ref({
|
||||
reference: "",
|
||||
date: "",
|
||||
vendorId: 0,
|
||||
lineItems: []
|
||||
})
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
#main {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
}
|
||||
|
||||
.previewDoc {
|
||||
width: 50vw;
|
||||
min-height: 80vh;
|
||||
}
|
||||
|
||||
.previewDoc embed {
|
||||
width: 90%;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.inputData {
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
.lineItemRow {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
}
|
||||
</style>
|
||||
@@ -1,72 +0,0 @@
|
||||
<template>
|
||||
<div id="main">
|
||||
<UFormGroup label="Lieferant:" required>
|
||||
<UInput />
|
||||
</UFormGroup>
|
||||
|
||||
<UFormGroup label="Rechnungsreferenz:" required>
|
||||
<UInput />
|
||||
</UFormGroup>
|
||||
|
||||
<UFormGroup label="Rechnungsdatum:" required>
|
||||
<UInput />
|
||||
</UFormGroup>
|
||||
|
||||
<UButton @click="vendorInvoiceData.lineItems.push({})">+ Reihe</UButton>
|
||||
|
||||
|
||||
<div v-for="lineItem in vendorInvoiceData.lineItems" class="lineItemRow">
|
||||
<UFormGroup label="Text:" required>
|
||||
<UInput v-model="lineItem.text"/>
|
||||
</UFormGroup>
|
||||
<UFormGroup label="Produkt:" required>
|
||||
<UInput v-model="lineItem.productId"/>
|
||||
</UFormGroup>
|
||||
<UFormGroup label="Projekt:" required>
|
||||
<UInput v-model="lineItem.projectId"/>
|
||||
</UFormGroup>
|
||||
<UFormGroup label="Anzahl:" required>
|
||||
<UInput v-model="lineItem.quantity"/>
|
||||
</UFormGroup>
|
||||
<UFormGroup label="Einheit:" required>
|
||||
<UInput v-model="lineItem.unit"/>
|
||||
</UFormGroup>
|
||||
<UFormGroup label="Einzelpreis:" required>
|
||||
<UInput v-model="lineItem.unitPriceNet"/>
|
||||
</UFormGroup>
|
||||
<UFormGroup label="USt:" required>
|
||||
<UInput v-model="lineItem.vat"/>
|
||||
</UFormGroup>
|
||||
<UFormGroup label="Rabatt:" required>
|
||||
<UInput v-model="lineItem.discount"/>
|
||||
</UFormGroup>
|
||||
<UFormGroup label="Buchungskonto:" required>
|
||||
<UInput v-model="lineItem.skrAccountId"/>
|
||||
</UFormGroup>
|
||||
<UFormGroup label="Positionspreis:" required>
|
||||
<UInput disabled/>
|
||||
</UFormGroup>
|
||||
</div>
|
||||
{{vendorInvoiceData}}
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
|
||||
let vendorInvoiceData = ref({
|
||||
reference: "",
|
||||
date: "",
|
||||
vendorId: 0,
|
||||
lineItems: []
|
||||
})
|
||||
|
||||
|
||||
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.lineItemRow {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
}
|
||||
</style>
|
||||
@@ -32,7 +32,7 @@
|
||||
|
||||
<script setup>
|
||||
|
||||
import {useDataStore} from "../../store/data";
|
||||
import {useDataStore} from "~/stores/data.ts";
|
||||
import {storeToRefs} from "pinia"
|
||||
|
||||
|
||||
|
||||
BIN
spaces/public/fonts/Roboto-Bold.woff
Executable file
BIN
spaces/public/fonts/Roboto-Bold.woff
Executable file
Binary file not shown.
BIN
spaces/public/fonts/Roboto-Bold.woff2
Executable file
BIN
spaces/public/fonts/Roboto-Bold.woff2
Executable file
Binary file not shown.
BIN
spaces/public/fonts/Roboto-Light.woff
Executable file
BIN
spaces/public/fonts/Roboto-Light.woff
Executable file
Binary file not shown.
BIN
spaces/public/fonts/Roboto-Light.woff2
Executable file
BIN
spaces/public/fonts/Roboto-Light.woff2
Executable file
Binary file not shown.
BIN
spaces/public/fonts/Roboto-Medium.woff
Executable file
BIN
spaces/public/fonts/Roboto-Medium.woff
Executable file
Binary file not shown.
BIN
spaces/public/fonts/Roboto-Medium.woff2
Executable file
BIN
spaces/public/fonts/Roboto-Medium.woff2
Executable file
Binary file not shown.
BIN
spaces/public/fonts/Roboto-Regular.woff
Executable file
BIN
spaces/public/fonts/Roboto-Regular.woff
Executable file
Binary file not shown.
BIN
spaces/public/fonts/Roboto-Regular.woff2
Executable file
BIN
spaces/public/fonts/Roboto-Regular.woff2
Executable file
Binary file not shown.
BIN
spaces/public/fonts/fa-brands-400.ttf
Executable file
BIN
spaces/public/fonts/fa-brands-400.ttf
Executable file
Binary file not shown.
BIN
spaces/public/fonts/fa-brands-400.woff2
Executable file
BIN
spaces/public/fonts/fa-brands-400.woff2
Executable file
Binary file not shown.
BIN
spaces/public/fonts/fa-regular-400.ttf
Executable file
BIN
spaces/public/fonts/fa-regular-400.ttf
Executable file
Binary file not shown.
BIN
spaces/public/fonts/fa-regular-400.woff2
Executable file
BIN
spaces/public/fonts/fa-regular-400.woff2
Executable file
Binary file not shown.
BIN
spaces/public/fonts/fa-solid-900.ttf
Executable file
BIN
spaces/public/fonts/fa-solid-900.ttf
Executable file
Binary file not shown.
BIN
spaces/public/fonts/fa-solid-900.woff2
Executable file
BIN
spaces/public/fonts/fa-solid-900.woff2
Executable file
Binary file not shown.
BIN
spaces/public/fonts/fa-v4compatibility.ttf
Executable file
BIN
spaces/public/fonts/fa-v4compatibility.ttf
Executable file
Binary file not shown.
BIN
spaces/public/fonts/fa-v4compatibility.woff2
Executable file
BIN
spaces/public/fonts/fa-v4compatibility.woff2
Executable file
Binary file not shown.
1
spaces/public/grid.stockholm.css.map
Normal file
1
spaces/public/grid.stockholm.css.map
Normal file
File diff suppressed because one or more lines are too long
16
spaces/public/grid.stockholm.min.css
vendored
Normal file
16
spaces/public/grid.stockholm.min.css
vendored
Normal file
File diff suppressed because one or more lines are too long
7
spaces/public/grid.stockholm.min.css.map
Normal file
7
spaces/public/grid.stockholm.min.css.map
Normal file
File diff suppressed because one or more lines are too long
@@ -1,236 +0,0 @@
|
||||
import {defineStore} from 'pinia'
|
||||
import {CustomerInfo, ProjectInfo, VendorInvoice, ProductInfo} from "@/misc/interfaces";
|
||||
|
||||
export const useDataStore = defineStore('dataStore', {
|
||||
state: () => {
|
||||
return {
|
||||
customers: [
|
||||
{
|
||||
id: 10069,
|
||||
name: "NOA Service GmbH",
|
||||
addresses: [
|
||||
{
|
||||
type: "invoice",
|
||||
street: "Oldenburger Str. ",
|
||||
number: "52",
|
||||
zip: 26340,
|
||||
city: "Zetel"
|
||||
}
|
||||
],
|
||||
contacts: [
|
||||
{
|
||||
name: "Noa",
|
||||
firstname: "Stefanie",
|
||||
role: "Geschäftsführerin",
|
||||
email: ""
|
||||
}, {
|
||||
name: "Kramer",
|
||||
firstname: "Lena",
|
||||
role: "",
|
||||
email: ""
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
id: 10083,
|
||||
name: "Specht Reepsholt e.K.",
|
||||
addresses: [
|
||||
{
|
||||
type: "invoice",
|
||||
street: "Reepsholter Hauptstr. ",
|
||||
number: "17",
|
||||
zip: 26446,
|
||||
city: "Reepsholt"
|
||||
}
|
||||
],
|
||||
contacts: [
|
||||
{
|
||||
name: "Specht",
|
||||
firstname: "Oliver",
|
||||
role: "",
|
||||
email: ""
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
id: 10023,
|
||||
name: "M&K Nordsonne GmbH & Co. KG",
|
||||
addresses: [
|
||||
{
|
||||
type: "invoice",
|
||||
street: "Berghamm",
|
||||
number: "1",
|
||||
zip: 26434,
|
||||
city: "Wangerland"
|
||||
}
|
||||
],
|
||||
contacts: [
|
||||
{
|
||||
name: "Mick",
|
||||
firstname: "Martin",
|
||||
role: "Geschäftsführer",
|
||||
email: ""
|
||||
}, {
|
||||
name: "Obst",
|
||||
firstname: "Yvonne",
|
||||
role: "",
|
||||
email: ""
|
||||
}
|
||||
]
|
||||
}
|
||||
] as CustomerInfo[],
|
||||
projects: [
|
||||
{
|
||||
id: 1001,
|
||||
name: "FRIOS052PV001",
|
||||
customerId: 10069,
|
||||
notes: ""
|
||||
},
|
||||
{
|
||||
id: 1002,
|
||||
name: "WTMRH017PV001",
|
||||
customerId: 10083,
|
||||
notes: ""
|
||||
},
|
||||
{
|
||||
id: 1003,
|
||||
name: "Kamerainstallation WHVAS19",
|
||||
customerId: 10069,
|
||||
notes: ""
|
||||
}
|
||||
] as ProjectInfo[],
|
||||
vendorInvoices: [
|
||||
{
|
||||
id: 230001,
|
||||
vendorId: 10001,
|
||||
date: "2023-11-01",
|
||||
reference: "2023-11-01-1000",
|
||||
lineItems: [
|
||||
{
|
||||
pos: 0,
|
||||
text: "Ja Solar",
|
||||
projectId: 1001,
|
||||
quantity: 10,
|
||||
unit: "Stk",
|
||||
unitPriceNet: 120.50,
|
||||
vat: 19,
|
||||
skrAccountId: 3400
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
id: 230002,
|
||||
vendorId: 10001,
|
||||
date: "2023-10-29",
|
||||
reference: "2023-11-01-1001",
|
||||
lineItems: [
|
||||
{
|
||||
pos: 0,
|
||||
productId: 10003,
|
||||
projectId: 1003,
|
||||
quantity: 3,
|
||||
unit: "Stk",
|
||||
unitPriceNet: 96.00,
|
||||
vat: 19,
|
||||
skrAccountId: 3400
|
||||
}
|
||||
]
|
||||
}
|
||||
] as VendorInvoice[],
|
||||
products: [
|
||||
{
|
||||
id:10001,
|
||||
name: "STP-10SE",
|
||||
manufacturer: "SMA",
|
||||
purchasePriceNet: 1500.00,
|
||||
profitPercentage: 20,
|
||||
retailPriceNet: 1800.00,
|
||||
tags: ["pv","wechselrichter"]
|
||||
},
|
||||
{
|
||||
id:10002,
|
||||
name: "RLC-810A",
|
||||
manufacturer: "Reolink",
|
||||
purchasePriceNet: 80.00,
|
||||
profitPercentage: 20,
|
||||
retailPriceNet: 96.00,
|
||||
tags: ["kamera","outdoor","lan","poe"],
|
||||
optionalProductIds: [10003]
|
||||
},
|
||||
{
|
||||
id:10003,
|
||||
name: "RLC-510WA",
|
||||
manufacturer: "Reolink",
|
||||
purchasePriceNet: 80.00,
|
||||
profitPercentage: 20,
|
||||
retailPriceNet: 96.00,
|
||||
tags: ["kamera","outdoor","wlan"],
|
||||
optionalProductIds: [10002]
|
||||
}
|
||||
] as ProductInfo[],
|
||||
}
|
||||
|
||||
},
|
||||
actions: {
|
||||
async getData(){
|
||||
const {data} = await useFetch("/api/customers")
|
||||
console.log(data)
|
||||
// @ts-ignore
|
||||
this.customers = data
|
||||
|
||||
},
|
||||
addCustomer(value: CustomerInfo) {
|
||||
this.customers.push(value)
|
||||
},
|
||||
addProject(value: ProjectInfo){
|
||||
this.projects.push(value)
|
||||
}
|
||||
},
|
||||
getters: {
|
||||
customerList(state){
|
||||
return state.customers
|
||||
},
|
||||
customersForSelect(state){
|
||||
return state.customers.map((customer:any) => {return {label: customer.name, value: customer.id}})
|
||||
},
|
||||
getCustomerById: (state) => (id:number) => state.customers.find((customer:any) => customer.id === id),
|
||||
projectList(state){
|
||||
return state.projects
|
||||
},
|
||||
getVendorInvoiceList: (state) => state.vendorInvoices,
|
||||
getVendorInvoicesByProjectId: (state) => (id:number) => {
|
||||
let invoices:any[] = []
|
||||
|
||||
state.vendorInvoices.forEach((invoice:any) => {
|
||||
//Store Current Invoice Data
|
||||
let temp:any = {
|
||||
vendorInvoiceId: 0,
|
||||
value: 0
|
||||
}
|
||||
|
||||
//Check if Current Invoice Contains Relevant Data
|
||||
if(invoice.lineItems.filter((lineItem:any) => lineItem.projectId === id).length > 0) {
|
||||
console.log("in if")
|
||||
temp.vendorInvoiceId = invoice.id
|
||||
invoice.lineItems.filter((lineItem:any) => lineItem.projectId === id).forEach((lineItem:any) => {
|
||||
console.log(temp)
|
||||
temp.value = Number(temp.value) + lineItem.quantity * lineItem.unitPriceNet
|
||||
console.log(lineItem)
|
||||
})
|
||||
|
||||
temp.value = String(temp.value.toFixed(2)) + "€"
|
||||
|
||||
invoices.push(temp)
|
||||
}
|
||||
|
||||
|
||||
|
||||
})
|
||||
|
||||
return invoices
|
||||
},
|
||||
getProductsList: (state) => state.products
|
||||
}
|
||||
|
||||
})
|
||||
|
||||
92
spaces/stores/data.ts
Normal file
92
spaces/stores/data.ts
Normal file
@@ -0,0 +1,92 @@
|
||||
import {defineStore} from 'pinia'
|
||||
|
||||
import {createClient} from '@supabase/supabase-js'
|
||||
|
||||
const supabase = createClient('https://uwppvcxflrcsibuzsbil.supabase.co','eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJzdXBhYmFzZSIsInJlZiI6InV3cHB2Y3hmbHJjc2lidXpzYmlsIiwicm9sZSI6ImFub24iLCJpYXQiOjE3MDA5MzgxOTQsImV4cCI6MjAxNjUxNDE5NH0.CkxYSQH0uLfwx9GVUlO6AYMU2FMLAxGMrwEKvyPv7Oo')
|
||||
|
||||
|
||||
// @ts-ignore
|
||||
export const useDataStore = defineStore('data', {
|
||||
state: () => ({
|
||||
loaded: false,
|
||||
customers: [] as any[],
|
||||
tasks: [] as any[],
|
||||
projects: [] as any[],
|
||||
documents: [] as any[],
|
||||
spaces: [] as any[],
|
||||
units: [] as any[],
|
||||
times: [] as any[],
|
||||
products: [] as any[],
|
||||
movements: [] as any[],
|
||||
forms: [] as any[],
|
||||
formSubmits: [] as any[],
|
||||
contact: [] as any[]
|
||||
}),
|
||||
actions: {
|
||||
async fetchData() {
|
||||
await this.fetchCustomers()
|
||||
await this.fetchTasks()
|
||||
await this.fetchForms()
|
||||
await this.fetchFormSubmits()
|
||||
await this.fetchProducts()
|
||||
await this.fetchUnits()
|
||||
await this.fetchProjects()
|
||||
await this.fetchDocuments()
|
||||
await this.fetchMovements()
|
||||
await this.fetchSpaces()
|
||||
this.loaded = true
|
||||
},
|
||||
async fetchCustomers() {
|
||||
// @ts-ignore
|
||||
this.customers = (await supabase.from("customers").select().order('customerNumber', {ascending: true})).data
|
||||
},
|
||||
async fetchTasks() {
|
||||
// @ts-ignore
|
||||
this.tasks = (await supabase.from("tasks").select()).data
|
||||
},
|
||||
async fetchForms() {
|
||||
// @ts-ignore
|
||||
this.forms = (await supabase.from("forms").select()).data
|
||||
},
|
||||
async fetchFormSubmits() {
|
||||
// @ts-ignore
|
||||
this.formSubmits = (await supabase.from("formSubmits").select()).data
|
||||
},
|
||||
async fetchProducts() {
|
||||
// @ts-ignore
|
||||
this.products = (await supabase.from("products").select()).data
|
||||
},
|
||||
async fetchUnits() {
|
||||
// @ts-ignore
|
||||
this.units = (await supabase.from("units").select()).data
|
||||
},
|
||||
async fetchProjects() {
|
||||
// @ts-ignore
|
||||
this.projects = (await supabase.from("projects").select()).data
|
||||
},
|
||||
async fetchSpaces() {
|
||||
// @ts-ignore
|
||||
this.spaces = (await supabase.from("spaces").select().order('spaceNumber', {ascending: true})).data
|
||||
},
|
||||
async fetchMovements() {
|
||||
// @ts-ignore
|
||||
this.movements = (await supabase.from("movements").select()).data
|
||||
},
|
||||
async fetchDocuments() {
|
||||
// @ts-ignore
|
||||
this.documents = (await supabase.from("documents").select()).data
|
||||
|
||||
for(const [index,doc] of this.documents.entries()){
|
||||
// @ts-ignore
|
||||
this.documents[index].url = (await supabase.storage.from('documents').createSignedUrl(doc.path, 60 * 60)).data.signedUrl
|
||||
}
|
||||
}
|
||||
},
|
||||
getters: {
|
||||
getOpenTasksCount: (state) => state.tasks.filter(task => task.categorie != "Erledigt").length,
|
||||
movementsBySpace: (state) => (spaceId:number) => state.movements.filter(move => move.spaceId === spaceId),
|
||||
getProductById: (state) => (productId:number) => state.products.find(product => product.id === productId),
|
||||
getProjectById: (state) => (projectId:number) => state.projects.find(project => project.id === projectId),
|
||||
getFormSubmitsWithLabelProp: (state) => (state.formSubmits.map(submit => {return{...submit, label: submit.id}}))
|
||||
}
|
||||
})
|
||||
@@ -50,7 +50,8 @@ const uploadAttachmentToSupabase = async (tenant, folder ,file ) => {
|
||||
object: storageData.id,
|
||||
folder: folder,
|
||||
tags: ["E-Mail Anhang"],
|
||||
path: storageData.path
|
||||
path: storageData.path,
|
||||
tenant: tenant
|
||||
|
||||
})
|
||||
.select()
|
||||
|
||||
Reference in New Issue
Block a user