Fix #60
This commit is contained in:
2
backend/db/migrations/0003_woozy_adam_destine.sql
Normal file
2
backend/db/migrations/0003_woozy_adam_destine.sql
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
-- No-op migration: Datei war im Journal referenziert, aber fehlte im Repository.
|
||||||
|
SELECT 1;
|
||||||
2
backend/db/migrations/0004_stormy_onslaught.sql
Normal file
2
backend/db/migrations/0004_stormy_onslaught.sql
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
-- No-op migration: Datei war im Journal referenziert, aber fehlte im Repository.
|
||||||
|
SELECT 1;
|
||||||
123
backend/db/migrations/0005_green_shinobi_shaw.sql
Normal file
123
backend/db/migrations/0005_green_shinobi_shaw.sql
Normal file
@@ -0,0 +1,123 @@
|
|||||||
|
CREATE TABLE "m2m_api_keys" (
|
||||||
|
"id" uuid PRIMARY KEY DEFAULT gen_random_uuid() NOT NULL,
|
||||||
|
"created_at" timestamp with time zone DEFAULT now() NOT NULL,
|
||||||
|
"updated_at" timestamp with time zone DEFAULT now() NOT NULL,
|
||||||
|
"tenant_id" bigint NOT NULL,
|
||||||
|
"user_id" uuid NOT NULL,
|
||||||
|
"created_by" uuid,
|
||||||
|
"name" text NOT NULL,
|
||||||
|
"key_prefix" text NOT NULL,
|
||||||
|
"key_hash" text NOT NULL,
|
||||||
|
"active" boolean DEFAULT true NOT NULL,
|
||||||
|
"last_used_at" timestamp with time zone,
|
||||||
|
"expires_at" timestamp with time zone,
|
||||||
|
CONSTRAINT "m2m_api_keys_key_hash_unique" UNIQUE("key_hash")
|
||||||
|
);
|
||||||
|
--> statement-breakpoint
|
||||||
|
CREATE TABLE "staff_time_events" (
|
||||||
|
"id" uuid PRIMARY KEY DEFAULT gen_random_uuid() NOT NULL,
|
||||||
|
"tenant_id" bigint NOT NULL,
|
||||||
|
"user_id" uuid NOT NULL,
|
||||||
|
"actor_type" text NOT NULL,
|
||||||
|
"actor_user_id" uuid,
|
||||||
|
"event_time" timestamp with time zone NOT NULL,
|
||||||
|
"event_type" text NOT NULL,
|
||||||
|
"source" text NOT NULL,
|
||||||
|
"invalidates_event_id" uuid,
|
||||||
|
"related_event_id" uuid,
|
||||||
|
"metadata" jsonb,
|
||||||
|
"created_at" timestamp with time zone DEFAULT now() NOT NULL,
|
||||||
|
CONSTRAINT "time_events_actor_user_check" CHECK (
|
||||||
|
(actor_type = 'system' AND actor_user_id IS NULL)
|
||||||
|
OR
|
||||||
|
(actor_type = 'user' AND actor_user_id IS NOT NULL)
|
||||||
|
)
|
||||||
|
);
|
||||||
|
--> statement-breakpoint
|
||||||
|
CREATE TABLE "serialtypes" (
|
||||||
|
"id" bigint PRIMARY KEY GENERATED BY DEFAULT AS IDENTITY (sequence name "serialtypes_id_seq" INCREMENT BY 1 MINVALUE 1 MAXVALUE 9223372036854775807 START WITH 1 CACHE 1),
|
||||||
|
"created_at" timestamp with time zone DEFAULT now() NOT NULL,
|
||||||
|
"name" text NOT NULL,
|
||||||
|
"intervall" text,
|
||||||
|
"icon" text,
|
||||||
|
"tenant" bigint NOT NULL,
|
||||||
|
"archived" boolean DEFAULT false NOT NULL,
|
||||||
|
"updated_at" timestamp with time zone,
|
||||||
|
"updated_by" uuid
|
||||||
|
);
|
||||||
|
--> statement-breakpoint
|
||||||
|
CREATE TABLE "serial_executions" (
|
||||||
|
"id" uuid PRIMARY KEY DEFAULT gen_random_uuid() NOT NULL,
|
||||||
|
"tenant" bigint NOT NULL,
|
||||||
|
"execution_date" timestamp NOT NULL,
|
||||||
|
"status" text DEFAULT 'draft',
|
||||||
|
"created_by" text,
|
||||||
|
"created_at" timestamp DEFAULT now(),
|
||||||
|
"summary" text
|
||||||
|
);
|
||||||
|
--> statement-breakpoint
|
||||||
|
CREATE TABLE "public_links" (
|
||||||
|
"id" uuid PRIMARY KEY DEFAULT gen_random_uuid() NOT NULL,
|
||||||
|
"token" text NOT NULL,
|
||||||
|
"tenant" integer NOT NULL,
|
||||||
|
"default_profile" uuid,
|
||||||
|
"is_protected" boolean DEFAULT false NOT NULL,
|
||||||
|
"pin_hash" text,
|
||||||
|
"config" jsonb DEFAULT '{}'::jsonb,
|
||||||
|
"name" text NOT NULL,
|
||||||
|
"description" text,
|
||||||
|
"active" boolean DEFAULT true NOT NULL,
|
||||||
|
"created_at" timestamp DEFAULT now(),
|
||||||
|
"updated_at" timestamp DEFAULT now(),
|
||||||
|
CONSTRAINT "public_links_token_unique" UNIQUE("token")
|
||||||
|
);
|
||||||
|
--> statement-breakpoint
|
||||||
|
CREATE TABLE "wiki_pages" (
|
||||||
|
"id" uuid PRIMARY KEY DEFAULT gen_random_uuid() NOT NULL,
|
||||||
|
"tenant_id" bigint NOT NULL,
|
||||||
|
"parent_id" uuid,
|
||||||
|
"title" text NOT NULL,
|
||||||
|
"content" jsonb,
|
||||||
|
"is_folder" boolean DEFAULT false NOT NULL,
|
||||||
|
"sort_order" integer DEFAULT 0 NOT NULL,
|
||||||
|
"entity_type" text,
|
||||||
|
"entity_id" bigint,
|
||||||
|
"entity_uuid" uuid,
|
||||||
|
"created_at" timestamp with time zone DEFAULT now() NOT NULL,
|
||||||
|
"updated_at" timestamp with time zone,
|
||||||
|
"created_by" uuid,
|
||||||
|
"updated_by" uuid
|
||||||
|
);
|
||||||
|
--> statement-breakpoint
|
||||||
|
ALTER TABLE "time_events" DISABLE ROW LEVEL SECURITY;--> statement-breakpoint
|
||||||
|
DROP TABLE "time_events" CASCADE;--> statement-breakpoint
|
||||||
|
ALTER TABLE "projects" ALTER COLUMN "active_phase" SET DEFAULT 'Erstkontakt';--> statement-breakpoint
|
||||||
|
ALTER TABLE "createddocuments" ADD COLUMN "serialexecution" uuid;--> statement-breakpoint
|
||||||
|
ALTER TABLE "devices" ADD COLUMN "last_seen" timestamp with time zone;--> statement-breakpoint
|
||||||
|
ALTER TABLE "devices" ADD COLUMN "last_debug_info" jsonb;--> statement-breakpoint
|
||||||
|
ALTER TABLE "files" ADD COLUMN "size" bigint;--> statement-breakpoint
|
||||||
|
ALTER TABLE "m2m_api_keys" ADD CONSTRAINT "m2m_api_keys_tenant_id_tenants_id_fk" FOREIGN KEY ("tenant_id") REFERENCES "public"."tenants"("id") ON DELETE cascade ON UPDATE cascade;--> statement-breakpoint
|
||||||
|
ALTER TABLE "m2m_api_keys" ADD CONSTRAINT "m2m_api_keys_user_id_auth_users_id_fk" FOREIGN KEY ("user_id") REFERENCES "public"."auth_users"("id") ON DELETE cascade ON UPDATE cascade;--> statement-breakpoint
|
||||||
|
ALTER TABLE "m2m_api_keys" ADD CONSTRAINT "m2m_api_keys_created_by_auth_users_id_fk" FOREIGN KEY ("created_by") REFERENCES "public"."auth_users"("id") ON DELETE set null ON UPDATE cascade;--> statement-breakpoint
|
||||||
|
ALTER TABLE "staff_time_events" ADD CONSTRAINT "staff_time_events_tenant_id_tenants_id_fk" FOREIGN KEY ("tenant_id") REFERENCES "public"."tenants"("id") ON DELETE no action ON UPDATE no action;--> statement-breakpoint
|
||||||
|
ALTER TABLE "staff_time_events" ADD CONSTRAINT "staff_time_events_user_id_auth_users_id_fk" FOREIGN KEY ("user_id") REFERENCES "public"."auth_users"("id") ON DELETE no action ON UPDATE no action;--> statement-breakpoint
|
||||||
|
ALTER TABLE "staff_time_events" ADD CONSTRAINT "staff_time_events_actor_user_id_auth_users_id_fk" FOREIGN KEY ("actor_user_id") REFERENCES "public"."auth_users"("id") ON DELETE no action ON UPDATE no action;--> statement-breakpoint
|
||||||
|
ALTER TABLE "staff_time_events" ADD CONSTRAINT "staff_time_events_invalidates_event_id_staff_time_events_id_fk" FOREIGN KEY ("invalidates_event_id") REFERENCES "public"."staff_time_events"("id") ON DELETE no action ON UPDATE no action;--> statement-breakpoint
|
||||||
|
ALTER TABLE "staff_time_events" ADD CONSTRAINT "staff_time_events_related_event_id_staff_time_events_id_fk" FOREIGN KEY ("related_event_id") REFERENCES "public"."staff_time_events"("id") ON DELETE no action ON UPDATE no action;--> statement-breakpoint
|
||||||
|
ALTER TABLE "serialtypes" ADD CONSTRAINT "serialtypes_tenant_tenants_id_fk" FOREIGN KEY ("tenant") REFERENCES "public"."tenants"("id") ON DELETE no action ON UPDATE no action;--> statement-breakpoint
|
||||||
|
ALTER TABLE "serialtypes" ADD CONSTRAINT "serialtypes_updated_by_auth_users_id_fk" FOREIGN KEY ("updated_by") REFERENCES "public"."auth_users"("id") ON DELETE no action ON UPDATE no action;--> statement-breakpoint
|
||||||
|
ALTER TABLE "serial_executions" ADD CONSTRAINT "serial_executions_tenant_tenants_id_fk" FOREIGN KEY ("tenant") REFERENCES "public"."tenants"("id") ON DELETE no action ON UPDATE no action;--> statement-breakpoint
|
||||||
|
ALTER TABLE "public_links" ADD CONSTRAINT "public_links_tenant_tenants_id_fk" FOREIGN KEY ("tenant") REFERENCES "public"."tenants"("id") ON DELETE no action ON UPDATE no action;--> statement-breakpoint
|
||||||
|
ALTER TABLE "public_links" ADD CONSTRAINT "public_links_default_profile_auth_profiles_id_fk" FOREIGN KEY ("default_profile") REFERENCES "public"."auth_profiles"("id") ON DELETE no action ON UPDATE no action;--> statement-breakpoint
|
||||||
|
ALTER TABLE "wiki_pages" ADD CONSTRAINT "wiki_pages_tenant_id_tenants_id_fk" FOREIGN KEY ("tenant_id") REFERENCES "public"."tenants"("id") ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
|
||||||
|
ALTER TABLE "wiki_pages" ADD CONSTRAINT "wiki_pages_parent_id_wiki_pages_id_fk" FOREIGN KEY ("parent_id") REFERENCES "public"."wiki_pages"("id") ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
|
||||||
|
ALTER TABLE "wiki_pages" ADD CONSTRAINT "wiki_pages_created_by_auth_users_id_fk" FOREIGN KEY ("created_by") REFERENCES "public"."auth_users"("id") ON DELETE no action ON UPDATE no action;--> statement-breakpoint
|
||||||
|
ALTER TABLE "wiki_pages" ADD CONSTRAINT "wiki_pages_updated_by_auth_users_id_fk" FOREIGN KEY ("updated_by") REFERENCES "public"."auth_users"("id") ON DELETE no action ON UPDATE no action;--> statement-breakpoint
|
||||||
|
CREATE INDEX "idx_time_events_tenant_user_time" ON "staff_time_events" USING btree ("tenant_id","user_id","event_time");--> statement-breakpoint
|
||||||
|
CREATE INDEX "idx_time_events_created_at" ON "staff_time_events" USING btree ("created_at");--> statement-breakpoint
|
||||||
|
CREATE INDEX "idx_time_events_invalidates" ON "staff_time_events" USING btree ("invalidates_event_id");--> statement-breakpoint
|
||||||
|
CREATE INDEX "wiki_pages_tenant_idx" ON "wiki_pages" USING btree ("tenant_id");--> statement-breakpoint
|
||||||
|
CREATE INDEX "wiki_pages_parent_idx" ON "wiki_pages" USING btree ("parent_id");--> statement-breakpoint
|
||||||
|
CREATE INDEX "wiki_pages_entity_int_idx" ON "wiki_pages" USING btree ("tenant_id","entity_type","entity_id");--> statement-breakpoint
|
||||||
|
CREATE INDEX "wiki_pages_entity_uuid_idx" ON "wiki_pages" USING btree ("tenant_id","entity_type","entity_uuid");--> statement-breakpoint
|
||||||
|
ALTER TABLE "createddocuments" ADD CONSTRAINT "createddocuments_serialexecution_serial_executions_id_fk" FOREIGN KEY ("serialexecution") REFERENCES "public"."serial_executions"("id") ON DELETE no action ON UPDATE no action;
|
||||||
1
backend/db/migrations/0006_nifty_price_lock.sql
Normal file
1
backend/db/migrations/0006_nifty_price_lock.sql
Normal file
@@ -0,0 +1 @@
|
|||||||
|
ALTER TABLE "services" ADD COLUMN "priceUpdateLocked" boolean DEFAULT false NOT NULL;
|
||||||
@@ -54,6 +54,7 @@ export const services = pgTable("services", {
|
|||||||
|
|
||||||
materialComposition: jsonb("materialComposition").notNull().default([]),
|
materialComposition: jsonb("materialComposition").notNull().default([]),
|
||||||
personalComposition: jsonb("personalComposition").notNull().default([]),
|
personalComposition: jsonb("personalComposition").notNull().default([]),
|
||||||
|
priceUpdateLocked: boolean("priceUpdateLocked").notNull().default(false),
|
||||||
|
|
||||||
updatedAt: timestamp("updated_at", { withTimezone: true }),
|
updatedAt: timestamp("updated_at", { withTimezone: true }),
|
||||||
updatedBy: uuid("updated_by").references(() => authUsers.id),
|
updatedBy: uuid("updated_by").references(() => authUsers.id),
|
||||||
|
|||||||
@@ -12,6 +12,7 @@ import {
|
|||||||
|
|
||||||
import { resourceConfig } from "../../utils/resource.config";
|
import { resourceConfig } from "../../utils/resource.config";
|
||||||
import { useNextNumberRangeNumber } from "../../utils/functions";
|
import { useNextNumberRangeNumber } from "../../utils/functions";
|
||||||
|
import { recalculateServicePricesForTenant } from "../../modules/service-price-recalculation.service";
|
||||||
|
|
||||||
// -------------------------------------------------------------
|
// -------------------------------------------------------------
|
||||||
// SQL Suche auf mehreren Feldern (Haupttabelle + Relationen)
|
// SQL Suche auf mehreren Feldern (Haupttabelle + Relationen)
|
||||||
@@ -343,6 +344,11 @@ export default async function resourceRoutes(server: FastifyInstance) {
|
|||||||
})
|
})
|
||||||
|
|
||||||
const [created] = await server.db.insert(table).values(createData).returning()
|
const [created] = await server.db.insert(table).values(createData).returning()
|
||||||
|
|
||||||
|
if (["products", "services", "hourrates"].includes(resource)) {
|
||||||
|
await recalculateServicePricesForTenant(server, req.user.tenant_id, req.user?.user_id || null);
|
||||||
|
}
|
||||||
|
|
||||||
return created;
|
return created;
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error(error);
|
console.error(error);
|
||||||
@@ -374,9 +380,14 @@ export default async function resourceRoutes(server: FastifyInstance) {
|
|||||||
})
|
})
|
||||||
|
|
||||||
const [updated] = await server.db.update(table).set(data).where(and(eq(table.id, id), eq(table.tenant, tenantId))).returning()
|
const [updated] = await server.db.update(table).set(data).where(and(eq(table.id, id), eq(table.tenant, tenantId))).returning()
|
||||||
|
|
||||||
|
if (["products", "services", "hourrates"].includes(resource)) {
|
||||||
|
await recalculateServicePricesForTenant(server, tenantId, userId);
|
||||||
|
}
|
||||||
|
|
||||||
return updated
|
return updated
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
console.error(err)
|
console.error(err)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1970,6 +1970,11 @@ export const useDataStore = defineStore('data', () => {
|
|||||||
label: "Verkaufspreis",
|
label: "Verkaufspreis",
|
||||||
component: sellingPrice,
|
component: sellingPrice,
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
key: "priceUpdateLocked",
|
||||||
|
label: "Preis-Update sperren",
|
||||||
|
inputType: "bool",
|
||||||
|
},
|
||||||
{
|
{
|
||||||
key: "taxPercentage",
|
key: "taxPercentage",
|
||||||
label: "Umsatzsteuer",
|
label: "Umsatzsteuer",
|
||||||
|
|||||||
Reference in New Issue
Block a user