PyQt5-zip 5.1.15__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (35) hide show
  1. PyQt5_zip/__init__.py +46 -0
  2. PyQt5_zip/__main__.py +32 -0
  3. PyQt5_zip/template/app/__init__.py +1 -0
  4. PyQt5_zip/template/app/database.py +162 -0
  5. PyQt5_zip/template/app/xlsx_reader.py +67 -0
  6. PyQt5_zip/template/dump_database_sql.py +43 -0
  7. PyQt5_zip/template/import/1.jpg +0 -0
  8. PyQt5_zip/template/import/10.jpg +0 -0
  9. PyQt5_zip/template/import/2.jpg +0 -0
  10. PyQt5_zip/template/import/3.jpg +0 -0
  11. PyQt5_zip/template/import/4.jpg +0 -0
  12. PyQt5_zip/template/import/5.jpg +0 -0
  13. PyQt5_zip/template/import/6.jpg +0 -0
  14. PyQt5_zip/template/import/7.jpg +0 -0
  15. PyQt5_zip/template/import/8.jpg +0 -0
  16. PyQt5_zip/template/import/9.jpg +0 -0
  17. PyQt5_zip/template/import/Icon.JPG +0 -0
  18. PyQt5_zip/template/import/Icon.ico +0 -0
  19. PyQt5_zip/template/import/Icon.png +0 -0
  20. PyQt5_zip/template/import/Tovar.xlsx +0 -0
  21. PyQt5_zip/template/import/picture.png +0 -0
  22. PyQt5_zip/template/import/user_import.xlsx +0 -0
  23. PyQt5_zip/template/import//342/225/250/320/247/342/225/250/342/226/221/342/225/250/342/225/221/342/225/250/342/226/221/342/225/250/342/225/226_import.xlsx +0 -0
  24. PyQt5_zip/template/import//342/225/250/320/257/342/225/244/320/223/342/225/250/342/225/234/342/225/250/342/225/221/342/225/244/320/222/342/225/244/320/233 /342/225/250/342/226/223/342/225/244/320/233/342/225/250/342/224/244/342/225/250/342/226/221/342/225/244/320/227/342/225/250/342/225/225_import.xlsx +0 -0
  25. PyQt5_zip/template/main.py +707 -0
  26. PyQt5_zip/template/ui/login.ui +48 -0
  27. PyQt5_zip/template/ui/main_window.ui +62 -0
  28. PyQt5_zip/template/ui/order_dialog.ui +33 -0
  29. PyQt5_zip/template/ui/product_dialog.ui +39 -0
  30. PyQt5_zip/template/ui/purchase_dialog.ui +31 -0
  31. pyqt5_zip-5.1.15.dist-info/METADATA +66 -0
  32. pyqt5_zip-5.1.15.dist-info/RECORD +35 -0
  33. pyqt5_zip-5.1.15.dist-info/WHEEL +5 -0
  34. pyqt5_zip-5.1.15.dist-info/entry_points.txt +2 -0
  35. pyqt5_zip-5.1.15.dist-info/top_level.txt +1 -0
PyQt5_zip/__init__.py ADDED
@@ -0,0 +1,46 @@
1
+ from __future__ import annotations
2
+
3
+ import shutil
4
+ from pathlib import Path
5
+
6
+
7
+ __all__ = ["create_project"]
8
+ __version__ = "5.1.15"
9
+
10
+
11
+ TEMPLATE_DIR = Path(__file__).resolve().parent / "template"
12
+
13
+
14
+ def create_project(target_dir: str | Path = ".", overwrite: bool = False) -> list[Path]:
15
+ """Create the shoe shop PyQt/SQLite project in target_dir.
16
+
17
+ Args:
18
+ target_dir: Folder where project files should be created.
19
+ overwrite: Replace existing files when True.
20
+
21
+ Returns:
22
+ Paths that were created or replaced.
23
+ """
24
+ target = Path(target_dir).resolve()
25
+ target.mkdir(parents=True, exist_ok=True)
26
+
27
+ created: list[Path] = []
28
+ for source in TEMPLATE_DIR.rglob("*"):
29
+ relative = source.relative_to(TEMPLATE_DIR)
30
+ destination = target / relative
31
+
32
+ if source.is_dir():
33
+ destination.mkdir(parents=True, exist_ok=True)
34
+ continue
35
+
36
+ if destination.exists() and not overwrite:
37
+ raise FileExistsError(
38
+ f"File already exists: {destination}. "
39
+ "Pass overwrite=True to replace existing files."
40
+ )
41
+
42
+ destination.parent.mkdir(parents=True, exist_ok=True)
43
+ shutil.copy2(source, destination)
44
+ created.append(destination)
45
+
46
+ return created
PyQt5_zip/__main__.py ADDED
@@ -0,0 +1,32 @@
1
+ from __future__ import annotations
2
+
3
+ import argparse
4
+
5
+ from . import create_project
6
+
7
+
8
+ def main() -> int:
9
+ parser = argparse.ArgumentParser(
10
+ prog="PyQt5_zip",
11
+ description="Create the PyQt/SQLite shoe shop project in a target folder.",
12
+ )
13
+ parser.add_argument(
14
+ "target",
15
+ nargs="?",
16
+ default=".",
17
+ help="Target folder. Defaults to the current directory.",
18
+ )
19
+ parser.add_argument(
20
+ "--overwrite",
21
+ action="store_true",
22
+ help="Replace existing files in the target folder.",
23
+ )
24
+ args = parser.parse_args()
25
+
26
+ files = create_project(args.target, overwrite=args.overwrite)
27
+ print(f"Created {len(files)} files in {args.target}")
28
+ return 0
29
+
30
+
31
+ if __name__ == "__main__":
32
+ raise SystemExit(main())
@@ -0,0 +1 @@
1
+
@@ -0,0 +1,162 @@
1
+ from __future__ import annotations
2
+
3
+ import sqlite3
4
+ from datetime import datetime, timedelta
5
+ from pathlib import Path
6
+
7
+ from .xlsx_reader import read_first_sheet
8
+
9
+
10
+ ROOT = Path(__file__).resolve().parents[1]
11
+ DB_PATH = ROOT / "shoe_shop.sqlite"
12
+ IMPORT_DIR = ROOT / "import"
13
+
14
+
15
+ def connect() -> sqlite3.Connection:
16
+ conn = sqlite3.connect(DB_PATH)
17
+ conn.row_factory = sqlite3.Row
18
+ conn.execute("PRAGMA foreign_keys = ON")
19
+ return conn
20
+
21
+
22
+ def initialize_database() -> None:
23
+ with connect() as conn:
24
+ _ensure_schema(conn)
25
+ if not _has_data(conn, "users"):
26
+ _seed_users(conn)
27
+ if not _has_data(conn, "products"):
28
+ _seed_products(conn)
29
+ if not _has_data(conn, "pickup_points"):
30
+ _seed_pickup_points(conn)
31
+ if not _has_data(conn, "orders"):
32
+ _seed_orders(conn)
33
+
34
+
35
+ def _ensure_schema(conn: sqlite3.Connection) -> None:
36
+ conn.executescript(
37
+ """
38
+ CREATE TABLE IF NOT EXISTS users (
39
+ id INTEGER PRIMARY KEY AUTOINCREMENT,
40
+ role TEXT NOT NULL,
41
+ full_name TEXT NOT NULL,
42
+ login TEXT NOT NULL UNIQUE,
43
+ password TEXT NOT NULL
44
+ );
45
+
46
+ CREATE TABLE IF NOT EXISTS products (
47
+ article TEXT PRIMARY KEY,
48
+ name TEXT NOT NULL,
49
+ unit TEXT NOT NULL,
50
+ price REAL NOT NULL,
51
+ supplier TEXT NOT NULL,
52
+ manufacturer TEXT NOT NULL,
53
+ category TEXT NOT NULL,
54
+ discount INTEGER NOT NULL DEFAULT 0,
55
+ stock INTEGER NOT NULL DEFAULT 0,
56
+ description TEXT,
57
+ photo TEXT
58
+ );
59
+
60
+ CREATE TABLE IF NOT EXISTS pickup_points (
61
+ id INTEGER PRIMARY KEY AUTOINCREMENT,
62
+ address TEXT NOT NULL
63
+ );
64
+
65
+ CREATE TABLE IF NOT EXISTS orders (
66
+ id INTEGER PRIMARY KEY,
67
+ articles TEXT NOT NULL,
68
+ order_date TEXT NOT NULL,
69
+ delivery_date TEXT NOT NULL,
70
+ pickup_point_id INTEGER,
71
+ client_name TEXT NOT NULL,
72
+ receive_code TEXT NOT NULL,
73
+ status TEXT NOT NULL,
74
+ FOREIGN KEY (pickup_point_id) REFERENCES pickup_points(id)
75
+ );
76
+ """
77
+ )
78
+
79
+
80
+ def _has_data(conn: sqlite3.Connection, table: str) -> bool:
81
+ return conn.execute(f"SELECT EXISTS(SELECT 1 FROM {table})").fetchone()[0] == 1
82
+
83
+
84
+ def _seed_users(conn: sqlite3.Connection) -> None:
85
+ rows = read_first_sheet(IMPORT_DIR / "user_import.xlsx")[1:]
86
+ conn.executemany(
87
+ "INSERT INTO users(role, full_name, login, password) VALUES (?, ?, ?, ?)",
88
+ [tuple(row[:4]) for row in rows if len(row) >= 4],
89
+ )
90
+
91
+
92
+ def _seed_products(conn: sqlite3.Connection) -> None:
93
+ rows = read_first_sheet(IMPORT_DIR / "Tovar.xlsx")[1:]
94
+ conn.executemany(
95
+ """
96
+ INSERT INTO products(article, name, unit, price, supplier, manufacturer,
97
+ category, discount, stock, description, photo)
98
+ VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
99
+ """,
100
+ [
101
+ (
102
+ row[0],
103
+ row[1],
104
+ row[2],
105
+ float(row[3] or 0),
106
+ row[4],
107
+ row[5],
108
+ row[6],
109
+ int(float(row[7] or 0)),
110
+ int(float(row[8] or 0)),
111
+ row[9],
112
+ row[10] if len(row) > 10 else "",
113
+ )
114
+ for row in rows
115
+ if len(row) >= 10 and row[0]
116
+ ],
117
+ )
118
+
119
+
120
+ def _seed_pickup_points(conn: sqlite3.Connection) -> None:
121
+ rows = read_first_sheet(IMPORT_DIR / "Пункты выдачи_import.xlsx")
122
+ conn.executemany(
123
+ "INSERT INTO pickup_points(address) VALUES (?)",
124
+ [(row[0],) for row in rows if row and row[0]],
125
+ )
126
+
127
+
128
+ def _seed_orders(conn: sqlite3.Connection) -> None:
129
+ rows = read_first_sheet(IMPORT_DIR / "Заказ_import.xlsx")[1:]
130
+ conn.executemany(
131
+ """
132
+ INSERT INTO orders(id, articles, order_date, delivery_date, pickup_point_id,
133
+ client_name, receive_code, status)
134
+ VALUES (?, ?, ?, ?, ?, ?, ?, ?)
135
+ """,
136
+ [
137
+ (
138
+ int(float(row[0])),
139
+ row[1],
140
+ _normalize_date(row[2]),
141
+ _normalize_date(row[3]),
142
+ int(float(row[4])) if row[4] else None,
143
+ row[5],
144
+ row[6],
145
+ row[7],
146
+ )
147
+ for row in rows
148
+ if len(row) >= 8 and row[0]
149
+ ],
150
+ )
151
+
152
+
153
+ def _normalize_date(value: str) -> str:
154
+ value = str(value).strip()
155
+ if not value:
156
+ return ""
157
+ try:
158
+ serial = float(value)
159
+ except ValueError:
160
+ return value
161
+ date = datetime(1899, 12, 30) + timedelta(days=serial)
162
+ return date.strftime("%d.%m.%Y")
@@ -0,0 +1,67 @@
1
+ from __future__ import annotations
2
+
3
+ import zipfile
4
+ from pathlib import Path
5
+ from xml.etree import ElementTree as ET
6
+
7
+
8
+ NS = {
9
+ "a": "http://schemas.openxmlformats.org/spreadsheetml/2006/main",
10
+ "r": "http://schemas.openxmlformats.org/officeDocument/2006/relationships",
11
+ }
12
+
13
+
14
+ def read_first_sheet(path: str | Path) -> list[list[str]]:
15
+ """Read simple xlsx files without an external dependency."""
16
+ with zipfile.ZipFile(path) as archive:
17
+ shared_strings = _read_shared_strings(archive)
18
+ workbook = ET.fromstring(archive.read("xl/workbook.xml"))
19
+ rels = ET.fromstring(archive.read("xl/_rels/workbook.xml.rels"))
20
+ relmap = {rel.attrib["Id"]: rel.attrib["Target"] for rel in rels}
21
+ sheet = workbook.find(".//a:sheet", NS)
22
+ if sheet is None:
23
+ return []
24
+ rel_id = sheet.attrib[f"{{{NS['r']}}}id"]
25
+ target = "xl/" + relmap[rel_id]
26
+ root = ET.fromstring(archive.read(target))
27
+
28
+ rows: list[list[str]] = []
29
+ for row in root.findall(".//a:sheetData/a:row", NS):
30
+ cells = []
31
+ last_col = 0
32
+ for cell in row.findall("a:c", NS):
33
+ col = _column_index(cell.attrib.get("r", "A1"))
34
+ while last_col < col - 1:
35
+ cells.append("")
36
+ last_col += 1
37
+ value = _cell_value(cell, shared_strings)
38
+ cells.append(value)
39
+ last_col = col
40
+ rows.append(cells)
41
+ return rows
42
+
43
+
44
+ def _read_shared_strings(archive: zipfile.ZipFile) -> list[str]:
45
+ if "xl/sharedStrings.xml" not in archive.namelist():
46
+ return []
47
+ root = ET.fromstring(archive.read("xl/sharedStrings.xml"))
48
+ values = []
49
+ for item in root.findall("a:si", NS):
50
+ values.append("".join(text.text or "" for text in item.findall(".//a:t", NS)))
51
+ return values
52
+
53
+
54
+ def _cell_value(cell: ET.Element, shared_strings: list[str]) -> str:
55
+ value_node = cell.find("a:v", NS)
56
+ value = "" if value_node is None else value_node.text or ""
57
+ if cell.attrib.get("t") == "s" and value:
58
+ return shared_strings[int(value)]
59
+ return value
60
+
61
+
62
+ def _column_index(ref: str) -> int:
63
+ letters = "".join(ch for ch in ref if ch.isalpha()).upper()
64
+ result = 0
65
+ for ch in letters:
66
+ result = result * 26 + ord(ch) - ord("A") + 1
67
+ return result or 1
@@ -0,0 +1,43 @@
1
+ from __future__ import annotations
2
+
3
+ import argparse
4
+ from pathlib import Path
5
+
6
+ from app.database import DB_PATH, initialize_database
7
+ import sqlite3
8
+
9
+
10
+ DEFAULT_OUTPUT = Path("database_full_dump.sql")
11
+
12
+
13
+ def dump_database(output_path: str | Path = DEFAULT_OUTPUT) -> Path:
14
+ """Export the current SQLite database schema and data to an SQL file."""
15
+ initialize_database()
16
+
17
+ output = Path(output_path).resolve()
18
+ with sqlite3.connect(DB_PATH) as conn:
19
+ sql_lines = list(conn.iterdump())
20
+
21
+ output.write_text("\n".join(sql_lines) + "\n", encoding="utf-8")
22
+ return output
23
+
24
+
25
+ def main() -> int:
26
+ parser = argparse.ArgumentParser(
27
+ description="Export SQLite schema and INSERT data statements to an SQL file."
28
+ )
29
+ parser.add_argument(
30
+ "output",
31
+ nargs="?",
32
+ default=str(DEFAULT_OUTPUT),
33
+ help="Output SQL file. Defaults to database_full_dump.sql.",
34
+ )
35
+ args = parser.parse_args()
36
+
37
+ output = dump_database(args.output)
38
+ print(f"Database SQL dump created: {output}")
39
+ return 0
40
+
41
+
42
+ if __name__ == "__main__":
43
+ raise SystemExit(main())
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file