Skip to content

Phase 12: Liquor Permits

Duration: 1.5 days Goal: Implement permit management for LIF (Liquor/IMFL) items


Liquor items require permits from state excise authorities before receipt at depots.


class Permit(BaseDocType):
"""Excise permit for liquor item receipt."""
permit_number: str = Field(max_length=50, unique=True)
# Reference
purchase_order: str # FK to PurchaseOrder
item: str # FK to Item
depot: str # FK to Depot
# Dates
permit_date: date
validity_date: date
extended_validity_date: date | None = None
# Quantity
permit_quantity: Decimal # Cases
# Status
is_cancelled: bool = False
is_utilized: bool = False
utilized_quantity: Decimal = Decimal("0")
remarks: str | None = None
class Meta:
table_name = "permit"
indexes = ["purchase_order", "item", "depot"]

class LiquorReceiptController:
"""Special handling for LIF item receipts."""
async def validate_permit(
self,
receipt: PurchaseReceipt,
item: PurchaseReceiptItem,
) -> None:
"""Validate permit exists and has available quantity."""
if not await self.is_liquor_item(item.item):
return
permit = await self.permit_repo.find_active(
purchase_order=receipt.purchase_order,
item=item.item,
depot=receipt.depot,
)
if not permit:
raise ValidationError(f"No valid permit for {item.item_name}")
if permit.validity_date < date.today():
if not permit.extended_validity_date or permit.extended_validity_date < date.today():
raise ValidationError(f"Permit {permit.permit_number} has expired")
available = permit.permit_quantity - permit.utilized_quantity
if available < item.qty:
raise ValidationError(
f"Permit has only {available} cases, trying to receive {item.qty}"
)
async def on_receipt_submit(
self,
receipt: PurchaseReceipt,
item: PurchaseReceiptItem,
) -> None:
"""Update permit utilization on receipt."""
if not await self.is_liquor_item(item.item):
return
permit = await self.permit_repo.find_active(
purchase_order=receipt.purchase_order,
item=item.item,
depot=receipt.depot,
)
permit.utilized_quantity += item.qty
if permit.utilized_quantity >= permit.permit_quantity:
permit.is_utilized = True
await self.permit_repo.save(permit)

Endpoint Method Description
/api/v1/permit GET, POST List/Create permits
/api/v1/permit/{id} GET, PUT Permit CRUD
/api/v1/permit/{id}/extend POST Extend validity
/api/v1/permit/{id}/cancel POST Cancel permit
/api/v1/permit/pending GET Unutilized permits

  • Permit creation linked to PO
  • Receipt blocked without valid permit
  • Permit utilization tracked
  • Extension workflow
  • Permit expiry alerts