From e2ece2d3989c10a5663dc63b627ed63dbf7339ee Mon Sep 17 00:00:00 2001 From: stuppie Date: Tue, 13 Oct 2026 16:43:02 -0700 Subject: business update model and manager method --- generalresearch/managers/gr/business.py | 29 +++++++++++++++++++++++++++++ generalresearch/models/gr/business.py | 29 ++++++++++++++++++++++++++++- pyproject.toml | 2 +- 3 files changed, 58 insertions(+), 2 deletions(-) diff --git a/generalresearch/managers/gr/business.py b/generalresearch/managers/gr/business.py index 238469c..e59f3d9 100644 --- a/generalresearch/managers/gr/business.py +++ b/generalresearch/managers/gr/business.py @@ -17,6 +17,7 @@ from generalresearch.models.gr.business import ( Business, BusinessBankAccount, BusinessCreate, + BusinessUpdate, ) from generalresearch.models.gr.definitions import BusinessType, TransferMethod @@ -244,6 +245,34 @@ class BusinessManager(PostgresManagerWithRedis): assert persisted_business is not None return persisted_business + def update( + self, + business_id: PositiveInt, + update: BusinessUpdate, + ) -> Business: + data = update.model_dump(exclude_unset=True) + + assignments = sql.SQL(", ").join( + sql.SQL("{} = %s").format(sql.Identifier(field)) for field in data + ) + + query = sql.SQL(""" + UPDATE common_business + SET {assignments} + WHERE id = %s + """).format(assignments=assignments) + + with self.pg_config.make_connection() as conn: + with conn.cursor() as cursor: + cursor.execute(query, [*data.values(), business_id]) + if cursor.rowcount != 1: + raise LookupError(f"Business {business_id} does not exist") + conn.commit() + + business = self.get_by_id(business_id) + assert business is not None + return business + def get_all(self) -> list[Business]: """WARNING: This should be access by the /god/ page only, and only used by GRUser.is_staff as it doesn't provide any authentication diff --git a/generalresearch/models/gr/business.py b/generalresearch/models/gr/business.py index efda584..098b9f7 100644 --- a/generalresearch/models/gr/business.py +++ b/generalresearch/models/gr/business.py @@ -5,7 +5,7 @@ import logging import os from datetime import UTC, datetime from pathlib import Path -from typing import TYPE_CHECKING +from typing import TYPE_CHECKING, Self from uuid import uuid4 import pandas as pd @@ -19,6 +19,8 @@ from pydantic import ( Field, PositiveInt, ValidationError, + field_validator, + model_validator, ) from pydantic.json_schema import SkipJsonSchema from pydantic_extra_types.phone_numbers import PhoneNumber @@ -175,6 +177,31 @@ class BusinessContact(BaseModel): ) +class BusinessUpdate(BaseModel): + model_config = ConfigDict(extra="forbid") + + name: str | None = Field( + min_length=3, + max_length=255, + examples=["General Research Laboratories, LLC"], + default=None, + ) + tax_number: str | None = Field(default=None, max_length=20) + + @field_validator("name") + @classmethod + def name_cannot_be_null(cls, value: str | None) -> str: + if value is None: + raise ValueError("name cannot be null") + return value + + @model_validator(mode="after") + def require_field(self) -> Self: + if not self.model_fields_set: + raise ValueError("Must provide a key to update") + return self + + class BusinessCreate(BaseModel): """This is the Base model to represent a Business,""" diff --git a/pyproject.toml b/pyproject.toml index c9fc83c..f116f7e 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta" [project] name = "generalresearch" -version = "3.8.1" +version = "3.8.2" description = "Python Utilities for General Research" readme = "README.md" requires-python = ">=3.14" -- cgit v1.2.3