diff --git a/.vscode/mcp.json b/.vscode/mcp.json new file mode 100644 index 00000000..956af8c6 --- /dev/null +++ b/.vscode/mcp.json @@ -0,0 +1,9 @@ +{ + // For more information, visit: https://angular.dev/ai/mcp + "servers": { + "angular-cli": { + "command": "npx", + "args": ["-y", "@angular/cli", "mcp"] + } + } +} diff --git a/barker/barker/db/base.py b/barker/barker/db/base.py index 381d4137..7236e1be 100644 --- a/barker/barker/db/base.py +++ b/barker/barker/db/base.py @@ -38,7 +38,7 @@ from ..models.stock_keeping_unit import StockKeepingUnit from ..models.tax import Tax from ..models.user import User from ..models.user_role import UserRole -from ..models.voucher import Voucher # noqa +from ..models.voucher import Voucher from ..models.voucher_type import VoucherType from .base_class import reg diff --git a/barker/barker/routers/product.py b/barker/barker/routers/product.py index 1da9cee3..23ef0278 100644 --- a/barker/barker/routers/product.py +++ b/barker/barker/routers/product.py @@ -32,7 +32,7 @@ from ..schemas.sale_category import SaleCategoryLink from ..schemas.stock_keeping_unit import StockKeepingUnit as StockKeepingUnitSchema from ..schemas.tax import TaxLink from ..schemas.user_token import UserToken -from . import _pv_active, _pv_onclause, _sv_onclause, effective_date +from . import _pv_active, _pv_onclause, _sv_active, _sv_onclause, effective_date router = APIRouter() @@ -117,21 +117,6 @@ def save( def add_modifiers( sku_id: uuid.UUID, product_id: uuid.UUID, menu_category_id: uuid.UUID, date_: date, db: Session ) -> None: - sv_active = and_( - or_(SkuVersion.valid_from == None, SkuVersion.valid_from <= date_), # noqa: E711 - or_(SkuVersion.valid_till == None, SkuVersion.valid_till >= date_), # noqa: E711 - ) - product_version_onclause = and_( - ProductVersion.product_id == Product.id, - or_( - ProductVersion.valid_from == None, # noqa: E711 - ProductVersion.valid_from <= date_, - ), - or_( - ProductVersion.valid_till == None, # noqa: E711 - ProductVersion.valid_till >= date_, - ), - ) # how many DISTINCT products (excluding current product via sku_id) are in this menu category today? products_in_category = db.execute( select(func.count(func.distinct(StockKeepingUnit.product_id))) @@ -139,7 +124,7 @@ def add_modifiers( .join(SkuVersion.sku) # -> StockKeepingUnit .where( and_( - sv_active, + _sv_active(date_), SkuVersion.menu_category_id == menu_category_id, SkuVersion.sku_id != sku_id, ) @@ -152,7 +137,7 @@ def add_modifiers( ModifierCategory.id, ) .select_from(ProductVersion) - .join(Product, onclause=product_version_onclause) + .join(Product, onclause=_pv_onclause(date_)) .join(Product.modifier_categories) .group_by(ModifierCategory.id) ).all() @@ -224,12 +209,16 @@ def update_route( .scalars() .all() ) - for i in range(len(old_svers), 0, -1): sku: SkuVersion = old_svers[i - 1] - index = next((idx for (idx, d) in enumerate(data.skus) if d.id_ == sku.id), None) + index = next((idx for (idx, d) in enumerate(data.skus) if d.version_id == sku.id), None) if index is None: - sku.valid_till = date_ - timedelta(days=1) + if sku.valid_from == date_: + # Created/changed effective today, and now removed in the same request. + # Delete instead of creating an invalid interval. + db.delete(sku) + else: + sku.valid_till = date_ - timedelta(days=1) continue new_data_sku = data.skus.pop(index) sku_changed = ( @@ -285,7 +274,7 @@ def update_route( sku=new_s, ) db.add(new_sku) - db.commit() + db.commit() except SQLAlchemyError as e: raise HTTPException( status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, @@ -301,11 +290,6 @@ def delete_route( ) -> None: with SessionFuture() as db: # Active SkuVersion filter - sv_onclause = and_( - SkuVersion.sku_id == StockKeepingUnit.id, - or_(SkuVersion.valid_from == None, SkuVersion.valid_from <= date_), # noqa: E711 - or_(SkuVersion.valid_till == None, SkuVersion.valid_till >= date_), # noqa: E711 - ) day = func.cast( Voucher.date + timedelta(minutes=settings.TIMEZONE_OFFSET_MINUTES - settings.NEW_DAY_OFFSET_MINUTES), Date ).label("day") @@ -323,19 +307,7 @@ def delete_route( ) pv_active: ProductVersion = db.execute( - select(ProductVersion).where( - and_( - ProductVersion.product_id == id_, - or_( - ProductVersion.valid_from == None, # noqa: E711 - ProductVersion.valid_from <= date_, - ), - or_( - ProductVersion.valid_till == None, # noqa: E711 - ProductVersion.valid_till >= date_, - ), - ) - ) + select(ProductVersion).where(ProductVersion.product_id == id_, _pv_active(date_)) ).scalar_one() if pv_active.valid_from == date_: db.delete(pv_active) @@ -345,7 +317,7 @@ def delete_route( sv_active = ( db.execute( select(SkuVersion) - .join(StockKeepingUnit, onclause=sv_onclause) # -> StockKeepingUnit + .join(StockKeepingUnit, onclause=_sv_onclause(date_)) # -> StockKeepingUnit .where(StockKeepingUnit.product_id == id_) ) .scalars() @@ -374,28 +346,15 @@ def show_list(date_: date = Depends(effective_date), user: UserToken = Depends(g def product_list(date_: date, db: Session) -> list[schemas.Product]: - # Active ProductVersion filter - pv_active = and_( - or_(ProductVersion.valid_from == None, ProductVersion.valid_from <= date_), # noqa: E711 - or_(ProductVersion.valid_till == None, ProductVersion.valid_till >= date_), # noqa: E711 - ) - - # Active SkuVersion filter - sv_onclause = and_( - SkuVersion.sku_id == StockKeepingUnit.id, - or_(SkuVersion.valid_from == None, SkuVersion.valid_from <= date_), # noqa: E711 - or_(SkuVersion.valid_till == None, SkuVersion.valid_till >= date_), # noqa: E711 - ) - rows = ( db.execute( select(ProductVersion) .join(ProductVersion.sale_category) # ProductVersion has sale_category .join(ProductVersion.product) .join(Product.skus) - .join(SkuVersion, sv_onclause) + .join(SkuVersion, onclause=_sv_onclause(date_)) .join(SkuVersion.menu_category) # Menu category lives here - .where(pv_active) + .where(_pv_active(date_)) .order_by( MenuCategory.sort_order, MenuCategory.name, @@ -605,6 +564,7 @@ def product_info(version: ProductVersion) -> schemas.Product: skus=[ StockKeepingUnitSchema( id_=sku.id, + version_id=sku_version.id, units=sku_version.units, fraction=sku_version.fraction, product_yield=sku_version.product_yield, diff --git a/barker/barker/schemas/guest_book.py b/barker/barker/schemas/guest_book.py index 2e7eb0fc..32cf54b6 100644 --- a/barker/barker/schemas/guest_book.py +++ b/barker/barker/schemas/guest_book.py @@ -56,7 +56,7 @@ class GuestBookIn(BaseModel): return None if value is None else value.strftime("%d-%b-%Y %H:%M") @model_validator(mode="after") - def nulls(self) -> "GuestBookIn": + def nulls(self) -> GuestBookIn: if self.arrival_date is None and self.booking_date is None: raise ValueError("Both arrival and booking date cannot be null") return self diff --git a/barker/barker/schemas/voucher.py b/barker/barker/schemas/voucher.py index ae40eae4..45e8383f 100644 --- a/barker/barker/schemas/voucher.py +++ b/barker/barker/schemas/voucher.py @@ -26,7 +26,7 @@ class Inventory(BaseModel): tax_rate: Daf | None = None discount: Annotated[Daf, Field(ge=0, le=1)] modifiers: list[ModifierLink] - children: Annotated[list["Inventory"], Field(default_factory=list)] + children: Annotated[list[Inventory], Field(default_factory=list)] amount: Daf | None = None model_config = ConfigDict(alias_generator=to_camel, populate_by_name=True) @@ -59,7 +59,7 @@ class Inventory(BaseModel): return round(value, 5) @model_validator(mode="after") - def calculate_amount(self) -> "Inventory": + def calculate_amount(self) -> Inventory: price = Decimal(0) if self.is_happy_hour else (self.price or Decimal(0)) self.amount = round( Decimal(price * self.quantity * (1 - self.discount) * (1 + (self.tax_rate or Decimal(0)))), diff --git a/barker/barker/schemas/voucher_out.py b/barker/barker/schemas/voucher_out.py index 3ed3d12c..556f061d 100644 --- a/barker/barker/schemas/voucher_out.py +++ b/barker/barker/schemas/voucher_out.py @@ -50,7 +50,7 @@ class Inventory(BaseModel): is_happy_hour: bool type_: InventoryType parent_id: uuid.UUID | None = None - children: Annotated[list["Inventory"], Field(default_factory=list)] + children: Annotated[list[Inventory], Field(default_factory=list)] modifiers: list[ModifierLink] amount: Daf | None = None model_config = ConfigDict(alias_generator=to_camel, populate_by_name=True) @@ -84,7 +84,7 @@ class Inventory(BaseModel): return round(value, 5) @model_validator(mode="after") - def calculate_amount(self) -> "Inventory": + def calculate_amount(self) -> Inventory: price = Decimal(0) if self.is_happy_hour else (self.price or Decimal(0)) self.amount = round( ( diff --git a/barker/pyproject.toml b/barker/pyproject.toml index 6902c75e..cb21699d 100644 --- a/barker/pyproject.toml +++ b/barker/pyproject.toml @@ -36,8 +36,8 @@ build-backend = "poetry.core.masonry.api" [tool.ruff] line-length = 120 -# Assume Python 3.13. -target-version = "py313" +# Assume Python 3.14. +target-version = "py314" exclude = [ ".eggs", ".git",