Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
37 changes: 24 additions & 13 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -39,10 +39,17 @@ async def main():
for month in usage.by_month.months:
print(f"{month.month} {month.year}: {month.usage_total} kWh — RM {month.amount_total}")

# Bill history & due amount
# Bill history, payment history & due amount
history = await client.get_bill_history("220123456789")
payments = await client.get_payment_history("220123456789")
due = await client.get_account_due_amount("220123456789")

# Most account-scoped methods also accept a CustomerAccount directly
# (is_owner and account_type are derived automatically)
for acc in accounts:
if acc.is_smart_meter:
usage = await client.get_account_usage_smart(acc)

asyncio.run(main())
```

Expand Down Expand Up @@ -81,7 +88,8 @@ mytnb usage --daily <account> # Daily usage breakdown
mytnb usage --json <account> # Full usage data as JSON
mytnb current-usage <account> # Simplified current usage summary
mytnb due-amount <account> # Outstanding balance
mytnb bill-history <account> # Payment history
mytnb bill-history <account> # Bill history (bills issued)
mytnb payment-history <account> # Bill & payment history
```

Global options: `--debug` for full tracebacks, `--version`.
Expand All @@ -106,17 +114,20 @@ Request encryption for the ASMX API is automatic — just pass plaintext paramet

## Data Models

| Model | Description |
| ----------------- | ---------------------------------------------------- |
| `CustomerAccount` | Linked account: number, owner, address, SMR status |
| `AccountUsage` | Full usage response: metrics, monthly and daily data |
| `UsageMetric` | Current/average usage (kWh) |
| `CostMetric` | Current/projected cost (RM) |
| `BillingMonth` | Monthly billing record with tariff blocks |
| `DailyUsage` | Daily consumption and cost |
| `TariffBlock` | Tariff pricing block details |
| `SMRAccount` | Smart Meter Reading eligibility status |
| `BREligibility` | Bill rendering opt-in status |
| Model | Description |
| --------------------- | ---------------------------------------------------- |
| `CustomerAccount` | Linked account: number, owner, address, SMR status |
| `AccountUsage` | Full usage response: metrics, monthly and daily data |
| `UsageMetric` | Current/average usage (kWh) |
| `CostMetric` | Current/projected cost (RM) |
| `BillingMonth` | Monthly billing record with tariff blocks |
| `DailyUsage` | Daily consumption and cost |
| `TariffBlock` | Tariff pricing block details |
| `BillHistoryEntry` | Single bill issued (date, amount, billing number) |
| `PaymentHistoryEntry` | Bill or payment entry with type, method, reference |
| `AccountDueAmount` | Outstanding balance and due date |
| `SMRAccount` | Smart Meter Reading eligibility status |
| `BREligibility` | Bill rendering opt-in status |

## Geographic Restrictions

Expand Down
38 changes: 37 additions & 1 deletion src/mytnb/cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -313,7 +313,7 @@ async def _due():
@click.option("--json", "as_json", is_flag=True, help="Output full JSON.")
@click.pass_context
def bill_history(ctx, account, as_json):
"""Get bill payment history."""
"""Get bill history (bills issued)."""

async def _history():
client = await _get_client(ctx)
Expand All @@ -340,6 +340,42 @@ async def _history():
_run_async(_history())


@cli.command("payment-history")
@click.argument("account")
@click.option("--json", "as_json", is_flag=True, help="Output full JSON.")
@click.pass_context
def payment_history(ctx, account, as_json):
"""Get bill & payment history."""

async def _history():
client = await _get_client(ctx)
async with client:
with console.status("[bold green]Fetching..."):
result = await client.get_payment_history(account)

if as_json:
_print_json(result)
return

table = Table(title=f"Bill & Payment History — {account}")
table.add_column("Date", style="cyan")
table.add_column("Type")
table.add_column("Amount (RM)", justify="right", style="green")
table.add_column("Method / Ref")
for entry in result:
style = "green" if entry.is_payment else "red"
table.add_row(
entry.date.isoformat() if entry.date else "--",
entry.history_type_text or entry.history_type or "--",
f"[{style}]--[/{style}]" if entry.amount is None
else f"[{style}]{entry.amount:,.2f}[/{style}]",
entry.paid_via or entry.reference_number or "--",
Comment thread
danieyal marked this conversation as resolved.
)
console.print(table)

_run_async(_history())


@cli.command("init-config")
@click.option("-o", "--output", default="mytnb.json", help="Output path.")
def init_config(output):
Expand Down
Loading