A local single-user ledger tool for telecom enterprise account managers: manage client organizations, contacts, ten asset categories, contract archiving with expiry alerts, and project progress. Supports Excel batch import and ships a built-in dashboard.
All data lives in telecom_crm.db (SQLite) next to the program — backup = copy the
directory. Deleting the database resets to demo data.
中文说明见 README_ZH.md。
| Module | Capability |
|---|---|
| Dashboard | Alert banner (expired / 30-day warning + one-click jump to alert center), 6 KPIs, asset-category distribution, contract expiry distribution (12 months), project status pie, client asset ranking |
| Clients | Add / rename / delete (cascading cleanup with confirmation) |
| Contacts | Department (office / IT / finance / business), role, phone, key-person marking |
| Assets | 10 categories: landline / mobile / broadband / e-gov WAN / PON leased line / internet leased line / VPN / local OTN / provincial OTN / dark fiber; fields: number, tariff, department, user, purpose, location, device MAC (PON CPE), linked contract |
| Contracts | Sign/expiry dates, amount, historical file upload (auto-archived, no overwrite), type |
| Projects | Amount, status flow (won→contracting→executing→done/terminated), start/end dates, construction %, payment %, linked contract |
| Alert Center | Expired (red) / due within 30 days (yellow) list + live nav badges |
| Excel import | 5-sheet template (clients/contacts/assets/contracts/projects), auto-creates clients, row-level error report |
Python 3.11+ (3.12 recommended). Install dependencies:
uv syncLaunch:
uv run python main.py
# or
.venv/bin/python main.pyIf the shell has third-party site-packages on PYTHONPATH (e.g. Hermes tooling), clear it first:
export PYTHONPATH=— otherwise imports may collide.
- Click Excel模板 on any ledger page to generate the template (5 sheets with examples);
- Fill it in, then click Excel导入 and pick the file;
- The result dialog reports per-sheet success counts and problem rows (bad header, missing required field, invalid category, unmatched linked contract, ...).
Rules:
- 「所属客户」takes the client name; unknown clients are auto-created (name is unique, re-imports are idempotent);
- Header order is free; extra columns are ignored; dates accept
YYYY-MM-DD,YYYY/MM/DDand Excel serial numbers; - Asset category must be one of the 10; unknown contract types / project statuses fall back to 「其他」/「执行中」with a note;
- Linked contracts match by (client, contract name); unmatched → cleared + noted;
- Key-person column: 是 / 1 / TRUE / √ count as key person.
- Alert (red): contract expiry date already passed;
- Warning (yellow): expiring within 30 days (window in
database.WARN_DAYS).
- Backup: copy
telecom_crm.dbandcontracts_archive/from the program directory; - Migrate: place both files back next to the program on the new machine;
- Reset demo data: delete
telecom_crm.dband restart (auto-recreated + seeded).
cmdb/
├── main.py # Entry point
├── main_window.py # Main window: nav + 7 stacked pages + alert badges
├── database.py # SQLite schema / connection / seed data
├── crud_base.py # Generic ledger CRUD base (table + form + inline edit + view)
├── client_page.py # Clients page
├── contact_page.py # Contacts page
├── asset_page.py # Assets page
├── contract_page.py # Contracts page (file archiving)
├── project_page.py # Projects page
├── alert_page.py # Alert center page
├── dashboard.py # Dashboard (QWebEngine + offline ECharts)
├── excel_import.py # Excel template generation & batch import
├── assets/ # Offline assets: echarts.min.js / qwebchannel.js / dashboard.html
├── verify.py # Full regression suite (48 checks, stdlib + project modules only)
├── pyproject.toml # uv manifest (deps + dev group)
└── telecom_crm.db # Created on first run
.venv/bin/python verify.py # full (db / CRUD / archive / import / GUI smoke)
.venv/bin/python verify.py --db-only # skip GUI sectionAll PASS = exit code 0; tests use isolated temp databases, real data untouched. Run this on the target OS before distributing.
Build on a Windows machine with uv installed:
-
Copy the project folder to Windows (exclude
.venv,telecom_crm.db,contracts_archive/). -
Install dependencies (project root):
uv sync
One command installs PySide6 + openpyxl + pyinstaller (declared in the
[dependency-groups] devsection ofpyproject.toml). -
Build:
uv run pyinstaller --noconfirm --windowed --name "电信台账" --add-data "assets;assets" main.py
(
;is the Windows separator in--add-data;--windowed= no console window. PySide6 + QtWebEngine deps are collected automatically by PyInstaller hooks.) -
Distribute the whole
dist/电信台账/folder (exe +_internal/+ QtWebEngineProcess.exe, etc.). First run creates an emptytelecom_crm.db(no demo data) andcontracts_archive/next to the exe.
Repeat after code changes: copy new sources → uv sync → re-run step 3
(--noconfirm overwrites old output).
Post-build checklist
- Launch → dashboard renders (first start is slow, WebEngine init);
- All 7 pages, add/edit/delete, inline cell edit (double-click);
- Excel import / export / template;
- Contract upload → file lands in
contracts_archive/next to the exe; - 「查看详情」jumps to the alert center;
- If double-click does nothing: run
电信台账.exefrom a console to see the error (--windowedhides crashes).
Known pitfalls
| Symptom | Fix |
|---|---|
| Antivirus false positive | Common with PyInstaller; whitelist or code-sign for enterprise rollout |
| No reaction on double-click | Run from console to see the traceback |
| ~300 MB output | QtWebEngine dominates; normal |
| Non-ASCII install path issues | Prefer an English path |
- Single user, single machine: no login, no per-manager KPIs, no revenue-recognition (列收) — those belong to company management views, not in the customer's requests;
- No cloud sync: data travels with the machine;
- Contract analytics (amount summaries/trends) deferred until requested.