Skip to content

johnaljennegalos/django-pos-scanner

Repository files navigation

πŸͺ Django POS Scanner System

A comprehensive, production-ready Point of Sale (POS) management system built with Django for Galos Gadget Hub β€” featuring multi-branch inventory, installment credit management, warranty claims, real-time sales analytics, audit trail logging, email notifications, CSV exports, and role-based employee access.

Django CI Check Python Django License Live Demo

Capture1 Capture Capture11

πŸ“‹ Table of Contents πŸ“‹

  1. Executive Summary
  2. Features
  3. Tech Stack
  4. Project Structure
  5. Setup & Installation
  6. Database Models
  7. User Roles & Permissions
  8. URL Endpoints
  9. Key Features Deep Dive
  10. Configuration & Settings
  11. Troubleshooting
  12. Development Guidelines
  13. Production Deployment
  14. Contributing
  15. License & Support

🏒 Executive Summary

The Django POS Scanner System is a full-featured retail management platform designed for Galos Gadget Hub β€” a multi-branch electronics gadget store. It replaces manual sales tracking with a barcode-driven POS terminal, automates installment credit approvals, streamlines warranty processing, and provides real-time analytics for managers.

Business Value

Metric Benefit
Sales Speed Barcode scan β†’ checkout in seconds
Credit Risk Credit Officer approval workflow for every installment
Warranty Handling Structured Repair vs Replacement with cost tracking
Inventory Visibility Per-branch low-stock alerts with minimum thresholds
Reporting Weekly / Monthly / Yearly revenue, commissions, and outstanding balances
Accountability Employee login/logout tracking, session timestamps, and full audit trail
Data Export One-click CSV exports for sales, inventory, installments, employees, warranties, audit logs
Email Automation HTML receipts on checkout + payment due reminders via scheduled tasks

✨ Features

Core POS Functions

  • Barcode-driven POS Terminal β€” scan products to add them to cart in real time
  • Cash Checkout β€” automatic change calculation, receipt generation, invoice OR number
  • Installment Checkout β€” configurable term (months), monthly due, and balance tracking
  • Order Management β€” create, view, soft-delete, and archive sales orders
  • Customer Lookup β€” phone-based customer identification (optional for cash sales)

Advanced Features

  • Warranty Claims β€” file Repair or Replacement claims with serial number tracking
    • Repair: 30-day window
    • Replacement: 7-day window with old/new serial swap record
  • Installment Plans β€” multi-month schedules with automatic next-due-date progression
  • Invoice Generation β€” unique OR numbers, VAT computation, issued-by tracking
  • Commission Tracking β€” per-agent rate Γ— total sales, cumulative earnings
  • Defective Inventory β€” log faulty units with reason, disposal status, and branch

Admin & Reporting

  • Admin Dashboard β€” real-time KPIs: revenue, cost, gross profit, transaction count
  • Branch Revenue Chart β€” bar chart comparison of all branches
  • Employee Sales Chart β€” individual sales agent performance
  • Top 5 Products Chart β€” top-selling products by units sold (last 30 days)
  • Weekly / Monthly / Yearly Totals β€” period-based revenue aggregation
  • Outstanding Balance Monitor β€” total owed from pending installments
  • Payment Method Breakdown β€” cash vs installment revenue split
  • Average Order Value (AOV) β€” computed from the last 30-day transaction window

Enhanced Manager Dashboard

  • Warranty Claims Summary β€” counts by status (Pending / In-Progress / Completed / Released)
  • Repair vs Replacement Breakdown β€” claim counts and total cost impact per type
  • Stock Health Overview β€” healthy / low-stock / out-of-stock item counts + items restocked in last 24 hrs
  • Overdue Installments Counter β€” number of installment plans past their due date
  • Today's Collections β€” expected collection amount and payment progress percentage
  • Day-over-Day Revenue Growth β€” today vs yesterday percentage change
  • Active Staff Panel β€” list of currently logged-in employees

CSV Export

  • Sales Export β€” full filtered order list downloadable as sales_data.csv
  • Branch Inventory Export β€” current stock levels as branch_inventory.csv
  • Installment Export β€” filtered installment records as installment_data.csv
  • Employee List Export β€” active employee roster as employee_list.csv
  • Warranty List Export β€” filtered warranty claims as warranty_list.csv
  • Audit Log Export β€” filtered audit trail as audit_logs.csv

Audit Trail System

  • AuditTrail Model β€” logs every CREATE / UPDATE / DELETE action on key models (Product, BranchInventory, Order, OrderItem, InstallmentPlan, Employee, WarrantyClaims, Supplier)
  • Django Signals β€” automatic audit capture via pre_save, post_save, and post_delete receivers
  • AuditMiddleware β€” thread-local user capture so signals know which employee made the change
  • Audit Logs View (/audit_logs/) β€” paginated, filterable by date range and action type; Manager / Superuser only
  • Audit CSV Export β€” downloadable audit log

Email Notification System

  • Cash Receipt Email β€” HTML-formatted receipt sent to customer email on cash checkout
  • Installment Confirmation Email β€” HTML installment plan summary sent on installment checkout
  • Payment Due Reminder β€” scheduled task (tasks.py: send_due_reminders()) sends reminder 5 days before next due date
  • Configurable via environment variables (EMAIL_HOST, EMAIL_PORT, EMAIL_HOST_USER, etc.)

Employee Management

  • Role-based access: Manager, Sales Agent, Credit Officer
  • Login/logout timestamps (last_login_time, last_logout_time, is_logged_in)
  • Soft-delete with cascading Django User.is_active = False
  • Profile pictures, email, phone, branch assignment, hire date

Multi-Branch Support

  • Inventory tracked per branch (BranchInventory)
  • Orders tagged to the processing branch
  • Branch-level revenue reporting
  • Soft-deletable branches

Supplier Management

  • Contract start/expiration with automatic contract_status property
  • Supplier archive/restore actions in admin
  • Products linked to suppliers with cascade behavior

πŸ›  Tech Stack

Backend

Component Technology Version
Web Framework Django 6.0.2
WSGI Server asgiref 3.11.1
Database SQLite (dev) β€”
Date Utilities python-dateutil 2.9.0.post0
Slug Utilities python-slugify 8.0.4
SQL Parsing sqlparse 0.5.5
Timezone Data tzdata 2025.3

Frontend

Component Technology
Template Engine Django Templates
Styling HTML/CSS (Tailwind utility classes)
Barcode Scanning JavaScript (posScanner.js)
POS UI JavaScript (posTerminal.js, posUI.js, posCalculations.js, posInit.js)
Image Preview JavaScript (image-preview.js)

Django Extensions

Package Version Purpose
django-admin-interface 0.32.0 Enhanced admin panel UI
django-colorfield 0.14.0 Color picker for admin interface
django-filter 25.2 Advanced queryset filtering
django-q β€” Background task queue (scheduled email reminders)
Pillow 12.1.1 Image processing for product/profile pics
six 1.17.0 Python 2/3 compatibility utility
text-unidecode 1.3 Unicode slug support
whitenoise β€” Efficient static file serving in production

πŸ“ Project Structure

django-pos-scanner/
β”‚
β”œβ”€β”€ accounts/                        # Main application
β”‚   β”œβ”€β”€ migrations/                  # 37 database migrations
β”‚   β”‚   β”œβ”€β”€ 0001_initial.py
β”‚   β”‚   └── ... (0002–0037)
β”‚   β”œβ”€β”€ templates/
β”‚   β”‚   β”œβ”€β”€ accounts/                # Page templates
β”‚   β”‚   β”‚   β”œβ”€β”€ login.html           # Authentication page
β”‚   β”‚   β”‚   β”œβ”€β”€ main.html            # Sales agent home
β”‚   β”‚   β”‚   β”œβ”€β”€ dashboard.html       # Manager/admin dashboard
β”‚   β”‚   β”‚   β”œβ”€β”€ pos_terminal.html    # POS scanner interface
β”‚   β”‚   β”‚   β”œβ”€β”€ branch_inventory.html
β”‚   β”‚   β”‚   β”œβ”€β”€ inventory_update.html
β”‚   β”‚   β”‚   β”œβ”€β”€ sales_display.html   # Order list with filters
β”‚   β”‚   β”‚   β”œβ”€β”€ admin_reports.html   # Analytics & charts
β”‚   β”‚   β”‚   β”œβ”€β”€ admin_installment.html
β”‚   β”‚   β”‚   β”œβ”€β”€ manage_installment.html
β”‚   β”‚   β”‚   β”œβ”€β”€ employee_list.html
β”‚   β”‚   β”‚   β”œβ”€β”€ employee_form.html
β”‚   β”‚   β”‚   β”œβ”€β”€ employee_profile.html
β”‚   β”‚   β”‚   β”œβ”€β”€ manage_employee.html
β”‚   β”‚   β”‚   β”œβ”€β”€ inst_calculator.html
β”‚   β”‚   β”‚   β”œβ”€β”€ emp_receipt.html     # Receipt/invoice print view
β”‚   β”‚   β”‚   β”œβ”€β”€ warranty.html        # File a warranty claim
β”‚   β”‚   β”‚   β”œβ”€β”€ warranty_list.html   # List of all claims
β”‚   β”‚   β”‚   β”œβ”€β”€ audit_logs.html      # Audit trail viewer
β”‚   β”‚   β”‚   └── navbar.html
β”‚   β”‚   β”œβ”€β”€ components/              # Partial/reusable templates
β”‚   β”‚   β”‚   β”œβ”€β”€ cart.html
β”‚   β”‚   β”‚   β”œβ”€β”€ cash_modal.html
β”‚   β”‚   β”‚   β”œβ”€β”€ installment_modal.html
β”‚   β”‚   β”‚   β”œβ”€β”€ pos_product_list.html
β”‚   β”‚   β”‚   └── sales_edit.html
β”‚   β”‚   └── emails/                  # HTML email templates
β”‚   β”‚       β”œβ”€β”€ cash_receipt.html    # Cash purchase receipt
β”‚   β”‚       β”œβ”€β”€ installment_receipt.html  # Installment plan confirmation
β”‚   β”‚       └── due_reminder.html    # Payment due reminder
β”‚   β”œβ”€β”€ admin.py                     # Django admin registrations & customizations
β”‚   β”œβ”€β”€ apps.py                      # App configuration
β”‚   β”œβ”€β”€ decorators.py                # @unauthenticated_user decorator
β”‚   β”œβ”€β”€ filters.py                   # django-filter FilterSet classes
β”‚   β”œβ”€β”€ forms.py                     # ModelForm definitions
β”‚   β”œβ”€β”€ middleware.py                 # AuditMiddleware β€” thread-local user capture
β”‚   β”œβ”€β”€ models.py                    # All 15 data models
β”‚   β”œβ”€β”€ signals.py                   # Django signals for automatic audit trail
β”‚   β”œβ”€β”€ tasks.py                     # Scheduled tasks (payment due reminders)
β”‚   β”œβ”€β”€ urls.py                      # App-level URL patterns
β”‚   └── views.py                     # All view functions and class-based views
β”‚
β”œβ”€β”€ pos/                             # Django project configuration
β”‚   β”œβ”€β”€ settings.py                  # Application settings
β”‚   β”œβ”€β”€ urls.py                      # Root URL configuration
β”‚   β”œβ”€β”€ wsgi.py                      # WSGI entry point
β”‚   └── asgi.py                      # ASGI entry point
β”‚
β”œβ”€β”€ static/                          # Static assets
β”‚   β”œβ”€β”€ images/                      # Logos and static images
β”‚   β”‚   β”œβ”€β”€ ggh-logo.png
β”‚   β”‚   └── logo.PNG
β”‚   └── js/                          # JavaScript modules
β”‚       β”œβ”€β”€ posTerminal.js           # Main POS terminal controller
β”‚       β”œβ”€β”€ posScanner.js            # Barcode scanning logic
β”‚       β”œβ”€β”€ posUI.js                 # UI state management
β”‚       β”œβ”€β”€ posInit.js               # POS initialization
β”‚       β”œβ”€β”€ posCalculations.js       # Cart total calculations
β”‚       └── image-preview.js         # Profile/product image preview
β”‚
β”œβ”€β”€ templates/                       # Global templates
β”‚   └── admin/
β”‚       └── base_site.html           # Custom admin branding
β”‚
β”œβ”€β”€ media/                           # User-uploaded files (gitignored)
β”‚   └── media/                       # Product images and profile pictures
β”‚
β”œβ”€β”€ admin-interface/                 # django-admin-interface assets
β”‚
β”œβ”€β”€ .github/
β”‚   └── workflows/
β”‚       └── django.ci.yml            # CI: system check + flake8 linting
β”‚
β”œβ”€β”€ manage.py                        # Django management CLI
β”œβ”€β”€ requirements.txt                 # Python dependencies
└── .gitignore                       # Ignores db.sqlite3, media, env, backups

Model Relationship Diagram

Django User (auth)
    β”‚ 1:1
    β–Ό
Employee ──── Branch (ForeignKey)
    β”‚ 1:1              β”‚ 1:M
    β”œβ”€β”€β–Ί SalesAgent     └──► BranchInventory ◄── Product ◄── Supplier
    β”‚ 1:1
    └──► CreditOfficer
              β”‚ 1:M
              β–Ό
         InstallmentPlan ◄────────────────── Payment ◄── Order ◄── Customer
                                                              β”‚
                                                              β–Ό
                                                          OrderItem ──► Product
                                                              β”‚
                                                              β”œβ”€β”€β–Ί WarrantyClaims
                                                              β”‚         β”‚ 1:1
                                                              β”‚         └──► ReplacementRecord
                                                              β”‚
                                                         Invoice (OR#)

Product ──► DefectiveInventory ◄── Branch

AuditTrail ──► Employee (user)
           ──► ContentType (GenericFK β†’ any audited model)

πŸš€ Setup & Installation

Prerequisites

Requirement Minimum Version
Python 3.10+
pip 23.0+
Git 2.x
Virtual Environment venv / virtualenv

Step-by-Step Installation

1. Clone the repository

git clone https://github.com/johnaljennegalos/django-pos-scanner.git
cd django-pos-scanner

2. Create and activate a virtual environment

# Create
python -m venv .venv

# Activate β€” Windows (PowerShell)
.\.venv\Scripts\Activate.ps1

# Activate β€” Windows (CMD)
.\.venv\Scripts\activate.bat

# Activate β€” macOS / Linux
source .venv/bin/activate

3. Install all dependencies

pip install --upgrade pip
pip install -r requirements.txt

4. Initialize the database

python manage.py migrate

5. Create a superuser account

python manage.py createsuperuser
# Follow the prompts: username, email, password

6. (Optional) Load sample data

python manage.py loaddata data_backup_filtered.json

7. Collect static files (required for production; optional for dev)

python manage.py collectstatic

8. Start the development server

python manage.py runserver

Access the app at: http://127.0.0.1:8000/ Access the admin at: http://127.0.0.1:8000/admin/

Running Tests

# Django system check (model integrity, URL conflicts, settings validation)
python manage.py check

# Syntax/style linting
pip install flake8
flake8 . --count --select=E9,F63,F7,F82 --show-source --statistics

πŸ“Š Database Models

Complete Model Reference

Customer

Field Type Notes
name CharField(100) Required
email EmailField(100) Optional
address CharField(100) Optional
phone CharField(100) Used for quick lookup at POS
date_created DateField Auto-set on creation
is_active BooleanField Soft delete flag

Branch

Field Type Notes
name CharField(100) Branch display name
address CharField(100) Optional
phone_number CharField(100) Optional
is_active BooleanField Soft delete via overridden delete()

Employee

Field Type Notes
user OneToOneField(User) Linked Django auth user
branch ForeignKey(Branch) Required assignment
name CharField(100) Display name
role CharField Sales Agent / Credit Officer / Manager
email EmailField Optional contact
phone CharField(20) Optional contact
profile_pic ImageField Uploaded to media/
hire_date DateField Auto-set on creation
is_active BooleanField Cascades user.is_active = False
is_logged_in BooleanField Real-time session tracking
last_login_time DateTimeField Updated on each successful login
last_logout_time DateTimeField Updated on logout
# Soft delete cascades to Django user
def save(self, *args, **kwargs):
    if not self.is_active and self.user.is_active:
        self.user.is_active = False
        self.user.save()
    super().save(*args, **kwargs)

SalesAgent

Field Type Notes
employee OneToOneField(Employee) Active employees only
commission_rate DecimalField(5,2) Percentage, e.g. 5.00 = 5%
total_commission_earned DecimalField(12,2) Cumulative
total_sales DecimalField(12,2) Cumulative gross sales

CreditOfficer

Field Type Notes
employee OneToOneField(Employee) Active employees only
approval_limit DecimalField(12,2) Max installment they can approve
security_level IntegerField Authorization tier (default 1)
is_active BooleanField

Supplier

Field Type Notes
name CharField(100)
contact_person CharField(100)
phone CharField(100)
contract_expiration DateField
contract_start DateField Auto-set
status CharField Active / Renewed / Opted Out / Expired
is_active BooleanField Soft delete via soft_delete()

Computed properties:

  • contract_status β€” returns 'Expired' if today > expiration, else status
  • contract_period β€” formatted year range, e.g. "2024 - 2026"

Product

Field Type Notes
supplier ForeignKey(Supplier)
product_name CharField(100)
category CharField Laptop / Android / iPhone / Printer
base_price DecimalField(10,2) Selling price
barcode CharField(100) Unique, used for POS scanning
cost_price DecimalField(10,2) For gross profit calculation
min_stock_level PositiveIntegerField Low-stock threshold (default 3)
image ImageField Uploaded to media/
is_active BooleanField Soft delete flag
deleted_at DateTimeField Timestamp when soft-deleted
def soft_delete(self):
    self.is_active = False
    self.deleted_at = timezone.now()
    self.save()

BranchInventory

Field Type Notes
branch ForeignKey(Branch) Active branches only
product ForeignKey(Product)
quantity IntegerField Current stock count
date_added DateTimeField Auto-set, ordered descending

Order

Field Type Notes
customer ForeignKey(Customer) Optional (null for anonymous)
employee ForeignKey(Employee) Processing employee
branch ForeignKey(Branch) Originating branch
order_date DateField Auto-set on creation
total_amount DecimalField(10,2) Sum of all order items
order_status CharField Pending / Completed / Cancelled
payment_method CharField CASH / INSTALLMENT
is_active BooleanField Soft delete flag
deleted_at DateTimeField Timestamp when archived

OrderItem

Field Type Notes
order ForeignKey(Order) Active orders only
product ForeignKey(Product)
quantity IntegerField
unit_price DecimalField(10,2) Price at time of sale
cost_price DecimalField(10,2) Cost at time of sale

Computed property: line_total = quantity Γ— unit_price

Payment

Field Type Notes
order ForeignKey(Order) Protected from deletion
amount_paid DecimalField(10,2)
date_paid DateField
payment_type CharField CASH / INSTALLMENT

CashPayment

Field Type Notes
payment OneToOneField(Payment)
cash_received DecimalField(10,2) Amount tendered by customer
change_given DecimalField(10,2) Change returned

InstallmentPlan

Field Type Notes
payment OneToOneField(Payment)
credit_officer ForeignKey(CreditOfficer) Approving officer (nullable)
term_months IntegerField Duration in months
monthly_due DecimalField(10,2) Computed: total Γ· months
remaining_balance DecimalField(10,2) Decremented on each payment
next_due_date DateField Advanced by 1 month per payment
payment_status CharField Pending / Completed / Cancelled

Invoice

Field Type Notes
order ForeignKey(Order) Protected, active orders only
or_number CharField(100) Unique official receipt number
invoice_date DateField
vat_amount DecimalField(10,2)
grand_total DecimalField(10,2)
issued_by ForeignKey(Employee)

WarrantyClaims

Field Type Notes
order_item ForeignKey(OrderItem) Related sale item
claim_type CharField Repair / Replacement
faulty_serial CharField(100) Serial number of defective unit
issue_description TextField Customer-reported problem
status CharField Pending β†’ In-Progress β†’ Completed β†’ Released
date_filed DateTimeField Auto-set
resolution_date DateTimeField When resolved
cost_impact DecimalField(10,2) Financial cost to the store
handled_by ForeignKey(Employee) Assigned active employee

ReplacementRecord

Field Type Notes
warranty_claims OneToOneField(WarrantyClaims)
old_serial CharField(100) Faulty unit serial
new_serial CharField(100) Replacement unit serial
replacement_date DateTimeField Auto-set

DefectiveInventory

Field Type Notes
product ForeignKey(Product)
branch ForeignKey(Branch)
faulty_serial CharField(100)
reason TextField
date_received DateTimeField Auto-set
is_disposed BooleanField Whether disposed of (default True)

AuditTrail

Field Type Notes
user ForeignKey(Employee) Employee who performed the action (nullable)
action CharField CREATE / UPDATE / DELETE
content_type ForeignKey(ContentType) Django ContentType of the affected model
object_id PositiveIntegerField Primary key of the affected record
content_object GenericForeignKey Generic relation to the affected object
change_log JSONField Field-level diff: {"field": {"old": "...", "new": "..."}}
ip_address GenericIPAddressField Requester IP (nullable)
timestamp DateTimeField Auto-set on creation

Automatically populated via Django signals (signals.py) for the following models: Product, BranchInventory, Order, OrderItem, InstallmentPlan, Employee, WarrantyClaims, Supplier.


πŸ‘₯ User Roles & Permissions

Superuser / Admin

  • Full access to Django Admin panel at /admin/
  • Branded as "Galos Gadget Hub Admin" / "Galos POS Portal"
  • Can create, archive, and restore: Branches, Employees, Products, Suppliers, Orders
  • Read-only access to: CashPayments, Payments, Invoices, OrderItems
  • Custom admin actions replace the default delete_selected to prevent hard deletes

Manager

  • Redirected to dashboard on login
  • Access to:
    • Admin Reports (/admin_reports/) β€” revenue charts, KPI cards
    • Installment Management (/admin_installment/) β€” all plans with filters
    • Sales Display (/sales_display/) β€” full order history
    • Employee List (/employee_list) β€” view all staff
    • Warranty List (/warrnty_list/) β€” all warranty claims
    • Branch Inventory (/branch_inventory) β€” stock across all branches
    • Audit Logs (/audit_logs/) β€” full system activity trail
    • CSV exports for all of the above

Sales Agent

  • Redirected to home (main.html) on login
  • Access to:
    • POS Terminal (/pos_terminal/) β€” full barcode scanning checkout
    • Sales Display β€” their own orders
    • Employee Profile β€” update email, phone, profile picture
    • File Warranty Claims (/warranty/<pk>/)
    • View personal receipt (/accounts/<pk>/emp_receipt/)
    • Installment Calculator (/inst_calculator/)

Credit Officer

  • Redirected to home on login
  • Access to:
    • Manage Installment (/accounts/<pk>/manage_installment) β€” process payments
    • View installment plan details and update remaining_balance / next_due_date
    • Access to payment forms

πŸ”Œ URL Endpoints

Authentication

URL View Description
GET/POST /login/ loginPage Employee login with session tracking
POST /logout/ logoutPage Employee logout, updates last_logout_time

Main

URL View Description
GET / home Sales agent dashboard
GET /dashboard/ dashboard Manager analytics dashboard
GET /employee_profile employeeProfile View/edit own profile
GET /manage_employee/<pk>/ manageEmployee Manager: edit employee

POS Terminal

URL View Description
GET /pos_terminal/ posTerminal POS interface with product grid
GET /scan_product/ scanProduct JSON: lookup product by barcode
POST /checkout/cash/ checkout_cash Process cash transaction
POST /checkout/installment/ installment_checkout Create installment order

Inventory

URL View Description
GET /branch_inventory branchInventory View stock with filters
GET/POST /accounts/<pk>/inventory_update InventoryUpdateView Update stock quantity

Employees

URL View Description
GET /employee_list EmployeeList List all active employees
GET/POST /employee_form EmployeeCreate Create new employee + user

Sales

URL View Description
GET /sales_display/ salesDisplay Filtered order list
GET/POST /components/<pk>/sales_edit salesUpdateView Edit order status
POST /delete-order/<pk>/ delete_order Soft-delete an order
POST /delete-product/<pk>/ delete_product Soft-delete a product
GET /accounts/<pk>/emp_receipt/ emp_receipt Print/view receipt

Installment Management

URL View Description
GET /inst_calculator/ instCalculator Calculate installment terms
GET /admin_installment/ admin_installment Manager: all installment plans
GET/POST /accounts/<pk>/manage_installment manage_installment Process monthly payment

Warranty

URL View Description
GET/POST /warranty/<pk>/ warranty File a warranty claim
GET /warrnty_list/ warranty_list List all warranty claims
POST /update_claim_status/<pk>/ update_claim_status Advance claim status

Reporting

URL View Description
GET /admin_reports/ admin_reports Revenue analytics, charts, top products
GET /audit_logs/ audit_logs System audit trail (Manager/Superuser only)
GET /audit_logs/export_audit_logs/ audit_logs_export_csv Download audit logs as CSV

CSV Exports

URL View Description
GET /sales_display/export/ export_sales_csv Sales data as CSV
GET /branch_inventory/export/ export_branch_inventory_csv Branch inventory as CSV
GET /admin_installment/export_data_csv/ admin_installment_export_csv Installment records as CSV
GET /employee_list/export_employee_csv/ employee_list_export_csv Employee roster as CSV
GET /warrnty_list/export_warranty_list/ warranty_list_export_csv Warranty claims as CSV

Admin (Django built-in)

URL Description
/admin/ Django Admin Panel
/admin/accounts/branch/ Branch management
/admin/accounts/employee/ Employee management
/admin/accounts/product/ Product catalog
/admin/accounts/order/ Order management
/admin/accounts/supplier/ Supplier contracts
/admin/accounts/creditofficer/ Credit officer management
/admin/accounts/salesagent/ Sales agent management
/admin/accounts/warrantyclaims/ Warranty claims
/admin/accounts/defectiveinventory/ Defective stock

πŸ” Key Features Deep Dive

1. Login & Employee Session Tracking

On every successful login, the system:

  1. Authenticates using Django's authenticate()
  2. Sets employee.is_logged_in = True
  3. Records employee.last_login_time = timezone.now()
  4. Redirects based on role: Managers/Superusers β†’ dashboard, others β†’ home
if user is not None:
    login(request, user)
    if hasattr(user, 'employee'):
        employee = user.employee
        employee.is_logged_in = True
        employee.last_login_time = timezone.now()
        employee.save()

    is_manager = (user.employee.role == 'Manager') if hasattr(user, 'employee') else False
    return redirect('dashboard' if (user.is_superuser or is_manager) else 'home')

On logout, last_logout_time is set and is_logged_in is cleared.

2. POS Terminal with Barcode Scanning

The POS terminal at /pos_terminal/ works as follows:

  1. The JavaScript scanner (posScanner.js) listens for barcode input
  2. It calls /scan_product/?barcode=<value> which returns JSON with product info
  3. posUI.js renders the item in the cart; posCalculations.js updates totals
  4. The operator selects Cash or Installment checkout

3. Cash Checkout Process

POST /checkout/cash/
  β†’ Validate cart data (JSON)
  β†’ Create/look up Customer by phone
  → Create Order (CASH, Pending→Completed)
  β†’ Create OrderItem(s), deduct BranchInventory
  β†’ Create Payment + CashPayment (cash_received, change_given)
  β†’ Create Invoice with unique OR number
  β†’ Update SalesAgent.total_sales + commission
  β†’ Return invoice PK for receipt redirect

4. Installment Checkout

POST /checkout/installment/
  β†’ Validate cart + customer + term
  β†’ Create Customer (if new)
  β†’ Create Order (INSTALLMENT, Pending)
  β†’ Create OrderItem(s), deduct BranchInventory
  β†’ Create Payment + InstallmentPlan
     - monthly_due = total / term_months
     - next_due_date = today + 1 month
     - remaining_balance = total
  β†’ Create Invoice
  β†’ Update SalesAgent totals

5. Warranty Claims

  • Filing: Sales agent goes to /warranty/<order_item_pk>/, selects claim type, enters serial number and issue description
  • Repair flow: Status: Pending β†’ In-Progress β†’ Completed β†’ Released
  • Replacement flow: Same status progression; on completion a ReplacementRecord is created with old/new serial numbers; defective unit added to DefectiveInventory
  • Cost impact: Tracked per claim for financial reporting

6. Inventory Management

  • Each Product has a min_stock_level threshold
  • BranchInventory tracks quantity per branch
  • InventoryFilter supports filtering by: stock status (low/out/in stock), product name, barcode, branch
  • Stock is automatically decremented during checkout (wrapped in transaction.atomic())

7. Commission Calculations

When an order is completed, the system updates the Sales Agent's profile:

# Automatic commission update on sale completion
if agent:
    agent.total_sales += order.total_amount
    agent.total_commission_earned += (order.total_amount * agent.commission_rate / 100)
    agent.save()

8. Invoice Generation

Invoices use a unique OR number generated via get_random_string() with a standardized prefix. VAT is computed and stored separately. The receipt view at /accounts/<pk>/emp_receipt/ renders a printable invoice.

9. Admin Reports Analytics

The admin_reports view computes:

  • 30-day transaction window
  • Total revenue, total cost, and gross profit (via Sum(F('unit_price') * F('quantity')))
  • Average Order Value (AOV)
  • Weekly / Monthly / Yearly totals
  • Outstanding installment balances
  • Cash vs installment payment breakdown
  • Per-branch and per-employee revenue for chart rendering
  • Top 5 products by units sold β€” bar chart powered by aggregated OrderItem quantity sums

10. Enhanced Manager Dashboard

The dashboard view provides an at-a-glance operations overview:

Widget Data
Revenue Weekly / Monthly / Yearly totals
Warranty Claims Counts by status + cost impact by type
Stock Health Healthy / Low / Out-of-stock + last 24-hr restocks
Overdue Installments Plans past their next due date
Collections Today Expected vs paid amount + progress %
Day-over-Day Revenue Today vs yesterday with growth percentage
Active Staff Employees currently logged in

11. Audit Trail System

Every change to a key model is automatically captured:

Employee modifies a Product price
  β†’ AuditMiddleware stores user in thread-local
  β†’ pre_save signal fires
  β†’ AuditTrail record created:
      action: UPDATE
      change_log: {"base_price": {"old": "25000", "new": "24500"}}
      user: <Employee>
      timestamp: <now>

Audited models: Product, BranchInventory, Order, OrderItem, InstallmentPlan, Employee, WarrantyClaims, Supplier

Managers and superusers can view the log at /audit_logs/ with filters for date range and action type, and export the filtered results as CSV.

12. Email Notification System

The system sends HTML emails at three points:

Trigger Template Recipient
Cash checkout emails/cash_receipt.html Customer (if email provided)
Installment checkout emails/installment_receipt.html Customer (if email provided)
5 days before due date emails/due_reminder.html Customer (if email provided)

The due-date reminder is delivered by the send_due_reminders() function in tasks.py, intended to be scheduled via django-q.

13. CSV Data Export

Every major list view includes a one-click export button:

View Export URL File
Sales Display /sales_display/export/ sales_data.csv
Branch Inventory /branch_inventory/export/ branch_inventory.csv
Admin Installment /admin_installment/export_data_csv/ installment_data.csv
Employee List /employee_list/export_employee_csv/ employee_list.csv
Warranty List /warrnty_list/export_warranty_list/ warranty_list.csv
Audit Logs /audit_logs/export_audit_logs/ audit_logs.csv

Exports respect the same filters applied in the list view (date range, status, search query, etc.).


βš™οΈ Configuration & Settings

Key Settings (pos/settings.py)

# Timezone β€” set to Philippine Standard Time
TIME_ZONE = 'Asia/Manila'
USE_TZ = True

# Database
DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.sqlite3',
        'NAME': BASE_DIR / 'db.sqlite3',
    }
}

# Static & Media
STATIC_URL = 'static/'
STATICFILES_DIRS = [BASE_DIR / 'static']
MEDIA_URL = '/media/'
MEDIA_ROOT = os.path.join(BASE_DIR, 'media')

# Installed Apps
INSTALLED_APPS = [
    "admin_interface",   # Must be before django.contrib.admin
    "colorfield",
    'django_q',
    'django.contrib.admin',
    ...
    'accounts',
    'django_filters',
    'django.contrib.humanize'
]

# Middleware β€” includes custom AuditMiddleware
MIDDLEWARE = [
    'whitenoise.middleware.WhiteNoiseMiddleware',
    ...
    'accounts.middleware.AuditMiddleware',
]

Email Settings

Variable Description Example
EMAIL_BACKEND Django email backend django.core.mail.backends.smtp.EmailBackend
EMAIL_HOST SMTP server host smtp.mailprovider.com
EMAIL_PORT SMTP port 587
EMAIL_USE_TLS Enable TLS True
EMAIL_USE_SSL Enable SSL False
EMAIL_HOST_USER SMTP username / from address noreply@yourdomain.com
EMAIL_HOST_PASSWORD SMTP password (keep secret)
DEFAULT_FROM_EMAIL Sender display email Galos Gadget Hub <noreply@yourdomain.com>

In development, EMAIL_BACKEND defaults to console β€” emails are printed to the terminal instead of sent.

django-q Task Queue

django-q is used for scheduled background tasks such as send_due_reminders():

Q_CLUSTER = {
    'name': 'GalosGadgetHub',
    'workers': 4,
    'recycle': 500,
    'timeout': 60,
    'compress': True,
    'save_limit': 250,
    'queue_limit': 500,
    'label': 'Django Q',
    'orm': 'default',   # Uses the same database β€” no Redis required
}

Start the task worker alongside the web server:

python manage.py qcluster

Environment Variables

For production, set these via environment variables or a .env file (never commit them):

Variable Description Example
SECRET_KEY Django secret key A 50-char random string
DEBUG Debug mode flag False in production
ALLOWED_HOSTS Comma-separated allowed hosts yourdomain.com,www.yourdomain.com
DATABASE_URL Production DB connection postgres://user:pass@host/db
DB_ENGINE Django database engine django.db.backends.postgresql
DB_NAME Database name galos_pos
DB_USER Database user dbadmin
DB_PASSWORD Database password (keep secret)
DB_HOST Database host your-db-host.com
DB_PORT Database port 5432
EMAIL_HOST SMTP host smtp.mailprovider.com
EMAIL_PORT SMTP port 587
EMAIL_USE_TLS Enable TLS True
EMAIL_HOST_USER SMTP login noreply@yourdomain.com
EMAIL_HOST_PASSWORD SMTP password (keep secret)
DEFAULT_FROM_EMAIL Sender email noreply@yourdomain.com

Switching to PostgreSQL (Production)

# Install: pip install psycopg2-binary
DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.postgresql',
        'NAME': os.environ.get('DB_NAME'),
        'USER': os.environ.get('DB_USER'),
        'PASSWORD': os.environ.get('DB_PASSWORD'),
        'HOST': os.environ.get('DB_HOST', 'localhost'),
        'PORT': os.environ.get('DB_PORT', '5432'),
    }
}

πŸ› Troubleshooting

Database Issues

Problem: django.db.utils.OperationalError: no such table

# Reset and re-migrate
rm db.sqlite3
python manage.py migrate
python manage.py createsuperuser

Problem: Migration conflicts

python manage.py migrate --run-syncdb
# Or reset migrations for the accounts app:
python manage.py migrate accounts zero
python manage.py migrate accounts

Login Problems

Problem: User cannot log in despite correct credentials

Checklist:

  1. Verify user.is_active = True in Django Admin β†’ Users
  2. Verify employee.is_active = True for the corresponding Employee record
  3. Ensure the Employee has a branch assigned
  4. Check terminal output for Status update failed: errors

Problem: User logs in but sees wrong page

  • Managers must have employee.role == 'Manager'
  • Superusers always go to dashboard
  • All other roles go to home

Employee Profile Missing Error

Problem: RelatedObjectDoesNotExist: User has no employee

  • The user exists in Django Auth but has no linked Employee record
  • Fix: Create the Employee in Django Admin and link it to the user

File Upload Issues

Problem: Profile pictures or product images not displaying

# Ensure MEDIA_ROOT exists
mkdir -p media/media

# Verify settings.py
MEDIA_URL = '/media/'
MEDIA_ROOT = os.path.join(BASE_DIR, 'media')

# Verify pos/urls.py has static serving in debug mode
if settings.DEBUG:
    urlpatterns += static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)

Static Files Not Loading

python manage.py collectstatic --noinput
# Ensure STATICFILES_DIRS points to the correct path

Installment Balance Not Decreasing

  • Verify the manage_installment view is being called via POST
  • Check that remaining_balance >= monthly_due before processing
  • Ensure the InstallmentPlan has payment_status = 'Pending'

πŸ§‘β€πŸ’» Development Guidelines

Coding Standards

  • Follow PEP 8 for Python code style
  • Use Django class-based views for list/update operations, function-based views for complex logic
  • Wrap multi-step database operations in transaction.atomic()
  • Use select_related() and prefetch_related() to avoid N+1 queries

Soft Delete Pattern

All major models use soft deletes β€” never hard-delete production data:

# Pattern used across Branch, Employee, Product, Order, Supplier
def soft_delete(self):
    self.is_active = False
    self.deleted_at = timezone.now()   # where applicable
    self.save()

# Always filter active records in querysets
Product.objects.filter(is_active=True)
Order.objects.filter(is_active=True)

Database Transaction Handling

from django.db import transaction

@transaction.atomic
def checkout_cash(request):
    # All operations succeed or all roll back
    order = Order.objects.create(...)
    for item in cart_items:
        OrderItem.objects.create(order=order, ...)
        BranchInventory.objects.filter(...).update(quantity=F('quantity') - item['qty'])
    Payment.objects.create(...)
    CashPayment.objects.create(...)
    Invoice.objects.create(...)

Commission Calculation Logic

# commission_rate is stored as a percentage (e.g., 5.00 = 5%)
commission_earned = order.total_amount * Decimal(agent.commission_rate) / Decimal('100')
agent.total_commission_earned += commission_earned
agent.total_sales += order.total_amount
agent.save()

Warranty Business Rules

Claim Type Time Window Action Required
Repair 30 days from sale Log faulty serial, track cost impact
Replacement 7 days from sale Create ReplacementRecord, log DefectiveInventory

Status flow: Pending β†’ In-Progress β†’ Completed β†’ Released

Filter Classes

The system uses django-filter for dynamic queryset filtering:

# filters.py
class InventoryFilter(django_filters.FilterSet):
    stock_status = django_filters.ChoiceFilter(method='filter_stock_status')

    def filter_stock_status(self, queryset, name, value):
        if value == 'low':
            return queryset.filter(quantity__gt=0, quantity__lte=F('product__min_stock_level'))
        elif value == 'out':
            return queryset.filter(quantity__lte=0)
        elif value == 'in stock':
            return queryset.filter(quantity__gt=F('product__min_stock_level'))
        return queryset

🚒 Production Deployment

Pre-Deployment Security Checklist

  • Set DEBUG = False
  • Generate a new SECRET_KEY (never use the development key)
  • Set ALLOWED_HOSTS to your domain(s)
  • Switch to PostgreSQL or another production database
  • Configure a reverse proxy (nginx/Apache)
  • Set up HTTPS/TLS certificate
  • Configure SECURE_SSL_REDIRECT = True
  • Set SESSION_COOKIE_SECURE = True
  • Set CSRF_COOKIE_SECURE = True
  • Run python manage.py check --deploy

Deployment Steps

# 1. Set environment variables
export SECRET_KEY="your-new-secure-secret-key"
export DEBUG=False
export ALLOWED_HOSTS="yourdomain.com,www.yourdomain.com"

# 2. Install dependencies
pip install -r requirements.txt

# 3. Apply database migrations
python manage.py migrate

# 4. Collect static files
python manage.py collectstatic --noinput

# 5. Create superuser (first time only)
python manage.py createsuperuser

# 6. Run system checks
python manage.py check --deploy

# 7. Start the web server (example with gunicorn)
pip install gunicorn
gunicorn pos.wsgi:application --bind 0.0.0.0:8000 --workers 3

# 8. Start the django-q worker (separate process, for email reminders)
python manage.py qcluster

Azure App Service Deployment

The application is configured for Microsoft Azure App Service (Japan West). The startup.sh and Procfile handle the WSGI startup. The ALLOWED_HOSTS and CSRF_TRUSTED_ORIGINS in settings.py already include Azure domains.

Key Azure-specific settings that are pre-configured:

USE_X_FORWARDED_HOST = True
SECURE_PROXY_SSL_HEADER = ('HTTP_X_FORWARDED_PROTO', 'https')
CSRF_TRUSTED_ORIGINS = ['https://*.azurewebsites.net', ...]
STATICFILES_STORAGE = 'whitenoise.storage.CompressedManifestStaticFilesStorage'

Production settings.py Additions

# Security headers
SECURE_SSL_REDIRECT = True
SESSION_COOKIE_SECURE = True
CSRF_COOKIE_SECURE = True
SECURE_BROWSER_XSS_FILTER = True
SECURE_CONTENT_TYPE_NOSNIFF = True
X_FRAME_OPTIONS = 'DENY'

# Static files (serve via nginx in production)
STATIC_ROOT = BASE_DIR / 'staticfiles'

# Logging
LOGGING = {
    'version': 1,
    'disable_existing_loggers': False,
    'handlers': {
        'file': {
            'level': 'WARNING',
            'class': 'logging.FileHandler',
            'filename': BASE_DIR / 'logs/django.log',
        },
    },
    'loggers': {
        'django': {
            'handlers': ['file'],
            'level': 'WARNING',
            'propagate': True,
        },
    },
}

🀝 Contributing

Branch Naming Convention

feature/<short-description>     # New features
fix/<short-description>         # Bug fixes
chore/<short-description>       # Maintenance, refactoring
docs/<short-description>        # Documentation only

Workflow

  1. Fork the repository (external contributors) or create a branch (team members)

    git checkout -b feature/your-feature-name
  2. Make changes following the coding standards above

  3. Verify locally

    python manage.py check
    flake8 . --count --select=E9,F63,F7,F82 --show-source --statistics
  4. Commit with a clear message

    git commit -m "feat: add commission breakdown to admin reports"
  5. Push and open a Pull Request to main

    git push origin feature/your-feature-name
  6. PR will trigger the Django CI Check workflow automatically:

    • python manage.py check
    • flake8 syntax/undefined-name check

Commit Message Format

<type>: <short summary>

Types: feat | fix | docs | style | refactor | chore | test

πŸ“„ License & Support

License

This project is licensed under the CC BY-NC-SA 4.0.

  • Non-Commercial: You may not use this material for commercial purposes.
  • Attribution: You must give appropriate credit to the original author.
  • ShareAlike: If you remix or transform the material, you must distribute your contributions under the same license.

Support & Contact

Channel Details
Live Demo galosgadgethubpos.systems
Issues GitHub Issues
Repository github.com/johnaljennegalos/django-pos-scanner

Reporting Bugs

When opening an issue, please include:

  1. Python and Django version (python --version, django-admin --version)
  2. Steps to reproduce
  3. Expected vs actual behavior
  4. Relevant error messages or stack traces

Galos Gadget Hub POS System β€’ Built with ❀️ using Django 6.0.2

Last Updated: April 2026 β€’ Version 1.0.0

About

A feature-rich Django POS System for Galos Gadget Hub. Handles multi-branch inventory, barcode scanning, credit-approved installments, warranty management, and supplier contracts. Real-time analytics dashboard with CSV exports & audit logs. Production-ready deployment with custom SSL.

Topics

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors