OfferteTOOL
Beste iedereen weet dat een boekhoud programma geld kost en soms onnodig omdat je nog niet veel klanten hebt en niet wil vasthangen aan maandelijkse abonnementen.
Hoe Artificiële intelligentie DeepSeek jullie kan helpen zodat jullie altijd nog verteringen kunnen aanbrengen waar open-Source voor is ontwikkeld om verder op te bouwen om het uiteindelijke doel samen te bereiken zonder tegen gewerkt te worden. Alvast in de bijlage van het bestand zowel een voorbeeld als offerte of factuur.
Succes
Functionaliteiten van deze software:
-
Factuur/Offerte modus: Schakel eenvoudig tussen factuur- en offertemodus met een toggle.
-
Gegevens invoeren:
-
Bedrijfsgegevens (naam, adres, KVK, BTW-nummer)
-
Klantgegevens
-
Factuur/offerte nummer en datum
-
Producten/diensten met hoeveelheden en prijzen
-
Aanpasbare opmerkingen
-
-
Dynamische voorbeeldweergave: Alle wijzigingen worden direct weergegeven in de preview.
-
Itembeheer:
-
Voeg nieuwe regels toe
-
Verwijder regels
-
Automatische berekening van totaalbedragen
-
-
Afdrukfunctionaliteit:
-
Druk factuur/offerte af als PDF of op papier
-
Professionele opmaak voor afdrukken
-
-
Responsive design: Werkt op desktop en mobiele apparaten.
-
Geen server nodig: Alles werkt in de browser, geen gegevens worden extern opgeslagen.
Om de software te gebruiken, sla je de bovenstaande code op als HTML-bestand (bijvoorbeeld factuur-offerte.html) en open je het in een moderne webbrowser.
<!DOCTYPE html>
<html lang="nl">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Factuur als Offerte - Zelfstandige</title>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
<style>
* {
margin: 0;
padding: 0;
box-sizing: border-box;
font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
}
body {
background-color: #f5f7fa;
color: #333;
line-height: 1.6;
padding: 20px;
max-width: 1200px;
margin: 0 auto;
}
.container {
display: flex;
flex-direction: column;
gap: 25px;
}
header {
background: linear-gradient(135deg, #2c3e50, #4a6491);
color: white;
padding: 25px;
border-radius: 10px;
box-shadow: 0 5px 15px rgba(0, 0, 0, 0.1);
text-align: center;
}
.logo {
font-size: 2.5rem;
margin-bottom: 10px;
}
h1 {
font-size: 2.2rem;
margin-bottom: 10px;
}
.subtitle {
font-size: 1.1rem;
opacity: 0.9;
}
.app-container {
display: flex;
flex-wrap: wrap;
gap: 25px;
}
.input-section {
flex: 1;
min-width: 300px;
background-color: white;
padding: 25px;
border-radius: 10px;
box-shadow: 0 5px 15px rgba(0, 0, 0, 0.05);
}
.preview-section {
flex: 1;
min-width: 300px;
background-color: white;
padding: 25px;
border-radius: 10px;
box-shadow: 0 5px 15px rgba(0, 0, 0, 0.05);
display: flex;
flex-direction: column;
}
h2 {
color: #2c3e50;
margin-bottom: 20px;
padding-bottom: 10px;
border-bottom: 2px solid #eee;
}
.form-group {
margin-bottom: 20px;
}
label {
display: block;
margin-bottom: 8px;
font-weight: 600;
color: #444;
}
input, select, textarea {
width: 100%;
padding: 12px 15px;
border: 1px solid #ddd;
border-radius: 6px;
font-size: 16px;
transition: border-color 0.3s;
}
input:focus, select:focus, textarea:focus {
border-color: #4a6491;
outline: none;
}
.row {
display: flex;
gap: 15px;
}
.row .form-group {
flex: 1;
}
.items-table {
width: 100%;
border-collapse: collapse;
margin-top: 10px;
}
.items-table th, .items-table td {
padding: 12px;
text-align: left;
border-bottom: 1px solid #eee;
}
.items-table th {
background-color: #f8f9fa;
font-weight: 600;
}
.items-table input {
width: 100%;
border: none;
padding: 5px;
background: transparent;
}
.btn {
background-color: #4a6491;
color: white;
border: none;
padding: 12px 20px;
border-radius: 6px;
cursor: pointer;
font-size: 16px;
font-weight: 600;
transition: background-color 0.3s;
display: inline-flex;
align-items: center;
justify-content: center;
gap: 8px;
}
.btn:hover {
background-color: #3a5379;
}
.btn-add {
background-color: #2ecc71;
margin-top: 10px;
}
.btn-add:hover {
background-color: #27ae60;
}
.btn-remove {
background-color: #e74c3c;
padding: 6px 10px;
font-size: 14px;
}
.btn-remove:hover {
background-color: #c0392b;
}
.btn-print {
background-color: #3498db;
margin-top: 20px;
}
.btn-print:hover {
background-color: #2980b9;
}
.actions {
display: flex;
gap: 15px;
flex-wrap: wrap;
}
.toggle-container {
display: flex;
align-items: center;
margin-bottom: 20px;
background-color: #f8f9fa;
padding: 10px;
border-radius: 6px;
}
.toggle-label {
margin: 0;
flex: 1;
}
.switch {
position: relative;
display: inline-block;
width: 60px;
height: 30px;
}
.switch input {
opacity: 0;
width: 0;
height: 0;
}
.slider {
position: absolute;
cursor: pointer;
top: 0;
left: 0;
right: 0;
bottom: 0;
background-color: #ccc;
transition: .4s;
border-radius: 34px;
}
.slider:before {
position: absolute;
content: "";
height: 22px;
width: 22px;
left: 4px;
bottom: 4px;
background-color: white;
transition: .4s;
border-radius: 50%;
}
input:checked + .slider {
background-color: #4a6491;
}
input:checked + .slider:before {
transform: translateX(30px);
}
.invoice-preview {
flex: 1;
background-color: #fff;
border: 1px solid #ddd;
border-radius: 6px;
padding: 25px;
overflow-y: auto;
margin-bottom: 20px;
}
.invoice-header {
display: flex;
justify-content: space-between;
margin-bottom: 30px;
padding-bottom: 20px;
border-bottom: 2px solid #4a6491;
}
.invoice-title {
font-size: 2.5rem;
font-weight: 700;
color: #2c3e50;
}
.invoice-number {
font-size: 1.2rem;
color: #666;
}
.invoice-info {
display: flex;
justify-content: space-between;
margin-bottom: 30px;
}
.company-info, .client-info {
flex: 1;
}
.info-label {
font-weight: 600;
margin-bottom: 5px;
color: #2c3e50;
}
.invoice-table {
width: 100%;
border-collapse: collapse;
margin: 25px 0;
}
.invoice-table th {
background-color: #f8f9fa;
padding: 15px;
text-align: left;
border-bottom: 1px solid #ddd;
font-weight: 600;
}
.invoice-table td {
padding: 15px;
border-bottom: 1px solid #eee;
}
.text-right {
text-align: right;
}
.total-row {
font-weight: 700;
font-size: 1.1rem;
background-color: #f8f9fa;
}
.footer-note {
margin-top: 30px;
padding-top: 20px;
border-top: 1px solid #eee;
font-style: italic;
color: #666;
}
.invoice-type {
display: inline-block;
padding: 5px 15px;
background-color: #4a6491;
color: white;
border-radius: 4px;
font-weight: 600;
margin-bottom: 10px;
}
@media print {
body * {
visibility: hidden;
}
.preview-section, .preview-section * {
visibility: visible;
}
.preview-section {
position: absolute;
left: 0;
top: 0;
width: 100%;
box-shadow: none;
}
.btn, .toggle-container {
display: none !important;
}
}
footer {
text-align: center;
margin-top: 30px;
padding-top: 20px;
border-top: 1px solid #ddd;
color: #666;
font-size: 0.9rem;
}
</style>
</head>
<body>
<div class="container">
<header>
<div class="logo">
<i class="fas fa-file-invoice-dollar"></i>
</div>
<h1>Factuur als Offerte</h1>
<p class="subtitle">Voor zelfstandigen - Maak eenvoudig aanpasbare facturen die ook als offerte kunnen dienen</p>
</header>
<div class="toggle-container">
<span class="toggle-label">Factuur/Offerte modus:</span>
<label class="switch">
<input type="checkbox" id="invoiceToggle">
<span class="slider"></span>
</label>
<span id="toggleStatus">Factuur</span>
</div>
<div class="app-container">
<div class="input-section">
<h2>Gegevens invoeren</h2>
<div class="row">
<div class="form-group">
<label for="invoiceNumber">Nummer</label>
<input type="text" id="invoiceNumber" value="2023-001">
</div>
<div class="form-group">
<label for="invoiceDate">Datum</label>
<input type="date" id="invoiceDate" value="">
</div>
</div>
<div class="form-group">
<label for="companyName">Uw Bedrijfsnaam</label>
<input type="text" id="companyName" value="Jansen Consultancy">
</div>
<div class="row">
<div class="form-group">
<label for="companyKvk">KVK-nummer</label>
<input type="text" id="companyKvk" value="12345678">
</div>
<div class="form-group">
<label for="companyVat">BTW-nummer</label>
<input type="text" id="companyVat" value="NL123456789B01">
</div>
</div>
<div class="form-group">
<label for="companyAddress">Uw Adres</label>
<textarea id="companyAddress" rows="3">Hoofdstraat 123
1234 AB Amsterdam</textarea>
</div>
<h3>Klantgegevens</h3>
<div class="form-group">
<label for="clientName">Klantnaam</label>
<input type="text" id="clientName" value="Bakkerij de Bol">
</div>
<div class="form-group">
<label for="clientAddress">Klantadres</label>
<textarea id="clientAddress" rows="3">Dorpsstraat 45
5678 CD Rotterdam</textarea>
</div>
<h3>Producten/Diensten</h3>
<table class="items-table">
<thead>
<tr>
<th>Omschrijving</th>
<th>Aantal</th>
<th>Prijs</th>
<th>Totaal</th>
<th></th>
</tr>
</thead>
<tbody id="itemsTableBody">
<!-- Items worden hier dynamisch toegevoegd -->
</tbody>
</table>
<button class="btn btn-add" id="addItemBtn">
<i class="fas fa-plus"></i> Item toevoegen
</button>
<div class="form-group">
<label for="notes">Opmerkingen</label>
<textarea id="notes" rows="4">Bedankt voor uw vertrouwen. Gelieve het bedrag binnen 30 dagen over te maken op rekeningnummer NL12 ABCD 1234 5678 90 ten name van Jansen Consultancy.</textarea>
</div>
<div class="actions">
<button class="btn" id="updatePreviewBtn">
<i class="fas fa-sync-alt"></i> Voorbeeld bijwerken
</button>
<button class="btn btn-print" id="printBtn">
<i class="fas fa-print"></i> Afdrukken/PDF maken
</button>
</div>
</div>
<div class="preview-section">
<h2>Voorbeeld</h2>
<div class="invoice-preview" id="invoicePreview">
<!-- Factuur wordt hier gegenereerd -->
</div>
</div>
</div>
<footer>
<p>© 2023 Factuur als Offerte Software voor Zelfstandigen | Werkt volledig in je browser - geen gegevens worden opgeslagen op externe servers</p>
</footer>
</div>
<script>
document.addEventListener('DOMContentLoaded', function() {
// Stel de datum in op vandaag
const today = new Date().toISOString().split('T')[0];
document.getElementById('invoiceDate').value = today;
// Voeg standaard items toe
addInvoiceItem('Consultancy diensten', 5, 75);
addInvoiceItem('Website ontwikkeling', 1, 500);
addInvoiceItem('Onderhoudscontract', 1, 100);
// Update de preview
updateInvoicePreview();
// Event listeners
document.getElementById('updatePreviewBtn').addEventListener('click', updateInvoicePreview);
document.getElementById('addItemBtn').addEventListener('click', function() {
addInvoiceItem('', 1, 0);
updateInvoicePreview();
});
document.getElementById('printBtn').addEventListener('click', function() {
window.print();
});
// Toggle voor factuur/offerte
document.getElementById('invoiceToggle').addEventListener('change', function() {
const status = document.getElementById('toggleStatus');
if (this.checked) {
status.textContent = 'Offerte';
} else {
status.textContent = 'Factuur';
}
updateInvoicePreview();
});
// Auto-update bij invoer wijzigingen
const inputs = document.querySelectorAll('#input-section input, #input-section textarea, #input-section select');
inputs.forEach(input => {
input.addEventListener('input', updateInvoicePreview);
});
});
function addInvoiceItem(description, quantity, price) {
const tableBody = document.getElementById('itemsTableBody');
const row = document.createElement('tr');
row.innerHTML = `
<td><input type="text" class="item-desc" value="${description}"></td>
<td><input type="number" class="item-qty" min="0" step="1" value="${quantity}"></td>
<td><input type="number" class="item-price" min="0" step="0.01" value="${price}"></td>
<td class="item-total">€ ${(quantity * price).toFixed(2)}</td>
<td><button class="btn btn-remove remove-item-btn"><i class="fas fa-trash"></i></button></td>
`;
tableBody.appendChild(row);
// Voeg event listeners toe aan de nieuwe inputs
row.querySelector('.item-desc').addEventListener('input', updateInvoicePreview);
row.querySelector('.item-qty').addEventListener('input', function() {
updateItemTotal(row);
updateInvoicePreview();
});
row.querySelector('.item-price').addEventListener('input', function() {
updateItemTotal(row);
updateInvoicePreview();
});
// Voeg event listener toe aan verwijderknop
row.querySelector('.remove-item-btn').addEventListener('click', function() {
row.remove();
updateInvoicePreview();
});
}
function updateItemTotal(row) {
const qty = parseFloat(row.querySelector('.item-qty').value) || 0;
const price = parseFloat(row.querySelector('.item-price').value) || 0;
const total = qty * price;
row.querySelector('.item-total').textContent = '€ ' + total.toFixed(2);
}
function updateInvoicePreview() {
// Verzamel alle gegevens
const isOfferte = document.getElementById('invoiceToggle').checked;
const invoiceNumber = document.getElementById('invoiceNumber').value;
const invoiceDate = document.getElementById('invoiceDate').value;
const companyName = document.getElementById('companyName').value;
const companyKvk = document.getElementById('companyKvk').value;
const companyVat = document.getElementById('companyVat').value;
const companyAddress = document.getElementById('companyAddress').value;
const clientName = document.getElementById('clientName').value;
const clientAddress = document.getElementById('clientAddress').value;
const notes = document.getElementById('notes').value;
// Verzamel items
const items = [];
let subtotal = 0;
document.querySelectorAll('#itemsTableBody tr').forEach(row => {
const desc = row.querySelector('.item-desc').value;
const qty = parseFloat(row.querySelector('.item-qty').value) || 0;
const price = parseFloat(row.querySelector('.item-price').value) || 0;
const total = qty * price;
if (desc.trim() !== '') {
items.push({desc, qty, price, total});
subtotal += total;
}
});
// Bereken BTW en totaal
const vatRate = 21; // 21% BTW
const vatAmount = subtotal * (vatRate / 100);
const totalAmount = subtotal + vatAmount;
// Formatteer datum
const formattedDate = new Date(invoiceDate).toLocaleDateString('nl-NL', {
year: 'numeric',
month: 'long',
day: 'numeric'
});
// Bouw de factuur/offerte preview
const invoiceType = isOfferte ? 'Offerte' : 'Factuur';
const invoiceTitle = isOfferte ? 'OFFERTE' : 'FACTUUR';
let itemsHTML = '';
items.forEach(item => {
itemsHTML += `
<tr>
<td>${item.desc}</td>
<td>${item.qty}</td>
<td>€ ${item.price.toFixed(2)}</td>
<td class="text-right">€ ${item.total.toFixed(2)}</td>
</tr>
`;
});
const invoiceHTML = `
<div class="invoice-type">${invoiceType}</div>
<div class="invoice-header">
<div>
<div class="invoice-title">${invoiceTitle}</div>
<div class="invoice-number">${invoiceType}nummer: ${invoiceNumber}</div>
</div>
<div>
<div><strong>Datum:</strong> ${formattedDate}</div>
</div>
</div>
<div class="invoice-info">
<div class="company-info">
<div class="info-label">Van:</div>
<div><strong>${companyName}</strong></div>
<div>${companyAddress.replace(/\n/g, '<br>')}</div>
<div>KVK: ${companyKvk}</div>
<div>BTW: ${companyVat}</div>
</div>
<div class="client-info">
<div class="info-label">Aan:</div>
<div><strong>${clientName}</strong></div>
<div>${clientAddress.replace(/\n/g, '<br>')}</div>
</div>
</div>
<table class="invoice-table">
<thead>
<tr>
<th>Omschrijving</th>
<th>Aantal</th>
<th>Prijs</th>
<th class="text-right">Totaal</th>
</tr>
</thead>
<tbody>
${itemsHTML}
</tbody>
<tfoot>
<tr>
<td colspan="3" class="text-right"><strong>Subtotaal:</strong></td>
<td class="text-right">€ ${subtotal.toFixed(2)}</td>
</tr>
<tr>
<td colspan="3" class="text-right"><strong>BTW (${vatRate}%):</strong></td>
<td class="text-right">€ ${vatAmount.toFixed(2)}</td>
</tr>
<tr class="total-row">
<td colspan="3" class="text-right"><strong>Totaalbedrag:</strong></td>
<td class="text-right">€ ${totalAmount.toFixed(2)}</td>
</tr>
</tfoot>
</table>
<div class="footer-note">
<p><strong>Opmerkingen:</strong></p>
<p>${notes.replace(/\n/g, '<br>')}</p>
${isOfferte ? '<p><strong>Deze offerte is geldig tot 30 dagen na datum.</strong></p>' : ''}
</div>
`;
document.getElementById('invoicePreview').innerHTML = invoiceHTML;
}
</script>
</body>
</html>
Dit is waar onze reis begint. Maak kennis met ons bedrijf en wat we doen. Wij staan voor kwaliteit en goede service. Sluit je aan, terwijl we samen groeien en succesvol worden. We zijn blij dat je hier bent om deel uit te maken van ons verhaal.