feat(sag): Add Varekøb & Salg module with database migration and frontend template
- Created a new SQL migration for the sag_salgsvarer table to manage sales and purchase items.
- Implemented a new HTML template for the Varekøb & Salg module, including summary cards and tables for sales and purchases.
- Added JavaScript functions for loading and rendering order data dynamically.
- Introduced a new backend search module for customers, contacts, hardware, and locations with autocomplete functionality.
- Developed an email templates API for managing system and customer-specific email templates.
- Created multiple migrations for Nextcloud instances, cache, audit logs, email templates, sag comments, hardware locations, and billing methods.
- Enhanced the sag module with solutions, order lines, work types, and 2FA support for user authentication.
2026-02-02 20:23:56 +01:00
|
|
|
from fastapi import APIRouter, Query
|
|
|
|
|
from app.core.database import execute_query
|
|
|
|
|
|
|
|
|
|
router = APIRouter()
|
|
|
|
|
|
|
|
|
|
@router.get("/search/customers")
|
|
|
|
|
async def search_customers(q: str = Query(..., min_length=2)):
|
|
|
|
|
"""
|
|
|
|
|
Autocomplete search for customers.
|
|
|
|
|
Returns list of {id, name, cvr_nummer, email}
|
|
|
|
|
"""
|
|
|
|
|
sql = """
|
2026-02-10 14:40:38 +01:00
|
|
|
SELECT id, name, cvr_number as cvr_nummer, email
|
|
|
|
|
FROM customers
|
|
|
|
|
WHERE (name ILIKE %s OR cvr_number ILIKE %s)
|
|
|
|
|
AND deleted_at IS NULL
|
|
|
|
|
AND is_active = true
|
feat(sag): Add Varekøb & Salg module with database migration and frontend template
- Created a new SQL migration for the sag_salgsvarer table to manage sales and purchase items.
- Implemented a new HTML template for the Varekøb & Salg module, including summary cards and tables for sales and purchases.
- Added JavaScript functions for loading and rendering order data dynamically.
- Introduced a new backend search module for customers, contacts, hardware, and locations with autocomplete functionality.
- Developed an email templates API for managing system and customer-specific email templates.
- Created multiple migrations for Nextcloud instances, cache, audit logs, email templates, sag comments, hardware locations, and billing methods.
- Enhanced the sag module with solutions, order lines, work types, and 2FA support for user authentication.
2026-02-02 20:23:56 +01:00
|
|
|
ORDER BY name ASC
|
|
|
|
|
LIMIT 20
|
|
|
|
|
"""
|
|
|
|
|
term = f"%{q}%"
|
|
|
|
|
results = execute_query(sql, (term, term))
|
|
|
|
|
return results
|
|
|
|
|
|
|
|
|
|
@router.get("/search/contacts")
|
|
|
|
|
async def search_contacts(q: str = Query(..., min_length=2)):
|
|
|
|
|
"""
|
|
|
|
|
Autocomplete search for contacts.
|
|
|
|
|
Returns list of {id, first_name, last_name, email}
|
|
|
|
|
"""
|
|
|
|
|
sql = """
|
|
|
|
|
SELECT id, first_name, last_name, email
|
|
|
|
|
FROM contacts
|
|
|
|
|
WHERE
|
|
|
|
|
(first_name ILIKE %s OR
|
|
|
|
|
last_name ILIKE %s OR
|
|
|
|
|
email ILIKE %s)
|
|
|
|
|
ORDER BY first_name ASC, last_name ASC
|
|
|
|
|
LIMIT 20
|
|
|
|
|
"""
|
|
|
|
|
term = f"%{q}%"
|
|
|
|
|
results = execute_query(sql, (term, term, term))
|
|
|
|
|
return results
|
|
|
|
|
|
|
|
|
|
@router.get("/search/hardware")
|
|
|
|
|
async def search_hardware(q: str = Query(..., min_length=2)):
|
|
|
|
|
"""
|
|
|
|
|
Autocomplete search for hardware.
|
|
|
|
|
Returns list of {id, brand, model, serial_number, internal_asset_id}
|
|
|
|
|
"""
|
|
|
|
|
sql = """
|
|
|
|
|
SELECT id, brand, model, serial_number, internal_asset_id
|
|
|
|
|
FROM hardware_assets
|
|
|
|
|
WHERE
|
|
|
|
|
(brand ILIKE %s OR
|
|
|
|
|
model ILIKE %s OR
|
|
|
|
|
serial_number ILIKE %s OR
|
|
|
|
|
internal_asset_id ILIKE %s)
|
|
|
|
|
AND deleted_at IS NULL
|
|
|
|
|
ORDER BY brand ASC, model ASC
|
|
|
|
|
LIMIT 20
|
|
|
|
|
"""
|
|
|
|
|
term = f"%{q}%"
|
|
|
|
|
results = execute_query(sql, (term, term, term, term))
|
|
|
|
|
return results
|
|
|
|
|
|
|
|
|
|
@router.get("/search/locations")
|
|
|
|
|
async def search_locations(q: str = Query(..., min_length=2)):
|
|
|
|
|
"""
|
|
|
|
|
Autocomplete search for locations.
|
|
|
|
|
Returns list of {id, name, address_street, address_city}
|
|
|
|
|
"""
|
|
|
|
|
sql = """
|
|
|
|
|
SELECT id, name, address_street, address_city
|
|
|
|
|
FROM locations_locations
|
|
|
|
|
WHERE
|
|
|
|
|
(name ILIKE %s OR
|
|
|
|
|
address_street ILIKE %s OR
|
|
|
|
|
address_city ILIKE %s)
|
|
|
|
|
AND deleted_at IS NULL
|
|
|
|
|
ORDER BY name ASC
|
|
|
|
|
LIMIT 20
|
|
|
|
|
"""
|
|
|
|
|
term = f"%{q}%"
|
|
|
|
|
results = execute_query(sql, (term, term, term))
|
|
|
|
|
return results
|