Commit
·
80feb1b
0
Parent(s):
Initial commit with Git LFS
Browse filesThis view is limited to 50 files because it contains too many changes.
See raw diff
- .gitattributes +39 -0
- .gitignore +2 -0
- Dockerfile +32 -0
- HUGGINGFACE_README.md +75 -0
- README.md +0 -0
- app/__pycache__/database.cpython-311.pyc +0 -0
- app/__pycache__/database.cpython-312.pyc +0 -0
- app/__pycache__/database.cpython-313.pyc +0 -0
- app/__pycache__/firebase_config.cpython-312.pyc +0 -0
- app/__pycache__/main.cpython-311.pyc +0 -0
- app/__pycache__/main.cpython-312.pyc +0 -0
- app/__pycache__/main.cpython-313.pyc +0 -0
- app/database.py +204 -0
- app/main.py +126 -0
- app/models/__pycache__/dish.cpython-311.pyc +0 -0
- app/models/__pycache__/dish.cpython-312.pyc +0 -0
- app/models/__pycache__/feedback.cpython-311.pyc +0 -0
- app/models/__pycache__/feedback.cpython-312.pyc +0 -0
- app/models/__pycache__/inventory.cpython-311.pyc +0 -0
- app/models/__pycache__/loyalty.cpython-311.pyc +0 -0
- app/models/__pycache__/loyalty.cpython-312.pyc +0 -0
- app/models/__pycache__/order.cpython-311.pyc +0 -0
- app/models/__pycache__/order.cpython-312.pyc +0 -0
- app/models/__pycache__/selection_offer.cpython-311.pyc +0 -0
- app/models/__pycache__/selection_offer.cpython-312.pyc +0 -0
- app/models/__pycache__/settings.cpython-312.pyc +0 -0
- app/models/__pycache__/table.cpython-311.pyc +0 -0
- app/models/__pycache__/table.cpython-312.pyc +0 -0
- app/models/__pycache__/user.cpython-311.pyc +0 -0
- app/models/__pycache__/user.cpython-312.pyc +0 -0
- app/models/dish.py +36 -0
- app/models/feedback.py +22 -0
- app/models/loyalty.py +28 -0
- app/models/order.py +60 -0
- app/models/selection_offer.py +30 -0
- app/models/settings.py +34 -0
- app/models/table.py +33 -0
- app/models/user.py +39 -0
- app/routers/__pycache__/admin.cpython-311.pyc +0 -0
- app/routers/__pycache__/admin.cpython-312.pyc +0 -0
- app/routers/__pycache__/analytics.cpython-312.pyc +0 -0
- app/routers/__pycache__/chef.cpython-311.pyc +0 -0
- app/routers/__pycache__/chef.cpython-312.pyc +0 -0
- app/routers/__pycache__/customer.cpython-311.pyc +0 -0
- app/routers/__pycache__/customer.cpython-312.pyc +0 -0
- app/routers/__pycache__/feedback.cpython-311.pyc +0 -0
- app/routers/__pycache__/feedback.cpython-312.pyc +0 -0
- app/routers/__pycache__/loyalty.cpython-311.pyc +0 -0
- app/routers/__pycache__/loyalty.cpython-312.pyc +0 -0
- app/routers/__pycache__/selection_offer.cpython-311.pyc +0 -0
.gitattributes
ADDED
@@ -0,0 +1,39 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
*.7z filter=lfs diff=lfs merge=lfs -text
|
2 |
+
*.arrow filter=lfs diff=lfs merge=lfs -text
|
3 |
+
*.bin filter=lfs diff=lfs merge=lfs -text
|
4 |
+
*.bz2 filter=lfs diff=lfs merge=lfs -text
|
5 |
+
*.ckpt filter=lfs diff=lfs merge=lfs -text
|
6 |
+
*.ftz filter=lfs diff=lfs merge=lfs -text
|
7 |
+
*.gz filter=lfs diff=lfs merge=lfs -text
|
8 |
+
*.h5 filter=lfs diff=lfs merge=lfs -text
|
9 |
+
*.joblib filter=lfs diff=lfs merge=lfs -text
|
10 |
+
*.lfs.* filter=lfs diff=lfs merge=lfs -text
|
11 |
+
*.mlmodel filter=lfs diff=lfs merge=lfs -text
|
12 |
+
*.model filter=lfs diff=lfs merge=lfs -text
|
13 |
+
*.msgpack filter=lfs diff=lfs merge=lfs -text
|
14 |
+
*.npy filter=lfs diff=lfs merge=lfs -text
|
15 |
+
*.npz filter=lfs diff=lfs merge=lfs -text
|
16 |
+
*.onnx filter=lfs diff=lfs merge=lfs -text
|
17 |
+
*.ot filter=lfs diff=lfs merge=lfs -text
|
18 |
+
*.parquet filter=lfs diff=lfs merge=lfs -text
|
19 |
+
*.pb filter=lfs diff=lfs merge=lfs -text
|
20 |
+
*.pickle filter=lfs diff=lfs merge=lfs -text
|
21 |
+
*.pkl filter=lfs diff=lfs merge=lfs -text
|
22 |
+
*.pt filter=lfs diff=lfs merge=lfs -text
|
23 |
+
*.pth filter=lfs diff=lfs merge=lfs -text
|
24 |
+
*.rar filter=lfs diff=lfs merge=lfs -text
|
25 |
+
*.safetensors filter=lfs diff=lfs merge=lfs -text
|
26 |
+
saved_model/**/* filter=lfs diff=lfs merge=lfs -text
|
27 |
+
*.tar.* filter=lfs diff=lfs merge=lfs -text
|
28 |
+
*.tar filter=lfs diff=lfs merge=lfs -text
|
29 |
+
*.tflite filter=lfs diff=lfs merge=lfs -text
|
30 |
+
*.tgz filter=lfs diff=lfs merge=lfs -text
|
31 |
+
*.wasm filter=lfs diff=lfs merge=lfs -text
|
32 |
+
*.xz filter=lfs diff=lfs merge=lfs -text
|
33 |
+
*.zip filter=lfs diff=lfs merge=lfs -text
|
34 |
+
*.zst filter=lfs diff=lfs merge=lfs -text
|
35 |
+
*tfevents* filter=lfs diff=lfs merge=lfs -text
|
36 |
+
*.db filter=lfs diff=lfs merge=lfs -text
|
37 |
+
*.jpg filter=lfs diff=lfs merge=lfs -text
|
38 |
+
*.jpeg filter=lfs diff=lfs merge=lfs -text
|
39 |
+
*.webp filter=lfs diff=lfs merge=lfs -text
|
.gitignore
ADDED
@@ -0,0 +1,2 @@
|
|
|
|
|
|
|
1 |
+
.venv/
|
2 |
+
/frontend/node_modules/
|
Dockerfile
ADDED
@@ -0,0 +1,32 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
# Use Python 3.10 slim image as base
|
2 |
+
FROM python:3.10-slim
|
3 |
+
|
4 |
+
# Set working directory
|
5 |
+
WORKDIR /code
|
6 |
+
|
7 |
+
# Install system dependencies
|
8 |
+
RUN apt-get update && apt-get install -y \
|
9 |
+
build-essential \
|
10 |
+
&& rm -rf /var/lib/apt/lists/*
|
11 |
+
|
12 |
+
# Copy requirements first to leverage Docker cache
|
13 |
+
COPY requirements.txt .
|
14 |
+
|
15 |
+
# Install Python dependencies
|
16 |
+
RUN pip install --no-cache-dir -r requirements.txt
|
17 |
+
|
18 |
+
# Copy the rest of the application
|
19 |
+
COPY app app/
|
20 |
+
COPY templates templates/
|
21 |
+
COPY run.py .
|
22 |
+
COPY tabble_new.db .
|
23 |
+
|
24 |
+
# Set environment variables
|
25 |
+
ENV PORT=7860
|
26 |
+
ENV HOST=0.0.0.0
|
27 |
+
|
28 |
+
# Expose the port
|
29 |
+
EXPOSE 7860
|
30 |
+
|
31 |
+
# Command to run the application
|
32 |
+
CMD ["python", "run.py"]
|
HUGGINGFACE_README.md
ADDED
@@ -0,0 +1,75 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
# Deploying to Hugging Face Spaces
|
2 |
+
|
3 |
+
This guide explains how to deploy the FastAPI backend to Hugging Face Spaces using Docker.
|
4 |
+
|
5 |
+
## Prerequisites
|
6 |
+
|
7 |
+
1. A Hugging Face account
|
8 |
+
2. Git installed on your machine
|
9 |
+
3. Docker installed (for local testing)
|
10 |
+
|
11 |
+
## Steps to Deploy
|
12 |
+
|
13 |
+
1. Create a new Space on Hugging Face:
|
14 |
+
- Go to https://huggingface.co/spaces
|
15 |
+
- Click "Create new Space"
|
16 |
+
- Select "Docker" as the SDK
|
17 |
+
- Choose a name for your space
|
18 |
+
- Set visibility (public/private)
|
19 |
+
|
20 |
+
2. Clone the new Space repository:
|
21 |
+
```bash
|
22 |
+
git clone https://huggingface.co/spaces/YOUR_USERNAME/YOUR_SPACE_NAME
|
23 |
+
```
|
24 |
+
|
25 |
+
3. Copy the following files to the cloned repository:
|
26 |
+
- `Dockerfile`
|
27 |
+
- `requirements.txt`
|
28 |
+
- `app/` directory
|
29 |
+
- `templates/` directory
|
30 |
+
- `run.py`
|
31 |
+
- `tabble_new.db`
|
32 |
+
|
33 |
+
4. Update your environment variables:
|
34 |
+
- Go to your Space's Settings
|
35 |
+
- Add any necessary environment variables
|
36 |
+
- Make sure to add any sensitive information as secrets
|
37 |
+
|
38 |
+
5. Commit and push your changes:
|
39 |
+
```bash
|
40 |
+
git add .
|
41 |
+
git commit -m "Initial commit"
|
42 |
+
git push
|
43 |
+
```
|
44 |
+
|
45 |
+
## Local Testing
|
46 |
+
|
47 |
+
Before deploying to Hugging Face, you can test locally using Docker Compose:
|
48 |
+
|
49 |
+
1. Build and run the container:
|
50 |
+
```bash
|
51 |
+
docker-compose up --build
|
52 |
+
```
|
53 |
+
|
54 |
+
2. Access the API at `http://localhost:7860`
|
55 |
+
|
56 |
+
## Important Notes
|
57 |
+
|
58 |
+
1. The Dockerfile uses port 7860 as required by Hugging Face Spaces
|
59 |
+
2. Make sure your database is properly initialized before deployment
|
60 |
+
3. Static files and images should be stored in the appropriate directories
|
61 |
+
4. Any changes to the code require a new commit and push to update the Space
|
62 |
+
|
63 |
+
## Monitoring
|
64 |
+
|
65 |
+
- Monitor your Space's logs through the Hugging Face interface
|
66 |
+
- Check the Space's metrics for usage statistics
|
67 |
+
- Use the Space's terminal for debugging if needed
|
68 |
+
|
69 |
+
## Troubleshooting
|
70 |
+
|
71 |
+
If you encounter issues:
|
72 |
+
1. Check the Space's logs for error messages
|
73 |
+
2. Verify all environment variables are set correctly
|
74 |
+
3. Ensure all required files are present in the repository
|
75 |
+
4. Test the application locally using Docker Compose before deploying
|
README.md
ADDED
Binary file (2.77 kB). View file
|
|
app/__pycache__/database.cpython-311.pyc
ADDED
Binary file (11.3 kB). View file
|
|
app/__pycache__/database.cpython-312.pyc
ADDED
Binary file (10.9 kB). View file
|
|
app/__pycache__/database.cpython-313.pyc
ADDED
Binary file (3.34 kB). View file
|
|
app/__pycache__/firebase_config.cpython-312.pyc
ADDED
Binary file (1.7 kB). View file
|
|
app/__pycache__/main.cpython-311.pyc
ADDED
Binary file (5.26 kB). View file
|
|
app/__pycache__/main.cpython-312.pyc
ADDED
Binary file (6.03 kB). View file
|
|
app/__pycache__/main.cpython-313.pyc
ADDED
Binary file (4.54 kB). View file
|
|
app/database.py
ADDED
@@ -0,0 +1,204 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
from sqlalchemy import (
|
2 |
+
create_engine,
|
3 |
+
Column,
|
4 |
+
Integer,
|
5 |
+
String,
|
6 |
+
Float,
|
7 |
+
ForeignKey,
|
8 |
+
DateTime,
|
9 |
+
Text,
|
10 |
+
Boolean,
|
11 |
+
)
|
12 |
+
from sqlalchemy.ext.declarative import declarative_base
|
13 |
+
from sqlalchemy.orm import sessionmaker, relationship
|
14 |
+
from datetime import datetime, timezone
|
15 |
+
import os
|
16 |
+
|
17 |
+
# Database connection - Using SQLite
|
18 |
+
DATABASE_URL = "sqlite:///./tabble_new.db" # Using the new database with offers feature
|
19 |
+
engine = create_engine(DATABASE_URL, connect_args={"check_same_thread": False})
|
20 |
+
SessionLocal = sessionmaker(autocommit=False, autoflush=False, bind=engine)
|
21 |
+
Base = declarative_base()
|
22 |
+
|
23 |
+
|
24 |
+
# Database models
|
25 |
+
class Dish(Base):
|
26 |
+
__tablename__ = "dishes"
|
27 |
+
|
28 |
+
id = Column(Integer, primary_key=True, index=True)
|
29 |
+
name = Column(String, index=True)
|
30 |
+
description = Column(Text, nullable=True)
|
31 |
+
category = Column(String, index=True)
|
32 |
+
price = Column(Float)
|
33 |
+
quantity = Column(Integer, default=0)
|
34 |
+
image_path = Column(String, nullable=True)
|
35 |
+
discount = Column(Float, default=0) # Discount amount (percentage)
|
36 |
+
is_offer = Column(Integer, default=0) # 0 = not an offer, 1 = is an offer
|
37 |
+
is_special = Column(Integer, default=0) # 0 = not special, 1 = today's special
|
38 |
+
created_at = Column(DateTime, default=lambda: datetime.now(timezone.utc))
|
39 |
+
updated_at = Column(
|
40 |
+
DateTime,
|
41 |
+
default=lambda: datetime.now(timezone.utc),
|
42 |
+
onupdate=lambda: datetime.now(timezone.utc),
|
43 |
+
)
|
44 |
+
|
45 |
+
# Relationship with OrderItem
|
46 |
+
order_items = relationship("OrderItem", back_populates="dish")
|
47 |
+
|
48 |
+
|
49 |
+
class Order(Base):
|
50 |
+
__tablename__ = "orders"
|
51 |
+
|
52 |
+
id = Column(Integer, primary_key=True, index=True)
|
53 |
+
table_number = Column(Integer)
|
54 |
+
unique_id = Column(String, index=True)
|
55 |
+
person_id = Column(Integer, ForeignKey("persons.id"), nullable=True)
|
56 |
+
status = Column(String, default="pending") # pending, completed, paid
|
57 |
+
created_at = Column(DateTime, default=lambda: datetime.now(timezone.utc))
|
58 |
+
updated_at = Column(
|
59 |
+
DateTime,
|
60 |
+
default=lambda: datetime.now(timezone.utc),
|
61 |
+
onupdate=lambda: datetime.now(timezone.utc),
|
62 |
+
)
|
63 |
+
|
64 |
+
# Relationships
|
65 |
+
items = relationship("OrderItem", back_populates="order")
|
66 |
+
person = relationship("Person", back_populates="orders")
|
67 |
+
|
68 |
+
|
69 |
+
class Person(Base):
|
70 |
+
__tablename__ = "persons"
|
71 |
+
|
72 |
+
id = Column(Integer, primary_key=True, index=True)
|
73 |
+
username = Column(String, unique=True, index=True)
|
74 |
+
password = Column(String)
|
75 |
+
phone_number = Column(String, unique=True, index=True, nullable=True) # Added phone number field
|
76 |
+
visit_count = Column(Integer, default=1)
|
77 |
+
last_visit = Column(DateTime, default=lambda: datetime.now(timezone.utc))
|
78 |
+
created_at = Column(DateTime, default=lambda: datetime.now(timezone.utc))
|
79 |
+
|
80 |
+
# Relationship with Order
|
81 |
+
orders = relationship("Order", back_populates="person")
|
82 |
+
|
83 |
+
|
84 |
+
class OrderItem(Base):
|
85 |
+
__tablename__ = "order_items"
|
86 |
+
|
87 |
+
id = Column(Integer, primary_key=True, index=True)
|
88 |
+
order_id = Column(Integer, ForeignKey("orders.id"))
|
89 |
+
dish_id = Column(Integer, ForeignKey("dishes.id"))
|
90 |
+
quantity = Column(Integer, default=1)
|
91 |
+
remarks = Column(Text, nullable=True)
|
92 |
+
created_at = Column(DateTime, default=lambda: datetime.now(timezone.utc))
|
93 |
+
|
94 |
+
# Relationships
|
95 |
+
order = relationship("Order", back_populates="items")
|
96 |
+
dish = relationship("Dish", back_populates="order_items")
|
97 |
+
|
98 |
+
|
99 |
+
class Feedback(Base):
|
100 |
+
__tablename__ = "feedback"
|
101 |
+
|
102 |
+
id = Column(Integer, primary_key=True, index=True)
|
103 |
+
order_id = Column(Integer, ForeignKey("orders.id"))
|
104 |
+
person_id = Column(Integer, ForeignKey("persons.id"), nullable=True)
|
105 |
+
rating = Column(Integer) # 1-5 stars
|
106 |
+
comment = Column(Text, nullable=True)
|
107 |
+
created_at = Column(DateTime, default=lambda: datetime.now(timezone.utc))
|
108 |
+
|
109 |
+
# Relationships
|
110 |
+
order = relationship("Order")
|
111 |
+
person = relationship("Person")
|
112 |
+
|
113 |
+
|
114 |
+
class LoyaltyProgram(Base):
|
115 |
+
__tablename__ = "loyalty_program"
|
116 |
+
|
117 |
+
id = Column(Integer, primary_key=True, index=True)
|
118 |
+
visit_count = Column(Integer, unique=True) # Number of visits required
|
119 |
+
discount_percentage = Column(Float) # Discount percentage
|
120 |
+
is_active = Column(Boolean, default=True) # Whether this loyalty tier is active
|
121 |
+
created_at = Column(DateTime, default=lambda: datetime.now(timezone.utc))
|
122 |
+
updated_at = Column(
|
123 |
+
DateTime,
|
124 |
+
default=lambda: datetime.now(timezone.utc),
|
125 |
+
onupdate=lambda: datetime.now(timezone.utc),
|
126 |
+
)
|
127 |
+
|
128 |
+
|
129 |
+
class SelectionOffer(Base):
|
130 |
+
__tablename__ = "selection_offers"
|
131 |
+
|
132 |
+
id = Column(Integer, primary_key=True, index=True)
|
133 |
+
min_amount = Column(Float) # Minimum order amount to qualify
|
134 |
+
discount_amount = Column(Float) # Fixed discount amount to apply
|
135 |
+
is_active = Column(Boolean, default=True) # Whether this offer is active
|
136 |
+
description = Column(String, nullable=True) # Optional description of the offer
|
137 |
+
created_at = Column(DateTime, default=lambda: datetime.now(timezone.utc))
|
138 |
+
updated_at = Column(
|
139 |
+
DateTime,
|
140 |
+
default=lambda: datetime.now(timezone.utc),
|
141 |
+
onupdate=lambda: datetime.now(timezone.utc),
|
142 |
+
)
|
143 |
+
|
144 |
+
|
145 |
+
class Table(Base):
|
146 |
+
__tablename__ = "tables"
|
147 |
+
|
148 |
+
id = Column(Integer, primary_key=True, index=True)
|
149 |
+
table_number = Column(Integer, unique=True) # Table number
|
150 |
+
is_occupied = Column(
|
151 |
+
Boolean, default=False
|
152 |
+
) # Whether the table is currently occupied
|
153 |
+
current_order_id = Column(
|
154 |
+
Integer, ForeignKey("orders.id"), nullable=True
|
155 |
+
) # Current active order
|
156 |
+
created_at = Column(DateTime, default=lambda: datetime.now(timezone.utc))
|
157 |
+
updated_at = Column(
|
158 |
+
DateTime,
|
159 |
+
default=lambda: datetime.now(timezone.utc),
|
160 |
+
onupdate=lambda: datetime.now(timezone.utc),
|
161 |
+
)
|
162 |
+
|
163 |
+
# Relationship to current order
|
164 |
+
current_order = relationship("Order", foreign_keys=[current_order_id])
|
165 |
+
|
166 |
+
|
167 |
+
class Settings(Base):
|
168 |
+
__tablename__ = "settings"
|
169 |
+
|
170 |
+
id = Column(Integer, primary_key=True, index=True)
|
171 |
+
hotel_name = Column(String, nullable=False, default="Tabble Hotel")
|
172 |
+
address = Column(String, nullable=True)
|
173 |
+
contact_number = Column(String, nullable=True)
|
174 |
+
email = Column(String, nullable=True)
|
175 |
+
tax_id = Column(String, nullable=True)
|
176 |
+
logo_path = Column(String, nullable=True)
|
177 |
+
created_at = Column(DateTime, default=lambda: datetime.now(timezone.utc))
|
178 |
+
updated_at = Column(
|
179 |
+
DateTime,
|
180 |
+
default=lambda: datetime.now(timezone.utc),
|
181 |
+
onupdate=lambda: datetime.now(timezone.utc),
|
182 |
+
)
|
183 |
+
|
184 |
+
|
185 |
+
# Create tables
|
186 |
+
def create_tables():
|
187 |
+
# Drop the selection_offers table if it exists to force recreation
|
188 |
+
try:
|
189 |
+
SelectionOffer.__table__.drop(engine)
|
190 |
+
print("Dropped selection_offers table to recreate it with the correct schema")
|
191 |
+
except:
|
192 |
+
print("Could not drop selection_offers table, it might not exist yet")
|
193 |
+
|
194 |
+
# Create all tables
|
195 |
+
Base.metadata.create_all(bind=engine)
|
196 |
+
|
197 |
+
|
198 |
+
# Get database session
|
199 |
+
def get_db():
|
200 |
+
db = SessionLocal()
|
201 |
+
try:
|
202 |
+
yield db
|
203 |
+
finally:
|
204 |
+
db.close()
|
app/main.py
ADDED
@@ -0,0 +1,126 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
from fastapi import FastAPI, Request, Depends
|
2 |
+
from fastapi.staticfiles import StaticFiles
|
3 |
+
from fastapi.templating import Jinja2Templates
|
4 |
+
from fastapi.responses import HTMLResponse, RedirectResponse, FileResponse
|
5 |
+
from fastapi.middleware.cors import CORSMiddleware
|
6 |
+
from sqlalchemy.orm import Session
|
7 |
+
import uvicorn
|
8 |
+
import os
|
9 |
+
|
10 |
+
from .database import get_db, create_tables
|
11 |
+
from .routers import chef, customer, admin, feedback, loyalty, selection_offer, table, analytics, settings
|
12 |
+
|
13 |
+
# Create FastAPI app
|
14 |
+
app = FastAPI(title="Tabble - Hotel Management App")
|
15 |
+
|
16 |
+
# Add CORS middleware to allow cross-origin requests
|
17 |
+
app.add_middleware(
|
18 |
+
CORSMiddleware,
|
19 |
+
allow_origins=["*"], # Allow all origins
|
20 |
+
allow_credentials=True,
|
21 |
+
allow_methods=["*"], # Allow all methods
|
22 |
+
allow_headers=["*"], # Allow all headers
|
23 |
+
)
|
24 |
+
|
25 |
+
# Mount static files
|
26 |
+
app.mount("/static", StaticFiles(directory="app/static"), name="static")
|
27 |
+
|
28 |
+
# Setup templates
|
29 |
+
templates = Jinja2Templates(directory="templates")
|
30 |
+
|
31 |
+
# Include routers
|
32 |
+
app.include_router(chef.router)
|
33 |
+
app.include_router(customer.router)
|
34 |
+
app.include_router(admin.router)
|
35 |
+
app.include_router(feedback.router)
|
36 |
+
app.include_router(loyalty.router)
|
37 |
+
app.include_router(selection_offer.router)
|
38 |
+
app.include_router(table.router)
|
39 |
+
app.include_router(analytics.router)
|
40 |
+
app.include_router(settings.router)
|
41 |
+
|
42 |
+
# Create database tables
|
43 |
+
create_tables()
|
44 |
+
|
45 |
+
# Check if we have the React build folder
|
46 |
+
react_build_dir = "frontend/build"
|
47 |
+
has_react_build = os.path.isdir(react_build_dir)
|
48 |
+
|
49 |
+
if has_react_build:
|
50 |
+
# Mount the React build folder
|
51 |
+
app.mount("/", StaticFiles(directory=react_build_dir, html=True), name="react")
|
52 |
+
|
53 |
+
|
54 |
+
# Root route - serve React app in production, otherwise serve index.html template
|
55 |
+
@app.get("/", response_class=HTMLResponse)
|
56 |
+
async def root(request: Request):
|
57 |
+
if has_react_build:
|
58 |
+
return FileResponse(f"{react_build_dir}/index.html")
|
59 |
+
return templates.TemplateResponse("index.html", {"request": request})
|
60 |
+
|
61 |
+
|
62 |
+
# Chef page
|
63 |
+
@app.get("/chef", response_class=HTMLResponse)
|
64 |
+
async def chef_page(request: Request):
|
65 |
+
return templates.TemplateResponse("chef/index.html", {"request": request})
|
66 |
+
|
67 |
+
|
68 |
+
# Chef orders page
|
69 |
+
@app.get("/chef/orders", response_class=HTMLResponse)
|
70 |
+
async def chef_orders_page(request: Request):
|
71 |
+
return templates.TemplateResponse("chef/orders.html", {"request": request})
|
72 |
+
|
73 |
+
|
74 |
+
# Customer login page
|
75 |
+
@app.get("/customer", response_class=HTMLResponse)
|
76 |
+
async def customer_login_page(request: Request):
|
77 |
+
return templates.TemplateResponse("customer/login.html", {"request": request})
|
78 |
+
|
79 |
+
|
80 |
+
# Customer menu page
|
81 |
+
@app.get("/customer/menu", response_class=HTMLResponse)
|
82 |
+
async def customer_menu_page(request: Request, table_number: int, unique_id: str):
|
83 |
+
return templates.TemplateResponse(
|
84 |
+
"customer/menu.html",
|
85 |
+
{"request": request, "table_number": table_number, "unique_id": unique_id},
|
86 |
+
)
|
87 |
+
|
88 |
+
|
89 |
+
# Admin page
|
90 |
+
@app.get("/admin", response_class=HTMLResponse)
|
91 |
+
async def admin_page(request: Request):
|
92 |
+
return templates.TemplateResponse("admin/index.html", {"request": request})
|
93 |
+
|
94 |
+
|
95 |
+
# Admin dishes page
|
96 |
+
@app.get("/admin/dishes", response_class=HTMLResponse)
|
97 |
+
async def admin_dishes_page(request: Request):
|
98 |
+
return templates.TemplateResponse("admin/dishes.html", {"request": request})
|
99 |
+
|
100 |
+
|
101 |
+
# Analysis page
|
102 |
+
@app.get("/analysis", response_class=HTMLResponse)
|
103 |
+
async def analysis_page(request: Request):
|
104 |
+
return templates.TemplateResponse("analysis/index.html", {"request": request})
|
105 |
+
|
106 |
+
|
107 |
+
# Chef analysis page
|
108 |
+
@app.get("/analysis/chef", response_class=HTMLResponse)
|
109 |
+
async def chef_analysis_page(request: Request):
|
110 |
+
return templates.TemplateResponse("analysis/chef.html", {"request": request})
|
111 |
+
|
112 |
+
|
113 |
+
# Customer analysis page
|
114 |
+
@app.get("/analysis/customer", response_class=HTMLResponse)
|
115 |
+
async def customer_analysis_page(request: Request):
|
116 |
+
return templates.TemplateResponse("analysis/customer.html", {"request": request})
|
117 |
+
|
118 |
+
|
119 |
+
# Dish analysis page
|
120 |
+
@app.get("/analysis/dish", response_class=HTMLResponse)
|
121 |
+
async def dish_analysis_page(request: Request):
|
122 |
+
return templates.TemplateResponse("analysis/dish.html", {"request": request})
|
123 |
+
|
124 |
+
|
125 |
+
if __name__ == "__main__":
|
126 |
+
uvicorn.run("app.main:app", host="0.0.0.0", port=8000, reload=True)
|
app/models/__pycache__/dish.cpython-311.pyc
ADDED
Binary file (2.51 kB). View file
|
|
app/models/__pycache__/dish.cpython-312.pyc
ADDED
Binary file (1.99 kB). View file
|
|
app/models/__pycache__/feedback.cpython-311.pyc
ADDED
Binary file (1.48 kB). View file
|
|
app/models/__pycache__/feedback.cpython-312.pyc
ADDED
Binary file (1.19 kB). View file
|
|
app/models/__pycache__/inventory.cpython-311.pyc
ADDED
Binary file (2.4 kB). View file
|
|
app/models/__pycache__/loyalty.cpython-311.pyc
ADDED
Binary file (1.91 kB). View file
|
|
app/models/__pycache__/loyalty.cpython-312.pyc
ADDED
Binary file (1.53 kB). View file
|
|
app/models/__pycache__/order.cpython-311.pyc
ADDED
Binary file (3.63 kB). View file
|
|
app/models/__pycache__/order.cpython-312.pyc
ADDED
Binary file (2.94 kB). View file
|
|
app/models/__pycache__/selection_offer.cpython-311.pyc
ADDED
Binary file (2.04 kB). View file
|
|
app/models/__pycache__/selection_offer.cpython-312.pyc
ADDED
Binary file (1.63 kB). View file
|
|
app/models/__pycache__/settings.cpython-312.pyc
ADDED
Binary file (1.78 kB). View file
|
|
app/models/__pycache__/table.cpython-311.pyc
ADDED
Binary file (2.16 kB). View file
|
|
app/models/__pycache__/table.cpython-312.pyc
ADDED
Binary file (1.71 kB). View file
|
|
app/models/__pycache__/user.cpython-311.pyc
ADDED
Binary file (1.68 kB). View file
|
|
app/models/__pycache__/user.cpython-312.pyc
ADDED
Binary file (2.13 kB). View file
|
|
app/models/dish.py
ADDED
@@ -0,0 +1,36 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
from pydantic import BaseModel
|
2 |
+
from typing import Optional
|
3 |
+
from datetime import datetime
|
4 |
+
|
5 |
+
class DishBase(BaseModel):
|
6 |
+
name: str
|
7 |
+
description: Optional[str] = None
|
8 |
+
category: str
|
9 |
+
price: float
|
10 |
+
quantity: int
|
11 |
+
discount: Optional[float] = 0
|
12 |
+
is_offer: Optional[int] = 0
|
13 |
+
is_special: Optional[int] = 0
|
14 |
+
|
15 |
+
class DishCreate(DishBase):
|
16 |
+
pass
|
17 |
+
|
18 |
+
class DishUpdate(DishBase):
|
19 |
+
name: Optional[str] = None
|
20 |
+
description: Optional[str] = None
|
21 |
+
category: Optional[str] = None
|
22 |
+
price: Optional[float] = None
|
23 |
+
quantity: Optional[int] = None
|
24 |
+
image_path: Optional[str] = None
|
25 |
+
discount: Optional[float] = None
|
26 |
+
is_offer: Optional[int] = None
|
27 |
+
is_special: Optional[int] = None
|
28 |
+
|
29 |
+
class Dish(DishBase):
|
30 |
+
id: int
|
31 |
+
image_path: Optional[str] = None
|
32 |
+
created_at: datetime
|
33 |
+
updated_at: datetime
|
34 |
+
|
35 |
+
class Config:
|
36 |
+
from_attributes = True # Updated from orm_mode for Pydantic V2
|
app/models/feedback.py
ADDED
@@ -0,0 +1,22 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
from pydantic import BaseModel
|
2 |
+
from typing import Optional
|
3 |
+
from datetime import datetime
|
4 |
+
|
5 |
+
|
6 |
+
class FeedbackBase(BaseModel):
|
7 |
+
order_id: int
|
8 |
+
rating: int
|
9 |
+
comment: Optional[str] = None
|
10 |
+
person_id: Optional[int] = None
|
11 |
+
|
12 |
+
|
13 |
+
class FeedbackCreate(FeedbackBase):
|
14 |
+
pass
|
15 |
+
|
16 |
+
|
17 |
+
class Feedback(FeedbackBase):
|
18 |
+
id: int
|
19 |
+
created_at: datetime
|
20 |
+
|
21 |
+
class Config:
|
22 |
+
from_attributes = True # Updated from orm_mode for Pydantic V2
|
app/models/loyalty.py
ADDED
@@ -0,0 +1,28 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
from pydantic import BaseModel
|
2 |
+
from typing import Optional
|
3 |
+
from datetime import datetime
|
4 |
+
|
5 |
+
|
6 |
+
class LoyaltyProgramBase(BaseModel):
|
7 |
+
visit_count: int
|
8 |
+
discount_percentage: float
|
9 |
+
is_active: bool = True
|
10 |
+
|
11 |
+
|
12 |
+
class LoyaltyProgramCreate(LoyaltyProgramBase):
|
13 |
+
pass
|
14 |
+
|
15 |
+
|
16 |
+
class LoyaltyProgramUpdate(BaseModel):
|
17 |
+
visit_count: Optional[int] = None
|
18 |
+
discount_percentage: Optional[float] = None
|
19 |
+
is_active: Optional[bool] = None
|
20 |
+
|
21 |
+
|
22 |
+
class LoyaltyProgram(LoyaltyProgramBase):
|
23 |
+
id: int
|
24 |
+
created_at: datetime
|
25 |
+
updated_at: datetime
|
26 |
+
|
27 |
+
class Config:
|
28 |
+
from_attributes = True # Updated from orm_mode for Pydantic V2
|
app/models/order.py
ADDED
@@ -0,0 +1,60 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
from pydantic import BaseModel
|
2 |
+
from typing import List, Optional
|
3 |
+
from datetime import datetime
|
4 |
+
from .dish import Dish
|
5 |
+
|
6 |
+
|
7 |
+
class OrderItemBase(BaseModel):
|
8 |
+
dish_id: int
|
9 |
+
quantity: int = 1
|
10 |
+
remarks: Optional[str] = None
|
11 |
+
|
12 |
+
|
13 |
+
class OrderItemCreate(OrderItemBase):
|
14 |
+
pass
|
15 |
+
|
16 |
+
|
17 |
+
class OrderItem(OrderItemBase):
|
18 |
+
id: int
|
19 |
+
order_id: int
|
20 |
+
created_at: datetime
|
21 |
+
dish: Optional[Dish] = None
|
22 |
+
|
23 |
+
# Add dish_name property to ensure it's always available
|
24 |
+
@property
|
25 |
+
def dish_name(self) -> str:
|
26 |
+
if self.dish:
|
27 |
+
return self.dish.name
|
28 |
+
return "Unknown Dish"
|
29 |
+
|
30 |
+
class Config:
|
31 |
+
from_attributes = True # Updated from orm_mode for Pydantic V2
|
32 |
+
|
33 |
+
|
34 |
+
class OrderBase(BaseModel):
|
35 |
+
table_number: int
|
36 |
+
unique_id: str
|
37 |
+
|
38 |
+
|
39 |
+
class OrderCreate(OrderBase):
|
40 |
+
items: List[OrderItemCreate]
|
41 |
+
username: Optional[str] = None
|
42 |
+
password: Optional[str] = None
|
43 |
+
|
44 |
+
|
45 |
+
class OrderUpdate(BaseModel):
|
46 |
+
status: str
|
47 |
+
|
48 |
+
|
49 |
+
class Order(OrderBase):
|
50 |
+
id: int
|
51 |
+
status: str
|
52 |
+
created_at: datetime
|
53 |
+
updated_at: datetime
|
54 |
+
items: List[OrderItem] = []
|
55 |
+
person_id: Optional[int] = None
|
56 |
+
person_name: Optional[str] = None
|
57 |
+
visit_count: Optional[int] = None
|
58 |
+
|
59 |
+
class Config:
|
60 |
+
from_attributes = True # Updated from orm_mode for Pydantic V2
|
app/models/selection_offer.py
ADDED
@@ -0,0 +1,30 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
from pydantic import BaseModel
|
2 |
+
from typing import Optional
|
3 |
+
from datetime import datetime
|
4 |
+
|
5 |
+
|
6 |
+
class SelectionOfferBase(BaseModel):
|
7 |
+
min_amount: float
|
8 |
+
discount_amount: float
|
9 |
+
is_active: bool = True
|
10 |
+
description: Optional[str] = None
|
11 |
+
|
12 |
+
|
13 |
+
class SelectionOfferCreate(SelectionOfferBase):
|
14 |
+
pass
|
15 |
+
|
16 |
+
|
17 |
+
class SelectionOfferUpdate(BaseModel):
|
18 |
+
min_amount: Optional[float] = None
|
19 |
+
discount_amount: Optional[float] = None
|
20 |
+
is_active: Optional[bool] = None
|
21 |
+
description: Optional[str] = None
|
22 |
+
|
23 |
+
|
24 |
+
class SelectionOffer(SelectionOfferBase):
|
25 |
+
id: int
|
26 |
+
created_at: datetime
|
27 |
+
updated_at: datetime
|
28 |
+
|
29 |
+
class Config:
|
30 |
+
from_attributes = True # Updated from orm_mode for Pydantic V2
|
app/models/settings.py
ADDED
@@ -0,0 +1,34 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
from pydantic import BaseModel
|
2 |
+
from typing import Optional
|
3 |
+
from datetime import datetime
|
4 |
+
|
5 |
+
|
6 |
+
class SettingsBase(BaseModel):
|
7 |
+
hotel_name: str
|
8 |
+
address: Optional[str] = None
|
9 |
+
contact_number: Optional[str] = None
|
10 |
+
email: Optional[str] = None
|
11 |
+
tax_id: Optional[str] = None
|
12 |
+
logo_path: Optional[str] = None
|
13 |
+
|
14 |
+
|
15 |
+
class SettingsCreate(SettingsBase):
|
16 |
+
pass
|
17 |
+
|
18 |
+
|
19 |
+
class SettingsUpdate(BaseModel):
|
20 |
+
hotel_name: Optional[str] = None
|
21 |
+
address: Optional[str] = None
|
22 |
+
contact_number: Optional[str] = None
|
23 |
+
email: Optional[str] = None
|
24 |
+
tax_id: Optional[str] = None
|
25 |
+
logo_path: Optional[str] = None
|
26 |
+
|
27 |
+
|
28 |
+
class Settings(SettingsBase):
|
29 |
+
id: int
|
30 |
+
created_at: datetime
|
31 |
+
updated_at: datetime
|
32 |
+
|
33 |
+
class Config:
|
34 |
+
from_attributes = True # Updated from orm_mode for Pydantic V2
|
app/models/table.py
ADDED
@@ -0,0 +1,33 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
from pydantic import BaseModel
|
2 |
+
from typing import Optional
|
3 |
+
from datetime import datetime
|
4 |
+
|
5 |
+
|
6 |
+
class TableBase(BaseModel):
|
7 |
+
table_number: int
|
8 |
+
is_occupied: bool = False
|
9 |
+
current_order_id: Optional[int] = None
|
10 |
+
|
11 |
+
|
12 |
+
class TableCreate(TableBase):
|
13 |
+
pass
|
14 |
+
|
15 |
+
|
16 |
+
class TableUpdate(BaseModel):
|
17 |
+
is_occupied: Optional[bool] = None
|
18 |
+
current_order_id: Optional[int] = None
|
19 |
+
|
20 |
+
|
21 |
+
class Table(TableBase):
|
22 |
+
id: int
|
23 |
+
created_at: datetime
|
24 |
+
updated_at: datetime
|
25 |
+
|
26 |
+
class Config:
|
27 |
+
from_attributes = True # Updated from orm_mode for Pydantic V2
|
28 |
+
|
29 |
+
|
30 |
+
class TableStatus(BaseModel):
|
31 |
+
total_tables: int
|
32 |
+
occupied_tables: int
|
33 |
+
free_tables: int
|
app/models/user.py
ADDED
@@ -0,0 +1,39 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
from pydantic import BaseModel
|
2 |
+
from typing import Optional
|
3 |
+
from datetime import datetime
|
4 |
+
|
5 |
+
class PersonBase(BaseModel):
|
6 |
+
username: str
|
7 |
+
|
8 |
+
class PersonCreate(PersonBase):
|
9 |
+
password: str
|
10 |
+
table_number: int
|
11 |
+
phone_number: Optional[str] = None
|
12 |
+
|
13 |
+
class PersonLogin(PersonBase):
|
14 |
+
password: str
|
15 |
+
table_number: int
|
16 |
+
|
17 |
+
class PhoneAuthRequest(BaseModel):
|
18 |
+
phone_number: str
|
19 |
+
table_number: int
|
20 |
+
|
21 |
+
class PhoneVerifyRequest(BaseModel):
|
22 |
+
phone_number: str
|
23 |
+
verification_code: str
|
24 |
+
table_number: int
|
25 |
+
|
26 |
+
class UsernameRequest(BaseModel):
|
27 |
+
phone_number: str
|
28 |
+
username: str
|
29 |
+
table_number: int
|
30 |
+
|
31 |
+
class Person(PersonBase):
|
32 |
+
id: int
|
33 |
+
visit_count: int
|
34 |
+
last_visit: datetime
|
35 |
+
created_at: datetime
|
36 |
+
phone_number: Optional[str] = None
|
37 |
+
|
38 |
+
class Config:
|
39 |
+
from_attributes = True # Updated from orm_mode for Pydantic V2
|
app/routers/__pycache__/admin.cpython-311.pyc
ADDED
Binary file (14.4 kB). View file
|
|
app/routers/__pycache__/admin.cpython-312.pyc
ADDED
Binary file (18.9 kB). View file
|
|
app/routers/__pycache__/analytics.cpython-312.pyc
ADDED
Binary file (25 kB). View file
|
|
app/routers/__pycache__/chef.cpython-311.pyc
ADDED
Binary file (2.91 kB). View file
|
|
app/routers/__pycache__/chef.cpython-312.pyc
ADDED
Binary file (2.5 kB). View file
|
|
app/routers/__pycache__/customer.cpython-311.pyc
ADDED
Binary file (13.2 kB). View file
|
|
app/routers/__pycache__/customer.cpython-312.pyc
ADDED
Binary file (20 kB). View file
|
|
app/routers/__pycache__/feedback.cpython-311.pyc
ADDED
Binary file (4.06 kB). View file
|
|
app/routers/__pycache__/feedback.cpython-312.pyc
ADDED
Binary file (3.55 kB). View file
|
|
app/routers/__pycache__/loyalty.cpython-311.pyc
ADDED
Binary file (7.25 kB). View file
|
|
app/routers/__pycache__/loyalty.cpython-312.pyc
ADDED
Binary file (6.62 kB). View file
|
|
app/routers/__pycache__/selection_offer.cpython-311.pyc
ADDED
Binary file (7.57 kB). View file
|
|