More Shipstation integrations(warehouses)

This commit is contained in:
2026-08-31 15:00:37 -05:00
parent 4c172c1fd5
commit 9651b82415
12 changed files with 337 additions and 139 deletions
+36 -32
View File
@@ -14,12 +14,11 @@ from typing import List, Tuple, TypedDict
from PyQt6.QtCore import QThread, pyqtSignal
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.status_rules import get_active_statuses, get_cancelled_statuses, status_in
from app.tracking import get_fulfilled_statuses
@@ -209,63 +208,68 @@ def load_all_orders() -> List[Order]:
session.close()
def split_active_and_done(orders: List[Order]) -> Tuple[List[Order], List[Order]]:
def split_orders_by_view(orders: List[Order]) -> Tuple[List[Order], 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.
Three tabs, allowlist-driven:
- Active: status is in ACTIVE_STATUSES (just "Created" by default) -
the only tickets that represent real work still to do.
- Cancelled: status is in CANCELLED_STATUSES - its own tab so it
doesn't clutter Active, but still reviewable on demand.
- Done: everything else. This deliberately doesn't enumerate every
"finished" status by name - a JIRA-side automation status like
"1st Contact Attempt" falls in here automatically just by not
being Created or Cancelled, with no code change needed when your
JIRA workflow adds another downstream status later.
"""
fulfilled_statuses = get_fulfilled_statuses()
active, done = [], []
active_statuses = get_active_statuses()
cancelled_statuses = get_cancelled_statuses()
active, cancelled, done = [], [], []
for order in orders:
(done if status_in(order.status, fulfilled_statuses) else active).append(order)
return active, done
if status_in(order.status, active_statuses):
active.append(order)
elif status_in(order.status, cancelled_statuses):
cancelled.append(order)
else:
done.append(order)
return active, cancelled, done
def load_active_and_done_orders() -> Tuple[List[Order], List[Order]]:
return split_active_and_done(load_all_orders())
def load_orders_by_view() -> Tuple[List[Order], List[Order], List[Order]]:
return split_orders_by_view(load_all_orders())
def get_dashboard_stats() -> dict:
"""
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.
reflect only the Active tab (status in ACTIVE_STATUSES) - the actual
at-hand workload. Cancelled counts the Cancelled tab. Fulfilled-today
and past-cutoff-today look across ALL of today's tickets regardless
of which tab they ended up in, since both are about what happened
today specifically.
Carryover counts any still-open ticket that's already known to spill
Carryover counts any Active 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).
earlier). Since we're only looking at the Active bucket, every
ticket here is by definition still unresolved - no separate "is it
still open" check needed.
"""
orders = load_all_orders()
active_orders, _done_orders = split_active_and_done(orders)
active_orders, cancelled_orders, _done_orders = split_orders_by_view(orders)
cancelled_statuses = parse_status_list(
config.get("CANCELLED_STATUSES", config.DEFAULT_CANCELLED_STATUSES)
)
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
carryover_count = 0
tracking_received_count = 0
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 order.tracking_numbers:
tracking_received_count += 1
still_open = not status_in(order.status, terminal_statuses)
created_before_today = bool(
order.source_created_at and order.source_created_at.date() < today
)
@@ -277,7 +281,7 @@ def get_dashboard_stats() -> dict:
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):
if created_before_today or arrived_past_cutoff_today:
carryover_count += 1
fulfilled_today_count = sum(
@@ -294,7 +298,7 @@ def get_dashboard_stats() -> dict:
return {
"total": len(active_orders),
"by_company": by_company,
"cancelled_count": cancelled_count,
"cancelled_count": len(cancelled_orders),
"carryover_count": carryover_count,
"tracking_received_count": tracking_received_count,
"fulfilled_today_count": fulfilled_today_count,