Fix: Recipe was crashing the whole thing

This commit is contained in:
2021-11-02 16:39:15 +05:30
parent 5e66db381b
commit 4df8c916ab
5 changed files with 92 additions and 47 deletions

View File

@ -0,0 +1,55 @@
"""recipe
Revision ID: 0e6c5953a63f
Revises: c39eb451a683
Create Date: 2021-11-01 12:11:16.813756
"""
import sqlalchemy as sa
from alembic import op
from sqlalchemy import column, func, table, text
from sqlalchemy.dialects import postgresql
# revision identifiers, used by Alembic.
revision = "0e6c5953a63f"
down_revision = "c39eb451a683"
branch_labels = None
depends_on = None
def upgrade():
# ### commands auto generated by Alembic - please adjust! ###
op.alter_column("recipes", "product_id", new_column_name="sku_id")
op.alter_column("recipes", "valid_to", new_column_name="valid_till", existing_type=sa.DATE(), nullable=True)
op.alter_column("recipes", "valid_from", existing_type=sa.DATE(), nullable=True)
op.drop_constraint("recipes_product_id_fkey", "recipes", type_="foreignkey")
op.create_foreign_key(
op.f("fk_recipes_sku_id_stock_keeping_units"), "recipes", "stock_keeping_units", ["sku_id"], ["id"]
)
op.drop_column("recipes", "effective_to")
op.drop_column("recipes", "effective_from")
recipe = table(
"recipes",
column("sku_id", postgresql.UUID(as_uuid=True)),
column("valid_from", sa.Date()),
column("valid_till", sa.Date()),
)
op.create_exclude_constraint(
"uq_recipes_sku_id",
"recipes",
(recipe.c.sku_id, "="),
(func.daterange(recipe.c.valid_from, recipe.c.valid_till, text("'[]'")), "&&"),
)
# ### end Alembic commands ###
# delete from recipe_items where recipe_id in (select id from recipes where product_id in (select product_id from recipes group by product_id having count(*) > 1) and effective_to is not null);
# delete from recipes where id in (select id from recipes where product_id in (select product_id from recipes group by product_id having count(*) > 1) and effective_to is not null);
def downgrade():
pass

View File

@ -1,7 +1,5 @@
import uuid import uuid
from datetime import date
from sqlalchemy import Column, Date, ForeignKey, Numeric, Unicode from sqlalchemy import Column, Date, ForeignKey, Numeric, Unicode
from sqlalchemy.dialects.postgresql import UUID from sqlalchemy.dialects.postgresql import UUID
from sqlalchemy.orm import relationship from sqlalchemy.orm import relationship
@ -13,7 +11,7 @@ class Recipe(Base):
__tablename__ = "recipes" __tablename__ = "recipes"
id = Column("id", UUID(as_uuid=True), primary_key=True, default=uuid.uuid4) id = Column("id", UUID(as_uuid=True), primary_key=True, default=uuid.uuid4)
product_id = Column("product_id", UUID(as_uuid=True), ForeignKey("products.id"), nullable=False) sku_id = Column("sku_id", UUID(as_uuid=True), ForeignKey("stock_keeping_units.id"), nullable=False)
quantity = Column("quantity", Numeric(precision=15, scale=2), nullable=False) quantity = Column("quantity", Numeric(precision=15, scale=2), nullable=False)
cost_price = Column("cost_price", Numeric(precision=15, scale=2), nullable=False) cost_price = Column("cost_price", Numeric(precision=15, scale=2), nullable=False)
@ -23,31 +21,25 @@ class Recipe(Base):
valid_from = Column("valid_from", Date, nullable=True) valid_from = Column("valid_from", Date, nullable=True)
valid_till = Column("valid_till", Date, nullable=True) valid_till = Column("valid_till", Date, nullable=True)
effective_from = Column("effective_from", Date, nullable=False) items = relationship("RecipeItem", back_populates="recipe")
effective_to = Column("effective_to", Date) sku = relationship("StockKeepingUnit", back_populates="recipes")
recipe_items = relationship("RecipeItem", backref="recipe")
product = relationship("Product", back_populates="recipes")
def __init__( def __init__(
self, self,
product_id=None, sku_id=None,
quantity=None, quantity=None,
cost_price=None, cost_price=None,
sale_price=None, sale_price=None,
valid_from=None, valid_from=None,
valid_till=None, valid_till=None,
notes=None, notes=None,
effective_from=None,
id_=None, id_=None,
): ):
self.product_id = product_id self.sku_id = sku_id
self.quantity = quantity self.quantity = quantity
self.cost_price = cost_price self.cost_price = cost_price
self.sale_price = sale_price self.sale_price = sale_price
self.valid_from = valid_from self.valid_from = valid_from
self.valid_till = valid_till self.valid_till = valid_till
self.notes = "" if notes is None else notes self.notes = "" if notes is None else notes
self.effective_from = date.today() if effective_from is None else effective_from
self.effective_to = None
self.id = id_ self.id = id_

View File

@ -17,11 +17,17 @@ class RecipeItem(Base):
quantity = Column("quantity", Integer, nullable=False) quantity = Column("quantity", Integer, nullable=False)
price = Column("price", Integer, nullable=False) price = Column("price", Integer, nullable=False)
recipe = relationship("Recipe", back_populates="items")
product = relationship("Product") product = relationship("Product")
def __init__(self, recipe_id=None, product_id=None, quantity=None, price=None, id_=None): def __init__(self, recipe_id=None, product_id=None, quantity=None, price=None, recipe=None, id_=None):
self.recipe_id = recipe_id self.recipe_id = recipe_id
self.product_id = product_id self.product_id = product_id
self.quantity = quantity self.quantity = quantity
self.price = price self.price = price
if recipe is None:
self.recipe_id = recipe_id
else:
self.recipe_id = recipe.id
self.recipe = recipe
self.id = id_ self.id = id_

View File

@ -1,36 +1,14 @@
import uuid import uuid
from datetime import date from datetime import date, datetime
from decimal import Decimal from decimal import Decimal
from typing import List, Optional from typing import List, Optional
from pydantic import BaseModel, Field from pydantic import BaseModel, validator
from . import to_camel from . import to_camel
from .product import ProductLink
from .recipe_item import RecipeItem
class ProductLink(BaseModel):
id_: uuid.UUID = Field(...)
name: Optional[str]
units: Optional[str]
sale_price: Optional[Decimal]
is_sold: Optional[bool]
fraction_units: Optional[str]
fraction: Optional[Decimal]
product_yield: Optional[Decimal]
class Config:
alias_generator = to_camel
class RecipeItem(BaseModel):
id_: Optional[uuid.UUID]
product: ProductLink
quantity: int
price: int
class Config:
fields = {"id_": "id"}
class RecipeIn(BaseModel): class RecipeIn(BaseModel):
@ -44,9 +22,6 @@ class RecipeIn(BaseModel):
valid_from: Optional[date] valid_from: Optional[date]
valid_till: Optional[date] valid_till: Optional[date]
effective_from: Optional[date]
effective_till: Optional[date]
items: List[RecipeItem] items: List[RecipeItem]
class Config: class Config:
@ -54,6 +29,22 @@ class RecipeIn(BaseModel):
alias_generator = to_camel alias_generator = to_camel
json_encoders = {date: lambda v: v.strftime("%d-%b-%Y") if v is not None else None} json_encoders = {date: lambda v: v.strftime("%d-%b-%Y") if v is not None else None}
@validator("valid_from", pre=True)
def parse_valid_from(cls, value):
if isinstance(value, date):
return value
if value is None:
return value
return datetime.strptime(value, "%d-%b-%Y").date()
@validator("valid_till", pre=True)
def parse_valid_till(cls, value):
if isinstance(value, date):
return value
if value is None:
return value
return datetime.strptime(value, "%d-%b-%Y").date()
class Recipe(RecipeIn): class Recipe(RecipeIn):
id_: uuid.UUID id_: uuid.UUID
@ -65,8 +56,9 @@ class Recipe(RecipeIn):
class RecipeBlank(RecipeIn): class RecipeBlank(RecipeIn):
product: Optional[ProductLink] product: Optional[ProductLink] # type: ignore[assignment]
class Config: class Config:
anystr_strip_whitespace = True anystr_strip_whitespace = True
alias_generator = to_camel alias_generator = to_camel
json_encoders = {date: lambda v: v.strftime("%d-%b-%Y")}

View File

@ -1,9 +1,9 @@
import uuid import uuid
from typing import Optional from typing import Optional
from pydantic import BaseModel
from brewman.schemas.product import ProductLink from brewman.schemas.product import ProductLink
from pydantic import BaseModel
class RecipeItem(BaseModel): class RecipeItem(BaseModel):
@ -13,4 +13,4 @@ class RecipeItem(BaseModel):
price: int price: int
class Config: class Config:
fields = {"id_": "id"} fields = {"id_": "id"}