EOD and Carryover tickets added

This commit is contained in:
2026-08-27 15:46:15 -05:00
parent f3c9792117
commit ae74f78520
10 changed files with 224 additions and 59 deletions
+73 -24
View File
@@ -9,7 +9,7 @@ pattern rather than blocking the UI.
from __future__ import annotations
import datetime as dt
from typing import List, TypedDict
from typing import List, Tuple, TypedDict
from PyQt6.QtCore import QThread, pyqtSignal
from sqlalchemy import select
@@ -17,8 +17,10 @@ from sqlalchemy import select
from app import config
from app.database import get_session
from app.models import Order
from app.schedule import get_cutoff_time, is_past_cutoff
from app.services.base import OrderService, NormalizedOrder
from app.status_rules import parse_status_list, status_in
from app.tracking import get_fulfilled_statuses
class StatusChange(TypedDict):
@@ -69,6 +71,11 @@ def save_orders(orders: List[NormalizedOrder]) -> SaveResult:
existing JIRA row for that ticket. If no such row exists locally yet,
the ticket number is reported back as unmatched instead of silently
dropped.
Whenever a JIRA ticket's status transitions INTO a fulfilled status
(Waiting For Return / Device Return Not Needed), fulfilled_at is
stamped - that's what lets the dashboard show "fulfilled today" and
what moves it into the Done pile.
"""
session = get_session()
new_count = 0
@@ -76,6 +83,7 @@ def save_orders(orders: List[NormalizedOrder]) -> SaveResult:
enriched_count = 0
status_changes: List[StatusChange] = []
unmatched_tracking_tickets: List[str] = []
fulfilled_statuses = get_fulfilled_statuses()
try:
for order in orders:
@@ -103,6 +111,8 @@ def save_orders(orders: List[NormalizedOrder]) -> SaveResult:
)
).scalar_one_or_none()
new_status = order["status"]
if existing is None:
session.add(
Order(
@@ -112,15 +122,17 @@ def save_orders(orders: List[NormalizedOrder]) -> SaveResult:
company=order.get("company", "Unknown"),
skus=order.get("skus", []),
summary=order["summary"],
status=order["status"],
status=new_status,
source_created_at=order["source_created_at"],
raw_data=order["raw_data"],
fulfilled_at=(
dt.datetime.utcnow() if status_in(new_status, fulfilled_statuses) else None
),
)
)
new_count += 1
else:
old_status = existing.status
new_status = order["status"]
if old_status != new_status:
status_changes.append(
StatusChange(
@@ -129,6 +141,10 @@ def save_orders(orders: List[NormalizedOrder]) -> SaveResult:
new_status=new_status,
)
)
if status_in(new_status, fulfilled_statuses) and not status_in(
old_status, fulfilled_statuses
):
existing.fulfilled_at = dt.datetime.utcnow()
existing.ticket_number = order.get("ticket_number")
existing.company = order.get("company", "Unknown")
@@ -162,46 +178,59 @@ def load_all_orders() -> List[Order]:
session.close()
def split_active_and_done(orders: List[Order]) -> Tuple[List[Order], List[Order]]:
"""
Active = still being worked (includes cancelled - those still need
eyes on them). Done = fulfilled (Waiting For Return / Device Return
Not Needed) - archived out of the working view on purpose, per how
the team wants to keep the active list focused on what's at hand.
"""
fulfilled_statuses = get_fulfilled_statuses()
active, done = [], []
for order in orders:
(done if status_in(order.status, fulfilled_statuses) else active).append(order)
return active, done
def load_active_and_done_orders() -> Tuple[List[Order], List[Order]]:
return split_active_and_done(load_all_orders())
def get_dashboard_stats() -> dict:
"""
Counts for the dashboard: totals by company, how many are cancelled,
fulfilled, still-open-from-a-previous-day (carryover), and how many
have had tracking numbers pulled yet.
Counts for the dashboard. "Active Orders" and the company breakdown
reflect only the active workload (fulfilled tickets have moved to
the Done pile and don't clutter this). Fulfilled-today and
past-cutoff-today look across ALL of today's tickets regardless of
which pile they're in now, since both are about what happened today.
Carryover counts any still-open ticket that's already known to spill
into tomorrow - either it's genuinely left over from a prior day, or
it arrived today but after the cutoff (same effect, just known a day
earlier).
"""
orders = load_all_orders()
active_orders, _done_orders = split_active_and_done(orders)
cancelled_statuses = parse_status_list(
config.get("CANCELLED_STATUSES", config.DEFAULT_CANCELLED_STATUSES)
)
fulfilled_statuses = parse_status_list(
",".join(
[
config.get("FULFILLED_STATUS_WITH_RETURN", config.DEFAULT_FULFILLED_WITH_RETURN),
config.get(
"FULFILLED_STATUS_WITHOUT_RETURN", config.DEFAULT_FULFILLED_WITHOUT_RETURN
),
]
)
)
terminal_statuses = parse_status_list(
config.get("JIRA_TERMINAL_STATUSES", config.DEFAULT_TERMINAL_STATUSES)
)
cutoff = get_cutoff_time()
today = dt.date.today()
by_company: dict[str, int] = {}
cancelled_count = 0
fulfilled_count = 0
carryover_count = 0
tracking_received_count = 0
for order in orders:
for order in active_orders:
by_company[order.company] = by_company.get(order.company, 0) + 1
if status_in(order.status, cancelled_statuses):
cancelled_count += 1
if status_in(order.status, fulfilled_statuses):
fulfilled_count += 1
if order.tracking_numbers:
tracking_received_count += 1
@@ -209,14 +238,34 @@ def get_dashboard_stats() -> dict:
created_before_today = bool(
order.source_created_at and order.source_created_at.date() < today
)
if still_open and created_before_today:
# A ticket that arrived today but after the cutoff won't get worked
# today either - it's known carryover before the date even rolls
# over, not just once tomorrow arrives.
arrived_past_cutoff_today = bool(
order.source_created_at
and order.source_created_at.date() == today
and is_past_cutoff(order.source_created_at, cutoff)
)
if still_open and (created_before_today or arrived_past_cutoff_today):
carryover_count += 1
fulfilled_today_count = sum(
1 for o in orders if o.fulfilled_at and o.fulfilled_at.date() == today
)
past_cutoff_today_count = sum(
1
for o in orders
if o.source_created_at
and o.source_created_at.date() == today
and is_past_cutoff(o.source_created_at, cutoff)
)
return {
"total": len(orders),
"total": len(active_orders),
"by_company": by_company,
"cancelled_count": cancelled_count,
"fulfilled_count": fulfilled_count,
"carryover_count": carryover_count,
"tracking_received_count": tracking_received_count,
"fulfilled_today_count": fulfilled_today_count,
"past_cutoff_today_count": past_cutoff_today_count,
}