diff --git a/prisma/migrations/20260528000002_cleanup_offer_dead_columns/migration.sql b/prisma/migrations/20260528000002_cleanup_offer_dead_columns/migration.sql new file mode 100644 index 0000000..63daaa3 --- /dev/null +++ b/prisma/migrations/20260528000002_cleanup_offer_dead_columns/migration.sql @@ -0,0 +1,14 @@ +-- AlterTable: quotation_items +ALTER TABLE `quotation_items` DROP COLUMN `uuid`; +ALTER TABLE `quotation_items` DROP COLUMN `is_deleted`; +ALTER TABLE `quotation_items` DROP COLUMN `sync_version`; + +-- AlterTable: quotations +ALTER TABLE `quotations` DROP COLUMN `uuid`; +ALTER TABLE `quotations` DROP COLUMN `sync_version`; + +-- AlterTable: scope_sections +ALTER TABLE `scope_sections` DROP COLUMN `content_editor_height`; +ALTER TABLE `scope_sections` DROP COLUMN `uuid`; +ALTER TABLE `scope_sections` DROP COLUMN `is_deleted`; +ALTER TABLE `scope_sections` DROP COLUMN `sync_version`; \ No newline at end of file diff --git a/prisma/schema.prisma b/prisma/schema.prisma index 373286e..1315fef 100644 --- a/prisma/schema.prisma +++ b/prisma/schema.prisma @@ -378,10 +378,7 @@ model quotation_items { unit String? @db.VarChar(20) unit_price Decimal? @default(0.00) @db.Decimal(12, 2) is_included_in_total Boolean? @default(true) - uuid String? @db.VarChar(36) modified_at DateTime? @db.DateTime(0) - is_deleted Boolean? @default(false) - sync_version Int? @default(0) quotations quotations @relation(fields: [quotation_id], references: [id], onDelete: Cascade, onUpdate: NoAction, map: "quotation_items_ibfk_1") @@index([quotation_id], map: "quotation_id") @@ -404,9 +401,7 @@ model quotations { scope_description String? @db.Text locked_by Int? locked_at DateTime? @db.DateTime(0) - uuid String? @db.VarChar(36) modified_at DateTime? @db.DateTime(0) - sync_version Int? @default(0) orders orders[] projects projects[] quotation_items quotation_items[] @@ -491,11 +486,7 @@ model scope_sections { title String? @db.VarChar(500) title_cz String? @db.VarChar(500) content String? @db.Text - content_editor_height Int? - uuid String? @db.VarChar(36) modified_at DateTime? @db.DateTime(0) - is_deleted Boolean? @default(false) - sync_version Int? @default(0) quotations quotations @relation(fields: [quotation_id], references: [id], onDelete: Cascade, onUpdate: NoAction, map: "scope_sections_ibfk_1") @@index([quotation_id], map: "quotation_id") diff --git a/src/admin/lib/queries/offers.ts b/src/admin/lib/queries/offers.ts index 2d64063..f95fed6 100644 --- a/src/admin/lib/queries/offers.ts +++ b/src/admin/lib/queries/offers.ts @@ -19,6 +19,7 @@ export interface ScopeSection { export interface ScopeTemplate { id: number; name: string; + title?: string; description?: string; scope_template_sections?: ScopeSection[]; } @@ -134,8 +135,6 @@ export interface OfferDetailData { language: string; vat_rate: number; apply_vat: boolean; - scope_title: string; - scope_description: string; items?: OfferItemData[]; sections?: OfferSectionData[]; status: string; diff --git a/src/admin/offers.css b/src/admin/offers.css index c7ee408..0fdd00f 100644 --- a/src/admin/offers.css +++ b/src/admin/offers.css @@ -46,33 +46,6 @@ min-height: 32px; } -/* Template dropdown menu */ -.offers-template-menu { - position: absolute; - top: 100%; - right: 0; - z-index: 100; - min-width: 200px; - max-height: 250px; - overflow-y: auto; - background: var(--bg-primary); - border: 1px solid var(--border-color); - border-radius: 0.5rem; - box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15); - margin-top: 0.25rem; -} - -.offers-template-menu-item { - padding: 0.5rem 0.75rem; - cursor: pointer; - font-size: 0.875rem; - transition: background var(--transition); -} - -.offers-template-menu-item:hover { - background: var(--bg-secondary); -} - /* Language badges */ .offers-lang-badge { display: inline-flex; @@ -617,17 +590,6 @@ } /* Offer draft indicator */ -.offers-draft-indicator { - display: flex; - align-items: center; - gap: 0.3rem; - font-size: 0.72rem; - font-weight: 500; - color: var(--text-tertiary); - margin-top: 0.2rem; - opacity: 0.8; -} - /* Filters */ .admin-filters { display: flex; diff --git a/src/admin/pages/OfferDetail.tsx b/src/admin/pages/OfferDetail.tsx index d1126ba..be82dd5 100644 --- a/src/admin/pages/OfferDetail.tsx +++ b/src/admin/pages/OfferDetail.tsx @@ -16,12 +16,15 @@ import { offerCustomersOptions, scopeTemplatesOptions, offerNextNumberOptions, + itemTemplatesOptions, + type ItemTemplate, type OfferDetailData, type OfferItemData, type OfferSectionData, type OfferLockInfo, type OfferOrderInfo, type ScopeTemplate, + type Customer, } from "../lib/queries/offers"; import { @@ -90,14 +93,6 @@ interface OfferForm { language: string; vat_rate: number; apply_vat: boolean; - scope_title: string; - scope_description: string; -} - -interface Customer { - id: number; - name: string; - city?: string; } const emptyForm: OfferForm = { @@ -111,8 +106,6 @@ const emptyForm: OfferForm = { language: "EN", vat_rate: 21, apply_vat: false, - scope_title: "", - scope_description: "", }; const emptyScopeSection = (): ScopeSection => ({ @@ -319,6 +312,7 @@ export default function OfferDetail() { enabled: !isEdit, }); const { data: templatesData } = useQuery(scopeTemplatesOptions()); + const { data: itemTemplates } = useQuery(itemTemplatesOptions()); const { data: nextNumberData } = useQuery({ ...offerNextNumberOptions(), enabled: !isEdit, @@ -350,11 +344,6 @@ export default function OfferDetail() { language: (draft.form.language as string) || emptyForm.language, vat_rate: (draft.form.vat_rate as number) ?? emptyForm.vat_rate, apply_vat: (draft.form.apply_vat as boolean) ?? emptyForm.apply_vat, - scope_title: - (draft.form.scope_title as string) || emptyForm.scope_title, - scope_description: - (draft.form.scope_description as string) || - emptyForm.scope_description, }; } return emptyForm; @@ -445,8 +434,6 @@ export default function OfferDetail() { language: d.language || "EN", vat_rate: d.vat_rate ?? companySettings?.default_vat_rate ?? 21, apply_vat: !!d.apply_vat, - scope_title: d.scope_title || "", - scope_description: d.scope_description || "", }; setForm(formData); const mappedItems = @@ -1252,12 +1239,59 @@ export default function OfferDetail() {

Položky

{!readOnly && ( - + {itemTemplates && itemTemplates.length > 0 && ( + + )} + +
)} {errors.items && ( @@ -1408,13 +1442,6 @@ export default function OfferDetail() { content: s.content || "", })); setSections((prev) => [...prev, ...newSections]); - if (template.description) { - setForm((prev) => ({ - ...prev, - scope_description: - template.description || prev.scope_description, - })); - } alert.success(`Načtena šablona "${template.name}"`); } e.target.value = ""; diff --git a/src/routes/admin/offers-pdf.ts b/src/routes/admin/offers-pdf.ts index 9ceb77f..c3e3df7 100644 --- a/src/routes/admin/offers-pdf.ts +++ b/src/routes/admin/offers-pdf.ts @@ -186,7 +186,6 @@ function buildAddressLines( const TRANSLATIONS: Record> = { title: { EN: "PRICE QUOTATION", CZ: "CENOV\u00C1 NAB\u00CDDKA" }, - scope_title: { EN: "SCOPE OF THE PROJECT", CZ: "ROZSAH PROJEKTU" }, valid_until: { EN: "Valid until", CZ: "Platnost do" }, customer: { EN: "Customer", CZ: "Z\u00E1kazn\u00EDk" }, supplier: { EN: "Supplier", CZ: "Dodavatel" }, @@ -571,12 +570,6 @@ ${indentCSS} border-bottom: 2.5pt solid #de3a3a; padding-bottom: 1mm; } - .totals .exchange-rate { - text-align: right; - font-size: 7.5pt; - color: #969696; - margin-top: 3mm; - } /* ---- Scope sections ---- */ .scope-page {