Compare commits

...

12 Commits

Author SHA1 Message Date
Shiro-Nek0
b6cc945adb Merge branch 'main' of https://gitea.sekidesu.xyz/SekiDesu01/SekiPOS 2026-02-26 02:00:58 -03:00
Shiro-Nek0
a22d808b7b modified: README.md 2026-02-26 01:59:16 -03:00
3198696c46 new file: KeyGenerator/generate_keys.py 2026-02-26 00:46:51 -03:00
Shiro-Nek0
a90efc621d oops typo :3 2026-02-26 00:35:22 -03:00
Shiro-Nek0
d8b710805f docker FIX 2026-02-26 00:34:36 -03:00
1e6778f2bf modified: Dockerfile 2026-02-26 00:25:32 -03:00
574ee7773c modified: Dockerfile 2026-02-26 00:24:16 -03:00
Shiro-Nek0
fbb868c244 dockerfile v2 2026-02-26 00:19:59 -03:00
Shiro-Nek0
3a68431a21 finish 2026-02-26 00:10:36 -03:00
ad0fb66b7a modified: README.md 2026-02-26 00:09:41 -03:00
788867c1af new file: ScannerPython/scanner.py 2026-02-26 00:04:55 -03:00
a695640009 modified: README.md 2026-02-26 00:03:39 -03:00
8 changed files with 221 additions and 7 deletions

1
.gitignore vendored
View File

@@ -1 +1,2 @@
pos_database.db pos_database.db
ScannerGO/ScannerGO-*

View File

@@ -2,10 +2,21 @@ FROM python:3.11-slim
WORKDIR /app WORKDIR /app
COPY requirements.txt ./ # Install dependencies
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt RUN pip install --no-cache-dir -r requirements.txt
COPY . . # Copy source code
COPY app.py .
COPY templates/ ./templates/
COPY static/ ./static/
# Create the folder structure for the volume mounts
RUN mkdir -p /app/static/cache
EXPOSE 5000
# Run with unbuffered output so you can actually see the logs in Portainer
ENV PYTHONUNBUFFERED=1
CMD ["python", "app.py"] CMD ["python", "app.py"]

View File

@@ -0,0 +1,76 @@
import barcode
from barcode.writer import ImageWriter
from PIL import Image, ImageDraw, ImageFont
import os
import random
# Items to generate
ITEMS = [
{"name": "Plátano", "icon": "🍌"},
{"name": "Manzana", "icon": "🍎"},
{"name": "Tomate", "icon": "🍅"},
{"name": "Lechuga", "icon": "🥬"},
{"name": "Cebolla", "icon": "🧅"},
{"name": "Pan Batido", "icon": "🥖"}
]
os.makedirs('keychain_cards', exist_ok=True)
def generate_card(item):
name = item['name']
# Generate a private EAN-13 starting with 99
# We need 12 digits (the 13th is a checksum added by the library)
random_digits = ''.join([str(random.randint(0, 9)) for _ in range(10)])
code_str = f"99{random_digits}"
# Generate Barcode Image
EAN = barcode.get_barcode_class('ean13')
ean = EAN(code_str, writer=ImageWriter())
# Customizing the output image size
options = {
'module_height': 15.0,
'font_size': 10,
'text_distance': 3.0,
'write_text': True
}
# Create the card canvas (300x450 pixels ~ 2.5x3.5 inches)
card = Image.new('RGB', (300, 400), color='white')
draw = ImageDraw.Draw(card)
# Draw a border for cutting
draw.rectangle([0, 0, 299, 399], outline="black", width=2)
# Try to add the Emoji/Text (Requires a font that supports emojis, otherwise just text)
try:
# If on Linux, try to find a ttf
font = ImageFont.truetype("/usr/share/fonts/truetype/dejavu/DejaVuSans.ttf", 40)
title_font = ImageFont.truetype("/usr/share/fonts/truetype/dejavu/DejaVuSans-Bold.ttf", 25)
except:
font = ImageFont.load_default()
title_font = ImageFont.load_default()
# Draw Name and Emoji
draw.text((150, 60), item['icon'], fill="black", font=font, anchor="mm")
draw.text((150, 120), name, fill="black", font=title_font, anchor="mm")
# Save barcode to temp file
barcode_img_path = f"keychain_cards/{code_str}_tmp"
ean.save(barcode_img_path, options=options)
# Paste barcode onto card
b_img = Image.open(f"{barcode_img_path}.png")
b_img = b_img.resize((260, 180)) # Resize to fit card
card.paste(b_img, (20, 180))
# Cleanup and save final
os.remove(f"{barcode_img_path}.png")
final_path = f"keychain_cards/{name.replace(' ', '_')}.png"
card.save(final_path)
print(f"Generated {name}: {ean.get_fullcode()}")
for item in ITEMS:
generate_card(item)
print("\nAll cards generated in 'keychain_cards/' folder.")

View File

@@ -1,2 +1,85 @@
# SekiPOS # SekiPOS v1.0 🍫🥤
A reactive POS inventory system for software engineers with a snack addiction. Features real-time UI updates, automatic product discovery via Open Food Facts, and local image caching.
## 🚀 Features
- **Real-time UI:** Instant updates via Socket.IO.
- **Smart Fetch:** Pulls product names/images from Open Food Facts if not found locally.
- **Local Cache:** Saves images locally to `static/cache` to avoid IP bans.
- **CLP Ready:** Chilean Peso formatting ($1.234) for local commerce.
- **Secure:** Hashed password authentication via Flask-Login.
## 🐳 Docker Deployment (Server)
Build and run the central inventory server:
```bash
# Build the image
docker build -t sekipos:latest .
# Run the container (Map port 5000 and persist the database/cache)
docker run -d \
-p 5000:5000 \
-v $(pwd)/sekipos/db:/app/db \
-v $(pwd)/sekipos/static/cache:/app/static/cache \
--name sekipos-server \
sekipos:latest
```
Or use this stack:
```yml
name: sekipos
services:
sekipos:
ports:
- 5000:5000
volumes:
- YOUR_PATH/sekipos/db:/app/db
- YOUR_PATH/sekipos/static/cache:/app/static/cache
container_name: sekipos-server
image: sekipos:latest
```
## 🔌 Hardware Scanner Bridge (`ScannerGO`)
The server needs a bridge to talk to your physical COM port. Use the `ScannerGO` binary on the machine where the scanner is plugged in.
### 🐧 Linux
```bash
chmod +x ScannerGO-linux
./ScannerGO-linux -port "/dev/ttyACM0" -baud 115200 -url "http://<SERVER_IP>:5000/scan"
```
### 🪟 Windows
```powershell
.\ScannerGO-windows.exe -port "COM3" -baud 115200 -url "http://<SERVER_IP>:5000/scan"
```
*Note: Ensure the `-url` points to your Docker container's IP address.*
All this program does its send the COM data from the scanner gun to:
```
https://scanner.sekidesu.xyz/scan?content=BAR-CODE
```
## 📦 Local Installation (Development)
If you're too afraid of Docker:
```bash
pip install -r requirements.txt
python app.py
```
## 🔐 Credentials
- **Username:** `admin`
- **Password:** `seki123` (Change this in `app.py` or you'll be hacked by a smart-fridge)
## 📁 Structure
- `app.py`: The inventory/web server.
- `static/cache/`: Local repository for product images.
- `db/pos_database.db`: SQLite storage.
## 📋 TODOs?
- Fruits and vegetables list
- Better admin registration(?)
- Cache user edited pictures

41
ScannerPython/scanner.py Normal file
View File

@@ -0,0 +1,41 @@
import serial
import requests
import time
# --- CONFIGURATION ---
COM_PORT = 'COM5' # Change to /dev/ttyUSB0 on Linux
BAUD_RATE = 115200
# The IP of the PC running your Flask WebUI
SERVER_URL = "https://scanner.sekidesu.xyz/scan" # Change to your server's URL
def run_bridge():
try:
# Initialize serial connection
ser = serial.Serial(COM_PORT, BAUD_RATE, timeout=0.1)
print(f"Connected to {COM_PORT} at {BAUD_RATE} bauds.")
print("Ready to scan. Try not to break it.")
while True:
# Read line from scanner (most scanners send \r or \n at the end)
if ser.in_waiting > 0:
barcode = ser.readline().decode('utf-8').strip()
if barcode:
print(f"Scanned: {barcode}")
try:
# Send to your existing Flask server
# We use the same parameter 'content' so your server doesn't know the difference
resp = requests.get(SERVER_URL, params={'content': barcode})
print(f"Server responded: {resp.status_code}")
except Exception as e:
print(f"Failed to send to server: {e}")
time.sleep(0.01) # Don't melt your CPU
except serial.SerialException as e:
print(f"Error opening {COM_PORT}: {e}")
except KeyboardInterrupt:
print("\nBridge stopped by user. Quitter.")
if __name__ == "__main__":
run_bridge()

2
app.py
View File

@@ -14,7 +14,7 @@ socketio = SocketIO(app, cors_allowed_origins="*")
login_manager = LoginManager(app) login_manager = LoginManager(app)
login_manager.login_view = 'login' login_manager.login_view = 'login'
DB_FILE = 'pos_database.db' DB_FILE = 'db/pos_database.db'
CACHE_DIR = 'static/cache' CACHE_DIR = 'static/cache'
os.makedirs(CACHE_DIR, exist_ok=True) os.makedirs(CACHE_DIR, exist_ok=True)

2
db/.gitignore vendored Normal file
View File

@@ -0,0 +1,2 @@
*
!.gitignore

Binary file not shown.