keyinnovations's picture
Update app.py
8c017bb verified
import streamlit as st
import pandas as pd
st.set_page_config(
page_title="Key Innovations Inc.",
page_icon="https://tscstatic.keyinnovations.ca/logo/logo_1T895ONEIG.png"
)
st.image("https://tscstatic.keyinnovations.ca/logo/logo_1T895ONEIG.png", width=150)
st.title('Quoting System')
st.subheader('Key Innovation Inc.')
#Option to select a clothing method.
option = st.segmented_control(
"Select an option:",
["Embroidery", "Screen Print", "Embroidery & Screen Print"]
)
#Embroidory Pricing Dataset
data = {
"Quantity": ["0-11", "12-17", "18-23", "24-35", "36-59", "60-119", "120-239", "240-599","600+"],
"1-1,000": [10.00, 5.00, 4.00, 3.25, 2.75, 2.25, 2.00, 1.75, 1.50],
"1,000-2,000": [11.00, 5.50, 4.40, 3.60, 3.05, 2.53, 2.27, 2.01, 1.75],
"2,001-3,000": [12.00, 6.00, 4.80, 3.95, 3.35, 2.81, 2.54, 2.27, 2.00],
"3,001-4,000": [13.00, 6.50, 5.20, 4.30, 3.65, 3.09, 2.81, 2.53, 2.25],
"4,001-5,000": [14.00, 7.00, 5.60, 4.65, 3.95, 3.37, 3.08, 2.79, 2.50],
"5,001-6,000": [15.00, 7.50, 6.00, 5.00, 4.25, 3.65, 3.35, 3.05, 2.75],
"6,001-7,000": [16.00, 8.00, 6.40, 5.35, 4.55, 3.93, 3.62, 3.31, 3.00],
"7,001-8,000": [17.00, 8.50, 6.80, 5.70, 4.85, 4.21, 3.89, 3.57, 3.25],
"8,001-9,000": [18.00, 9.00, 7.20, 6.05, 5.15, 4.49, 4.16, 3.83, 3.50],
"9,001-10,000": [19.00, 9.50, 7.60, 6.40, 5.45, 4.77, 4.43, 4.09, 3.75],
"10,001-11,000": [20.00, 10.00, 8.00, 6.75, 5.75, 5.05, 4.70, 4.35, 4.00],
"11,001-12,000": [21.00, 10.50, 8.40, 7.10, 6.05, 5.33, 4.97, 4.61, 4.25],
"12,001-13,000": [22.00, 11.00, 8.80, 7.45, 6.35, 5.61, 5.24, 4.87, 4.50],
"13,001-14,000": [23.00, 11.50, 9.20, 7.80, 6.65, 5.89, 5.51, 5.13, 4.75],
"14,001-15,000": [24.00, 12.00, 9.60, 8.15, 6.95, 6.17, 5.78, 5.39, 5.00],
"15,001-16,000": [25.00, 12.50, 10.00, 8.50, 7.25, 6.45, 6.05, 5.65, 5.25],
"16,001-17,000": [26.00, 13.00, 10.40, 8.85, 7.55, 6.73, 6.32, 5.91, 5.50],
"17,001-18,000": [27.00, 13.50, 10.80, 9.20, 7.85, 7.01, 6.59, 6.17, 5.75],
"18,001-19,000": [28.00, 14.00, 11.20, 9.55, 8.15, 7.29, 6.86, 6.43, 6.00],
"19,001-20,000": [29.00, 14.50, 11.60, 9.90, 8.45, 7.57, 7.13, 6.69, 6.25]
}
df = pd.DataFrame(data)
net_value = 0
if option == 'Embroidery':
if "entries" not in st.session_state:
st.session_state.entries = []
st.subheader("Enter Item Details")
col1, col2, col3 = st.columns(3)
with col1:
quantity = st.number_input("Enter Quantity", min_value=1, step=1, key="quantity")
with col2:
stitch_count = st.selectbox(
"Select Stitch Count",
options=list(df.columns[1:]),
key="stitch_count"
)
with col3:
item_price = st.number_input('Item Cost (Fixed)', min_value=0.0, step=0.01, key="item_price")
use_manual_margin = st.checkbox("Use Manual Margin")
# Ensure selected_range & stitch_price are always calculated
selected_range = next((key for key, val in {
"0-11": range(0, 12), "12-17": range(12, 18), "18-23": range(18, 24),
"24-35": range(24, 36), "36-59": range(36, 60), "60-119": range(60, 120),
"120-239": range(120, 240), "240-599": range(240, 600), "600+": range(601, 2000)
}.items() if quantity in val), "600+")
stitch_price = df[df["Quantity"] == selected_range][stitch_count].values[0]
# Calculate Net Value Before Margin Selection
net_value = quantity * (item_price + stitch_price)
if use_manual_margin:
margin_percentage = st.slider("Select Margin (%)", min_value=1.0, max_value=99.0, step=0.5, value=60.0, format="%.2f%%")
margin = margin_percentage / 100 # Manual margin stored as decimal
margin_display = f"{margin_percentage:.2f}%" # Display the exact selected percentage
else:
# Automatic Margin Selection
margin_data = [
(0, 0.4), (150, 0.5), (210, 0.525), (275, 0.55), (345, 0.575),
(840, 0.6), (1563, 0.625), (2600, 0.65), (4290, 0.66), (6030, 0.67)
]
margin = next((rate for threshold, rate in reversed(margin_data) if net_value >= threshold), 0.67)
margin_display = f"{margin * 100:.2f}%" # Convert automatic margin
if st.button("βž• Add Entry"):
if quantity and stitch_count and item_price:
total_selling_price = net_value / (1 - margin)
unit_selling_price = total_selling_price / quantity
entry = {
"Quantity": quantity,
"Stitch Count": stitch_count,
"Stitch Price": stitch_price,
"Total Net Cost": f"${net_value:,.2f}",
"Margin": margin_display,
"Unit Selling Price": f"${unit_selling_price:.2f}",
"Total Selling Price": f"${total_selling_price:.2f}"
}
st.session_state.entries.append(entry)
if st.session_state.entries:
st.subheader("Pricing Breakdown")
for i, entry in enumerate(st.session_state.entries):
st.text("==========================================================================")
st.write(f"### Entry {i+1}")
col1, col2, col3 = st.columns(3)
with col1:
st.metric(label="πŸ“Œ Quantity", value=entry["Quantity"])
with col2:
#st.metric(label="πŸͺ‘ Stitch Count", value=entry["Stitch Count"])
st.metric(label="πŸͺ‘ Stitch Price (per unit)", value=entry["Stitch Price"])
with col3:
st.metric(label="πŸ’° Total Net Cost", value=entry["Total Net Cost"])
col1, col2, col3 = st.columns(3)
with col1:
st.metric(label="πŸ“ˆ Margin", value=entry["Margin"])
#st.metric(label="πŸ“Š Margin", value=f"{(entry['Margin']) * 100:.2f}%")
with col2:
st.metric(label=f"πŸ“Š Unit Price", value=entry["Unit Selling Price"])
with col3:
st.metric(label="πŸ’° Total Selling Price", value=entry["Total Selling Price"])
col1, col2 = st.columns(2)
with col1:
if st.button(f"❌ Delete {i+1}", key=f"delete_{i}"):
del st.session_state.entries[i]
st.rerun()
st.text("===========================================================================")
if st.button("πŸ”„ Reset Entries"):
st.session_state.entries = []
st.rerun()
elif option == 'Screen Print':
#Pricing data for screenprint.
pricing_data = {
"1-Color ScreenPrint": pd.DataFrame({
"Qty": ["below 6", "6 to 12", "13 - 18", "19 - 24", "25 - 36", "37 - 48","49 - 72", "73 - 96", "97 - 144", "145 - 288", "289 - 500", "Above 500"],
"4x4": [7.42, 4.61, 4.13, 3.53, 2.88, 2.49, 2.13, 1.79, 1.51, 1.19, 0.89, 0.73],
"12x12": [10.47, 6.17, 5.45, 4.51, 3.55, 2.96, 2.49, 1.96, 1.59, 1.35, 1.05, 0.85],
"14x16": [11.87, 7.27, 6.34, 5.19, 4.13, 3.53, 3.02, 2.47, 2.08, 1.75, 1.35, 1.14],
"Darks": [0.35, 0.35, 0.35, 0.35, 0.35, 0.25, 0.25, 0.25, 0.25, 0.15, 0.15, 0.15],
"Fleece": [0.6, 0.6, 0.6, 0.6, 0.6, 0.5, 0.5, 0.5, 0.5, 0.45, 0.45, 0.45],
"90% Poly+": [0.55, 0.55, 0.55, 0.55, 0.55, 0.45, 0.45, 0.45, 0.45, 0.3, 0.3, 0.3],
"Sleeves & Legs":[0.40,0.40,0.40,0.40,0.40,0.40,0.40,0.40,0.40,0.40,0.40,0.40]
}),
"2-Color ScreenPrint": pd.DataFrame({
"Qty": ["below 6", "6 to 12", "13 - 18", "19 - 24", "25 - 36", "37 - 48","49 - 72", "73 - 96", "97 - 144", "145 - 288", "289 - 500", "Above 500"],
"4x4": [11.0, 7.16, 6.17, 4.91, 3.93, 3.43, 2.84, 2.30, 1.83, 1.58, 1.19, 1.0],
"12x12": [16.74, 10.40, 8.77, 6.76, 5.28, 4.64, 3.74, 2.81, 2.30, 1.83, 1.48, 1.23],
"14x16": [19.29, 12.69, 10.55, 7.93, 6.34, 5.55, 4.54, 3.23, 2.71, 2.29, 1.95, 1.73],
"Darks": [0.45, 0.45, 0.45, 0.45, 0.45, 0.35, 0.35, 0.35, 0.35, 0.25, 0.25, 0.25],
"Fleece": [0.6, 0.6, 0.6, 0.6, 0.6, 0.5, 0.5, 0.5, 0.5, 0.45, 0.45, 0.45],
"90% Poly+": [0.55, 0.55, 0.55, 0.55, 0.55, 0.45, 0.45, 0.45, 0.45, 0.3, 0.3, 0.3],
"Sleeves & Legs":[0.40,0.40,0.40,0.40,0.40,0.40,0.40,0.40,0.40,0.40,0.40,0.40]
}),
"3-Color ScreenPrint": pd.DataFrame({
"Qty": ["below 6", "6 to 12", "13 - 18", "19 - 24", "25 - 36", "37 - 48","49 - 72", "73 - 96", "97 - 144", "145 - 288", "289 - 500", "Above 500"],
"4x4": [16.11, 10.13, 8.53, 6.58, 5.25, 4.35, 3.73, 3.04, 2.58, 2.02, 1.72, 1.51],
"12x12": [25.81, 15.87, 12.88, 9.72, 7.71, 6.32, 5.26, 3.82, 3.17, 2.75, 2.31, 2.01],
"14x16": [29.55, 17.87, 14.91, 11.29, 9.09, 7.65, 6.27, 4.77, 4.05, 3.40, 3.0, 2.56],
"Darks": [0.55, 0.55, 0.55, 0.55, 0.55, 0.45, 0.45, 0.45, 0.45, 0.35, 0.35, 0.35],
"Fleece": [0.6, 0.6, 0.6, 0.6, 0.6, 0.5, 0.5, 0.5, 0.5, 0.45, 0.45, 0.45],
"90% Poly+": [0.55, 0.55, 0.55, 0.55, 0.55, 0.45, 0.45, 0.45, 0.45, 0.3, 0.3, 0.3],
"Sleeves & Legs":[0.40,0.40,0.40,0.40,0.40,0.40,0.40,0.40,0.40,0.40,0.40,0.40]
}),
"4-Color ScreenPrint": pd.DataFrame({
"Qty": ["below 6", "6 to 12", "13 - 18", "19 - 24", "25 - 36", "37 - 48","49 - 72", "73 - 96", "97 - 144", "145 - 288", "289 - 500", "Above 500"],
"4x4": [18.88, 11.74, 9.95, 7.72, 6.07, 5.18, 4.37, 3.71, 3.21, 2.43, 2.29, 2.06],
"12x12": [30.81, 18.37, 15.36, 11.86, 9.2, 7.82, 6.27, 4.86, 4.07, 3.13, 2.75, 2.62],
"14x16": [35.8, 21.26, 18.58, 15.17, 10.8, 9.34, 7.62, 5.99, 5.19, 3.92, 3.55, 3.33],
"Darks": [0.65, 0.65, 0.65, 0.65, 0.65, 0.55, 0.55, 0.55, 0.55, 0.45, 0.45, 0.45],
"Fleece": [0.6, 0.6, 0.6, 0.6, 0.6, 0.5, 0.5, 0.5, 0.5, 0.45, 0.45, 0.45],
"90% Poly+": [0.55, 0.55, 0.55, 0.55, 0.55, 0.45, 0.45, 0.45, 0.45, 0.3, 0.3, 0.3],
"Sleeves & Legs":[0.40,0.40,0.40,0.40,0.40,0.40,0.40,0.40,0.40,0.40,0.40,0.40]
}),
"5-Color ScreenPrint": pd.DataFrame({
"Qty": ["below 6", "6 to 12", "13 - 18", "19 - 24", "25 - 36", "37 - 48","49 - 72", "73 - 96", "97 - 144", "145 - 288", "289 - 500", "Above 500"],
"4x4": [23.87, 14.02, 11.79, 9.04, 7.09, 6.05, 5.09, 4.28, 3.76, 2.84, 2.68, 2.54],
"12x12": [39.36, 22.53, 18.66, 13.93, 10.88, 9.34, 7.26, 5.87, 4.88, 3.56, 3.15, 3.10],
"14x16": [46.2, 26.02, 22.05, 17.14, 12.87, 11.05, 9.00, 7.21, 6.02, 4.51, 4.02, 3.74],
"Darks": [0.8, 0.8, 0.8, 0.8, 0.8, 0.65, 0.65, 0.65, 0.65, 0.55, 0.55, 0.55],
"Fleece": [0.55, 0.55, 0.55, 0.55, 0.55, 0.45, 0.45, 0.45, 0.45, 0.40, 0.40, 0.40],
"90% Poly+": [0.55, 0.55, 0.55, 0.55, 0.55, 0.45, 0.45, 0.45, 0.45, 0.3, 0.3, 0.3],
"Sleeves & Legs":[0.40,0.40,0.40,0.40,0.40,0.40,0.40,0.40,0.40,0.40,0.40,0.40]
}),
"6-Color ScreenPrint": pd.DataFrame({
"Qty": ["below 6", "6 to 12", "13 - 18", "19 - 24", "25 - 36", "37 - 48","49 - 72", "73 - 96", "97 - 144", "145 - 288", "289 - 500", "Above 500"],
"4x4": [28.07, 16.41, 13.69, 10.36, 8.15, 6.89, 5.45, 4.95, 4.33, 3.35, 3.07, 2.94],
"12x12": [46.62, 26.69, 22.32, 14.22, 12.60, 10.85, 8.35, 6.92, 5.73, 4.07, 3.47, 3.33],
"14x16": [55.03, 30.88, 25.52, 19.03, 14.98, 12.74, 10.34, 8.53, 6.96, 5.18, 4.42, 4.21],
"Darks": [0.9, 0.9, 0.9, 0.9, 0.9, 0.75, 0.75, 0.75, 0.75, 0.65, 0.65, 0.65],
"Fleece": [0.6, 0.6, 0.6, 0.6, 0.6, 0.5, 0.5, 0.5, 0.5, 0.45, 0.45, 0.45],
"90% Poly+": [0.55, 0.55, 0.55, 0.55, 0.55, 0.45, 0.45, 0.45, 0.45, 0.3, 0.3, 0.3],
"Sleeves & Legs":[0.40,0.40,0.40,0.40,0.40,0.40,0.40,0.40,0.40,0.40,0.40,0.40]
}),
}
# --- Margin Matrix ---
margin_data = [
(0, 0.4), (150, 0.5), (210, 0.525), (275, 0.55), (345, 0.575),
(840, 0.6), (1563, 0.625), (2600, 0.65), (4290, 0.66), (6030, 0.67)
]
# --- Session State Initialization ---
if "entries_screenprint" not in st.session_state:
st.session_state.entries_screenprint = []
# --- User Inputs ---
col1, col2, col3, col4 = st.columns(4)
selected_type = col1.selectbox("Select Screen Print Type", pricing_data.keys())
selected_size = col2.selectbox("Select Print Size", ["4x4", "12x12", "14x16"])
quantity = col3.number_input("Enter Quantity", min_value=1, step=1)
selected_options = col4.multiselect("Select Options", ["Darks", "Fleece", "90% Poly+", "Sleeves & Legs"])
item_cost = st.number_input("Enter Base Item Cost", min_value=0.0, step=0.01)
use_manual_margin = st.checkbox("Use Manual Margin")
# --- Determine the Price Tier Based on Quantity ---
df = pricing_data[selected_type]
selected_range = next((row["Qty"] for _, row in df.iterrows() if quantity <= int(row["Qty"].split()[-1])), "Above 500")
# --- Fetch the Price Per Unit ---
row = df[df["Qty"] == selected_range]
if not row.empty and item_cost > 0:
base_price = row[selected_size].values[0]
unit_price_before_margin = base_price + item_cost
# --- Apply Additional Costs ---
for option in selected_options:
unit_price_before_margin += row[option].values[0]
# --- Calculate Total Cost Before Margin ---
total_cost = unit_price_before_margin * quantity
# --- Apply Manual or Automatic Margin ---
if use_manual_margin:
margin_percentage = st.slider(
"Select Margin (%)",
min_value=1.0,
max_value=99.0,
step=0.5,
value=60.0,
format="%.2f%%"
)
margin = margin_percentage / 100 # βœ… correct logic
margin_display = f"{margin_percentage:.2f}%" # βœ… matches manual input
else:
margin_data = [
(0, 0.4), (150, 0.5), (210, 0.525), (275, 0.55), (345, 0.575),
(840, 0.6), (1563, 0.625), (2600, 0.65), (4290, 0.66), (6030, 0.67)
]
margin = next((rate for threshold, rate in reversed(margin_data) if total_cost >= threshold), 0.67)
margin_display = f"{margin * 100:.2f}%" # βœ… correct display
# --- Calculate Selling Prices ---
total_selling_price = total_cost / (1-margin)
unit_price_after_margin = total_selling_price / quantity
# --- Add Entry Button ---
if st.button("βž• Add Entry"):
entry = {
"Quantity": quantity,
"Print Type": selected_type,
"Print Size": selected_size,
"Options": ", ".join(selected_options) if selected_options else "None",
"Item Cost": item_cost,
"Base Price Per Unit": base_price,
"Total Cost": total_cost,
"Margin": margin,
"Unit Price After Margin": unit_price_after_margin,
"Total Selling Price": total_selling_price
}
st.session_state.entries_screenprint.append(entry)
# --- Display Pricing Breakdown ---
if st.session_state.entries_screenprint:
st.subheader("Pricing Breakdown")
for i, entry in enumerate(st.session_state.entries_screenprint):
st.text("===========================================================================")
st.write(f"### Entry {i+1}")
col1, col2, col3 = st.columns(3)
with col1:
st.metric(label="βœ… Quantity", value=entry["Quantity"])
st.metric(label="πŸ’° Total Net Cost", value=f"${entry['Total Cost']:.2f}")
with col2:
st.metric(label="πŸ“ Print Size", value=entry["Print Size"])
#st.metric(label="πŸ“Š Margin", value=f"{(1 - entry['Margin']) * 100:.2f}%")
st.metric(label="πŸ“Š Margin", value=f"{entry['Margin'] * 100:.2f}%")
with col3:
#st.metric(label="🎨 Print Option", value=entry["Options"])
st.metric(label="πŸͺ‘ Print Cost (Per Unit)", value=f"${entry['Base Price Per Unit']:.2f}")
st.metric(label="πŸ’Έ Unit Selling Price", value=f"${entry['Unit Price After Margin']:.2f}")
st.metric(label="πŸ’΅ Total Selling Price", value=f"${entry['Total Selling Price']:.2f}")
# Delete Button
if st.button(f"❌ Delete {i+1}", key=f"delete_{i}"):
del st.session_state.entries_screenprint[i]
st.rerun()
if st.button("πŸ”„ Reset Entries"):
st.session_state.entries_screenprint = []
st.rerun()
elif option == 'Embroidery & Screen Print':
st.text('\nDevelopment in Progress.......')
def footer():
theme_bg = st.get_option("theme.backgroundColor")
theme_text = st.get_option("theme.textColor")
theme_primary = st.get_option("theme.primaryColor")
footer_html = f"""
<style>
@media (max-width: 768px) {{
.footer {{ display: none; }}
}}
.footer {{
position: fixed;
bottom: 0;
width: 100%;
background-color: {theme_bg}; /* Uses Streamlit theme background */
color: {theme_text}; /* Uses Streamlit theme text color */
text-align: center;
padding: 10px;
font-size: 14px;
border-top: 1px solid rgba(255, 255, 255, 0.2); /* Semi-transparent border */
}}
.footer a {{
color: {theme_primary}; /* Uses Streamlit theme primary color */
text-decoration: none;
margin: 0 10px;
}}
</style>
<div class="footer">
&copy; 2025 Key Innovations Inc. All rights reserved.
<br>
Follow us on:
<a href="https://www.linkedin.com/company/keyinnovations" target="_blank">LinkedIn</a> |
<a href="https://twitter.com/keyinnovations" target="_blank">Twitter</a> |
<a href="https://www.instagram.com/key.innovations/" target="_blank">Instagram</a> |
<a href="https://www.facebook.com/KeyInnovations/" target="_blank">Facebook</a>
</div>
"""
st.markdown(footer_html, unsafe_allow_html=True)
footer()