Fix: Deleting voucher fucked up due to cascading changes was not
This commit is contained in:
1 parent
3d5d02a416
commit
952f030e8d
20 files changed
+248
-165
No files matched your search
@@ -0,0 +1,41 @@
|
|||||||
|
"""recipe yield
|
||||||
|
|
||||||
|
Revision ID: b13dbf97bd21
|
||||||
|
Revises: 0e6c5953a63f
|
||||||
|
Create Date: 2021-11-08 11:51:07.061978
|
||||||
|
|
||||||
|
"""
|
||||||
|
import sqlalchemy as sa
|
||||||
|
|
||||||
|
from alembic import op
|
||||||
|
|
||||||
|
|
||||||
|
# revision identifiers, used by Alembic.
|
||||||
|
revision = "b13dbf97bd21"
|
||||||
|
down_revision = "0e6c5953a63f"
|
||||||
|
branch_labels = None
|
||||||
|
depends_on = None
|
||||||
|
|
||||||
|
|
||||||
|
def upgrade():
|
||||||
|
# ### commands auto generated by Alembic - please adjust! ###
|
||||||
|
op.alter_column("recipes", "quantity", new_column_name="recipe_yield")
|
||||||
|
op.alter_column(
|
||||||
|
"recipe_items",
|
||||||
|
"quantity",
|
||||||
|
existing_type=sa.INTEGER(),
|
||||||
|
type_=sa.Numeric(precision=15, scale=2),
|
||||||
|
existing_nullable=False,
|
||||||
|
)
|
||||||
|
op.alter_column(
|
||||||
|
"recipe_items",
|
||||||
|
"price",
|
||||||
|
existing_type=sa.INTEGER(),
|
||||||
|
type_=sa.Numeric(precision=15, scale=5),
|
||||||
|
existing_nullable=False,
|
||||||
|
)
|
||||||
|
# ### end Alembic commands ###
|
||||||
|
|
||||||
|
|
||||||
|
def downgrade():
|
||||||
|
pass
|
||||||
@@ -58,23 +58,6 @@ class Batch(Base):
|
|||||||
def amount(self):
|
def amount(self):
|
||||||
return self.quantity_remaining * self.rate * (1 + self.tax) * (1 - self.discount)
|
return self.quantity_remaining * self.rate * (1 + self.tax) * (1 - self.discount)
|
||||||
|
|
||||||
@classmethod
|
|
||||||
def list(cls, q: str, include_nil: bool, date_: Optional[date], db: Session):
|
|
||||||
query = (
|
|
||||||
select(cls)
|
|
||||||
.join(cls.sku)
|
|
||||||
.join(StockKeepingUnit.product)
|
|
||||||
.options(contains_eager(cls.sku).contains_eager(StockKeepingUnit.product))
|
|
||||||
)
|
|
||||||
if not include_nil:
|
|
||||||
query = query.where(cls.quantity_remaining > 0)
|
|
||||||
if date_ is not None:
|
|
||||||
query = query.where(cls.name <= date_)
|
|
||||||
if q is not None:
|
|
||||||
for item in q.split():
|
|
||||||
query = query.where(Product.name.ilike(f"%{item}%"))
|
|
||||||
return db.execute(query.order_by(Product.name).order_by(cls.name)).scalars().all()
|
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def suspense(cls):
|
def suspense(cls):
|
||||||
return uuid.UUID("a955790e-93cf-493c-a816-c7d92b127383")
|
return uuid.UUID("a955790e-93cf-493c-a816-c7d92b127383")
|
||||||
@@ -1,33 +1,44 @@
|
|||||||
|
import datetime
|
||||||
import uuid
|
import uuid
|
||||||
|
|
||||||
|
from decimal import Decimal
|
||||||
|
from typing import TYPE_CHECKING, List
|
||||||
|
|
||||||
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 Mapped, relationship
|
||||||
|
|
||||||
from .meta import Base
|
from .meta import Base
|
||||||
|
|
||||||
|
|
||||||
|
if TYPE_CHECKING:
|
||||||
|
# if the target of the relationship is in another module
|
||||||
|
# that cannot normally be imported at runtime
|
||||||
|
from .recipe_item import RecipeItem
|
||||||
|
from .stock_keeping_unit import StockKeepingUnit
|
||||||
|
|
||||||
|
|
||||||
class Recipe(Base):
|
class Recipe(Base):
|
||||||
__tablename__ = "recipes"
|
__tablename__ = "recipes"
|
||||||
|
|
||||||
id = Column("id", UUID(as_uuid=True), primary_key=True, default=uuid.uuid4)
|
id: uuid.UUID = Column("id", UUID(as_uuid=True), primary_key=True, default=uuid.uuid4)
|
||||||
sku_id = Column("sku_id", UUID(as_uuid=True), ForeignKey("stock_keeping_units.id"), nullable=False)
|
sku_id: uuid.UUID = Column("sku_id", UUID(as_uuid=True), ForeignKey("stock_keeping_units.id"), nullable=False)
|
||||||
|
|
||||||
quantity = Column("quantity", Numeric(precision=15, scale=2), nullable=False)
|
recipe_yield: Decimal = Column("recipe_yield", Numeric(precision=15, scale=2), nullable=False)
|
||||||
cost_price = Column("cost_price", Numeric(precision=15, scale=2), nullable=False)
|
cost_price: Decimal = Column("cost_price", Numeric(precision=15, scale=2), nullable=False)
|
||||||
sale_price = Column("sale_price", Numeric(precision=15, scale=2), nullable=False)
|
sale_price: Decimal = Column("sale_price", Numeric(precision=15, scale=2), nullable=False)
|
||||||
notes = Column("notes", Unicode(255))
|
notes: str = Column("notes", Unicode(255))
|
||||||
|
|
||||||
valid_from = Column("valid_from", Date, nullable=True)
|
valid_from: datetime.date = Column("valid_from", Date, nullable=True)
|
||||||
valid_till = Column("valid_till", Date, nullable=True)
|
valid_till: datetime.date = Column("valid_till", Date, nullable=True)
|
||||||
|
|
||||||
items = relationship("RecipeItem", back_populates="recipe")
|
items: List["RecipeItem"] = relationship("RecipeItem", back_populates="recipe")
|
||||||
sku = relationship("StockKeepingUnit", back_populates="recipes")
|
sku: Mapped["StockKeepingUnit"] = relationship("StockKeepingUnit", back_populates="recipes")
|
||||||
|
|
||||||
def __init__(
|
def __init__(
|
||||||
self,
|
self,
|
||||||
sku_id=None,
|
sku_id=None,
|
||||||
quantity=None,
|
recipe_yield=None,
|
||||||
cost_price=None,
|
cost_price=None,
|
||||||
sale_price=None,
|
sale_price=None,
|
||||||
valid_from=None,
|
valid_from=None,
|
||||||
@@ -36,7 +47,7 @@ class Recipe(Base):
|
|||||||
id_=None,
|
id_=None,
|
||||||
):
|
):
|
||||||
self.sku_id = sku_id
|
self.sku_id = sku_id
|
||||||
self.quantity = quantity
|
self.recipe_yield = recipe_yield
|
||||||
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
|
||||||
|
|||||||
@@ -1,24 +1,33 @@
|
|||||||
import uuid
|
import uuid
|
||||||
|
|
||||||
from sqlalchemy import Column, ForeignKey, Integer, UniqueConstraint
|
from typing import TYPE_CHECKING
|
||||||
|
|
||||||
|
from sqlalchemy import Column, ForeignKey, Integer, Numeric, UniqueConstraint
|
||||||
from sqlalchemy.dialects.postgresql import UUID
|
from sqlalchemy.dialects.postgresql import UUID
|
||||||
from sqlalchemy.orm import relationship
|
from sqlalchemy.orm import Mapped, relationship
|
||||||
|
|
||||||
from .meta import Base
|
from .meta import Base
|
||||||
|
|
||||||
|
|
||||||
|
if TYPE_CHECKING:
|
||||||
|
# if the target of the relationship is in another module
|
||||||
|
# that cannot normally be imported at runtime
|
||||||
|
from .product import Product
|
||||||
|
from .recipe import Recipe
|
||||||
|
|
||||||
|
|
||||||
class RecipeItem(Base):
|
class RecipeItem(Base):
|
||||||
__tablename__ = "recipe_items"
|
__tablename__ = "recipe_items"
|
||||||
__table_args__ = (UniqueConstraint("recipe_id", "product_id"),)
|
__table_args__ = (UniqueConstraint("recipe_id", "product_id"),)
|
||||||
|
|
||||||
id = Column("recipe_item_id", UUID(as_uuid=True), primary_key=True, default=uuid.uuid4)
|
id: uuid.UUID = Column("recipe_item_id", UUID(as_uuid=True), primary_key=True, default=uuid.uuid4)
|
||||||
recipe_id = Column("recipe_id", UUID(as_uuid=True), ForeignKey("recipes.id"), nullable=False)
|
recipe_id: uuid.UUID = Column("recipe_id", UUID(as_uuid=True), ForeignKey("recipes.id"), nullable=False)
|
||||||
product_id = Column("product_id", UUID(as_uuid=True), ForeignKey("products.id"), nullable=False)
|
product_id: uuid.UUID = Column("product_id", UUID(as_uuid=True), ForeignKey("products.id"), nullable=False)
|
||||||
quantity = Column("quantity", Integer, nullable=False)
|
quantity: int = Column("quantity", Numeric(precision=15, scale=2), nullable=False)
|
||||||
price = Column("price", Integer, nullable=False)
|
price: int = Column("price", Numeric(precision=15, scale=5), nullable=False)
|
||||||
|
|
||||||
recipe = relationship("Recipe", back_populates="items")
|
recipe: Mapped["Recipe"] = relationship("Recipe", back_populates="items")
|
||||||
product = relationship("Product")
|
product: Mapped["Product"] = relationship("Product")
|
||||||
|
|
||||||
def __init__(self, recipe_id=None, product_id=None, quantity=None, price=None, recipe=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
|
||||||
|
|||||||
@@ -40,11 +40,15 @@ class Voucher(Base):
|
|||||||
user: Mapped["User"] = relationship("User", primaryjoin="User.id==Voucher.user_id")
|
user: Mapped["User"] = relationship("User", primaryjoin="User.id==Voucher.user_id")
|
||||||
poster: Mapped["User"] = relationship("User", primaryjoin="User.id==Voucher.poster_id")
|
poster: Mapped["User"] = relationship("User", primaryjoin="User.id==Voucher.poster_id")
|
||||||
|
|
||||||
journals: List["Journal"] = relationship("Journal", back_populates="voucher")
|
journals: List["Journal"] = relationship("Journal", cascade="delete, delete-orphan", back_populates="voucher")
|
||||||
|
|
||||||
inventories: List["Inventory"] = relationship("Inventory", back_populates="voucher")
|
inventories: List["Inventory"] = relationship(
|
||||||
employee_benefits: List["EmployeeBenefit"] = relationship("EmployeeBenefit", backref="voucher")
|
"Inventory", cascade="delete, delete-orphan", back_populates="voucher"
|
||||||
incentives: List["Incentive"] = relationship("Incentive", backref="voucher")
|
)
|
||||||
|
employee_benefits: List["EmployeeBenefit"] = relationship(
|
||||||
|
"EmployeeBenefit", cascade="delete, delete-orphan", backref="voucher"
|
||||||
|
)
|
||||||
|
incentives: List["Incentive"] = relationship("Incentive", cascade="delete, delete-orphan", backref="voucher")
|
||||||
|
|
||||||
def __init__(
|
def __init__(
|
||||||
self,
|
self,
|
||||||
|
|||||||
@@ -1,10 +1,14 @@
|
|||||||
import datetime
|
import datetime
|
||||||
|
|
||||||
from fastapi import APIRouter, Depends
|
from fastapi import APIRouter, Depends
|
||||||
|
from sqlalchemy import select
|
||||||
|
from sqlalchemy.orm import contains_eager
|
||||||
|
|
||||||
from ..core.security import get_current_active_user as get_user
|
from ..core.security import get_current_active_user as get_user
|
||||||
from ..db.session import SessionFuture
|
from ..db.session import SessionFuture
|
||||||
from ..models.batch import Batch
|
from ..models.batch import Batch
|
||||||
|
from ..models.product import Product
|
||||||
|
from ..models.stock_keeping_unit import StockKeepingUnit
|
||||||
from ..schemas.user import UserToken
|
from ..schemas.user import UserToken
|
||||||
|
|
||||||
|
|
||||||
@@ -14,13 +18,25 @@ router = APIRouter()
|
|||||||
@router.get("")
|
@router.get("")
|
||||||
def batch_term(
|
def batch_term(
|
||||||
q: str,
|
q: str,
|
||||||
d: str = None,
|
d: str,
|
||||||
current_user: UserToken = Depends(get_user),
|
current_user: UserToken = Depends(get_user),
|
||||||
):
|
):
|
||||||
date_ = None if not d else datetime.datetime.strptime(d, "%d-%b-%Y")
|
date_ = datetime.datetime.strptime(d, "%d-%b-%Y")
|
||||||
list_ = []
|
list_ = []
|
||||||
with SessionFuture() as db:
|
with SessionFuture() as db:
|
||||||
for item in Batch.list(q, include_nil=False, date_=date_, db=db):
|
query = (
|
||||||
|
select(Batch)
|
||||||
|
.join(Batch.sku)
|
||||||
|
.join(StockKeepingUnit.product)
|
||||||
|
.where(Batch.quantity_remaining > 0, Batch.name <= date_)
|
||||||
|
.options(contains_eager(Batch.sku).contains_eager(StockKeepingUnit.product))
|
||||||
|
)
|
||||||
|
if q is not None:
|
||||||
|
for item in q.split():
|
||||||
|
query = query.where(Product.name.ilike(f"%{item}%"))
|
||||||
|
result = db.execute(query.order_by(Product.name).order_by(Batch.name)).scalars().all()
|
||||||
|
|
||||||
|
for item in result:
|
||||||
text = (
|
text = (
|
||||||
f"{item.sku.product.name} ({item.sku.units}) {item.quantity_remaining:.2f}@"
|
f"{item.sku.product.name} ({item.sku.units}) {item.quantity_remaining:.2f}@"
|
||||||
f"{item.rate:.2f} from {item.name.strftime('%d-%b-%Y')}"
|
f"{item.rate:.2f} from {item.name.strftime('%d-%b-%Y')}"
|
||||||
|
|||||||
@@ -22,6 +22,7 @@ from ..models.journal import Journal
|
|||||||
from ..models.validations import check_journals_are_valid
|
from ..models.validations import check_journals_are_valid
|
||||||
from ..models.voucher import Voucher
|
from ..models.voucher import Voucher
|
||||||
from ..models.voucher_type import VoucherType
|
from ..models.voucher_type import VoucherType
|
||||||
|
from ..schemas.blank_voucher_info import BlankVoucherInfo
|
||||||
from ..schemas.employee_benefit import EmployeeBenefit as EmployeeBenefitSchema
|
from ..schemas.employee_benefit import EmployeeBenefit as EmployeeBenefitSchema
|
||||||
from ..schemas.user import UserToken
|
from ..schemas.user import UserToken
|
||||||
from . import get_lock_info
|
from . import get_lock_info
|
||||||
@@ -255,7 +256,7 @@ def show_blank(
|
|||||||
request: Request,
|
request: Request,
|
||||||
user: UserToken = Security(get_user, scopes=["employee-benefit"]),
|
user: UserToken = Security(get_user, scopes=["employee-benefit"]),
|
||||||
):
|
):
|
||||||
additional_info = {"date": get_date(request.session), "type": VoucherType.EMPLOYEE_BENEFIT}
|
additional_info = BlankVoucherInfo(date=get_date(request.session), type=VoucherType.EMPLOYEE_BENEFIT)
|
||||||
with SessionFuture() as db:
|
with SessionFuture() as db:
|
||||||
return blank_voucher(additional_info, db)
|
return blank_voucher(additional_info, db)
|
||||||
|
|
||||||
|
|||||||
@@ -25,6 +25,7 @@ from ..models.journal import Journal
|
|||||||
from ..models.validations import check_journals_are_valid
|
from ..models.validations import check_journals_are_valid
|
||||||
from ..models.voucher import Voucher
|
from ..models.voucher import Voucher
|
||||||
from ..models.voucher_type import VoucherType
|
from ..models.voucher_type import VoucherType
|
||||||
|
from ..schemas.blank_voucher_info import BlankVoucherInfo
|
||||||
from ..schemas.incentive import Incentive as IncentiveSchema
|
from ..schemas.incentive import Incentive as IncentiveSchema
|
||||||
from ..schemas.user import UserToken
|
from ..schemas.user import UserToken
|
||||||
from . import get_lock_info
|
from . import get_lock_info
|
||||||
@@ -208,7 +209,7 @@ def show_blank(
|
|||||||
d: str = None,
|
d: str = None,
|
||||||
user: UserToken = Security(get_user, scopes=["incentive"]),
|
user: UserToken = Security(get_user, scopes=["incentive"]),
|
||||||
):
|
):
|
||||||
additional_info = {"date": d or get_date(request.session), "type": VoucherType.INCENTIVE}
|
additional_info = BlankVoucherInfo(date=d or get_date(request.session), type=VoucherType.INCENTIVE)
|
||||||
with SessionFuture() as db:
|
with SessionFuture() as db:
|
||||||
return blank_voucher(additional_info, db)
|
return blank_voucher(additional_info, db)
|
||||||
|
|
||||||
|
|||||||
@@ -25,6 +25,8 @@ from ..models.stock_keeping_unit import StockKeepingUnit
|
|||||||
from ..models.validations import check_inventories_are_valid, check_journals_are_valid
|
from ..models.validations import check_inventories_are_valid, check_journals_are_valid
|
||||||
from ..models.voucher import Voucher
|
from ..models.voucher import Voucher
|
||||||
from ..models.voucher_type import VoucherType
|
from ..models.voucher_type import VoucherType
|
||||||
|
from ..schemas.blank_voucher_info import BlankVoucherInfo
|
||||||
|
from ..schemas.cost_centre import CostCentreLink
|
||||||
from ..schemas.inventory import Inventory as InventorySchema
|
from ..schemas.inventory import Inventory as InventorySchema
|
||||||
from ..schemas.user import UserToken
|
from ..schemas.user import UserToken
|
||||||
from . import get_lock_info
|
from . import get_lock_info
|
||||||
@@ -381,15 +383,15 @@ def get_id(
|
|||||||
def show_blank(
|
def show_blank(
|
||||||
request: Request,
|
request: Request,
|
||||||
date: str = None,
|
date: str = None,
|
||||||
source: str = None,
|
source: uuid.UUID = None,
|
||||||
destination: str = None,
|
destination: uuid.UUID = None,
|
||||||
user: UserToken = Security(get_user, scopes=["issue"]),
|
user: UserToken = Security(get_user, scopes=["issue"]),
|
||||||
) -> output.Voucher:
|
) -> output.Voucher:
|
||||||
date_ = date or get_date(request.session)
|
date_ = date or get_date(request.session)
|
||||||
additional_info = {"date": date_, "type": VoucherType.ISSUE}
|
additional_info = BlankVoucherInfo(date=date_, type=VoucherType.ISSUE)
|
||||||
if source:
|
if source:
|
||||||
additional_info["source"] = source
|
additional_info.source = CostCentreLink(id=source, name="")
|
||||||
if destination:
|
if destination:
|
||||||
additional_info["destination"] = destination
|
additional_info.destination = CostCentreLink(id=destination, name="")
|
||||||
with SessionFuture() as db:
|
with SessionFuture() as db:
|
||||||
return blank_voucher(additional_info, db)
|
return blank_voucher(additional_info, db)
|
||||||
@@ -19,6 +19,8 @@ from ..models.journal import Journal
|
|||||||
from ..models.validations import check_journals_are_valid
|
from ..models.validations import check_journals_are_valid
|
||||||
from ..models.voucher import Voucher
|
from ..models.voucher import Voucher
|
||||||
from ..models.voucher_type import VoucherType
|
from ..models.voucher_type import VoucherType
|
||||||
|
from ..schemas.account import AccountLink
|
||||||
|
from ..schemas.blank_voucher_info import BlankVoucherInfo
|
||||||
from ..schemas.user import UserToken
|
from ..schemas.user import UserToken
|
||||||
from . import get_lock_info
|
from . import get_lock_info
|
||||||
from .db_image import save_files, update_files
|
from .db_image import save_files, update_files
|
||||||
@@ -188,7 +190,7 @@ def get_id(
|
|||||||
@router.get("", response_model=output.Voucher)
|
@router.get("", response_model=output.Voucher)
|
||||||
def show_blank(
|
def show_blank(
|
||||||
request: Request,
|
request: Request,
|
||||||
a: str = None,
|
a: uuid.UUID = None,
|
||||||
user: UserToken = Security(get_user, scopes=["journal"]),
|
user: UserToken = Security(get_user, scopes=["journal"]),
|
||||||
) -> output.Voucher:
|
) -> output.Voucher:
|
||||||
if request.scope.get("path") == "/api/payment":
|
if request.scope.get("path") == "/api/payment":
|
||||||
@@ -198,8 +200,8 @@ def show_blank(
|
|||||||
else:
|
else:
|
||||||
type_ = VoucherType.JOURNAL
|
type_ = VoucherType.JOURNAL
|
||||||
|
|
||||||
additional_info = {"date": get_date(request.session), "type": type_}
|
additional_info = BlankVoucherInfo(date=get_date(request.session), type=type_)
|
||||||
if a:
|
if a:
|
||||||
additional_info["account"] = a
|
additional_info.ac = AccountLink(id=a)
|
||||||
with SessionFuture() as db:
|
with SessionFuture() as db:
|
||||||
return blank_voucher(additional_info, db)
|
return blank_voucher(additional_info, db)
|
||||||
@@ -216,8 +216,6 @@ async def show_term_sku(
|
|||||||
fractionUnits=item.fraction_units,
|
fractionUnits=item.fraction_units,
|
||||||
costPrice=sku.cost_price if rc_price is None else rc_price,
|
costPrice=sku.cost_price if rc_price is None else rc_price,
|
||||||
salePrice=sku.sale_price,
|
salePrice=sku.sale_price,
|
||||||
fraction=sku.fraction,
|
|
||||||
productYield=sku.product_yield,
|
|
||||||
isRateContracted=False if rc_price is None else True,
|
isRateContracted=False if rc_price is None else True,
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
@@ -252,8 +250,6 @@ async def show_term_product(
|
|||||||
fractionUnits=item.fraction_units,
|
fractionUnits=item.fraction_units,
|
||||||
costPrice=0,
|
costPrice=0,
|
||||||
salePrice=0,
|
salePrice=0,
|
||||||
fraction=1,
|
|
||||||
productYield=1,
|
|
||||||
isRateContracted=False,
|
isRateContracted=False,
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -26,6 +26,7 @@ from ..models.stock_keeping_unit import StockKeepingUnit
|
|||||||
from ..models.validations import check_inventories_are_valid, check_journals_are_valid
|
from ..models.validations import check_inventories_are_valid, check_journals_are_valid
|
||||||
from ..models.voucher import Voucher
|
from ..models.voucher import Voucher
|
||||||
from ..models.voucher_type import VoucherType
|
from ..models.voucher_type import VoucherType
|
||||||
|
from ..schemas.blank_voucher_info import BlankVoucherInfo
|
||||||
from ..schemas.inventory import Inventory as InventorySchema
|
from ..schemas.inventory import Inventory as InventorySchema
|
||||||
from ..schemas.user import UserToken
|
from ..schemas.user import UserToken
|
||||||
from . import get_lock_info
|
from . import get_lock_info
|
||||||
@@ -363,7 +364,7 @@ def show_blank(
|
|||||||
request: Request,
|
request: Request,
|
||||||
user: UserToken = Security(get_user, scopes=["purchase"]),
|
user: UserToken = Security(get_user, scopes=["purchase"]),
|
||||||
) -> output.Voucher:
|
) -> output.Voucher:
|
||||||
additional_info = {"date": get_date(request.session), "type": VoucherType.PURCHASE}
|
additional_info = BlankVoucherInfo(date=get_date(request.session), type=VoucherType.PURCHASE)
|
||||||
with SessionFuture() as db:
|
with SessionFuture() as db:
|
||||||
return blank_voucher(additional_info, db)
|
return blank_voucher(additional_info, db)
|
||||||
|
|
||||||
|
|||||||
@@ -23,6 +23,7 @@ from ..models.stock_keeping_unit import StockKeepingUnit
|
|||||||
from ..models.validations import check_inventories_are_valid, check_journals_are_valid
|
from ..models.validations import check_inventories_are_valid, check_journals_are_valid
|
||||||
from ..models.voucher import Voucher
|
from ..models.voucher import Voucher
|
||||||
from ..models.voucher_type import VoucherType
|
from ..models.voucher_type import VoucherType
|
||||||
|
from ..schemas.blank_voucher_info import BlankVoucherInfo
|
||||||
from ..schemas.inventory import Inventory as InventorySchema
|
from ..schemas.inventory import Inventory as InventorySchema
|
||||||
from ..schemas.user import UserToken
|
from ..schemas.user import UserToken
|
||||||
from . import get_lock_info
|
from . import get_lock_info
|
||||||
@@ -329,6 +330,6 @@ def show_blank(
|
|||||||
request: Request,
|
request: Request,
|
||||||
user: UserToken = Security(get_user, scopes=["purchase-return"]),
|
user: UserToken = Security(get_user, scopes=["purchase-return"]),
|
||||||
) -> output.Voucher:
|
) -> output.Voucher:
|
||||||
additional_info = {"date": get_date(request.session), "type": VoucherType.PURCHASE_RETURN}
|
additional_info = BlankVoucherInfo(date=get_date(request.session), type=VoucherType.PURCHASE_RETURN)
|
||||||
with SessionFuture() as db:
|
with SessionFuture() as db:
|
||||||
return blank_voucher(additional_info, db)
|
return blank_voucher(additional_info, db)
|
||||||
@@ -1,13 +1,13 @@
|
|||||||
import uuid
|
import uuid
|
||||||
|
|
||||||
from datetime import datetime
|
from datetime import date, datetime
|
||||||
from decimal import Decimal
|
from decimal import Decimal
|
||||||
from typing import List, Optional, Tuple
|
from typing import List, Optional, Tuple
|
||||||
|
|
||||||
import brewman.schemas.voucher as output
|
import brewman.schemas.voucher as output
|
||||||
|
|
||||||
from fastapi import APIRouter, HTTPException, Security, status
|
from fastapi import APIRouter, HTTPException, Security, status
|
||||||
from sqlalchemy import and_, distinct, func, or_, select
|
from sqlalchemy import and_, delete, distinct, func, or_, select
|
||||||
from sqlalchemy.exc import SQLAlchemyError
|
from sqlalchemy.exc import SQLAlchemyError
|
||||||
from sqlalchemy.orm import Session
|
from sqlalchemy.orm import Session
|
||||||
|
|
||||||
@@ -21,11 +21,14 @@ from ..models.attendance_type import AttendanceType
|
|||||||
from ..models.cost_centre import CostCentre
|
from ..models.cost_centre import CostCentre
|
||||||
from ..models.db_image import DbImage
|
from ..models.db_image import DbImage
|
||||||
from ..models.employee import Employee
|
from ..models.employee import Employee
|
||||||
|
from ..models.employee_benefit import EmployeeBenefit
|
||||||
|
from ..models.incentive import Incentive
|
||||||
from ..models.inventory import Inventory
|
from ..models.inventory import Inventory
|
||||||
from ..models.journal import Journal
|
from ..models.journal import Journal
|
||||||
from ..models.voucher import Voucher
|
from ..models.voucher import Voucher
|
||||||
from ..models.voucher_type import VoucherType
|
from ..models.voucher_type import VoucherType
|
||||||
from ..routers import get_lock_info
|
from ..routers import get_lock_info
|
||||||
|
from ..schemas.blank_voucher_info import BlankVoucherInfo
|
||||||
from ..schemas.user import UserToken
|
from ..schemas.user import UserToken
|
||||||
|
|
||||||
|
|
||||||
@@ -163,11 +166,19 @@ def delete_voucher(
|
|||||||
for image in images:
|
for image in images:
|
||||||
db.delete(image)
|
db.delete(image)
|
||||||
db.commit()
|
db.commit()
|
||||||
json_voucher.type_ = VoucherType[json_voucher.type_.replace(" ", "_").upper()]
|
|
||||||
return blank_voucher(info=json_voucher, db=db)
|
return blank_voucher(
|
||||||
|
info=BlankVoucherInfo(
|
||||||
|
date=json_voucher.date_,
|
||||||
|
type=VoucherType[json_voucher.type_],
|
||||||
|
source=json_voucher.source,
|
||||||
|
destination=json_voucher.destination,
|
||||||
|
),
|
||||||
|
db=db,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
def voucher_info(voucher, db: Session) -> output.Voucher:
|
def voucher_info(voucher: Voucher, db: Session) -> output.Voucher:
|
||||||
json_voucher = output.Voucher(
|
json_voucher = output.Voucher(
|
||||||
id=voucher.id,
|
id=voucher.id,
|
||||||
date=voucher.date,
|
date=voucher.date,
|
||||||
@@ -200,75 +211,77 @@ def voucher_info(voucher, db: Session) -> output.Voucher:
|
|||||||
item = [j for j in voucher.journals if j.debit == 1][0]
|
item = [j for j in voucher.journals if j.debit == 1][0]
|
||||||
json_voucher.vendor = output.AccountLink(id=item.account.id, name=item.account.name)
|
json_voucher.vendor = output.AccountLink(id=item.account.id, name=item.account.name)
|
||||||
else:
|
else:
|
||||||
for item in voucher.journals:
|
for journal in voucher.journals:
|
||||||
json_voucher.journals.append(
|
json_voucher.journals.append(
|
||||||
output.Journal(
|
output.Journal(
|
||||||
id=item.id,
|
id=journal.id,
|
||||||
debit=item.debit,
|
debit=journal.debit,
|
||||||
amount=item.amount,
|
amount=journal.amount,
|
||||||
account=output.AccountLink(id=item.account.id, name=item.account.name),
|
account=output.AccountLink(id=journal.account.id, name=journal.account.name),
|
||||||
costCentre=output.CostCentreLink(id=item.cost_centre_id),
|
costCentre=output.CostCentreLink(id=journal.cost_centre_id),
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
for item in voucher.employee_benefits:
|
for benefit in voucher.employee_benefits:
|
||||||
json_voucher.employee_benefits.append(
|
json_voucher.employee_benefits.append(
|
||||||
output.EmployeeBenefit(
|
output.EmployeeBenefit(
|
||||||
grossSalary=item.gross_salary,
|
grossSalary=benefit.gross_salary,
|
||||||
daysWorked=item.days_worked,
|
daysWorked=benefit.days_worked,
|
||||||
esiEmployee=item.esi_ee,
|
esiEmployee=benefit.esi_ee,
|
||||||
pfEmployee=item.pf_ee,
|
pfEmployee=benefit.pf_ee,
|
||||||
esiEmployer=item.esi_er,
|
esiEmployer=benefit.esi_er,
|
||||||
pfEmployer=item.pf_er,
|
pfEmployer=benefit.pf_er,
|
||||||
employee=output.EmployeeLink(
|
employee=output.EmployeeLink(
|
||||||
id=item.journal.account.id,
|
id=benefit.journal.account.id,
|
||||||
name=item.journal.account.name,
|
name=benefit.journal.account.name,
|
||||||
designation=item.journal.account.designation,
|
designation=benefit.journal.account.designation,
|
||||||
costCentre=output.CostCentreLink(
|
costCentre=output.CostCentreLink(
|
||||||
id=item.journal.account.cost_centre.id,
|
id=benefit.journal.account.cost_centre.id,
|
||||||
name=item.journal.account.cost_centre.name,
|
name=benefit.journal.account.cost_centre.name,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
for item in voucher.incentives:
|
for incentive in voucher.incentives:
|
||||||
employee: Employee = db.execute(select(Employee).where(Employee.id == item.journal.account_id)).scalar_one()
|
employee: Employee = db.execute(
|
||||||
|
select(Employee).where(Employee.id == incentive.journal.account_id)
|
||||||
|
).scalar_one()
|
||||||
json_voucher.incentives.append(
|
json_voucher.incentives.append(
|
||||||
output.Incentive(
|
output.Incentive(
|
||||||
employeeId=item.journal.account_id,
|
employeeId=incentive.journal.account_id,
|
||||||
name=item.journal.account.name,
|
name=incentive.journal.account.name,
|
||||||
designation=employee.designation,
|
designation=employee.designation,
|
||||||
department=item.journal.account.cost_centre.name,
|
department=incentive.journal.account.cost_centre.name,
|
||||||
daysWorked=item.days_worked,
|
daysWorked=incentive.days_worked,
|
||||||
points=item.points,
|
points=incentive.points,
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
if len(json_voucher.incentives) > 0:
|
if len(json_voucher.incentives) > 0:
|
||||||
json_voucher.incentive = next(x.amount for x in voucher.journals if x.account_id == Account.incentive_id())
|
json_voucher.incentive = next(x.amount for x in voucher.journals if x.account_id == Account.incentive_id())
|
||||||
for item in voucher.inventories:
|
for inventory in voucher.inventories:
|
||||||
text = (
|
text = (
|
||||||
f"{item.batch.sku.product.name} ({item.batch.sku.units}) {item.batch.quantity_remaining:.2f}@"
|
f"{inventory.batch.sku.product.name} ({inventory.batch.sku.units}) {inventory.batch.quantity_remaining:.2f}@"
|
||||||
f"{item.batch.rate:.2f} from {item.batch.name.strftime('%d-%b-%Y')}"
|
f"{inventory.batch.rate:.2f} from {inventory.batch.name.strftime('%d-%b-%Y')}"
|
||||||
)
|
)
|
||||||
json_voucher.inventories.append(
|
json_voucher.inventories.append(
|
||||||
output.Inventory(
|
output.Inventory(
|
||||||
id=item.id,
|
id=inventory.id,
|
||||||
quantity=item.quantity,
|
quantity=inventory.quantity,
|
||||||
rate=item.rate,
|
rate=inventory.rate,
|
||||||
tax=item.tax,
|
tax=inventory.tax,
|
||||||
discount=item.discount,
|
discount=inventory.discount,
|
||||||
amount=item.amount,
|
amount=inventory.amount,
|
||||||
batch=output.Batch(
|
batch=output.Batch(
|
||||||
id=item.batch.id,
|
id=inventory.batch.id,
|
||||||
name=text,
|
name=text,
|
||||||
quantityRemaining=item.batch.quantity_remaining,
|
quantityRemaining=inventory.batch.quantity_remaining,
|
||||||
tax=item.batch.tax,
|
tax=inventory.batch.tax,
|
||||||
discount=item.batch.discount,
|
discount=inventory.batch.discount,
|
||||||
rate=item.batch.rate,
|
rate=inventory.batch.rate,
|
||||||
sku=output.ProductLink(
|
sku=output.ProductLink(
|
||||||
id=item.batch.sku.id,
|
id=inventory.batch.sku.id,
|
||||||
name=f"{item.batch.sku.product.name} ({item.batch.sku.units})"
|
name=f"{inventory.batch.sku.product.name} ({inventory.batch.sku.units})"
|
||||||
if item.batch.sku.units
|
if inventory.batch.sku.units
|
||||||
else item.batch.sku.product.name,
|
else inventory.batch.sku.product.name,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
@@ -285,21 +298,10 @@ def voucher_info(voucher, db: Session) -> output.Voucher:
|
|||||||
return json_voucher
|
return json_voucher
|
||||||
|
|
||||||
|
|
||||||
def blank_voucher(info, db: Session) -> output.Voucher:
|
def blank_voucher(info: BlankVoucherInfo, db: Session) -> output.Voucher:
|
||||||
if "type" not in info:
|
|
||||||
raise HTTPException(
|
|
||||||
status_code=status.HTTP_404_NOT_FOUND,
|
|
||||||
detail="Voucher Type is null",
|
|
||||||
)
|
|
||||||
type_ = info["type"]
|
|
||||||
if "date" not in info:
|
|
||||||
raise HTTPException(
|
|
||||||
status_code=status.HTTP_404_NOT_FOUND,
|
|
||||||
detail="Date cannot be null",
|
|
||||||
)
|
|
||||||
json_voucher = output.Voucher(
|
json_voucher = output.Voucher(
|
||||||
type=type_.name,
|
type=info.type_.name,
|
||||||
date=info["date"],
|
date=info.date_,
|
||||||
isStarred=False,
|
isStarred=False,
|
||||||
posted=False,
|
posted=False,
|
||||||
narration="",
|
narration="",
|
||||||
@@ -309,65 +311,56 @@ def blank_voucher(info, db: Session) -> output.Voucher:
|
|||||||
employeeBenefits=[],
|
employeeBenefits=[],
|
||||||
files=[],
|
files=[],
|
||||||
)
|
)
|
||||||
if type_ == VoucherType.JOURNAL:
|
if info.type_ == VoucherType.JOURNAL:
|
||||||
pass
|
pass
|
||||||
elif type_ == VoucherType.PAYMENT:
|
elif info.type_ == VoucherType.PAYMENT:
|
||||||
account = None
|
account = None
|
||||||
if info and "account" in info and info["account"]:
|
if info.account is not None:
|
||||||
account = (
|
account = db.execute(select(AccountBase).where(AccountBase.id == info.account.id_)).scalars().one_or_none()
|
||||||
db.execute(select(AccountBase).where(AccountBase.id == uuid.UUID(info["account"])))
|
|
||||||
.scalars()
|
|
||||||
.one_or_none()
|
|
||||||
)
|
|
||||||
if account is not None:
|
if account is not None:
|
||||||
j_account = output.AccountLink(id=account.id, name=account.name)
|
j_account = output.AccountLink(id=account.id, name=account.name)
|
||||||
else:
|
else:
|
||||||
j_account = output.AccountLink(id=AccountBase.cash_in_hand()["id"], name=AccountBase.cash_in_hand()["name"])
|
j_account = output.AccountLink(id=AccountBase.cash_in_hand()["id"], name=AccountBase.cash_in_hand()["name"])
|
||||||
json_voucher.journals.append(output.Journal(account=j_account, amount=0, debit=-1))
|
json_voucher.journals.append(output.Journal(account=j_account, amount=0, debit=-1))
|
||||||
elif type_ == VoucherType.RECEIPT:
|
elif info.type_ == VoucherType.RECEIPT:
|
||||||
account = None
|
account = None
|
||||||
if info and "account" in info and info["account"]:
|
if info.account is not None:
|
||||||
account = (
|
account = db.execute(select(AccountBase).where(AccountBase.id == info.account.id_)).scalars().one_or_none()
|
||||||
db.execute(select(AccountBase).where(AccountBase.id == uuid.UUID(info["account"])))
|
|
||||||
.scalars()
|
|
||||||
.one_or_none()
|
|
||||||
)
|
|
||||||
if account is not None:
|
if account is not None:
|
||||||
j_account = output.AccountLink(id=account.id, name=account.name)
|
j_account = output.AccountLink(id=account.id, name=account.name)
|
||||||
else:
|
else:
|
||||||
j_account = output.AccountLink(id=AccountBase.cash_in_hand()["id"], name=AccountBase.cash_in_hand()["name"])
|
j_account = output.AccountLink(id=AccountBase.cash_in_hand()["id"], name=AccountBase.cash_in_hand()["name"])
|
||||||
json_voucher.journals.append(output.Journal(account=j_account, amount=0, debit=1))
|
json_voucher.journals.append(output.Journal(account=j_account, amount=0, debit=1))
|
||||||
elif type_ == VoucherType.PURCHASE:
|
elif info.type_ == VoucherType.PURCHASE:
|
||||||
json_voucher.vendor = output.AccountLink(
|
json_voucher.vendor = output.AccountLink(
|
||||||
id=AccountBase.local_purchase()["id"], name=AccountBase.local_purchase()["name"]
|
id=AccountBase.local_purchase()["id"], name=AccountBase.local_purchase()["name"]
|
||||||
)
|
)
|
||||||
elif type_ == VoucherType.PURCHASE_RETURN:
|
elif info.type_ == VoucherType.PURCHASE_RETURN:
|
||||||
json_voucher.vendor = output.AccountLink(
|
json_voucher.vendor = output.AccountLink(
|
||||||
id=AccountBase.local_purchase()["id"], name=AccountBase.local_purchase()["name"]
|
id=AccountBase.local_purchase()["id"], name=AccountBase.local_purchase()["name"]
|
||||||
)
|
)
|
||||||
elif type_ == VoucherType.ISSUE:
|
elif info.type_ == VoucherType.ISSUE:
|
||||||
if "source" in info:
|
if info.source is not None:
|
||||||
json_voucher.source = output.CostCentreLink(id=info["source"])
|
json_voucher.source = output.CostCentreLink(id=info.source.id_)
|
||||||
else:
|
else:
|
||||||
json_voucher.source = output.CostCentreLink(id=CostCentre.cost_centre_purchase())
|
json_voucher.source = output.CostCentreLink(id=CostCentre.cost_centre_purchase())
|
||||||
if "destination" in info:
|
if info.destination is not None:
|
||||||
json_voucher.destination = output.CostCentreLink(id=info["destination"])
|
json_voucher.destination = output.CostCentreLink(id=info.destination.id_)
|
||||||
else:
|
else:
|
||||||
json_voucher.destination = output.CostCentreLink(id=CostCentre.cost_centre_kitchen())
|
json_voucher.destination = output.CostCentreLink(id=CostCentre.cost_centre_kitchen())
|
||||||
elif type_ == VoucherType.EMPLOYEE_BENEFIT:
|
elif info.type_ == VoucherType.EMPLOYEE_BENEFIT:
|
||||||
pass
|
pass
|
||||||
elif type_ == VoucherType.INCENTIVE:
|
elif info.type_ == VoucherType.INCENTIVE:
|
||||||
json_voucher.incentives, json_voucher.incentive = incentive_employees(info["date"], db)
|
json_voucher.incentives, json_voucher.incentive = incentive_employees(info.date_, db)
|
||||||
else:
|
else:
|
||||||
raise HTTPException(
|
raise HTTPException(
|
||||||
status_code=status.HTTP_404_NOT_FOUND,
|
status_code=status.HTTP_404_NOT_FOUND,
|
||||||
detail=f'Voucher of type "{type_}" does not exist.',
|
detail=f'Voucher of type "{info.type_.name}" does not exist.',
|
||||||
)
|
)
|
||||||
return json_voucher
|
return json_voucher
|
||||||
|
|
||||||
|
|
||||||
def incentive_employees(date_, db: Session) -> Tuple[List[output.Incentive], Decimal]:
|
def incentive_employees(date_: date, db: Session) -> Tuple[List[output.Incentive], Decimal]:
|
||||||
date_ = datetime.strptime(date_, "%d-%b-%Y")
|
|
||||||
start_date = get_first_day(date_)
|
start_date = get_first_day(date_)
|
||||||
finish_date = date_
|
finish_date = date_
|
||||||
details: List[output.Incentive] = []
|
details: List[output.Incentive] = []
|
||||||
@@ -427,7 +420,7 @@ def incentive_employees(date_, db: Session) -> Tuple[List[output.Incentive], Dec
|
|||||||
return details, amount
|
return details, amount
|
||||||
|
|
||||||
|
|
||||||
def check_voucher_edit_allowed(voucher: Voucher, user: UserToken):
|
def check_voucher_edit_allowed(voucher: Voucher, user: UserToken) -> None:
|
||||||
if voucher.posted and "edit-posted-vouchers" not in user.permissions:
|
if voucher.posted and "edit-posted-vouchers" not in user.permissions:
|
||||||
raise HTTPException(
|
raise HTTPException(
|
||||||
status_code=status.HTTP_403_FORBIDDEN,
|
status_code=status.HTTP_403_FORBIDDEN,
|
||||||
|
|||||||
@@ -0,0 +1,27 @@
|
|||||||
|
from datetime import date, datetime
|
||||||
|
from typing import Optional
|
||||||
|
|
||||||
|
from pydantic import BaseModel, validator
|
||||||
|
|
||||||
|
from ..models.voucher_type import VoucherType
|
||||||
|
from . import to_camel
|
||||||
|
from .account import AccountLink
|
||||||
|
from .cost_centre import CostCentreLink
|
||||||
|
|
||||||
|
|
||||||
|
class BlankVoucherInfo(BaseModel):
|
||||||
|
type_: VoucherType
|
||||||
|
date_: date
|
||||||
|
account: Optional[AccountLink]
|
||||||
|
source: Optional[CostCentreLink]
|
||||||
|
destination: Optional[CostCentreLink]
|
||||||
|
|
||||||
|
class Config:
|
||||||
|
alias_generator = to_camel
|
||||||
|
json_encoders = {date: lambda v: v.strftime("%d-%b-%Y")}
|
||||||
|
|
||||||
|
@validator("date_", pre=True)
|
||||||
|
def parse_date(cls, value):
|
||||||
|
if isinstance(value, date):
|
||||||
|
return value
|
||||||
|
return datetime.strptime(value, "%d-%b-%Y").date()
|
||||||
@@ -12,8 +12,6 @@ class ProductSku(BaseModel):
|
|||||||
fraction_units: str
|
fraction_units: str
|
||||||
cost_price: Decimal
|
cost_price: Decimal
|
||||||
sale_price: Decimal
|
sale_price: Decimal
|
||||||
fraction: Decimal
|
|
||||||
product_yield: Decimal
|
|
||||||
is_rate_contracted: bool
|
is_rate_contracted: bool
|
||||||
|
|
||||||
class Config:
|
class Config:
|
||||||
|
|||||||
@@ -12,9 +12,9 @@ from .recipe_item import RecipeItem
|
|||||||
|
|
||||||
|
|
||||||
class RecipeIn(BaseModel):
|
class RecipeIn(BaseModel):
|
||||||
product: ProductLink
|
sku: ProductLink
|
||||||
|
|
||||||
quantity: Decimal
|
recipe_yield: Decimal
|
||||||
cost_price: Decimal
|
cost_price: Decimal
|
||||||
sale_price: Decimal
|
sale_price: Decimal
|
||||||
notes: str
|
notes: str
|
||||||
@@ -56,7 +56,7 @@ class Recipe(RecipeIn):
|
|||||||
|
|
||||||
|
|
||||||
class RecipeBlank(RecipeIn):
|
class RecipeBlank(RecipeIn):
|
||||||
product: Optional[ProductLink] # type: ignore[assignment]
|
sku: Optional[ProductLink] # type: ignore[assignment]
|
||||||
|
|
||||||
class Config:
|
class Config:
|
||||||
anystr_strip_whitespace = True
|
anystr_strip_whitespace = True
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
import uuid
|
import uuid
|
||||||
|
|
||||||
|
from decimal import Decimal
|
||||||
from typing import Optional
|
from typing import Optional
|
||||||
|
|
||||||
from brewman.schemas.product import ProductLink
|
from brewman.schemas.product import ProductLink
|
||||||
@@ -9,8 +10,8 @@ from pydantic import BaseModel
|
|||||||
class RecipeItem(BaseModel):
|
class RecipeItem(BaseModel):
|
||||||
id_: Optional[uuid.UUID]
|
id_: Optional[uuid.UUID]
|
||||||
product: ProductLink
|
product: ProductLink
|
||||||
quantity: int
|
quantity: Decimal
|
||||||
price: int
|
price: Decimal
|
||||||
|
|
||||||
class Config:
|
class Config:
|
||||||
fields = {"id_": "id"}
|
fields = {"id_": "id"}
|
||||||
@@ -3,8 +3,6 @@ export class ProductSku {
|
|||||||
name: string;
|
name: string;
|
||||||
costPrice: number;
|
costPrice: number;
|
||||||
salePrice: number;
|
salePrice: number;
|
||||||
fraction: number;
|
|
||||||
productYield: number;
|
|
||||||
fractionUnits: string;
|
fractionUnits: string;
|
||||||
|
|
||||||
isRateContracted: boolean;
|
isRateContracted: boolean;
|
||||||
@@ -14,8 +12,6 @@ export class ProductSku {
|
|||||||
this.name = '';
|
this.name = '';
|
||||||
this.costPrice = 0;
|
this.costPrice = 0;
|
||||||
this.salePrice = 0;
|
this.salePrice = 0;
|
||||||
this.fraction = 0;
|
|
||||||
this.productYield = 0;
|
|
||||||
this.fractionUnits = '';
|
this.fractionUnits = '';
|
||||||
this.isRateContracted = false;
|
this.isRateContracted = false;
|
||||||
|
|
||||||
|
|||||||
@@ -94,7 +94,7 @@
|
|||||||
<mat-label>Sale Price</mat-label>
|
<mat-label>Sale Price</mat-label>
|
||||||
<input matInput type="number" placeholder="Sale Price" formControlName="salePrice" />
|
<input matInput type="number" placeholder="Sale Price" formControlName="salePrice" />
|
||||||
</mat-form-field>
|
</mat-form-field>
|
||||||
<button mat-raised-button color="primary" (click)="addRow()" fxFlex="15">Add</button>
|
<button mat-raised-button color="primary" (click)="addRow()" fxFlex>Add</button>
|
||||||
</div>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
<mat-table [dataSource]="dataSource" aria-label="Elements">
|
<mat-table [dataSource]="dataSource" aria-label="Elements">
|
||||||
|
|||||||
Reference in new issue
Block a user