GUI updates and misc fixes for the Cancel cutoff

This commit is contained in:
2026-08-31 17:01:13 -05:00
parent 9651b82415
commit df9958cb97
7 changed files with 148 additions and 61 deletions
+1 -1
View File
@@ -62,7 +62,7 @@ class DashboardWidget(QWidget):
# Top row: active workload health (fulfilled tickets have moved to the Done tab)
top_row = QHBoxLayout()
self.total_card = StatCard("Active Orders")
self.cancelled_card = StatCard("Cancelled")
self.cancelled_card = StatCard("Cancelled Today")
self.cancelled_card.setStyleSheet("QLabel { color: #b00020; }")
self.carryover_card = StatCard("Carryover (still open from an earlier day)")
self.carryover_card.setStyleSheet("QLabel { color: #b06a00; }")
+38 -22
View File
@@ -26,35 +26,37 @@ from PyQt6.QtWidgets import (
QLabel,
)
from app import config
from app.models import Order
from app.schedule import get_cutoff_time, is_past_cutoff
from app.status_rules import parse_status_list, status_in
from app.schedule import get_cutoff_time, is_past_cutoff_today
from app.status_rules import get_cancelled_statuses, status_in
from app.tracking import get_fulfilled_statuses
CANCELLED_ROW_COLOR = QColor(255, 210, 210)
CANCELLED_TEXT_COLOR = QColor(180, 0, 0)
FULFILLED_ROW_COLOR = QColor(210, 240, 210)
CHECK_MARK = "\u2713"
# Order here is display order, left to right.
COLUMNS = [
("company", "Company"),
("ticket_number", "Ticket #"),
("status", "Status"),
("skus_display", "SKUs"),
("summary", "Summary"),
("status", "Status"),
("tracking_display", "Tracking #"),
("created_display", "Created"),
("outgoing_tracking_display", "Outgoing Tracking"),
("return_tracking_display", "Return Tracking"),
("uploaded_display", "Uploaded"),
("past_cutoff_display", "Past Cutoff"),
("created_display", "Created"),
]
ALL_COMPANIES = "All Companies"
def _format_tracking(tracking_numbers) -> str:
def _format_tracking_numbers(tracking_numbers, is_return: bool) -> str:
if not tracking_numbers:
return ""
return ", ".join(
f"{t.get('number')} ({'return' if t.get('is_return') else 'out'})"
for t in tracking_numbers
t.get("number", "") for t in tracking_numbers if bool(t.get("is_return")) == is_return
)
@@ -74,9 +76,7 @@ class OrdersTableModel(QAbstractTableModel):
def set_orders(self, orders: List[Order]) -> None:
# Re-read status lists and cutoff time each refresh, in case Settings changed.
self._cancelled_statuses = parse_status_list(
config.get("CANCELLED_STATUSES", config.DEFAULT_CANCELLED_STATUSES)
)
self._cancelled_statuses = get_cancelled_statuses()
self._fulfilled_statuses = get_fulfilled_statuses()
self._cutoff_time = get_cutoff_time()
self.beginResetModel()
@@ -101,11 +101,17 @@ class OrdersTableModel(QAbstractTableModel):
return None
order = self._orders[index.row()]
is_cancelled = status_in(order.status, self._cancelled_statuses)
if role == Qt.ItemDataRole.ForegroundRole:
return CANCELLED_TEXT_COLOR if is_cancelled else None
if role == Qt.ItemDataRole.BackgroundRole:
if status_in(order.status, self._cancelled_statuses):
return CANCELLED_ROW_COLOR
if status_in(order.status, self._fulfilled_statuses):
# Cancelled rows use red TEXT (above) instead of a background,
# so it stays readable regardless of theme. Fulfilled rows
# still get a background tint since there's no text-color
# signal already in use for them.
if not is_cancelled and status_in(order.status, self._fulfilled_statuses):
return FULFILLED_ROW_COLOR
return None
@@ -116,12 +122,16 @@ class OrdersTableModel(QAbstractTableModel):
if field_name == "skus_display":
return ", ".join(order.skus or [])
if field_name == "tracking_display":
return _format_tracking(order.tracking_numbers)
if field_name == "outgoing_tracking_display":
return _format_tracking_numbers(order.tracking_numbers, is_return=False)
if field_name == "return_tracking_display":
return _format_tracking_numbers(order.tracking_numbers, is_return=True)
if field_name == "uploaded_display":
return CHECK_MARK if order.shipstation_sent_at else ""
if field_name == "created_display":
return _format_created(order.source_created_at)
if field_name == "past_cutoff_display":
return "Yes" if is_past_cutoff(order.source_created_at, self._cutoff_time) else ""
return CHECK_MARK if is_past_cutoff_today(order.source_created_at, self._cutoff_time) else ""
value = getattr(order, field_name)
return "" if value is None else str(value)
@@ -154,13 +164,16 @@ class OrdersFilterProxyModel(QSortFilterProxyModel):
return False
if self.search_text:
tracking_text = " ".join(
t.get("number", "") for t in (order.tracking_numbers or [])
)
haystack = " ".join(
[
order.ticket_number or "",
order.summary or "",
order.status or "",
" ".join(order.skus or []),
_format_tracking(order.tracking_numbers),
tracking_text,
]
).lower()
if self.search_text not in haystack:
@@ -204,8 +217,11 @@ class OrdersTableView(QWidget):
self.table.setSelectionBehavior(QAbstractItemView.SelectionBehavior.SelectRows)
self.table.setEditTriggers(QAbstractItemView.EditTrigger.NoEditTriggers)
self.table.setSortingEnabled(True)
self.table.horizontalHeader().setSectionResizeMode(QHeaderView.ResizeMode.Stretch)
self.table.horizontalHeader().setStretchLastSection(False)
# Interactive (not Stretch) so columns size to their own content and
# stay individually resizable by dragging, rather than every column
# being force-stretched to equal widths regardless of content.
self.table.horizontalHeader().setSectionResizeMode(QHeaderView.ResizeMode.Interactive)
self.table.horizontalHeader().setStretchLastSection(True)
self.table.doubleClicked.connect(self._on_row_double_clicked)
layout.addWidget(self.table)