editing users

This commit is contained in:
Flatlogic Bot 2026-02-11 02:44:41 +00:00
parent cfa7d80ecc
commit 739a0d397f
8 changed files with 169 additions and 31 deletions

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.8 KiB

View File

@ -200,7 +200,7 @@
margin: 0; margin: 0;
} }
/* Direct Print Mode */ /* Direct Print Mode Overrides */
body.direct-print-mode @page { body.direct-print-mode @page {
size: auto; size: auto;
margin: 0; margin: 0;
@ -209,53 +209,91 @@
.label-sheet { .label-sheet {
position: relative; position: relative;
width: 210mm; width: 210mm;
height: 297mm; min-height: 297mm; /* Ensure full page height for sheets */
margin: 0 auto; margin: 0 auto;
background: white; background: white;
page-break-after: always; page-break-after: always;
box-sizing: border-box; box-sizing: border-box;
display: block; /* Default fallback */
}
/* Direct print container override */
body.direct-print-mode .label-sheet {
width: auto;
min-height: auto;
page-break-after: auto;
display: block; display: block;
font-size: 0; /* Remove whitespace between inline-blocks */
} }
.label-item { .label-item {
box-sizing: border-box; box-sizing: border-box;
display: inline-block; /* More robust than flex for print grids */
vertical-align: top;
text-align: center; text-align: center;
overflow: hidden; overflow: hidden;
font-size: initial; /* Reset font size */ display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
width: 100%; /* Fills the grid cell or container */
height: 100%;
page-break-inside: avoid;
} }
/* --- SHEET GRIDS --- */
/* Avery L7651 (5x13 = 65) */ /* Avery L7651 (5x13 = 65) */
.sheet-l7651 { .sheet-l7651 {
display: grid !important;
grid-template-columns: repeat(5, 38.1mm) !important;
grid-auto-rows: 21.2mm !important;
padding: 10.7mm 9.75mm !important; padding: 10.7mm 9.75mm !important;
gap: 0;
} }
.label-l7651 { .label-l7651 { padding: 1mm; }
width: 38.1mm !important;
height: 21.2mm !important; /* Avery L7656 (4x21 = 84) */
padding: 1mm; .sheet-l7656 {
} display: grid !important;
grid-template-columns: repeat(4, 46mm) !important;
/* Other layouts ... */ grid-auto-rows: 11.1mm !important;
.sheet-a4-24 { padding: 0 !important; } padding: 31.95mm 13mm !important;
.label-a4-24 { width: 70mm; height: 37.125mm; padding: 2mm; } gap: 0;
.sheet-a4-40 { padding: 0 !important; }
.label-a4-40 { width: 52.5mm; height: 29.7mm; padding: 1mm; }
.sheet-l7656 { padding: 31.95mm 13mm !important; }
.label-l7656 {
width: 46mm; height: 11.1mm; padding: 0.5mm;
} }
.label-l7656 { padding: 0.5mm; }
.label-l7656 .inner-flex { .label-l7656 .inner-flex {
display: flex; flex-direction: row; justify-content: space-around; align-items: center; height: 100%; width: 100%; display: flex; flex-direction: row; justify-content: space-around; align-items: center; height: 100%; width: 100%;
} }
.label-l7656 svg { height: 8mm !important; width: auto; } .label-l7656 svg { height: 8mm !important; width: auto; }
.label-l7656 .label-text { font-size: 5pt !important; width: auto !important; margin: 0 2px; } .label-l7656 .label-text { font-size: 5pt !important; width: auto !important; margin: 0 2px; }
.sheet-l7156 { padding: 15.15mm 9.75mm !important; } /* Avery L7156 (3x7 = 21) */
.label-l7156 { width: 63.5mm; height: 38.1mm; padding: 2mm; } .sheet-l7156 {
display: grid !important;
grid-template-columns: repeat(3, 63.5mm) !important;
grid-auto-rows: 38.1mm !important;
padding: 15.15mm 9.75mm !important;
gap: 0;
}
.label-l7156 { padding: 2mm; }
/* A4 24 (3x8) */
.sheet-a4-24 {
display: grid !important;
grid-template-columns: repeat(3, 63.5mm) !important;
grid-auto-rows: 33.9mm !important;
padding: 12.9mm 9.75mm !important;
gap: 0;
}
.label-a4-24 { padding: 2mm; }
/* A4 40 (4x10) */
.sheet-a4-40 {
display: grid !important;
grid-template-columns: repeat(4, 48.5mm) !important;
grid-auto-rows: 25.4mm !important;
padding: 21.5mm 8mm !important;
gap: 0;
}
.label-a4-40 { padding: 1mm; }
.label-item svg { .label-item svg {
max-width: 100%; max-width: 100%;
@ -568,7 +606,8 @@ document.addEventListener('DOMContentLoaded', function() {
// --- PREPARE PRINT (Full Queue) --- // --- PREPARE PRINT (Full Queue) ---
function preparePrint() { function preparePrint() {
if (document.body.classList.contains('direct-print-mode')) return; // Ensure we are not in direct print mode
document.body.classList.remove('direct-print-mode');
printArea.innerHTML = ''; printArea.innerHTML = '';
const labelType = document.getElementById('labelType').value; const labelType = document.getElementById('labelType').value;
@ -595,7 +634,6 @@ document.addEventListener('DOMContentLoaded', function() {
for (let s = 0; s < allLabels.length; s += labelsPerSheet) { for (let s = 0; s < allLabels.length; s += labelsPerSheet) {
const sheetLabels = allLabels.slice(s, s + labelsPerSheet); const sheetLabels = allLabels.slice(s, s + labelsPerSheet);
const sheet = document.createElement('div'); const sheet = document.createElement('div');
sheet.className = `label-sheet sheet-${labelType}`;
// Add specific classes // Add specific classes
if (labelType === 'a4-24') sheet.classList.add('sheet-a4-24'); if (labelType === 'a4-24') sheet.classList.add('sheet-a4-24');
@ -604,6 +642,9 @@ document.addEventListener('DOMContentLoaded', function() {
else if (labelType === 'l7656') sheet.classList.add('sheet-l7656'); else if (labelType === 'l7656') sheet.classList.add('sheet-l7656');
else if (labelType === 'l7156') sheet.classList.add('sheet-l7156'); else if (labelType === 'l7156') sheet.classList.add('sheet-l7156');
sheet.classList.add('label-sheet');
sheet.classList.add('sheet-' + labelType);
printArea.appendChild(sheet); printArea.appendChild(sheet);
sheetLabels.forEach((p, idx) => { sheetLabels.forEach((p, idx) => {

View File

@ -18,6 +18,8 @@ import logging
import base64 import base64
import os import os
from django.conf import settings as django_settings from django.conf import settings as django_settings
from django.contrib.auth.models import User, Group, Permission
from django.contrib.contenttypes.models import ContentType
from .models import ( from .models import (
SystemSetting, Customer, Supplier, Product, Category, Unit, SystemSetting, Customer, Supplier, Product, Category, Unit,
@ -166,6 +168,7 @@ def index(request):
@login_required @login_required
def inventory(request): def inventory(request):
logger.info("Inventory view accessed")
products = Product.objects.all().order_by('name_en') products = Product.objects.all().order_by('name_en')
categories = Category.objects.all() categories = Category.objects.all()
units = Unit.objects.all() units = Unit.objects.all()
@ -176,6 +179,7 @@ def inventory(request):
next_30_days = today + datetime.timedelta(days=30) next_30_days = today + datetime.timedelta(days=30)
expired_products = products.filter(has_expiry=True, expiry_date__lt=today) expired_products = products.filter(has_expiry=True, expiry_date__lt=today)
expiring_soon_products = products.filter(has_expiry=True, expiry_date__gte=today, expiry_date__lte=next_30_days)
settings = SystemSetting.objects.first() settings = SystemSetting.objects.first()
if not settings: if not settings:
settings = SystemSetting.objects.create() settings = SystemSetting.objects.create()
@ -296,11 +300,99 @@ def profile_view(request):
@login_required @login_required
def user_management(request): def user_management(request):
return render(request, 'core/users.html') if request.method == 'POST':
action = request.POST.get('action')
try:
if action == 'add':
username = request.POST.get('username')
email = request.POST.get('email')
password = request.POST.get('password')
group_ids = request.POST.getlist('groups')
if User.objects.filter(username=username).exists():
messages.error(request, _("Username already exists."))
else:
user = User.objects.create_user(username=username, email=email, password=password)
if group_ids:
user.groups.set(group_ids)
messages.success(request, _("User created successfully."))
elif action == 'edit_user':
user_id = request.POST.get('user_id')
user = get_object_or_404(User, id=user_id)
user.email = request.POST.get('email')
password = request.POST.get('password')
if password:
user.set_password(password)
user.save()
group_ids = request.POST.getlist('groups')
user.groups.set(group_ids)
messages.success(request, _("User updated successfully."))
elif action == 'toggle_status':
user_id = request.POST.get('user_id')
if int(user_id) == request.user.id:
messages.error(request, _("You cannot deactivate yourself."))
else:
user = get_object_or_404(User, id=user_id)
user.is_active = not user.is_active
user.save()
status = _("activated") if user.is_active else _("deactivated")
messages.success(request, _(f"User {status}."))
elif action == 'add_group':
name = request.POST.get('name')
perm_ids = request.POST.getlist('permissions')
if Group.objects.filter(name=name).exists():
messages.error(request, _("Group name already exists."))
else:
group = Group.objects.create(name=name)
if perm_ids:
group.permissions.set(perm_ids)
messages.success(request, _("Group created successfully."))
elif action == 'edit_group':
group_id = request.POST.get('group_id')
group = get_object_or_404(Group, id=group_id)
group.name = request.POST.get('name')
group.save()
perm_ids = request.POST.getlist('permissions')
group.permissions.set(perm_ids)
messages.success(request, _("Group updated successfully."))
elif action == 'delete_group':
group_id = request.POST.get('group_id')
group = get_object_or_404(Group, id=group_id)
group.delete()
messages.success(request, _("Group deleted successfully."))
except Exception as e:
logger.error(f"User Management Error: {e}")
messages.error(request, _(f"An error occurred: {e}"))
return redirect('user_management')
users = User.objects.all().order_by('username')
groups = Group.objects.all().order_by('name')
# Filter permissions to exclude internal/system apps if desired, or show all
permissions = Permission.objects.select_related('content_type').order_by('content_type__app_label', 'content_type__model')
return render(request, 'core/users.html', {
'users': users,
'groups': groups,
'permissions': permissions
})
@login_required @login_required
def group_details_api(request, pk): def group_details_api(request, pk):
return JsonResponse({}) group = get_object_or_404(Group, pk=pk)
permissions = list(group.permissions.values_list('id', flat=True))
return JsonResponse({'permissions': permissions})
# --- POS Views --- # --- POS Views ---
@ -687,13 +779,18 @@ def edit_purchase(request, pk):
decimal_places = site_settings.decimal_places or 2 decimal_places = site_settings.decimal_places or 2
cart_items = [] cart_items = []
logger.info(f"EDIT_PURCHASE: Processing {purchase.items.count()} items for purchase {pk}")
for item in purchase.items.all().select_related('product'): for item in purchase.items.all().select_related('product'):
# Debugging attributes
if hasattr(item, 'unit_price'):
logger.warning(f"Item {item.id} has unit_price attribute! {item.unit_price}")
cart_items.append({ cart_items.append({
'id': item.product.id, 'id': item.product.id,
'name_en': item.product.name_en, 'name_en': item.product.name_en,
'name_ar': item.product.name_ar, 'name_ar': item.product.name_ar,
'sku': item.product.sku, 'sku': item.product.sku,
'cost_price': float(item.unit_price), 'cost_price': float(item.cost_price),
'quantity': float(item.quantity) 'quantity': float(item.quantity)
}) })