Files
app/prisma/schema.prisma
BOHA db7a5c3d15 feat(suppliers)!: full customers model - structured address + custom fields
The dodavatele modal is now an exact mirror of the customers modal
(minus the PDF field-order picker): Nazev+ARES, Ulice, Mesto+PSC, Zeme,
ICO+ARES, DIC, and the same "Vlastni pole" editor (maxWidth md).

Two migrations on sklad_suppliers:
- structured street/city/postal_code/country replace the free-text
  address blob (best-effort split: street / PSC regex / city)
- custom_fields LONGTEXT replaces contact_person/email/phone/notes;
  existing values are preserved as labeled custom fields

The encode/decode of the custom_fields blob is shared with customers
via the new utils/custom-fields.ts. The PO PDF supplier block renders
the structured address + custom-field lines like the customer block;
the supplier picker/detail selects and types follow. Legacy clients
sending the dropped keys are silently stripped (tested). Suppliers
list shows Ulice/Mesto instead of the dropped contact columns; search
covers name/ico/city.

BREAKING CHANGE: sklad_suppliers.address, contact_person, email,
phone, notes columns dropped (data migrated); deploy must run
prisma migrate deploy + generate.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-06-10 20:11:22 +02:00

1095 lines
48 KiB
Plaintext

generator client {
provider = "prisma-client-js"
}
datasource db {
provider = "mysql"
}
model attendance {
id Int @id @default(autoincrement())
user_id Int
shift_date DateTime @db.Date
arrival_time DateTime? @db.DateTime(0)
arrival_lat Decimal? @db.Decimal(10, 8)
arrival_lng Decimal? @db.Decimal(11, 8)
arrival_accuracy Decimal? @db.Decimal(10, 2)
arrival_address String? @db.VarChar(500)
break_start DateTime? @db.DateTime(0)
break_end DateTime? @db.DateTime(0)
departure_time DateTime? @db.DateTime(0)
departure_lat Decimal? @db.Decimal(10, 8)
departure_lng Decimal? @db.Decimal(11, 8)
departure_accuracy Decimal? @db.Decimal(10, 2)
departure_address String? @db.VarChar(500)
notes String? @db.Text
project_id Int?
leave_type attendance_leave_type? @default(work)
leave_hours Decimal? @db.Decimal(4, 2)
created_at DateTime? @default(now()) @db.Timestamp(0)
updated_at DateTime? @default(now()) @db.Timestamp(0)
users users @relation(fields: [user_id], references: [id], onDelete: Cascade, onUpdate: NoAction, map: "attendance_ibfk_1")
attendance_project_logs attendance_project_logs[]
@@index([user_id, shift_date], map: "idx_attendance_user_date")
@@index([user_id, departure_time], map: "idx_attendance_user_departure")
@@index([project_id], map: "idx_project_id")
}
model attendance_project_logs {
id Int @id @default(autoincrement())
attendance_id Int
project_id Int
started_at DateTime? @db.DateTime(0)
ended_at DateTime? @db.DateTime(0)
hours Int? @db.UnsignedInt
minutes Int? @db.UnsignedInt
attendance attendance @relation(fields: [attendance_id], references: [id], onDelete: Cascade, onUpdate: NoAction)
projects projects? @relation(fields: [project_id], references: [id], onDelete: Cascade, onUpdate: NoAction)
@@index([attendance_id], map: "idx_attendance_project_logs_aid")
@@index([project_id], map: "idx_project_id")
@@index([started_at], map: "idx_started_at")
}
model audit_logs {
id Int @id @default(autoincrement())
user_id Int?
username String? @db.VarChar(100)
user_ip String? @db.VarChar(45)
action String @db.VarChar(100)
entity_type String? @db.VarChar(50)
entity_id Int?
description String? @db.Text
old_values String? @db.LongText
new_values String? @db.LongText
user_agent String? @db.Text
session_id String? @db.VarChar(128)
created_at DateTime? @default(now()) @db.Timestamp(0)
@@index([action], map: "idx_audit_logs_action")
@@index([created_at], map: "idx_audit_logs_created")
@@index([entity_type, entity_id, created_at], map: "idx_audit_logs_entity")
@@index([user_id, created_at], map: "idx_audit_logs_user_created")
@@fulltext([description], map: "idx_audit_search")
}
model ai_usage {
id Int @id @default(autoincrement())
user_id Int?
kind String @db.VarChar(20)
model String @db.VarChar(50)
input_tokens Int @default(0)
output_tokens Int @default(0)
cost_usd Decimal @default(0) @db.Decimal(10, 6)
created_at DateTime @default(now()) @db.Timestamp(0)
@@index([created_at], map: "idx_ai_usage_created")
}
model ai_conversations {
id Int @id @default(autoincrement())
user_id Int
title String @db.VarChar(255)
created_at DateTime @default(now()) @db.Timestamp(0)
updated_at DateTime @default(now()) @updatedAt @db.Timestamp(0)
messages ai_chat_messages[]
@@index([user_id, id], map: "idx_ai_conv_user")
}
model ai_chat_messages {
id Int @id @default(autoincrement())
user_id Int
conversation_id Int
role String @db.VarChar(20)
content String @db.Text
created_at DateTime @default(now()) @db.Timestamp(0)
conversation ai_conversations @relation(fields: [conversation_id], references: [id], onDelete: Cascade)
@@index([conversation_id, id], map: "idx_ai_chat_conv")
}
model bank_accounts {
id Int @id @default(autoincrement())
account_name String? @db.VarChar(255)
bank_name String? @db.VarChar(255)
account_number String? @db.VarChar(50)
iban String? @db.VarChar(50)
bic String? @db.VarChar(20)
currency String? @default("CZK") @db.VarChar(10)
is_default Boolean? @default(false)
position Int? @default(0)
created_at DateTime? @default(now()) @db.DateTime(0)
modified_at DateTime? @db.DateTime(0)
@@index([is_default], map: "idx_bank_accounts_is_default")
}
model company_settings {
id Int @id @default(autoincrement())
company_name String? @db.VarChar(255)
street String? @db.VarChar(255)
city String? @db.VarChar(255)
postal_code String? @db.VarChar(20)
country String? @db.VarChar(100)
company_id String? @db.VarChar(50)
vat_id String? @db.VarChar(50)
custom_fields String? @db.LongText
logo_data Bytes?
logo_data_dark Bytes? @db.MediumBlob
quotation_prefix String? @db.VarChar(20)
default_currency String? @default("CZK") @db.VarChar(10)
default_vat_rate Decimal? @default(21.00) @db.Decimal(5, 2)
uuid String? @unique @db.VarChar(36)
modified_at DateTime? @db.DateTime(0)
is_deleted Boolean? @default(false)
sync_version Int? @default(0)
order_type_code String? @db.VarChar(10)
invoice_type_code String? @db.VarChar(10)
require_2fa Boolean @default(false)
break_threshold_hours Decimal? @default(6.00) @db.Decimal(4, 2)
break_duration_short Int? @default(15)
break_duration_long Int? @default(30)
clock_rounding_minutes Int? @default(15)
invoice_alert_email String? @db.VarChar(255)
leave_notify_email String? @db.VarChar(255)
max_login_attempts Int? @default(5)
lockout_minutes Int? @default(15)
max_requests_per_minute Int? @default(300)
available_vat_rates String? @db.LongText
available_currencies String? @db.LongText
smtp_from String? @db.VarChar(255)
smtp_from_name String? @db.VarChar(255)
offer_number_pattern String? @db.VarChar(100)
order_number_pattern String? @db.VarChar(100)
invoice_number_pattern String? @db.VarChar(100)
issued_order_number_pattern String? @db.VarChar(100)
issued_order_type_code String? @db.VarChar(10)
project_number_pattern String? @db.VarChar(100)
project_type_code String? @db.VarChar(10)
warehouse_receipt_prefix String? @db.VarChar(20)
warehouse_receipt_number_pattern String? @db.VarChar(100)
warehouse_issue_prefix String? @db.VarChar(20)
warehouse_issue_number_pattern String? @db.VarChar(100)
warehouse_inventory_prefix String? @db.VarChar(20)
warehouse_inventory_number_pattern String? @db.VarChar(100)
ai_monthly_budget_usd Decimal? @default(50.00) @db.Decimal(10, 2)
}
model customers {
id Int @id @default(autoincrement())
name String @db.VarChar(255)
street String? @db.VarChar(255)
city String? @db.VarChar(255)
postal_code String? @db.VarChar(20)
country String? @db.VarChar(100)
company_id String? @db.VarChar(50)
vat_id String? @db.VarChar(50)
custom_fields String? @db.LongText
created_at DateTime? @default(now()) @db.DateTime(0)
uuid String? @db.VarChar(36)
modified_at DateTime? @db.DateTime(0)
sync_version Int? @default(0)
invoices invoices[]
orders orders[]
projects projects[]
quotations quotations[]
}
model invoice_items {
id Int @id @default(autoincrement())
invoice_id Int
description String? @db.VarChar(500)
item_description String? @db.Text
quantity Decimal? @default(1.000) @db.Decimal(12, 3)
unit String? @db.VarChar(20)
unit_price Decimal? @default(0.00) @db.Decimal(12, 2)
vat_rate Decimal? @default(21.00) @db.Decimal(5, 2)
position Int? @default(0)
invoices invoices @relation(fields: [invoice_id], references: [id], onDelete: Cascade, onUpdate: NoAction, map: "invoice_items_ibfk_1")
@@index([invoice_id], map: "invoice_id")
}
model invoices {
id Int @id @default(autoincrement())
invoice_number String? @unique(map: "idx_invoices_number_unique") @db.VarChar(50)
order_id Int?
customer_id Int?
status String? @default("issued") @db.VarChar(30)
currency String? @default("CZK") @db.VarChar(10)
vat_rate Decimal? @default(21.00) @db.Decimal(5, 2)
apply_vat Boolean? @default(true)
payment_method String? @db.VarChar(50)
constant_symbol String? @db.VarChar(20)
bank_name String? @db.VarChar(255)
bank_swift String? @db.VarChar(20)
bank_iban String? @db.VarChar(50)
bank_account String? @db.VarChar(50)
issue_date DateTime? @db.Date
due_date DateTime? @db.Date
tax_date DateTime? @db.Date
paid_date DateTime? @db.Date
issued_by String? @db.VarChar(255)
billing_text String? @db.VarChar(500)
language String? @default("cs") @db.VarChar(5)
internal_notes String? @db.Text
created_at DateTime? @default(now()) @db.DateTime(0)
modified_at DateTime? @db.DateTime(0)
invoice_items invoice_items[]
invoice_sections invoice_sections[]
orders orders? @relation(fields: [order_id], references: [id], onDelete: Restrict, onUpdate: NoAction, map: "invoices_ibfk_1")
customers customers? @relation(fields: [customer_id], references: [id], onDelete: Restrict, onUpdate: NoAction, map: "invoices_ibfk_2")
@@index([customer_id], map: "customer_id")
@@index([due_date], map: "idx_invoices_due_date")
@@index([status, issue_date], map: "idx_invoices_status_issue")
@@index([status, due_date], map: "idx_invoices_status_due")
@@index([order_id], map: "order_id")
}
model invoice_sections {
id Int @id @default(autoincrement())
invoice_id Int
position Int? @default(0)
title String? @db.VarChar(500)
title_cz String? @db.VarChar(500)
content String? @db.Text
modified_at DateTime? @db.DateTime(0)
invoices invoices @relation(fields: [invoice_id], references: [id], onDelete: Cascade, onUpdate: NoAction, map: "invoice_sections_fk")
@@index([invoice_id], map: "invoice_sections_invoice_id")
}
model item_templates {
id Int @id @default(autoincrement())
name String? @db.VarChar(255)
description String? @db.Text
default_price Decimal? @default(0.00) @db.Decimal(12, 2)
category String? @db.VarChar(100)
uuid String? @db.VarChar(36)
modified_at DateTime? @db.DateTime(0)
is_deleted Boolean? @default(false)
sync_version Int? @default(0)
}
model leave_balances {
id Int @id @default(autoincrement())
user_id Int
year Int
vacation_total Decimal? @default(160.00) @db.Decimal(5, 2)
vacation_used Decimal? @default(0.00) @db.Decimal(5, 2)
sick_used Decimal? @default(0.00) @db.Decimal(5, 2)
created_at DateTime? @default(now()) @db.Timestamp(0)
updated_at DateTime? @default(now()) @db.Timestamp(0)
users users @relation(fields: [user_id], references: [id], onDelete: Cascade, onUpdate: NoAction, map: "leave_balances_ibfk_1")
@@unique([user_id, year], map: "idx_leave_balances_user_year")
}
model leave_requests {
id Int @id @default(autoincrement())
user_id Int
leave_type leave_requests_leave_type
date_from DateTime @db.Date
date_to DateTime @db.Date
total_hours Decimal @db.Decimal(5, 2)
total_days Int
notes String? @db.Text
status leave_requests_status? @default(pending)
reviewer_id Int?
reviewer_note String? @db.Text
reviewed_at DateTime? @db.DateTime(0)
created_at DateTime? @default(now()) @db.Timestamp(0)
updated_at DateTime? @default(now()) @db.Timestamp(0)
users_leave_requests_user_idTousers users @relation("leave_requests_user_idTousers", fields: [user_id], references: [id], onDelete: Cascade, onUpdate: NoAction, map: "leave_requests_ibfk_1")
users_leave_requests_reviewer_idTousers users? @relation("leave_requests_reviewer_idTousers", fields: [reviewer_id], references: [id], onUpdate: NoAction, map: "leave_requests_ibfk_2")
@@index([user_id, status], map: "idx_leave_requests_user_status")
@@index([status], map: "idx_status")
@@index([reviewer_id], map: "reviewer_id")
}
model number_sequences {
id Int @id @default(autoincrement())
type String? @db.VarChar(50)
year Int?
last_number Int? @default(0)
@@unique([type, year], map: "idx_number_sequences_type_year")
}
model order_items {
id Int @id @default(autoincrement())
order_id Int
description String? @db.VarChar(500)
item_description String? @db.Text
quantity Decimal? @default(1.000) @db.Decimal(12, 3)
unit String? @db.VarChar(20)
unit_price Decimal? @default(0.00) @db.Decimal(12, 2)
is_included_in_total Boolean? @default(true)
position Int? @default(0)
modified_at DateTime? @db.DateTime(0)
orders orders @relation(fields: [order_id], references: [id], onDelete: Cascade, onUpdate: NoAction, map: "order_items_ibfk_1")
@@index([order_id], map: "order_id")
}
model order_sections {
id Int @id @default(autoincrement())
order_id Int
title String? @db.VarChar(500)
title_cz String? @db.VarChar(500)
content String? @db.Text
position Int? @default(0)
modified_at DateTime? @db.DateTime(0)
orders orders @relation(fields: [order_id], references: [id], onDelete: Cascade, onUpdate: NoAction, map: "order_sections_ibfk_1")
@@index([order_id], map: "order_id")
}
model orders {
id Int @id @default(autoincrement())
order_number String? @unique(map: "idx_orders_number_unique") @db.VarChar(50)
customer_order_number String? @db.VarChar(100)
attachment_data Bytes?
attachment_name String? @db.VarChar(255)
quotation_id Int?
customer_id Int?
status String? @default("prijata") @db.VarChar(30)
currency String? @default("CZK") @db.VarChar(10)
language String? @default("cs") @db.VarChar(5)
exchange_rate Decimal? @default(1.0000) @db.Decimal(10, 4)
scope_title String? @db.VarChar(500)
scope_description String? @db.Text
notes String? @db.Text
created_at DateTime? @default(now()) @db.DateTime(0)
modified_at DateTime? @db.DateTime(0)
invoices invoices[]
order_items order_items[]
order_sections order_sections[]
quotations quotations? @relation(fields: [quotation_id], references: [id], onDelete: Restrict, onUpdate: NoAction, map: "orders_ibfk_1")
customers customers? @relation(fields: [customer_id], references: [id], onDelete: Restrict, onUpdate: NoAction, map: "orders_ibfk_2")
projects projects[]
@@index([customer_id], map: "customer_id")
@@index([quotation_id], map: "quotation_id")
}
model issued_orders {
id Int @id @default(autoincrement())
po_number String? @unique(map: "idx_issued_orders_number_unique") @db.VarChar(50)
supplier_id Int?
status issued_orders_status @default(draft)
currency String? @default("CZK") @db.VarChar(10)
exchange_rate Decimal? @default(1.0000) @db.Decimal(10, 4)
order_date DateTime? @db.Date
delivery_date DateTime? @db.Date
language String? @default("cs") @db.VarChar(5)
order_text String? @db.VarChar(500)
internal_notes String? @db.Text
locked_by Int?
locked_at DateTime? @db.DateTime(0)
created_at DateTime? @default(now()) @db.DateTime(0)
modified_at DateTime? @db.DateTime(0)
issued_order_items issued_order_items[]
issued_order_sections issued_order_sections[]
suppliers sklad_suppliers? @relation(fields: [supplier_id], references: [id], onDelete: Restrict, onUpdate: NoAction, map: "issued_orders_supplier_fk")
@@index([supplier_id], map: "issued_orders_supplier_id")
@@index([status, order_date], map: "idx_issued_orders_status_date")
}
// Mirrors scope_sections (offers) 1:1 — free-form bilingual rich-text sections
// rendered on their own PDF page. Kept as a separate table (not shared) so the
// FK cascade and per-document ordering stay simple.
model issued_order_sections {
id Int @id @default(autoincrement())
issued_order_id Int
position Int? @default(0)
title String? @db.VarChar(500)
title_cz String? @db.VarChar(500)
content String? @db.Text
modified_at DateTime? @db.DateTime(0)
issued_orders issued_orders @relation(fields: [issued_order_id], references: [id], onDelete: Cascade, onUpdate: NoAction, map: "issued_order_sections_fk")
@@index([issued_order_id], map: "issued_order_sections_order_id")
}
model issued_order_items {
id Int @id @default(autoincrement())
issued_order_id Int
description String? @db.VarChar(500)
item_description String? @db.Text
quantity Decimal? @default(1.000) @db.Decimal(12, 3)
unit String? @db.VarChar(20)
unit_price Decimal? @default(0.00) @db.Decimal(12, 2)
position Int? @default(0)
issued_orders issued_orders @relation(fields: [issued_order_id], references: [id], onDelete: Cascade, onUpdate: NoAction, map: "issued_order_items_ibfk_1")
@@index([issued_order_id], map: "issued_order_id")
}
enum issued_orders_status {
draft
sent
confirmed
completed
cancelled
}
model permissions {
id Int @id @default(autoincrement())
name String @unique(map: "name") @db.VarChar(50)
display_name String @db.VarChar(100)
description String? @db.Text
module String @db.VarChar(50)
created_at DateTime? @default(now()) @db.Timestamp(0)
role_permissions role_permissions[]
}
model project_notes {
id Int @id @default(autoincrement())
project_id Int
user_id Int?
user_name String? @db.VarChar(100)
content String? @db.Text
created_at DateTime? @default(now()) @db.DateTime(0)
projects projects @relation(fields: [project_id], references: [id], onDelete: Cascade, onUpdate: NoAction, map: "project_notes_ibfk_1")
@@index([project_id], map: "project_id")
}
model projects {
id Int @id @default(autoincrement())
project_number String? @unique @db.VarChar(50)
name String? @db.VarChar(255)
customer_id Int?
responsible_user_id Int?
quotation_id Int?
order_id Int?
status String? @default("aktivni") @db.VarChar(30)
start_date DateTime? @db.Date
end_date DateTime? @db.Date
notes String? @db.Text
created_at DateTime? @default(now()) @db.DateTime(0)
modified_at DateTime? @db.DateTime(0)
attendance_project_logs attendance_project_logs[]
project_notes project_notes[]
sklad_issues sklad_issues[]
sklad_reservations sklad_reservations[]
work_plan_entries work_plan_entries[]
work_plan_overrides work_plan_overrides[]
users users? @relation(fields: [responsible_user_id], references: [id], onUpdate: NoAction, map: "fk_projects_responsible_user")
customers customers? @relation(fields: [customer_id], references: [id], onDelete: Restrict, onUpdate: NoAction, map: "projects_ibfk_1")
quotations quotations? @relation(fields: [quotation_id], references: [id], onDelete: Restrict, onUpdate: NoAction, map: "projects_ibfk_2")
orders orders? @relation(fields: [order_id], references: [id], onDelete: Restrict, onUpdate: NoAction, map: "projects_ibfk_3")
@@index([customer_id], map: "customer_id")
@@index([responsible_user_id], map: "fk_projects_responsible_user")
@@index([order_id], map: "order_id")
@@index([quotation_id], map: "quotation_id")
}
model quotation_items {
id Int @id @default(autoincrement())
quotation_id Int
position Int? @default(0)
description String? @db.VarChar(500)
item_description String? @db.Text
quantity Decimal? @default(1.000) @db.Decimal(12, 3)
unit String? @db.VarChar(20)
unit_price Decimal? @default(0.00) @db.Decimal(12, 2)
is_included_in_total Boolean? @default(true)
modified_at DateTime? @db.DateTime(0)
quotations quotations @relation(fields: [quotation_id], references: [id], onDelete: Cascade, onUpdate: NoAction, map: "quotation_items_ibfk_1")
@@index([quotation_id], map: "quotation_id")
}
model quotations {
id Int @id @default(autoincrement())
quotation_number String? @unique @db.VarChar(50)
project_code String? @db.VarChar(100)
customer_id Int?
created_at DateTime? @default(now()) @db.DateTime(0)
valid_until DateTime? @db.Date
currency String? @default("CZK") @db.VarChar(10)
language String? @default("cs") @db.VarChar(5)
order_id Int?
status String @default("active") @db.VarChar(20)
scope_title String? @db.VarChar(500)
scope_description String? @db.Text
locked_by Int?
locked_at DateTime? @db.DateTime(0)
modified_at DateTime? @db.DateTime(0)
orders orders[]
projects projects[]
quotation_items quotation_items[]
customers customers? @relation(fields: [customer_id], references: [id], onDelete: Restrict, onUpdate: NoAction, map: "quotations_ibfk_1")
scope_sections scope_sections[]
@@index([customer_id], map: "customer_id")
@@index([quotation_number], map: "idx_quotations_number")
}
model received_invoices {
id Int @id @default(autoincrement()) @db.UnsignedInt
month Int @db.UnsignedTinyInt
year Int @db.UnsignedSmallInt
supplier_name String @db.VarChar(255)
invoice_number String? @db.VarChar(100)
description String? @db.VarChar(500)
amount Decimal @default(0.00) @db.Decimal(12, 2)
currency String @default("CZK") @db.VarChar(3)
vat_rate Decimal @default(21.00) @db.Decimal(5, 2)
vat_amount Decimal @default(0.00) @db.Decimal(12, 2)
issue_date DateTime? @db.Date
due_date DateTime? @db.Date
paid_date DateTime? @db.Date
status received_invoices_status @default(unpaid)
file_name String? @db.VarChar(255)
file_mime String? @db.VarChar(100)
file_size Int? @db.UnsignedInt
notes String? @db.Text
uploaded_by Int? @db.UnsignedInt
created_at DateTime @default(now()) @db.DateTime(0)
modified_at DateTime @default(now()) @db.DateTime(0)
@@index([year, month], map: "idx_month_year")
@@index([status], map: "idx_status")
@@index([supplier_name], map: "idx_supplier")
}
/// This model or at least one of its fields has comments in the database, and requires an additional setup for migrations: Read more: https://pris.ly/d/database-comments
model refresh_tokens {
id Int @id @default(autoincrement()) @db.UnsignedInt
user_id Int @db.UnsignedInt
token_hash String @unique(map: "token_hash") @db.VarChar(64)
expires_at DateTime @db.DateTime(0)
replaced_at DateTime? @db.DateTime(0)
replaced_by_hash String? @db.VarChar(64)
remember_me Boolean @default(false)
ip_address String? @db.VarChar(45)
user_agent String? @db.VarChar(255)
created_at DateTime? @default(now()) @db.DateTime(0)
@@index([expires_at], map: "idx_refresh_tokens_expires_at")
@@index([user_id, expires_at], map: "idx_refresh_tokens_user_exp")
@@index([user_id], map: "idx_refresh_tokens_user_id")
}
model role_permissions {
role_id Int
permission_id Int
roles roles @relation(fields: [role_id], references: [id], onDelete: Cascade, onUpdate: NoAction, map: "role_permissions_ibfk_1")
permissions permissions @relation(fields: [permission_id], references: [id], onDelete: Cascade, onUpdate: NoAction, map: "role_permissions_ibfk_2")
@@id([role_id, permission_id])
@@index([permission_id], map: "permission_id")
}
model roles {
id Int @id @default(autoincrement())
name String @unique(map: "name") @db.VarChar(50)
display_name String @db.VarChar(100)
description String? @db.Text
created_at DateTime? @default(now()) @db.Timestamp(0)
updated_at DateTime? @default(now()) @db.Timestamp(0)
role_permissions role_permissions[]
users users[]
}
model scope_sections {
id Int @id @default(autoincrement())
quotation_id Int
position Int? @default(0)
title String? @db.VarChar(500)
title_cz String? @db.VarChar(500)
content String? @db.Text
modified_at DateTime? @db.DateTime(0)
quotations quotations @relation(fields: [quotation_id], references: [id], onDelete: Cascade, onUpdate: NoAction, map: "scope_sections_ibfk_1")
@@index([quotation_id], map: "quotation_id")
}
model scope_template_sections {
id Int @id @default(autoincrement())
scope_template_id Int
position Int? @default(0)
title String? @db.VarChar(500)
title_cz String? @db.VarChar(500)
content String? @db.Text
uuid String? @db.VarChar(36)
modified_at DateTime? @db.DateTime(0)
is_deleted Boolean? @default(false)
sync_version Int? @default(0)
scope_templates scope_templates @relation(fields: [scope_template_id], references: [id], onDelete: Cascade, onUpdate: NoAction, map: "scope_template_sections_ibfk_1")
@@index([scope_template_id], map: "scope_template_id")
}
model scope_templates {
id Int @id @default(autoincrement())
name String? @db.VarChar(255)
title String? @db.VarChar(500)
description String? @db.Text
uuid String? @db.VarChar(36)
modified_at DateTime? @db.DateTime(0)
is_deleted Boolean? @default(false)
sync_version Int? @default(0)
scope_template_sections scope_template_sections[]
}
model totp_login_tokens {
id Int @id @default(autoincrement())
user_id Int
token_hash String @db.VarChar(64)
expires_at DateTime @db.DateTime(0)
created_at DateTime @default(now()) @db.DateTime(0)
@@index([expires_at], map: "idx_expires")
@@index([token_hash], map: "idx_totp_login_tokens_hash")
@@index([user_id], map: "idx_user_id")
}
/// This model or at least one of its fields has comments in the database, and requires an additional setup for migrations: Read more: https://pris.ly/d/database-comments
model trips {
id Int @id @default(autoincrement())
vehicle_id Int
user_id Int
trip_date DateTime @db.Date
start_km Int
end_km Int
distance Int?
route_from String @db.VarChar(100)
route_to String @db.VarChar(100)
is_business Boolean @default(true)
notes String? @db.Text
created_at DateTime? @default(now()) @db.Timestamp(0)
updated_at DateTime? @default(now()) @db.Timestamp(0)
users users @relation(fields: [user_id], references: [id], onDelete: Cascade, onUpdate: NoAction, map: "trips_user_fk")
vehicles vehicles @relation(fields: [vehicle_id], references: [id], onDelete: Cascade, onUpdate: NoAction, map: "trips_vehicle_fk")
@@index([trip_date], map: "trip_date")
@@index([user_id], map: "user_id")
@@index([vehicle_id], map: "vehicle_id")
}
model users {
id Int @id @default(autoincrement())
username String @unique(map: "username") @db.VarChar(50)
email String @unique(map: "email") @db.VarChar(255)
password_hash String @db.VarChar(255)
first_name String @db.VarChar(50)
last_name String @db.VarChar(50)
role_id Int?
is_active Boolean? @default(true)
last_login DateTime? @db.Timestamp(0)
failed_login_attempts Int? @default(0)
locked_until DateTime? @db.Timestamp(0)
password_changed_at DateTime? @default(now()) @db.Timestamp(0)
created_at DateTime? @default(now()) @db.Timestamp(0)
updated_at DateTime? @default(now()) @db.Timestamp(0)
totp_secret String? @db.VarChar(255)
totp_enabled Boolean @default(false)
totp_backup_codes String? @db.Text
totp_last_used_counter Int?
attendance attendance[]
leave_balances leave_balances[]
leave_requests_leave_requests_user_idTousers leave_requests[] @relation("leave_requests_user_idTousers")
leave_requests_leave_requests_reviewer_idTousers leave_requests[] @relation("leave_requests_reviewer_idTousers")
projects projects[]
trips trips[]
sklad_receipts_received sklad_receipts[] @relation("SkladReceivedBy")
sklad_issues_issued sklad_issues[] @relation("SkladIssuedBy")
sklad_reservations sklad_reservations[] @relation("SkladReservedBy")
work_plan_entries work_plan_entries[] @relation("work_plan_entries_creator")
work_plan_entries_owned work_plan_entries[]
work_plan_overrides work_plan_overrides[] @relation("work_plan_overrides_creator")
work_plan_overrides_owned work_plan_overrides[]
roles roles? @relation(fields: [role_id], references: [id], onUpdate: NoAction, map: "users_ibfk_1")
@@index([is_active], map: "idx_users_is_active")
@@index([role_id], map: "idx_users_role_id")
}
/// This model or at least one of its fields has comments in the database, and requires an additional setup for migrations: Read more: https://pris.ly/d/database-comments
model vehicles {
id Int @id @default(autoincrement())
spz String @unique(map: "spz") @db.VarChar(20)
name String @db.VarChar(100)
brand String? @db.VarChar(50)
model String? @db.VarChar(50)
initial_km Int @default(0)
actual_km Int @default(0)
is_active Boolean @default(true)
created_at DateTime? @default(now()) @db.Timestamp(0)
updated_at DateTime? @default(now()) @db.Timestamp(0)
trips trips[]
}
enum leave_requests_leave_type {
vacation
sick
unpaid
}
enum leave_requests_status {
pending
approved
rejected
cancelled
}
model invoice_alert_log {
id Int @id @default(autoincrement())
invoice_type String @db.VarChar(20) // "created" or "received"
invoice_id Int
alert_type String @db.VarChar(20) // "3days" or "due"
sent_at DateTime @default(now()) @db.DateTime(0)
created_at DateTime @default(now()) @db.DateTime(0)
@@unique([invoice_type, invoice_id, alert_type], map: "invoice_type_invoice_id_alert_type")
}
enum received_invoices_status {
unpaid
paid
}
enum attendance_leave_type {
work
vacation
sick
holiday
unpaid
}
enum sklad_receipt_status {
DRAFT
CONFIRMED
CANCELLED
}
enum sklad_issue_status {
DRAFT
CONFIRMED
CANCELLED
}
enum sklad_reservation_status {
ACTIVE
FULFILLED
CANCELLED
}
enum sklad_inventory_status {
DRAFT
CONFIRMED
}
model sklad_categories {
id Int @id @default(autoincrement())
name String @db.VarChar(100)
description String? @db.Text
sort_order Int @default(0)
created_at DateTime? @default(now()) @db.DateTime(0)
modified_at DateTime? @db.DateTime(0)
items sklad_items[]
@@map("sklad_categories")
}
model sklad_suppliers {
id Int @id @default(autoincrement())
name String @db.VarChar(255)
ico String? @db.VarChar(20)
dic String? @db.VarChar(20)
street String? @db.VarChar(255)
city String? @db.VarChar(255)
postal_code String? @db.VarChar(20)
country String? @db.VarChar(100)
custom_fields String? @db.LongText
is_active Boolean @default(true)
created_at DateTime? @default(now()) @db.DateTime(0)
modified_at DateTime? @db.DateTime(0)
receipts sklad_receipts[]
issued_orders issued_orders[]
@@map("sklad_suppliers")
}
model sklad_locations {
id Int @id @default(autoincrement())
code String @unique @db.VarChar(20)
name String @db.VarChar(100)
description String? @db.Text
is_active Boolean @default(true)
created_at DateTime? @default(now()) @db.DateTime(0)
modified_at DateTime? @db.DateTime(0)
items sklad_item_locations[]
receipt_lines sklad_receipt_lines[]
issue_lines sklad_issue_lines[]
inventory_lines sklad_inventory_lines[]
@@map("sklad_locations")
}
model sklad_items {
id Int @id @default(autoincrement())
item_number String? @unique @db.VarChar(50)
name String @db.VarChar(255)
description String? @db.Text
category_id Int?
unit String @db.VarChar(20)
min_quantity Decimal? @db.Decimal(12, 3)
is_active Boolean @default(true)
notes String? @db.Text
created_at DateTime? @default(now()) @db.DateTime(0)
modified_at DateTime? @db.DateTime(0)
category sklad_categories? @relation(fields: [category_id], references: [id], onDelete: SetNull)
batches sklad_batches[]
item_locations sklad_item_locations[]
receipt_lines sklad_receipt_lines[]
issue_lines sklad_issue_lines[]
reservations sklad_reservations[]
inventory_lines sklad_inventory_lines[]
@@index([category_id], map: "sklad_items_category_id")
@@map("sklad_items")
}
model sklad_batches {
id Int @id @default(autoincrement())
item_id Int
receipt_line_id Int @unique
quantity Decimal @db.Decimal(12, 3)
original_qty Decimal @db.Decimal(12, 3)
unit_price Decimal @db.Decimal(12, 2)
received_at DateTime? @db.DateTime(0)
is_consumed Boolean @default(false)
item sklad_items @relation(fields: [item_id], references: [id], onDelete: Restrict)
receipt_line sklad_receipt_lines @relation(fields: [receipt_line_id], references: [id], onDelete: Restrict)
issue_lines sklad_issue_lines[]
@@index([item_id, is_consumed, received_at], map: "sklad_batches_fifo")
@@map("sklad_batches")
}
model sklad_item_locations {
id Int @id @default(autoincrement())
item_id Int
location_id Int
quantity Decimal @default(0) @db.Decimal(12, 3)
item sklad_items @relation(fields: [item_id], references: [id], onDelete: Restrict)
location sklad_locations @relation(fields: [location_id], references: [id], onDelete: Restrict)
@@unique([item_id, location_id], map: "sklad_item_locations_unique")
@@map("sklad_item_locations")
}
model sklad_receipts {
id Int @id @default(autoincrement())
receipt_number String? @unique @db.VarChar(50)
supplier_id Int?
delivery_note_number String? @db.VarChar(100)
delivery_note_date DateTime? @db.DateTime(0)
received_by Int?
notes String? @db.Text
status sklad_receipt_status @default(DRAFT)
created_at DateTime? @default(now()) @db.DateTime(0)
modified_at DateTime? @db.DateTime(0)
supplier sklad_suppliers? @relation(fields: [supplier_id], references: [id], onDelete: SetNull)
received_by_user users? @relation("SkladReceivedBy", fields: [received_by], references: [id], onDelete: SetNull)
items sklad_receipt_lines[]
attachments sklad_receipt_attachments[]
@@index([supplier_id], map: "sklad_receipts_supplier_id")
@@index([received_by], map: "sklad_receipts_received_by")
@@map("sklad_receipts")
}
model sklad_receipt_lines {
id Int @id @default(autoincrement())
receipt_id Int
item_id Int
quantity Decimal @db.Decimal(12, 3)
unit_price Decimal @db.Decimal(12, 2)
location_id Int?
notes String? @db.VarChar(255)
receipt sklad_receipts @relation(fields: [receipt_id], references: [id], onDelete: Cascade)
item sklad_items @relation(fields: [item_id], references: [id], onDelete: Restrict)
location sklad_locations? @relation(fields: [location_id], references: [id], onDelete: Restrict)
batch sklad_batches?
@@index([receipt_id], map: "sklad_receipt_lines_receipt_id")
@@map("sklad_receipt_lines")
}
model sklad_receipt_attachments {
id Int @id @default(autoincrement())
receipt_id Int
file_name String @db.VarChar(255)
file_mime String @db.VarChar(100)
file_size Int
file_path String @db.VarChar(500)
created_at DateTime? @default(now()) @db.DateTime(0)
receipt sklad_receipts @relation(fields: [receipt_id], references: [id], onDelete: Cascade)
@@map("sklad_receipt_attachments")
}
model sklad_issues {
id Int @id @default(autoincrement())
issue_number String? @unique @db.VarChar(50)
project_id Int
issued_by Int?
notes String? @db.Text
status sklad_issue_status @default(DRAFT)
created_at DateTime? @default(now()) @db.DateTime(0)
modified_at DateTime? @db.DateTime(0)
project projects @relation(fields: [project_id], references: [id], onDelete: Restrict)
issued_by_user users? @relation("SkladIssuedBy", fields: [issued_by], references: [id], onDelete: SetNull)
items sklad_issue_lines[]
@@index([project_id], map: "sklad_issues_project_id")
@@index([issued_by], map: "sklad_issues_issued_by")
@@map("sklad_issues")
}
model sklad_issue_lines {
id Int @id @default(autoincrement())
issue_id Int
item_id Int
batch_id Int
quantity Decimal @db.Decimal(12, 3)
location_id Int?
reservation_id Int?
notes String? @db.VarChar(255)
issue sklad_issues @relation(fields: [issue_id], references: [id], onDelete: Cascade)
item sklad_items @relation(fields: [item_id], references: [id], onDelete: Restrict)
batch sklad_batches @relation(fields: [batch_id], references: [id], onDelete: Restrict)
location sklad_locations? @relation(fields: [location_id], references: [id], onDelete: Restrict)
reservation sklad_reservations? @relation(fields: [reservation_id], references: [id], onDelete: SetNull)
@@index([issue_id], map: "sklad_issue_lines_issue_id")
@@map("sklad_issue_lines")
}
model sklad_reservations {
id Int @id @default(autoincrement())
item_id Int
project_id Int
quantity Decimal @db.Decimal(12, 3)
remaining_qty Decimal @db.Decimal(12, 3)
reserved_by Int?
notes String? @db.Text
status sklad_reservation_status @default(ACTIVE)
created_at DateTime? @default(now()) @db.DateTime(0)
modified_at DateTime? @db.DateTime(0)
item sklad_items @relation(fields: [item_id], references: [id], onDelete: Restrict)
project projects @relation(fields: [project_id], references: [id], onDelete: Restrict)
reserved_by_user users? @relation("SkladReservedBy", fields: [reserved_by], references: [id], onDelete: SetNull)
issue_lines sklad_issue_lines[]
@@index([item_id, status], map: "sklad_reservations_item_status")
@@map("sklad_reservations")
}
model sklad_inventory_sessions {
id Int @id @default(autoincrement())
session_number String? @unique @db.VarChar(50)
notes String? @db.Text
status sklad_inventory_status @default(DRAFT)
created_at DateTime? @default(now()) @db.DateTime(0)
modified_at DateTime? @db.DateTime(0)
items sklad_inventory_lines[]
@@map("sklad_inventory_sessions")
}
model sklad_inventory_lines {
id Int @id @default(autoincrement())
session_id Int
item_id Int
location_id Int?
system_qty Decimal @db.Decimal(12, 3)
actual_qty Decimal @db.Decimal(12, 3)
difference Decimal @db.Decimal(12, 3)
notes String? @db.VarChar(255)
session sklad_inventory_sessions @relation(fields: [session_id], references: [id], onDelete: Cascade)
item sklad_items @relation(fields: [item_id], references: [id], onDelete: Restrict)
location sklad_locations? @relation(fields: [location_id], references: [id], onDelete: Restrict)
@@index([session_id], map: "sklad_inventory_lines_session_id")
@@map("sklad_inventory_lines")
}
model plan_categories {
id Int @id @default(autoincrement())
key String @unique @db.VarChar(50)
label String @db.VarChar(100)
color String @db.VarChar(7)
sort_order Int @default(0)
is_active Boolean @default(true)
created_at DateTime? @default(now()) @db.DateTime(0)
updated_at DateTime? @default(now()) @updatedAt @db.DateTime(0)
}
model work_plan_entries {
id Int @id @default(autoincrement())
user_id Int
date_from DateTime @db.Date
date_to DateTime @db.Date
project_id Int?
category String @default("work") @db.VarChar(50)
note String @db.VarChar(500)
created_by Int
created_at DateTime? @default(now()) @db.Timestamp(0)
updated_at DateTime? @default(now()) @db.Timestamp(0)
is_deleted Boolean? @default(false)
users users @relation(fields: [user_id], references: [id], onDelete: Cascade, onUpdate: NoAction)
projects projects? @relation(fields: [project_id], references: [id], onDelete: SetNull, onUpdate: NoAction)
creator users @relation("work_plan_entries_creator", fields: [created_by], references: [id], onDelete: Restrict, onUpdate: NoAction)
@@index([user_id, date_from], map: "idx_wpe_user_from")
@@index([user_id, date_to], map: "idx_wpe_user_to")
@@index([project_id], map: "idx_wpe_project")
@@index([date_from, date_to], map: "idx_wpe_dates")
}
model work_plan_overrides {
id Int @id @default(autoincrement())
user_id Int
shift_date DateTime @db.Date
project_id Int?
category String @db.VarChar(50)
note String @db.VarChar(500)
created_by Int
created_at DateTime? @default(now()) @db.Timestamp(0)
updated_at DateTime? @default(now()) @db.Timestamp(0)
is_deleted Boolean? @default(false)
users users @relation(fields: [user_id], references: [id], onDelete: Cascade, onUpdate: NoAction)
projects projects? @relation(fields: [project_id], references: [id], onDelete: SetNull, onUpdate: NoAction)
creator users @relation("work_plan_overrides_creator", fields: [created_by], references: [id], onDelete: Restrict, onUpdate: NoAction)
@@index([user_id, shift_date], map: "idx_wpo_user_date")
@@index([shift_date], map: "idx_wpo_date")
}