- Added a file input for PDF uploads with validation for file type and size. - Implemented file size formatting and user feedback for selected files. - Created upload and cancel methods with placeholder for future API integration. feat: Create PaymentForm.vue for handling payments - Developed a form for entering payment details including date, amount, method, and notes. - Integrated currency formatting and dropdown for payment methods. - Implemented save and cancel actions with API call for saving payment data. docs: Add documentation for dynamic plugin menus and permissions - Provided guidelines for defining menu items and permissions in plugins. - Explained the process for synchronizing permissions and integrating menus in the frontend. - Included examples and best practices for plugin development. feat: Add database migrations for invoices, invoice items, and payments - Created migration scripts to define the database schema for invoices, invoice items, and payments. - Established foreign key relationships between invoices and related entities. feat: Implement command for synchronizing plugin permissions - Developed a console command to synchronize plugin permissions with the database. - Added options for dry-run and force synchronization for unlicensed modules. feat: Create API controller for plugin menu items - Implemented API endpoints to retrieve plugin menu items in both flat and grouped formats. - Ensured access control with role-based permissions for API access. feat: Develop service for managing plugin menu items - Created a service to collect and manage menu items from installed plugins. - Implemented methods for retrieving flat and grouped menu items for frontend use. feat: Add service for synchronizing plugin permissions - Developed a service to handle the synchronization of plugin permissions with the database. - Included logic for creating and updating permission modules based on plugin definitions.
122 lines
3.4 KiB
Vue
122 lines
3.4 KiB
Vue
<template>
|
|
<div class="payment-form">
|
|
<div class="grid p-fluid">
|
|
<div class="col-12">
|
|
<p>
|
|
<strong>Rechnung:</strong> {{ invoice?.invoiceNumber }}<br />
|
|
<strong>Offener Betrag:</strong> {{ formatCurrency(invoice?.openAmount) }}
|
|
</p>
|
|
</div>
|
|
|
|
<!-- Zahlungsdatum -->
|
|
<div class="col-12">
|
|
<label for="paymentDate">Zahlungsdatum *</label>
|
|
<Calendar id="paymentDate" v-model="form.paymentDate" date-format="dd.mm.yy" />
|
|
</div>
|
|
|
|
<!-- Betrag -->
|
|
<div class="col-12">
|
|
<label for="amount">Betrag *</label>
|
|
<InputNumber
|
|
id="amount"
|
|
v-model="form.amount"
|
|
mode="currency"
|
|
currency="EUR"
|
|
locale="de-DE"
|
|
/>
|
|
</div>
|
|
|
|
<!-- Zahlungsart -->
|
|
<div class="col-12">
|
|
<label for="paymentMethod">Zahlungsart</label>
|
|
<Dropdown
|
|
id="paymentMethod"
|
|
v-model="form.paymentMethod"
|
|
:options="paymentMethods"
|
|
option-label="label"
|
|
option-value="value"
|
|
/>
|
|
</div>
|
|
|
|
<!-- Notizen -->
|
|
<div class="col-12">
|
|
<label for="notes">Notizen</label>
|
|
<Textarea id="notes" v-model="form.notes" rows="3" />
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Actions -->
|
|
<div class="flex gap-2 mt-4">
|
|
<Button label="Speichern" icon="pi pi-check" @click="save" />
|
|
<Button label="Abbrechen" icon="pi pi-times" severity="secondary" text @click="cancel" />
|
|
</div>
|
|
</div>
|
|
</template>
|
|
|
|
<script setup>
|
|
import { ref } from 'vue'
|
|
import InputNumber from 'primevue/inputnumber'
|
|
import Calendar from 'primevue/calendar'
|
|
import Dropdown from 'primevue/dropdown'
|
|
import Textarea from 'primevue/textarea'
|
|
import Button from 'primevue/button'
|
|
|
|
const props = defineProps({
|
|
invoice: Object
|
|
})
|
|
|
|
const emit = defineEmits(['save', 'cancel'])
|
|
|
|
const form = ref({
|
|
paymentDate: new Date(),
|
|
amount: parseFloat(props.invoice?.openAmount || 0),
|
|
paymentMethod: 'bank_transfer',
|
|
notes: ''
|
|
})
|
|
|
|
const paymentMethods = [
|
|
{ label: 'Überweisung', value: 'bank_transfer' },
|
|
{ label: 'Bar', value: 'cash' },
|
|
{ label: 'Karte', value: 'card' },
|
|
{ label: 'PayPal', value: 'paypal' },
|
|
{ label: 'SEPA-Lastschrift', value: 'sepa' },
|
|
{ label: 'Sonstiges', value: 'other' }
|
|
]
|
|
|
|
const formatCurrency = (amount) => {
|
|
if (!amount) return '0,00 €'
|
|
return new Intl.NumberFormat('de-DE', {
|
|
style: 'currency',
|
|
currency: 'EUR'
|
|
}).format(parseFloat(amount))
|
|
}
|
|
|
|
const save = async () => {
|
|
const payload = {
|
|
invoice: `/api/invoices/${props.invoice.id}`,
|
|
paymentDate: form.value.paymentDate.toISOString().split('T')[0],
|
|
amount: form.value.amount.toString(),
|
|
paymentMethod: form.value.paymentMethod,
|
|
notes: form.value.notes
|
|
}
|
|
|
|
await fetch('/api/payments', {
|
|
method: 'POST',
|
|
headers: { 'Content-Type': 'application/json' },
|
|
body: JSON.stringify(payload)
|
|
})
|
|
|
|
emit('save')
|
|
}
|
|
|
|
const cancel = () => {
|
|
emit('cancel')
|
|
}
|
|
</script>
|
|
|
|
<style scoped>
|
|
.payment-form {
|
|
padding: 1rem;
|
|
}
|
|
</style>
|