feat: add time-entry editing; improve invoices/PDF; harden Docker startup

Timer/Editing
- Add/edit time-entry UI and flows in templates (`templates/timer/*`)
- Extend timer and API routes (`app/routes/timer.py`, `app/routes/api.py`)
- Update mobile interactions (`app/static/mobile.js`)

Invoices/PDF
- Improve invoice model and route handling (`app/models/invoice.py`, `app/routes/invoices.py`)
- Enhance PDF generation and fallback logic (`app/utils/pdf_generator*.py`)
- Adjust invoice view layout (`templates/invoices/view.html`)

Docker/Startup
- Refine Docker build and startup paths (`Dockerfile`)
- Improve init/entrypoint scripts (`docker/init-database-*.py`, new `docker/entrypoint*.sh`, `docker/entrypoint.py`)
- General startup robustness and permissions fixes

Docs/UI
- Refresh README and Docker docs (setup, troubleshooting, structure)
- Minor UI/help updates (`templates/main/help.html`, `templates/projects/create.html`)
- Remove obsolete asset (`assets/screenshots/Task_Management.png`)
- Add repo hygiene updates (e.g., `.gitattributes`)
This commit is contained in:
Dries Peeters
2025-09-03 09:48:19 +02:00
parent 3894b3be94
commit b880191c16
26 changed files with 1709 additions and 340 deletions

View File

@@ -82,6 +82,7 @@ def create_tables_sql(engine):
CREATE TABLE IF NOT EXISTS invoices (
id SERIAL PRIMARY KEY,
invoice_number VARCHAR(50) UNIQUE NOT NULL,
client_id INTEGER NOT NULL REFERENCES clients(id) ON DELETE CASCADE,
project_id INTEGER REFERENCES projects(id) ON DELETE CASCADE,
client_name VARCHAR(200) NOT NULL,
client_email VARCHAR(200),
@@ -186,6 +187,7 @@ def create_indexes(engine):
CREATE INDEX IF NOT EXISTS idx_time_entries_user_id ON time_entries(user_id);
CREATE INDEX IF NOT EXISTS idx_time_entries_project_id ON time_entries(project_id);
CREATE INDEX IF NOT EXISTS idx_time_entries_start_time ON time_entries(start_time);
CREATE INDEX IF NOT EXISTS idx_invoices_client_id ON invoices(client_id);
"""
try:
@@ -261,20 +263,42 @@ def insert_initial_data(engine):
admin_username = os.getenv('ADMIN_USERNAMES', 'admin').split(',')[0]
insert_sql = f"""
-- Insert default admin user
-- Insert default admin user idempotently
INSERT INTO users (username, role, is_active)
VALUES ('{admin_username}', 'admin', true)
ON CONFLICT (username) DO NOTHING;
SELECT '{admin_username}', 'admin', true
WHERE NOT EXISTS (
SELECT 1 FROM users WHERE username = '{admin_username}'
);
-- Insert default project
-- Ensure default client exists
INSERT INTO clients (name, status)
SELECT 'Default Client', 'active'
WHERE NOT EXISTS (
SELECT 1 FROM clients WHERE name = 'Default Client'
);
-- Insert default project idempotently and link to default client
INSERT INTO projects (name, client, description, billable, status)
VALUES ('General', 'Default Client', 'Default project for general tasks', true, 'active')
ON CONFLICT DO NOTHING;
SELECT 'General', 'Default Client', 'Default project for general tasks', true, 'active'
WHERE NOT EXISTS (
SELECT 1 FROM projects WHERE name = 'General'
);
-- Insert default settings
INSERT INTO settings (timezone, currency, rounding_minutes, single_active_timer, allow_self_register, idle_timeout_minutes, backup_retention_days, backup_time, export_delimiter, company_name, company_address, company_email, company_phone, company_website, company_logo_filename, company_tax_id, company_bank_info, invoice_prefix, invoice_start_number, invoice_terms, invoice_notes)
VALUES ('Europe/Rome', 'EUR', 1, true, true, 30, 30, '02:00', ',', 'Your Company Name', 'Your Company Address', 'info@yourcompany.com', '+1 (555) 123-4567', 'www.yourcompany.com', '', '', '', 'INV', 1000, 'Payment is due within 30 days of invoice date.', 'Thank you for your business!')
ON CONFLICT (id) DO NOTHING;
-- Insert default settings only if none exist
INSERT INTO settings (
timezone, currency, rounding_minutes, single_active_timer, allow_self_register,
idle_timeout_minutes, backup_retention_days, backup_time, export_delimiter,
company_name, company_address, company_email, company_phone, company_website,
company_logo_filename, company_tax_id, company_bank_info, invoice_prefix,
invoice_start_number, invoice_terms, invoice_notes
)
SELECT 'Europe/Rome', 'EUR', 1, true, true, 30, 30, '02:00', ',',
'Your Company Name', 'Your Company Address', 'info@yourcompany.com',
'+1 (555) 123-4567', 'www.yourcompany.com', '', '', '', 'INV', 1000,
'Payment is due within 30 days of invoice date.', 'Thank you for your business!'
WHERE NOT EXISTS (
SELECT 1 FROM settings
);
"""
try: