Spaces:
Build error
Build error
| 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"> | |
| © 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() |