mirror of
https://github.com/Horizontal42/warehouse-master.git
synced 2026-11-10 16:02:07 +03:00
5.7 KiB
5.7 KiB
Architecture
Overview
Warehouse Master is a desktop application for printing numbered PDF labels and tracking laptop reassembly via Google Sheets. Two independent tabs: Labels (PDF generation) and Reassembly (Google Sheets sync).
File structure
| File | Purpose |
|---|---|
| main.py | Entry point, LabelApp main window, tab lifecycle, i18n dispatch |
| printing.py | Utilities: file I/O, resource paths, printer discovery, app config folder |
| styles.py | Stylesheet builder: build_stylesheet(dark: bool) → returns CSS for both themes |
| workers.py | Background threads: PDFWorker (reportlab), ReassemblyWorker (gspread sync) |
| widgets.py | Reusable UI: NoScrollComboBox, RangeRowWidget, PreferencesDialog |
| strings.py | i18n: STRINGS dict {"en": {...}, "ru": {...}} with all UI strings |
| sheet_manager.py | Google Sheets API wrapper: config-driven column indices, category calculation, batch updates |
| sheet_config.example.json | Template config: worksheets, column mappings, translators, statuses |
| WarehouseMaster.spec | PyInstaller spec: bundles Inter.ttf, builds single-file exe |
| requirements.txt | Dependencies: PyQt5, reportlab, gspread, google-auth |
Module responsibilities
main.py
- Loads/saves QSettings (theme, language, window state)
- Renders two tabs: labels and reassembly
- Wires up event handlers
- Calls
_retranslate()on locale change - Temp file cleanup on close
printing.py
resource_path()— finds bundled files (Inter.ttf, icon.ico)app_data_dir()—%APPDATA%/WarehouseMaster/for token.json, local configsconfig_path()— returns sheet_config.json (local or appdata)register_fonts()— loads Inter.ttf into reportlabget_installed_printers()— enumerates Windows printers (win32api)open_file()— cross-platform file open (Windows/macOS/Linux)print_file()— print to specific printer or system default
styles.py
build_stylesheet(dark: bool)— single function, returns full QPalette CSS- Colors hardcoded (dark: #212529 bg, #f8f9fa text; light: inverse)
- Called on theme toggle →
setStyleSheet()
workers.py
PDFWorker(QThread)— generates PDF in background, emitsfinished(filepath)orerror_occurred(str)ReassemblyWorker(QThread)— callsSheetManager.process_reassembly(), emitsfinished_signal(comment, tech_op)orerror_signal(str)- Both prevent UI freeze
widgets.py
NoScrollComboBox— suppresses scroll-wheel zoomRangeRowWidget— start/end inputs + +/- buttons; callback-drivenPreferencesDialog— language + theme + sheet URL + save folder, saves to QSettings
strings.py
- Two dicts:
STRINGS["en"],STRINGS["ru"] - Keys:
"window_title","tab_labels", message templates with{n}placeholders - No locale switching logic — main.py reads
settings.value("locale")and indexes
sheet_manager.py
SheetManager(sheet_url, config_path)— loads config.json, authorizes gspreadprocess_reassembly(laptop_id, parts_str, ssd_id, akb_id)— atomically updates: marks parts shipped, writes grades to laptop row, recalculates category (D/C/B/A/NEW)_calculate_category(laptop_data)— rule-based scoring (D if any part ≤rank 1, NEW if all ≥A and cycles < 150, etc.)- Config-driven: all column indices, range clears, status values from sheet_config.json
Hot paths
PDF generation
- User clicks "Generate PDF"
_start_generation()validates ranges (start ≤ end), spawnsPDFWorkerPDFWorker.run()→reportlab.canvasdraws labels in grid layout- On success:
_on_pdf_done()→ open file or print - UI unblocked (worker thread)
Reassembly sync
- User fills order/parts, clicks "Apply changes"
_run_reassembly()spawnsReassemblyWorkerReassemblyWorker.run()→SheetManager.process_reassembly()- Manager: fetches IDs from all worksheets, processes each part (SSD/battery/part), calculates new category
- Batch updates all sheets, returns comment + tech lines
_on_reassembly_done()displays results- UI unblocked
Adding things
New label format (e.g., 6×6 grid)
- Add to
PAGE_SIZESandDEFAULT_FONT_SIZESin workers.py - Add radio button in
_init_gen_tab() - Add branch in
PDFWorker.run()for grid layout
New reassembly field
- Add config key to sheet_config.example.json (e.g.,
"warranty_months": 52) - Read in
SheetManager.__init__()via self.cfg - Add processing in
_process_part()or new_process_<thing>()method
New language
- Add
STRINGS["new_lang"]dict in strings.py - Add to language combo in PreferencesDialog (widgets.py)
- Map combo index → locale code (e.g., index 2 → "de")
New Google Sheets worksheet
- Add to
sheet_config.json→worksheets - Add column mappings if needed
- Add fetch/batch in
SheetManagermethods - Wire up in
process_reassembly()
Gotchas
- QSettings casing: Linux filenames are case-sensitive; use lowercase keys (
"sheet_url"not"SheetURL") - Token refresh: If gspread credentials expire mid-session, worker will fail; user must restart and re-auth
- Column alignment: reportlab canvas Y-axis is bottom-up (0 = bottom). Grid layout offsets Y correctly with
ph - (row + 1) * cell_h - Config missing: If sheet_config.json missing, SheetManager raises on init; handle in UI with try-except, show user-friendly message
- Cyrillic grades: Before rank check, normalize Cyrillic А/В/С/Д → Latin A/B/C/D via
str.maketrans() - Printer not found: If saved printer deleted,
findText()returns -1; guard beforesetCurrentIndex() - Temp files: If app crashes, temp PDFs not deleted; consider OS-level temp cleanup (tmp dirs auto-purge)