fix(number-fields): избегаем потери точности длинных чисел
- number-поля теперь рендерятся как text + inputMode=numeric, чтобы браузер не округлял значения через input type=number - пробелы при вставке в number-поля удаляются - бэкенд нормализует значения number-полей в строку перед сохранением - добавлен хелпер normalizeFieldValueForStorage Closes: искажение расчётного счёта и других длинных числовых полей
This commit is contained in:
135
migrations/0025_user_profile_fields.sql
Normal file
135
migrations/0025_user_profile_fields.sql
Normal file
@@ -0,0 +1,135 @@
|
||||
-- User profile tabs (analogous to formTabs for users)
|
||||
CREATE TABLE IF NOT EXISTS "user_profile_tabs" (
|
||||
"id" serial PRIMARY KEY NOT NULL,
|
||||
"organization_id" integer NOT NULL,
|
||||
"name" varchar(200) NOT NULL,
|
||||
"code" varchar(100) NOT NULL,
|
||||
"position" integer DEFAULT 0 NOT NULL,
|
||||
"display_order" integer DEFAULT 0,
|
||||
"created_at" timestamp DEFAULT now(),
|
||||
CONSTRAINT "user_profile_tabs_organization_id_code_unique" UNIQUE("organization_id","code")
|
||||
);
|
||||
|
||||
--> statement-breakpoint
|
||||
|
||||
-- User profile fields (analogous to formFields for users)
|
||||
CREATE TABLE IF NOT EXISTS "user_profile_fields" (
|
||||
"id" serial PRIMARY KEY NOT NULL,
|
||||
"organization_id" integer NOT NULL,
|
||||
"tab_id" integer,
|
||||
"name" varchar(200) NOT NULL,
|
||||
"code" varchar(100) NOT NULL,
|
||||
"type" varchar(50) NOT NULL,
|
||||
"is_required" boolean DEFAULT false,
|
||||
"placeholder" text,
|
||||
"default_value" text,
|
||||
"validation_rules" jsonb,
|
||||
"options" jsonb,
|
||||
"position" integer DEFAULT 0 NOT NULL,
|
||||
"display_order" integer DEFAULT 0,
|
||||
"linked_form_id" integer,
|
||||
"company_autofill" jsonb,
|
||||
"max_file_count" integer,
|
||||
"max_file_size_mb" integer,
|
||||
"auto_prolongation" boolean DEFAULT false,
|
||||
"auto_prolongation_label" text,
|
||||
"created_at" timestamp DEFAULT now(),
|
||||
CONSTRAINT "user_profile_fields_organization_id_code_unique" UNIQUE("organization_id","code")
|
||||
);
|
||||
|
||||
--> statement-breakpoint
|
||||
|
||||
-- User profile field values (analogous to taskFieldValues for users)
|
||||
CREATE TABLE IF NOT EXISTS "user_profile_field_values" (
|
||||
"id" serial PRIMARY KEY NOT NULL,
|
||||
"user_id" integer NOT NULL,
|
||||
"field_id" integer NOT NULL,
|
||||
"value" jsonb,
|
||||
"created_at" timestamp DEFAULT now(),
|
||||
"updated_at" timestamp DEFAULT now(),
|
||||
CONSTRAINT "user_profile_field_values_user_id_field_id_unique" UNIQUE("user_id","field_id")
|
||||
);
|
||||
|
||||
--> statement-breakpoint
|
||||
|
||||
-- Foreign keys
|
||||
DO $$ BEGIN
|
||||
ALTER TABLE "user_profile_tabs" ADD CONSTRAINT "user_profile_tabs_organization_id_organizations_id_fk" FOREIGN KEY ("organization_id") REFERENCES "organizations"("id") ON DELETE cascade ON UPDATE no action;
|
||||
EXCEPTION
|
||||
WHEN duplicate_object THEN null;
|
||||
END $$;
|
||||
|
||||
--> statement-breakpoint
|
||||
|
||||
DO $$ BEGIN
|
||||
ALTER TABLE "user_profile_fields" ADD CONSTRAINT "user_profile_fields_organization_id_organizations_id_fk" FOREIGN KEY ("organization_id") REFERENCES "organizations"("id") ON DELETE cascade ON UPDATE no action;
|
||||
EXCEPTION
|
||||
WHEN duplicate_object THEN null;
|
||||
END $$;
|
||||
|
||||
--> statement-breakpoint
|
||||
|
||||
DO $$ BEGIN
|
||||
ALTER TABLE "user_profile_fields" ADD CONSTRAINT "user_profile_fields_tab_id_user_profile_tabs_id_fk" FOREIGN KEY ("tab_id") REFERENCES "user_profile_tabs"("id") ON DELETE set null ON UPDATE no action;
|
||||
EXCEPTION
|
||||
WHEN duplicate_object THEN null;
|
||||
END $$;
|
||||
|
||||
--> statement-breakpoint
|
||||
|
||||
DO $$ BEGIN
|
||||
ALTER TABLE "user_profile_fields" ADD CONSTRAINT "user_profile_fields_linked_form_id_forms_id_fk" FOREIGN KEY ("linked_form_id") REFERENCES "forms"("id") ON DELETE set null ON UPDATE no action;
|
||||
EXCEPTION
|
||||
WHEN duplicate_object THEN null;
|
||||
END $$;
|
||||
|
||||
--> statement-breakpoint
|
||||
|
||||
DO $$ BEGIN
|
||||
ALTER TABLE "user_profile_field_values" ADD CONSTRAINT "user_profile_field_values_user_id_users_id_fk" FOREIGN KEY ("user_id") REFERENCES "users"("id") ON DELETE cascade ON UPDATE no action;
|
||||
EXCEPTION
|
||||
WHEN duplicate_object THEN null;
|
||||
END $$;
|
||||
|
||||
--> statement-breakpoint
|
||||
|
||||
DO $$ BEGIN
|
||||
ALTER TABLE "user_profile_field_values" ADD CONSTRAINT "user_profile_field_values_field_id_user_profile_fields_id_fk" FOREIGN KEY ("field_id") REFERENCES "user_profile_fields"("id") ON DELETE cascade ON UPDATE no action;
|
||||
EXCEPTION
|
||||
WHEN duplicate_object THEN null;
|
||||
END $$;
|
||||
|
||||
--> statement-breakpoint
|
||||
|
||||
-- Index for fast lookup
|
||||
CREATE INDEX IF NOT EXISTS "user_profile_field_values_user_field_idx" ON "user_profile_field_values" USING btree ("user_id","field_id");
|
||||
|
||||
--> statement-breakpoint
|
||||
|
||||
-- Migrate existing user custom fields data (optional, preserves data)
|
||||
INSERT INTO "user_profile_fields" ("organization_id", "tab_id", "name", "code", "type", "is_required", "options", "position")
|
||||
SELECT
|
||||
"organization_id",
|
||||
NULL,
|
||||
"name",
|
||||
"code",
|
||||
"type",
|
||||
COALESCE("is_required", false),
|
||||
CASE
|
||||
WHEN "options" IS NOT NULL AND jsonb_typeof("options") = 'array' THEN "options"
|
||||
ELSE NULL
|
||||
END,
|
||||
COALESCE("position", 0)
|
||||
FROM "user_custom_fields";
|
||||
|
||||
--> statement-breakpoint
|
||||
|
||||
-- Migrate existing user custom values (convert text to jsonb string)
|
||||
INSERT INTO "user_profile_field_values" ("user_id", "field_id", "value")
|
||||
SELECT
|
||||
ucv."user_id",
|
||||
upf."id",
|
||||
to_jsonb(ucv."value")
|
||||
FROM "user_custom_values" ucv
|
||||
JOIN "user_custom_fields" ucf ON ucv."field_id" = ucf."id"
|
||||
JOIN "user_profile_fields" upf ON upf."code" = ucf."code" AND upf."organization_id" = ucf."organization_id";
|
||||
Reference in New Issue
Block a user