paid status
This commit is contained in:
5 files changed
+96
-5
No files matched your search
@@ -832,6 +832,54 @@ td a:hover {
|
||||
min-height: 260px;
|
||||
}
|
||||
|
||||
.status-none {
|
||||
color: #94a3b8;
|
||||
background: rgba(148, 163, 184, 0.1);
|
||||
border: 1px solid rgba(148, 163, 184, 0.2);
|
||||
}
|
||||
|
||||
.status-unpaid {
|
||||
color: #f59e0b;
|
||||
background: rgba(245, 158, 11, 0.12);
|
||||
border: 1px solid rgba(245, 158, 11, 0.24);
|
||||
}
|
||||
|
||||
.status-partial {
|
||||
color: #fb923c;
|
||||
background: rgba(251, 146, 60, 0.12);
|
||||
border: 1px solid rgba(251, 146, 60, 0.24);
|
||||
}
|
||||
|
||||
.status-paid {
|
||||
color: #22c55e;
|
||||
background: rgba(34, 197, 94, 0.12);
|
||||
border: 1px solid rgba(34, 197, 94, 0.24);
|
||||
}
|
||||
|
||||
.pill-paid {
|
||||
color: #22c55e;
|
||||
background: rgba(34, 197, 94, 0.12);
|
||||
border: 1px solid rgba(34, 197, 94, 0.22);
|
||||
}
|
||||
|
||||
.pill-cashout {
|
||||
color: #f59e0b;
|
||||
background: rgba(245, 158, 11, 0.12);
|
||||
border: 1px solid rgba(245, 158, 11, 0.22);
|
||||
}
|
||||
|
||||
.pill-buyin {
|
||||
color: #60a5fa;
|
||||
background: rgba(96, 165, 250, 0.12);
|
||||
border: 1px solid rgba(96, 165, 250, 0.22);
|
||||
}
|
||||
|
||||
.pill-note {
|
||||
color: #cbd5e1;
|
||||
background: rgba(203, 213, 225, 0.08);
|
||||
border: 1px solid rgba(203, 213, 225, 0.14);
|
||||
}
|
||||
|
||||
@media (max-width: 980px) {
|
||||
.site-shell {
|
||||
width: min(100% - 24px, 100%);
|
||||
|
||||
@@ -30,12 +30,31 @@ class SessionEntry:
|
||||
player_name: str
|
||||
buy_in_cents: int = 0
|
||||
cash_out_cents: int = 0
|
||||
paid_cents: int = 0
|
||||
notes: list[str] = field(default_factory=list)
|
||||
|
||||
@property
|
||||
def net_cents(self) -> int:
|
||||
return self.cash_out_cents - self.buy_in_cents
|
||||
|
||||
@property
|
||||
def payout_due_cents(self) -> int:
|
||||
return max(self.cash_out_cents, 0)
|
||||
|
||||
@property
|
||||
def payout_remaining_cents(self) -> int:
|
||||
return max(self.payout_due_cents - self.paid_cents, 0)
|
||||
|
||||
@property
|
||||
def payout_status(self) -> str:
|
||||
if self.payout_due_cents <= 0:
|
||||
return "none"
|
||||
if self.paid_cents <= 0:
|
||||
return "unpaid"
|
||||
if self.payout_remaining_cents <= 0:
|
||||
return "paid"
|
||||
return "partial"
|
||||
|
||||
|
||||
@dataclass
|
||||
class SessionSummary:
|
||||
@@ -171,6 +190,8 @@ def build_session_summaries(events: list[EventRow]) -> list[SessionSummary]:
|
||||
entry.buy_in_cents += event["amount_cents"]
|
||||
elif event_type == "cashout":
|
||||
entry.cash_out_cents += event["amount_cents"]
|
||||
elif event_type == "paid":
|
||||
entry.paid_cents += event["amount_cents"]
|
||||
|
||||
if event["note"]:
|
||||
entry.notes.append(event["note"])
|
||||
|
||||
+8
-1
@@ -30,7 +30,14 @@ class EventRow(TypedDict):
|
||||
actor: str
|
||||
|
||||
|
||||
VALID_EVENT_TYPES = {"buyin", "cashout", "note", "session_open", "session_close"}
|
||||
VALID_EVENT_TYPES = {
|
||||
"buyin",
|
||||
"cashout",
|
||||
"paid",
|
||||
"note",
|
||||
"session_open",
|
||||
"session_close",
|
||||
}
|
||||
|
||||
|
||||
def ensure_data_file(csv_path: Path) -> None:
|
||||
|
||||
@@ -34,6 +34,7 @@
|
||||
<select name="event_type" required>
|
||||
<option value="buyin">Buy-in</option>
|
||||
<option value="cashout">Cash-out</option>
|
||||
<option value="paid">Paid out</option>
|
||||
<option value="note">Note only</option>
|
||||
</select>
|
||||
</label>
|
||||
@@ -45,7 +46,7 @@
|
||||
|
||||
<label>
|
||||
<span>Note</span>
|
||||
<textarea name="note" rows="4" placeholder="Rebuy, correction, settled chips later, etc."></textarea>
|
||||
<textarea name="note" rows="4" placeholder="Rebuy, correction, partial payout, e-transfer sent, cash paid, etc."></textarea>
|
||||
</label>
|
||||
|
||||
<button class="primary-button" type="submit">Add event</button>
|
||||
@@ -135,7 +136,7 @@
|
||||
<article class="event-card">
|
||||
<div class="event-card-top">
|
||||
<strong>{{ event.player_name }}</strong>
|
||||
<span class="pill">{{ event.event_type }}</span>
|
||||
<span class="pill pill-{{ event.event_type }}">{{ event.event_type }}</span>
|
||||
</div>
|
||||
<p class="event-amount">{{ event.amount_cents | money }}</p>
|
||||
<p class="muted-text small">{{ event.session_date | pretty_date }}</p>
|
||||
|
||||
@@ -35,6 +35,9 @@
|
||||
<th>Player</th>
|
||||
<th>Buy-in</th>
|
||||
<th>Cash-out</th>
|
||||
<th>Paid</th>
|
||||
<th>Remaining</th>
|
||||
<th>Status</th>
|
||||
<th>Net</th>
|
||||
<th>Notes</th>
|
||||
</tr>
|
||||
@@ -45,7 +48,18 @@
|
||||
<td><a href="{{ url_for('player_detail', player_name=entry.player_name) }}">{{ entry.player_name }}</a></td>
|
||||
<td>{{ entry.buy_in_cents | money }}</td>
|
||||
<td>{{ entry.cash_out_cents | money }}</td>
|
||||
<td class="{{ 'positive' if entry.net_cents > 0 else 'negative' if entry.net_cents < 0 else '' }}">{{ entry.net_cents | money }}</td>
|
||||
<td>{{ entry.paid_cents | money }}</td>
|
||||
<td class="{{ 'positive' if entry.payout_remaining_cents == 0 else 'negative' if entry.payout_remaining_cents > 0 else '' }}">
|
||||
{{ entry.payout_remaining_cents | money }}
|
||||
</td>
|
||||
<td>
|
||||
<span class="status-badge status-{{ entry.payout_status }}">
|
||||
{{ entry.payout_status }}
|
||||
</span>
|
||||
</td>
|
||||
<td class="{{ 'positive' if entry.net_cents > 0 else 'negative' if entry.net_cents < 0 else '' }}">
|
||||
{{ entry.net_cents | money }}
|
||||
</td>
|
||||
<td>
|
||||
{% if entry.notes %}
|
||||
<ul class="note-list">
|
||||
@@ -76,7 +90,7 @@
|
||||
<article class="event-card">
|
||||
<div class="event-card-top">
|
||||
<strong>{{ event.player_name }}</strong>
|
||||
<span class="pill">{{ event.event_type }}</span>
|
||||
<span class="pill pill-{{ event.event_type }}">{{ event.event_type }}</span>
|
||||
</div>
|
||||
<p class="event-amount">{{ event.amount_cents | money }}</p>
|
||||
{% if event.note %}
|
||||
|
||||
Reference in new issue
Block a user