mirror of
https://github.com/Hestia-Homes/insight.git
synced 2026-06-30 13:10:44 +00:00
push to main
This commit is contained in:
parent
ff28c5654f
commit
28b41db0bf
1 changed files with 31 additions and 34 deletions
|
|
@ -35,7 +35,7 @@ def weeks_between(start, end):
|
|||
|
||||
|
||||
# -----------------------------------------------------
|
||||
# Build Forecast DF
|
||||
# Build Forecast DF (CORRECT PRICE × QUANTITY)
|
||||
# -----------------------------------------------------
|
||||
def build_master_df(local=False) -> pd.DataFrame:
|
||||
if not local:
|
||||
|
|
@ -58,15 +58,25 @@ def build_master_df(local=False) -> pd.DataFrame:
|
|||
if deal["company_info"]["name"] == "Apple":
|
||||
continue
|
||||
|
||||
price = next(
|
||||
# -------- Match correct line item --------
|
||||
line_item = next(
|
||||
(
|
||||
float(item.get("price", 0))
|
||||
item
|
||||
for item in deal.get("line_items", [])
|
||||
if work_type.lower() in item.get("name", "").lower()
|
||||
),
|
||||
0,
|
||||
None,
|
||||
)
|
||||
|
||||
if not line_item:
|
||||
continue
|
||||
|
||||
unit_price = float(line_item.get("price", 0))
|
||||
quantity = float(line_item.get("quantity", 1))
|
||||
|
||||
# 🔥 CRITICAL FIX
|
||||
total_revenue = unit_price * quantity
|
||||
|
||||
start = pd.to_datetime(
|
||||
hubspot_data.to_date_only(
|
||||
deal["deal_properties"].get("expected_project_start_date")
|
||||
|
|
@ -85,10 +95,13 @@ def build_master_df(local=False) -> pd.DataFrame:
|
|||
|
||||
if pd.notna(end) and end >= start:
|
||||
weeks = weeks_between(start, end)
|
||||
weekly_rev = price / len(weeks) if weeks else 0
|
||||
n = len(weeks)
|
||||
weekly_revenue = total_revenue / n if n else 0
|
||||
weekly_quantity = quantity / n if n else 0
|
||||
else:
|
||||
weeks = [pd.to_datetime(week_start_monday(start))]
|
||||
weekly_rev = price
|
||||
weekly_revenue = total_revenue
|
||||
weekly_quantity = quantity
|
||||
|
||||
for w in weeks:
|
||||
rows.append(
|
||||
|
|
@ -98,12 +111,15 @@ def build_master_df(local=False) -> pd.DataFrame:
|
|||
"company_name": deal["company_info"]["name"],
|
||||
"work_type": work_type,
|
||||
"Planned Week": w.strftime("%Y-%m-%d"),
|
||||
"revenue": weekly_rev,
|
||||
"revenue": weekly_revenue,
|
||||
"quantity": weekly_quantity,
|
||||
}
|
||||
)
|
||||
|
||||
df = pd.DataFrame(rows)
|
||||
df["revenue"] = pd.to_numeric(df["revenue"], errors="coerce").fillna(0)
|
||||
df["quantity"] = pd.to_numeric(df["quantity"], errors="coerce").fillna(0)
|
||||
|
||||
return df
|
||||
|
||||
|
||||
|
|
@ -117,26 +133,16 @@ layout = html.Div(
|
|||
html.H1("Sales Forecast", className="text-center"),
|
||||
html.Hr(),
|
||||
|
||||
# ---------------- SUMMARY TABLES ----------------
|
||||
html.H3("Revenue by Work Type"),
|
||||
dash_table.DataTable(
|
||||
id="sf-worktype-table",
|
||||
sort_action="native",
|
||||
style_cell={"textAlign": "center"},
|
||||
),
|
||||
dash_table.DataTable(id="sf-worktype-table", sort_action="native"),
|
||||
|
||||
html.Hr(),
|
||||
|
||||
html.H3("Revenue by Company"),
|
||||
dash_table.DataTable(
|
||||
id="sf-company-table",
|
||||
sort_action="native",
|
||||
style_cell={"textAlign": "center"},
|
||||
),
|
||||
dash_table.DataTable(id="sf-company-table", sort_action="native"),
|
||||
|
||||
html.Hr(),
|
||||
|
||||
# ---------------- WEEKLY FUTURE VIEW ----------------
|
||||
html.H3("Weekly Planned Revenue (£)"),
|
||||
dash_table.DataTable(
|
||||
id="sf-weekly-table",
|
||||
|
|
@ -149,7 +155,6 @@ layout = html.Div(
|
|||
|
||||
dcc.Graph(id="sf-weekly-revenue-graph"),
|
||||
|
||||
# ---------------- MODAL (NAMESPACED) ----------------
|
||||
dbc.Modal(
|
||||
[
|
||||
dbc.ModalHeader("HubSpot Deals"),
|
||||
|
|
@ -176,35 +181,33 @@ layout = html.Div(
|
|||
Output("sf-weekly-table", "data"),
|
||||
Output("sf-weekly-table", "columns"),
|
||||
Output("sf-weekly-revenue-graph", "figure"),
|
||||
Input("sf-weekly-table", "id"), # run once
|
||||
Input("sf-weekly-table", "id"),
|
||||
)
|
||||
def build_outputs(_):
|
||||
|
||||
# -------- Revenue by work type --------
|
||||
by_work = (
|
||||
df.groupby("work_type")
|
||||
.agg(
|
||||
revenue=("revenue", "sum"),
|
||||
jobs=("hubspot_id", "nunique"),
|
||||
jobs=("quantity", "sum"),
|
||||
)
|
||||
.reset_index()
|
||||
)
|
||||
|
||||
# -------- Revenue by company --------
|
||||
by_company = (
|
||||
df.groupby("company_name")
|
||||
.agg(
|
||||
revenue=("revenue", "sum"),
|
||||
jobs=("hubspot_id", "nunique"),
|
||||
jobs=("quantity", "sum"),
|
||||
)
|
||||
.reset_index()
|
||||
)
|
||||
|
||||
# -------- Weekly pivot --------
|
||||
pivot = (
|
||||
df.groupby(["work_type", "Planned Week"])
|
||||
.agg(
|
||||
revenue=("revenue", "sum"),
|
||||
jobs=("quantity", "sum"),
|
||||
ids=("hubspot_id", lambda x: SAFE_DELIM.join(sorted(set(x)))),
|
||||
)
|
||||
.reset_index()
|
||||
|
|
@ -223,7 +226,6 @@ def build_outputs(_):
|
|||
|
||||
weekly = revenue_tbl.merge(ids_tbl, on="Work Type", suffixes=("", "_ids"))
|
||||
|
||||
# -------- Weekly graph --------
|
||||
weekly_rev = (
|
||||
df.groupby("Planned Week")["revenue"]
|
||||
.sum()
|
||||
|
|
@ -253,7 +255,7 @@ def build_outputs(_):
|
|||
|
||||
|
||||
# -----------------------------------------------------
|
||||
# Modal: HubSpot debug (SINGLE CALLBACK, NAMESPACED)
|
||||
# Modal: HubSpot debug
|
||||
# -----------------------------------------------------
|
||||
def id_to_link(deal_id):
|
||||
url = f"https://app.hubspot.com/contacts/145275138/record/0-3/{deal_id}"
|
||||
|
|
@ -273,9 +275,7 @@ def id_to_link(deal_id):
|
|||
)
|
||||
def open_modal(cell, close_click, table_data, is_open):
|
||||
|
||||
triggered = ctx.triggered_id
|
||||
|
||||
if triggered == "sf-close-modal":
|
||||
if ctx.triggered_id == "sf-close-modal":
|
||||
return False, "", None
|
||||
|
||||
if not cell:
|
||||
|
|
@ -296,6 +296,3 @@ def open_modal(cell, close_click, table_data, is_open):
|
|||
html.Ul([id_to_link(d) for d in ids.split(SAFE_DELIM)]),
|
||||
None,
|
||||
)
|
||||
|
||||
|
||||
# TODO: FOROGT TO ADD QUANTITY - IDIOT
|
||||
Loading…
Add table
Reference in a new issue