mirror of
https://github.com/Sea-Haven-Industries/stampli-bulk-editor.git
synced 2026-09-30 10:23:12 +00:00
Mac GUI app (tkinter + Playwright) for bulk-editing invoice pay dates on Stampli's Select to Pay dashboard. Features: - Scan MUI DataGrid rows via virtual scroll - Auto-calculate pay dates (due - 5 days, business day adjusted) - Bulk edit pay date cells via calendar input - Filter to error-free invoices, select all, submit for payment - Scan Pending Approval tab to verify edits - PyInstaller .app bundle with custom icon
72 lines
2.3 KiB
Python
72 lines
2.3 KiB
Python
#!/usr/bin/env python3
|
|
"""
|
|
Scan the Stampli "Pending Approval" tab and report rows with incorrect pay dates.
|
|
|
|
Usage:
|
|
python scan_pending.py
|
|
python scan_pending.py --snap
|
|
"""
|
|
|
|
import argparse
|
|
import time
|
|
from pathlib import Path
|
|
from playwright.sync_api import sync_playwright
|
|
|
|
from stampli_core import (
|
|
launch_browser, navigate, active_page, wait_for_login, needs_login,
|
|
collect_scan_rows, compute_scan_results, PENDING_APPROVAL_URL, DATE_FMT,
|
|
)
|
|
|
|
|
|
def main():
|
|
parser = argparse.ArgumentParser(description="Scan Stampli Pending Approval")
|
|
parser.add_argument("--snap", action="store_true")
|
|
args = parser.parse_args()
|
|
|
|
with sync_playwright() as p:
|
|
browser = launch_browser(p)
|
|
navigate(browser, PENDING_APPROVAL_URL)
|
|
|
|
time.sleep(3)
|
|
page = active_page(browser)
|
|
if needs_login(page):
|
|
if not wait_for_login(browser, on_status=print):
|
|
browser.close()
|
|
return
|
|
|
|
page = active_page(browser)
|
|
print("Waiting for page to settle...")
|
|
time.sleep(3)
|
|
|
|
if args.snap:
|
|
html = page.content()
|
|
snap_path = Path(__file__).parent / "pending_snapshot.html"
|
|
with open(snap_path, "w") as f:
|
|
f.write(html)
|
|
print(f"Saved snapshot to {snap_path}")
|
|
|
|
print("\nScanning Pending Approval rows...\n")
|
|
all_rows = collect_scan_rows(page)
|
|
print(f"Found {len(all_rows)} rows\n")
|
|
|
|
results, incorrect = compute_scan_results(all_rows)
|
|
|
|
print(f" {'Invoice':<20s} {'Vendor':<35s} {'Due':<12s} {'Pay Date':<12s} {'Expected':<12s} {'Status'}")
|
|
print(f" {'-'*20} {'-'*35} {'-'*12} {'-'*12} {'-'*12} {'-'*8}")
|
|
for r in results:
|
|
print(f" {r['invoicesNumbers']:<20s} {r['vendorName'][:35]:<35s} "
|
|
f"{r['dueDate']:<12s} {r['sendPaymentOn']:<12s} {r['expected']:<12s} {r['status']}")
|
|
|
|
print(f"\n{len(incorrect)} rows with incorrect pay dates out of {len(all_rows)} total.")
|
|
if incorrect:
|
|
print(f"\nIncorrect rows:")
|
|
for r in incorrect:
|
|
print(f" {r['invoicesNumbers']:<20s} {r['vendorName'][:35]:<35s} "
|
|
f"pay={r['sendPaymentOn']} (due={r['dueDate']})")
|
|
|
|
input("\nPress Enter to close the browser...")
|
|
browser.close()
|
|
|
|
|
|
if __name__ == "__main__":
|
|
main()
|