Merge pull request 'vsp_fixes' (#15) from vsp_fixes into test

Reviewed-on: #15
This commit is contained in:
Raykov-MS 2026-06-30 09:56:54 +03:00
commit 2e5cf3d2af
6 changed files with 46 additions and 57 deletions

View File

@ -1123,9 +1123,9 @@ END;
$function$ $function$
; ;
-- DROP FUNCTION v3.add_vsp(int4, varchar, varchar, varchar, date, varchar, int4, numeric, date, bool, bool, varchar, int4, varchar, text, varchar, int4, varchar, date); -- DROP FUNCTION v3.add_vsp(int4, varchar, varchar, varchar, date, varchar, int4, numeric, date, bool, bool, varchar, int4, varchar, text, varchar, varchar, date);
CREATE OR REPLACE FUNCTION v3.add_vsp(p_branch_id integer, p_reg_number character varying DEFAULT NULL::character varying, p_address character varying DEFAULT NULL::character varying, p_format character varying DEFAULT NULL::character varying, p_opened_at date DEFAULT NULL::date, p_placement_type character varying DEFAULT NULL::character varying, p_staff_count integer DEFAULT NULL::integer, p_total_area numeric DEFAULT NULL::numeric, p_closed_at date DEFAULT NULL::date, p_is_active boolean DEFAULT true, p_is_deleted boolean DEFAULT false, p_system_code character varying DEFAULT NULL::character varying, p_created_by integer DEFAULT NULL::integer, p_vsp_type character varying DEFAULT NULL::character varying, p_notes text DEFAULT NULL::text, p_location_form character varying DEFAULT NULL::character varying, p_numbers integer DEFAULT NULL::integer, p_rent_contract_num character varying DEFAULT NULL::character varying, p_rent_end_date date DEFAULT NULL::date) CREATE OR REPLACE FUNCTION v3.add_vsp(p_branch_id integer, p_reg_number character varying DEFAULT NULL::character varying, p_address character varying DEFAULT NULL::character varying, p_format character varying DEFAULT NULL::character varying, p_opened_at date DEFAULT NULL::date, p_placement_type character varying DEFAULT NULL::character varying, p_staff_count integer DEFAULT NULL::integer, p_total_area numeric DEFAULT NULL::numeric, p_closed_at date DEFAULT NULL::date, p_is_active boolean DEFAULT true, p_is_deleted boolean DEFAULT false, p_system_code character varying DEFAULT NULL::character varying, p_created_by integer DEFAULT NULL::integer, p_vsp_type character varying DEFAULT NULL::character varying, p_notes text DEFAULT NULL::text, p_location_form character varying DEFAULT NULL::character varying, p_rent_contract_num character varying DEFAULT NULL::character varying, p_rent_end_date date DEFAULT NULL::date)
RETURNS integer RETURNS integer
LANGUAGE plpgsql LANGUAGE plpgsql
AS $function$ AS $function$
@ -1153,14 +1153,12 @@ BEGIN
(branch_id, reg_number, address, format, opened_at, (branch_id, reg_number, address, format, opened_at,
placement_type, staff_count, total_area, closed_at, placement_type, staff_count, total_area, closed_at,
is_active, is_deleted, system_code, created_by, is_active, is_deleted, system_code, created_by,
vsp_type, notes, location_form, numbers, vsp_type, notes, location_form, rent_contract_num, rent_end_date)
rent_contract_num, rent_end_date)
VALUES VALUES
(p_branch_id, p_reg_number, p_address, p_format, p_opened_at, (p_branch_id, p_reg_number, p_address, p_format, p_opened_at,
p_placement_type, p_staff_count, p_total_area, p_closed_at, p_placement_type, p_staff_count, p_total_area, p_closed_at,
p_is_active, p_is_deleted, p_system_code, p_created_by, p_is_active, p_is_deleted, p_system_code, p_created_by,
p_vsp_type, p_notes, p_location_form, p_numbers, p_vsp_type, p_notes, p_location_form, p_rent_contract_num, p_rent_end_date)
p_rent_contract_num, p_rent_end_date)
RETURNING id INTO v_id; RETURNING id INTO v_id;
PERFORM v3.log_event( PERFORM v3.log_event(
@ -1185,7 +1183,6 @@ BEGIN
'vsp_type', p_vsp_type, 'vsp_type', p_vsp_type,
'notes', p_notes, 'notes', p_notes,
'location_form', p_location_form, 'location_form', p_location_form,
'numbers', p_numbers,
'rent_contract_num', p_rent_contract_num, 'rent_contract_num', p_rent_contract_num,
'rent_end_date', v3._diff_val(p_rent_end_date), 'rent_end_date', v3._diff_val(p_rent_end_date),
'user_email', v_actor_email, 'user_email', v_actor_email,
@ -2738,9 +2735,9 @@ END;
$function$ $function$
; ;
-- DROP FUNCTION v3.upd_vsp(int4, int4, varchar, varchar, varchar, date, varchar, int4, numeric, date, bool, bool, varchar, int4, varchar, text, varchar, int4, varchar, date); -- DROP FUNCTION v3.upd_vsp(int4, int4, varchar, varchar, varchar, date, varchar, int4, numeric, date, bool, bool, varchar, int4, varchar, text, varchar, varchar, date);
CREATE OR REPLACE FUNCTION v3.upd_vsp(p_vsp_id integer, p_branch_id integer DEFAULT NULL::integer, p_reg_number character varying DEFAULT NULL::character varying, p_address character varying DEFAULT NULL::character varying, p_format character varying DEFAULT NULL::character varying, p_opened_at date DEFAULT NULL::date, p_placement_type character varying DEFAULT NULL::character varying, p_staff_count integer DEFAULT NULL::integer, p_total_area numeric DEFAULT NULL::numeric, p_closed_at date DEFAULT NULL::date, p_is_active boolean DEFAULT NULL::boolean, p_is_deleted boolean DEFAULT NULL::boolean, p_system_code character varying DEFAULT NULL::character varying, p_updated_by integer DEFAULT NULL::integer, p_vsp_type character varying DEFAULT NULL::character varying, p_notes text DEFAULT NULL::text, p_location_form character varying DEFAULT NULL::character varying, p_numbers integer DEFAULT NULL::integer, p_rent_contract_num character varying DEFAULT NULL::character varying, p_rent_end_date date DEFAULT NULL::date) CREATE OR REPLACE FUNCTION v3.upd_vsp(p_vsp_id integer, p_branch_id integer DEFAULT NULL::integer, p_reg_number character varying DEFAULT NULL::character varying, p_address character varying DEFAULT NULL::character varying, p_format character varying DEFAULT NULL::character varying, p_opened_at date DEFAULT NULL::date, p_placement_type character varying DEFAULT NULL::character varying, p_staff_count integer DEFAULT NULL::integer, p_total_area numeric DEFAULT NULL::numeric, p_closed_at date DEFAULT NULL::date, p_is_active boolean DEFAULT NULL::boolean, p_is_deleted boolean DEFAULT NULL::boolean, p_system_code character varying DEFAULT NULL::character varying, p_updated_by integer DEFAULT NULL::integer, p_vsp_type character varying DEFAULT NULL::character varying, p_notes text DEFAULT NULL::text, p_location_form character varying DEFAULT NULL::character varying, p_rent_contract_num character varying DEFAULT NULL::character varying, p_rent_end_date date DEFAULT NULL::date)
RETURNS void RETURNS void
LANGUAGE plpgsql LANGUAGE plpgsql
AS $function$ AS $function$
@ -2758,8 +2755,7 @@ BEGIN
SELECT v.branch_id, v.reg_number, v.address, v.format, v.opened_at, SELECT v.branch_id, v.reg_number, v.address, v.format, v.opened_at,
v.placement_type, v.staff_count, v.total_area, v.closed_at, v.placement_type, v.staff_count, v.total_area, v.closed_at,
v.is_active, v.is_deleted, v.system_code, v.is_active, v.is_deleted, v.system_code,
v.vsp_type, v.notes, v.location_form, v.numbers, v.vsp_type, v.notes, v.location_form, v.rent_contract_num, v.rent_end_date
v.rent_contract_num, v.rent_end_date
INTO v_old INTO v_old
FROM v3.vsp v FROM v3.vsp v
WHERE v.id = p_vsp_id; WHERE v.id = p_vsp_id;
@ -2899,13 +2895,6 @@ BEGIN
'after', v3._diff_val(p_location_form))); 'after', v3._diff_val(p_location_form)));
END IF; END IF;
IF p_numbers IS NOT NULL AND p_numbers IS DISTINCT FROM v_old.numbers THEN
UPDATE v3.vsp SET numbers = p_numbers WHERE id = p_vsp_id;
v_changes := v_changes || jsonb_build_object('numbers',
jsonb_build_object('before', v3._diff_val(v_old.numbers),
'after', v3._diff_val(p_numbers)));
END IF;
IF p_rent_contract_num IS NOT NULL AND p_rent_contract_num IS DISTINCT FROM v_old.rent_contract_num THEN IF p_rent_contract_num IS NOT NULL AND p_rent_contract_num IS DISTINCT FROM v_old.rent_contract_num THEN
UPDATE v3.vsp SET rent_contract_num = p_rent_contract_num WHERE id = p_vsp_id; UPDATE v3.vsp SET rent_contract_num = p_rent_contract_num WHERE id = p_vsp_id;
v_changes := v_changes || jsonb_build_object('rent_contract_num', v_changes := v_changes || jsonb_build_object('rent_contract_num',

View File

@ -28,8 +28,8 @@ async def get_vsp(
open_date_start: date | None = None, open_date_start: date | None = None,
open_date_end: date | None = None, open_date_end: date | None = None,
location_form: str | None = None, location_form: str | None = None,
numbers_min: int | None = None, staff_count_min: int | None = None,
numbers_max: int | None = None, staff_count_max: int | None = None,
db: AsyncSession = Depends(get_db), db: AsyncSession = Depends(get_db),
current_user: AppUser = Depends(require_executor), current_user: AppUser = Depends(require_executor),
): ):
@ -43,8 +43,8 @@ async def get_vsp(
open_date_start=open_date_start, open_date_start=open_date_start,
open_date_end=open_date_end, open_date_end=open_date_end,
location_form=location_form, location_form=location_form,
numbers_min=numbers_min, staff_count_min=staff_count_min,
numbers_max=numbers_max, staff_count_max=staff_count_max,
load_org_unit=True, load_org_unit=True,
with_count=True, with_count=True,
) )
@ -90,8 +90,8 @@ async def export_info(
open_date_start=body.open_date_start, open_date_start=body.open_date_start,
open_date_end=body.open_date_end, open_date_end=body.open_date_end,
location_form=body.location_form, location_form=body.location_form,
numbers_min=body.numbers_min, staff_count_min=body.staff_count_min,
numbers_max=body.numbers_max, staff_count_max=body.staff_count_max,
) )
return StreamingResponse( return StreamingResponse(
stream, stream,

View File

@ -494,8 +494,9 @@ class VSPBase(BaseModel):
serialization_alias='approved_format', serialization_alias='approved_format',
) )
notes: Optional[str] = Field(None, description="Примечания") notes: Optional[str] = Field(None, description="Примечания")
placement_type: Optional[str] = Field(None, description="Тип размещения")
staff_count: Optional[int] = Field(None, description="Штатная численность")
location_form: Optional[str] = Field(None, description="Форма расположения") location_form: Optional[str] = Field(None, description="Форма расположения")
numbers: Optional[int] = Field(None, description="Штатная численность")
area: Optional[float] = Field( area: Optional[float] = Field(
None, None,
description="Арендная площадь", description="Арендная площадь",
@ -543,8 +544,9 @@ class VSPEditBase(BaseModel):
serialization_alias='format', serialization_alias='format',
) )
notes: Optional[str] = Field(None, description="Примечания") notes: Optional[str] = Field(None, description="Примечания")
placement_type: Optional[str] = Field(None, description="Тип размещения")
staff_count: Optional[int] = Field(None, description="Штатная численность")
location_form: Optional[str] = Field(None, description="Форма расположения") location_form: Optional[str] = Field(None, description="Форма расположения")
numbers: Optional[int] = Field(None, description="Штатная численность")
total_area: Optional[float] = Field( total_area: Optional[float] = Field(
None, None,
description="Арендная площадь", description="Арендная площадь",
@ -616,8 +618,8 @@ class VSPExportRequest(BaseModel):
open_date_start: Optional[date] = None open_date_start: Optional[date] = None
open_date_end: Optional[date] = None open_date_end: Optional[date] = None
location_form: Optional[str] = None location_form: Optional[str] = None
numbers_min: Optional[int] = None staff_count_min: Optional[int] = None
numbers_max: Optional[int] = None staff_count_max: Optional[int] = None
class ExpenseItemBaseSchema(BaseModel): class ExpenseItemBaseSchema(BaseModel):

View File

@ -37,8 +37,8 @@ class VSPRepository:
open_date_start: date | None = None, open_date_start: date | None = None,
open_date_end: date | None = None, open_date_end: date | None = None,
location_form: str | None = None, location_form: str | None = None,
numbers_min: int | None = None, staff_count_min: int | None = None,
numbers_max: int | None = None, staff_count_max: int | None = None,
is_active: bool | None = True, is_active: bool | None = True,
close_date_is_null: bool | None = None, close_date_is_null: bool | None = None,
load_org_unit: bool = False, load_org_unit: bool = False,
@ -56,8 +56,8 @@ class VSPRepository:
("location_form", location_form), ("location_form", location_form),
("open_date_start", open_date_start), ("open_date_start", open_date_start),
("open_date_end", open_date_end), ("open_date_end", open_date_end),
("numbers_min", numbers_min), ("staff_count_min", staff_count_min),
("numbers_max", numbers_max), ("staff_count_max", staff_count_max),
("is_active", is_active), ("is_active", is_active),
] ]
for filter_name, filter_value in filters: for filter_name, filter_value in filters:
@ -73,10 +73,10 @@ class VSPRepository:
queries.append(Vsp.opened_at >= value) queries.append(Vsp.opened_at >= value)
case ("open_date_end", value) if value is not None: case ("open_date_end", value) if value is not None:
queries.append(Vsp.opened_at <= value) queries.append(Vsp.opened_at <= value)
case ("numbers_min", value) if value is not None: case ("staff_count_min", value) if value is not None:
queries.append(Vsp.numbers >= value) queries.append(Vsp.staff_count >= value)
case ("numbers_max", value) if value is not None: case ("staff_count_max", value) if value is not None:
queries.append(Vsp.numbers <= value) queries.append(Vsp.staff_count <= value)
case ("is_active", value) if value is not None: case ("is_active", value) if value is not None:
queries.append(Vsp.is_active == value) queries.append(Vsp.is_active == value)
case _: case _:
@ -116,6 +116,7 @@ class VSPRepository:
async def create(self, payload: VSPCreate, created_by: int, load_org_unit: bool = False) -> Vsp: async def create(self, payload: VSPCreate, created_by: int, load_org_unit: bool = False) -> Vsp:
data = payload.model_dump() data = payload.model_dump()
vsp_id = ( vsp_id = (
await self.db.execute( await self.db.execute(
text(""" text("""
@ -124,8 +125,7 @@ class VSPRepository:
:p_opened_at, :p_placement_type, :p_staff_count, :p_opened_at, :p_placement_type, :p_staff_count,
:p_total_area, :p_closed_at, :p_is_active, :p_is_deleted, :p_total_area, :p_closed_at, :p_is_active, :p_is_deleted,
:p_system_code, :p_created_by, :p_vsp_type, :p_notes, :p_system_code, :p_created_by, :p_vsp_type, :p_notes,
:p_location_form, :p_numbers, :p_rent_contract_num, :p_location_form, :p_rent_contract_num, :p_rent_end_date
:p_rent_end_date
) )
"""), """),
{ {
@ -145,7 +145,6 @@ class VSPRepository:
"p_vsp_type": data.get("vsp_type"), "p_vsp_type": data.get("vsp_type"),
"p_notes": data.get("notes"), "p_notes": data.get("notes"),
"p_location_form": data.get("location_form"), "p_location_form": data.get("location_form"),
"p_numbers": data.get("numbers"),
"p_rent_contract_num": data.get("rent_contract_num"), "p_rent_contract_num": data.get("rent_contract_num"),
"p_rent_end_date": data.get("rent_end_date"), "p_rent_end_date": data.get("rent_end_date"),
} }
@ -176,9 +175,10 @@ class VSPRepository:
"opened_at": "p_opened_at", "opened_at": "p_opened_at",
"closed_at": "p_closed_at", "closed_at": "p_closed_at",
"format": "p_format", "format": "p_format",
"placement_type": "p_placement_type",
"staff_count": "p_staff_count",
"notes": "p_notes", "notes": "p_notes",
"location_form": "p_location_form", "location_form": "p_location_form",
"numbers": "p_numbers",
"total_area": "p_total_area", "total_area": "p_total_area",
"rent_contract_num": "p_rent_contract_num", "rent_contract_num": "p_rent_contract_num",
"rent_end_date": "p_rent_end_date", "rent_end_date": "p_rent_end_date",
@ -190,8 +190,7 @@ class VSPRepository:
params = {"p_vsp_id": vsp.id, "p_updated_by": updated_by} params = {"p_vsp_id": vsp.id, "p_updated_by": updated_by}
for field, param in FIELD_TO_PARAM.items(): for field, param in FIELD_TO_PARAM.items():
params[param] = data.get(field) params[param] = data.get(field)
params.setdefault("p_placement_type", data.get("placement_type"))
params.setdefault("p_staff_count", data.get("staff_count"))
await self.db.execute( await self.db.execute(
text(""" text("""
SELECT v3.upd_vsp( SELECT v3.upd_vsp(
@ -199,8 +198,7 @@ class VSPRepository:
:p_format, :p_opened_at, :p_placement_type, :p_staff_count, :p_format, :p_opened_at, :p_placement_type, :p_staff_count,
:p_total_area, :p_closed_at, :p_is_active, :p_is_deleted, :p_total_area, :p_closed_at, :p_is_active, :p_is_deleted,
:p_system_code, :p_updated_by, :p_vsp_type, :p_notes, :p_system_code, :p_updated_by, :p_vsp_type, :p_notes,
:p_location_form, :p_numbers, :p_rent_contract_num, :p_location_form, :p_rent_contract_num, :p_rent_end_date
:p_rent_end_date
) )
"""), """),
params, params,

View File

@ -21,7 +21,7 @@ _info_close_sync_lock = asyncio.Lock()
class VSPService: class VSPService:
EXECUTOR_EDITABLE_FIELDS = { EXECUTOR_EDITABLE_FIELDS = {
"location_form", "location_form",
"numbers", "staff_count",
"total_area", "total_area",
"rent_contract_num", "rent_contract_num",
"rent_end_date", "rent_end_date",
@ -55,8 +55,8 @@ class VSPService:
open_date_start: date | None = None, open_date_start: date | None = None,
open_date_end: date | None = None, open_date_end: date | None = None,
location_form: str | None = None, location_form: str | None = None,
numbers_min: int | None = None, staff_count_min: int | None = None,
numbers_max: int | None = None, staff_count_max: int | None = None,
is_active: bool | None = None, is_active: bool | None = None,
load_org_unit: bool = False, load_org_unit: bool = False,
with_count: bool = False, with_count: bool = False,
@ -85,8 +85,8 @@ class VSPService:
open_date_start=open_date_start, open_date_start=open_date_start,
open_date_end=open_date_end, open_date_end=open_date_end,
location_form=location_form, location_form=location_form,
numbers_min=numbers_min, staff_count_min=staff_count_min,
numbers_max=numbers_max, staff_count_max=staff_count_max,
is_active=is_active, is_active=is_active,
load_org_unit=load_org_unit, load_org_unit=load_org_unit,
with_count=with_count, with_count=with_count,
@ -155,8 +155,8 @@ class VSPService:
open_date_start: date | None = None, open_date_start: date | None = None,
open_date_end: date | None = None, open_date_end: date | None = None,
location_form: str | None = None, location_form: str | None = None,
numbers_min: int | None = None, staff_count_min: int | None = None,
numbers_max: int | None = None, staff_count_max: int | None = None,
) -> tuple[io.BytesIO, str]: ) -> tuple[io.BytesIO, str]:
data = await self.get_list( data = await self.get_list(
user=user, user=user,
@ -166,8 +166,8 @@ class VSPService:
open_date_start=open_date_start, open_date_start=open_date_start,
open_date_end=open_date_end, open_date_end=open_date_end,
location_form=location_form, location_form=location_form,
numbers_min=numbers_min, staff_count_min=staff_count_min,
numbers_max=numbers_max, staff_count_max=staff_count_max,
is_active=None, is_active=None,
load_org_unit=True, load_org_unit=True,
) )
@ -189,7 +189,7 @@ class VSPService:
"close_date", "close_date",
"notes", "notes",
"location_form", "location_form",
"numbers", "staff_count",
"area", "area",
"rent_contract_num", "rent_contract_num",
"rent_end_date", "rent_end_date",
@ -216,7 +216,7 @@ class VSPService:
item.closed_at.isoformat() if item.closed_at else None, item.closed_at.isoformat() if item.closed_at else None,
item.notes or None, item.notes or None,
item.location_form or None, item.location_form or None,
item.numbers if item.numbers is not None else None, item.staff_count if item.staff_count is not None else None,
float(item.total_area) if item.total_area is not None else None, float(item.total_area) if item.total_area is not None else None,
item.rent_contract_num or None, item.rent_contract_num or None,
item.rent_end_date.isoformat() if item.rent_end_date else None, item.rent_end_date.isoformat() if item.rent_end_date else None,

View File

@ -111,7 +111,7 @@ def test_vsp_create_with_all_fields(client, admin_tokens, auth_headers):
"approved_format": "Стандарт", "approved_format": "Стандарт",
"notes": "Тестовое примечание", "notes": "Тестовое примечание",
"location_form": "Встроенное", "location_form": "Встроенное",
"numbers": 10, "staff_count": 10,
"area": 150.5, "area": 150.5,
"rent_contract_num": "Д-123/24", "rent_contract_num": "Д-123/24",
"rent_end_date": "2025-12-31", "rent_end_date": "2025-12-31",
@ -128,7 +128,7 @@ def test_vsp_create_with_all_fields(client, admin_tokens, auth_headers):
assert payload["result"]["close_date"] == "2025-12-31" assert payload["result"]["close_date"] == "2025-12-31"
assert payload["result"]["approved_format"] == "Стандарт" assert payload["result"]["approved_format"] == "Стандарт"
assert payload["result"]["location_form"] == "Встроенное" assert payload["result"]["location_form"] == "Встроенное"
assert payload["result"]["numbers"] == 10 assert payload["result"]["staff_count"] == 10
assert payload["result"]["area"] == 150.5 assert payload["result"]["area"] == 150.5
assert payload["result"]["rent_contract_num"] == "Д-123/24" assert payload["result"]["rent_contract_num"] == "Д-123/24"
assert payload["result"]["rent_end_date"] == "2025-12-31" assert payload["result"]["rent_end_date"] == "2025-12-31"