Autosave: 20260202-103700
This commit is contained in:
parent
f80934e391
commit
1e0d4f6540
Binary file not shown.
Binary file not shown.
@ -19,6 +19,9 @@
|
||||
<button class="btn btn-primary shadow-sm" data-bs-toggle="modal" data-bs-target="#addProductModal">
|
||||
<i class="bi bi-plus-lg me-2"></i>{% trans "Add Item" %}
|
||||
</button>
|
||||
<button class="btn btn-success shadow-sm" data-bs-toggle="modal" data-bs-target="#importModal">
|
||||
<i class="bi bi-file-earmark-excel me-2"></i>{% trans "Import" %}
|
||||
</button>
|
||||
<button class="btn btn-outline-primary shadow-sm" data-bs-toggle="modal" data-bs-target="#addCategoryModal">
|
||||
<i class="bi bi-folder-plus me-2"></i>{% trans "Add Category" %}
|
||||
</button>
|
||||
@ -475,8 +478,7 @@
|
||||
<button type="button" class="btn btn-light rounded-3" data-bs-dismiss="modal">{% trans "Cancel" %}</button>
|
||||
<button type="submit" class="btn btn-primary rounded-3 px-4">{% trans "Update Unit" %}</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</form> </div>
|
||||
</div>
|
||||
</div>
|
||||
{% empty %}
|
||||
@ -516,34 +518,54 @@
|
||||
</div>
|
||||
<div class="col-md-4">
|
||||
<label class="form-label small fw-bold">{% trans "Barcode / SKU" %}</label>
|
||||
<input type="text" name="sku" class="form-control rounded-3" required>
|
||||
<div class="input-group">
|
||||
<input type="text" name="sku" id="skuInput" class="form-control rounded-3" placeholder="{% trans 'Auto-generated if empty' %}">
|
||||
<button class="btn btn-outline-primary" type="button" id="suggestSkuBtn" title="{% trans 'Suggest SKU' %}">
|
||||
<i class="bi bi-magic"></i>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-4">
|
||||
<label class="form-label small fw-bold">{% trans "Category" %}</label>
|
||||
<select name="category" class="form-select rounded-3" required>
|
||||
<option value="">{% trans "Select Category" %}</option>
|
||||
{% for category in categories %}
|
||||
<option value="{{ category.id }}">{% if LANGUAGE_CODE == 'ar' %}{{ category.name_ar }}{% else %}{{ category.name_en }}{% endif %}</option>
|
||||
{% endfor %}
|
||||
</select>
|
||||
<div class="input-group">
|
||||
<select name="category" id="categorySelect" class="form-select rounded-3" required>
|
||||
<option value="">{% trans "Select Category" %}</option>
|
||||
{% for category in categories %}
|
||||
<option value="{{ category.id }}">{% if LANGUAGE_CODE == 'ar' %}{{ category.name_ar }}{% else %}{{ category.name_en }}{% endif %}</option>
|
||||
{% endfor %}
|
||||
</select>
|
||||
<button class="btn btn-outline-primary" type="button" data-bs-toggle="modal" data-bs-target="#quickAddCategoryModal">
|
||||
<i class="bi bi-plus-lg"></i>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-4">
|
||||
<label class="form-label small fw-bold">{% trans "Unit" %}</label>
|
||||
<select name="unit" class="form-select rounded-3">
|
||||
<option value="">{% trans "Select Unit" %}</option>
|
||||
{% for unit in units %}
|
||||
<option value="{{ unit.id }}">{% if LANGUAGE_CODE == 'ar' %}{{ unit.name_ar }}{% else %}{{ unit.name_en }}{% endif %}</option>
|
||||
{% endfor %}
|
||||
</select>
|
||||
<div class="input-group">
|
||||
<select name="unit" id="unitSelect" class="form-select rounded-3">
|
||||
<option value="">{% trans "Select Unit" %}</option>
|
||||
{% for unit in units %}
|
||||
<option value="{{ unit.id }}">{% if LANGUAGE_CODE == 'ar' %}{{ unit.name_ar }}{% else %}{{ unit.name_en }}{% endif %}</option>
|
||||
{% endfor %}
|
||||
</select>
|
||||
<button class="btn btn-outline-primary" type="button" data-bs-toggle="modal" data-bs-target="#quickAddUnitModal">
|
||||
<i class="bi bi-plus-lg"></i>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-6">
|
||||
<label class="form-label small fw-bold">{% trans "Supplier" %}</label>
|
||||
<select name="supplier" class="form-select rounded-3">
|
||||
<option value="">{% trans "Select Supplier" %}</option>
|
||||
{% for supplier in suppliers %}
|
||||
<option value="{{ supplier.id }}">{{ supplier.name }}</option>
|
||||
{% endfor %}
|
||||
</select>
|
||||
<div class="input-group">
|
||||
<select name="supplier" id="supplierSelect" class="form-select rounded-3">
|
||||
<option value="">{% trans "Select Supplier" %}</option>
|
||||
{% for supplier in suppliers %}
|
||||
<option value="{{ supplier.id }}">{{ supplier.name }}</option>
|
||||
{% endfor %}
|
||||
</select>
|
||||
<button class="btn btn-outline-primary" type="button" data-bs-toggle="modal" data-bs-target="#quickAddSupplierModal">
|
||||
<i class="bi bi-plus-lg"></i>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-6">
|
||||
<label class="form-label small fw-bold">{% trans "Product Picture" %}</label>
|
||||
@ -598,6 +620,131 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Quick Add Category Modal -->
|
||||
<div class="modal fade" id="quickAddCategoryModal" tabindex="-1" aria-hidden="true">
|
||||
<div class="modal-dialog">
|
||||
<div class="modal-content rounded-4 border-0 shadow">
|
||||
<div class="modal-header border-0 pb-0">
|
||||
<h5 class="modal-title fw-bold">{% trans "Quick Add Category" %}</h5>
|
||||
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<div class="row g-3">
|
||||
<div class="col-12">
|
||||
<label class="form-label small fw-bold">{% trans "Name (English)" %}</label>
|
||||
<input type="text" id="quickCatNameEn" class="form-control rounded-3" required>
|
||||
</div>
|
||||
<div class="col-12">
|
||||
<label class="form-label small fw-bold">{% trans "Name (Arabic)" %}</label>
|
||||
<input type="text" id="quickCatNameAr" class="form-control rounded-3" dir="rtl" required>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="modal-footer border-0">
|
||||
<button type="button" class="btn btn-light rounded-3" data-bs-dismiss="modal">{% trans "Cancel" %}</button>
|
||||
<button type="button" class="btn btn-primary rounded-3 px-4" id="saveQuickCategory">{% trans "Save" %}</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Quick Add Unit Modal -->
|
||||
<div class="modal fade" id="quickAddUnitModal" tabindex="-1" aria-hidden="true">
|
||||
<div class="modal-dialog">
|
||||
<div class="modal-content rounded-4 border-0 shadow">
|
||||
<div class="modal-header border-0 pb-0">
|
||||
<h5 class="modal-title fw-bold">{% trans "Quick Add Unit" %}</h5>
|
||||
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<div class="row g-3">
|
||||
<div class="col-12">
|
||||
<label class="form-label small fw-bold">{% trans "Name (English)" %}</label>
|
||||
<input type="text" id="quickUnitNameEn" class="form-control rounded-3" required>
|
||||
</div>
|
||||
<div class="col-12">
|
||||
<label class="form-label small fw-bold">{% trans "Name (Arabic)" %}</label>
|
||||
<input type="text" id="quickUnitNameAr" class="form-control rounded-3" dir="rtl" required>
|
||||
</div>
|
||||
<div class="col-12">
|
||||
<label class="form-label small fw-bold">{% trans "Short Name" %}</label>
|
||||
<input type="text" id="quickUnitShortName" class="form-control rounded-3" required>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="modal-footer border-0">
|
||||
<button type="button" class="btn btn-light rounded-3" data-bs-dismiss="modal">{% trans "Cancel" %}</button>
|
||||
<button type="button" class="btn btn-primary rounded-3 px-4" id="saveQuickUnit">{% trans "Save" %}</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Quick Add Supplier Modal -->
|
||||
<div class="modal fade" id="quickAddSupplierModal" tabindex="-1" aria-hidden="true">
|
||||
<div class="modal-dialog">
|
||||
<div class="modal-content rounded-4 border-0 shadow">
|
||||
<div class="modal-header border-0 pb-0">
|
||||
<h5 class="modal-title fw-bold">{% trans "Quick Add Supplier" %}</h5>
|
||||
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<div class="row g-3">
|
||||
<div class="col-12">
|
||||
<label class="form-label small fw-bold">{% trans "Supplier Name" %}</label>
|
||||
<input type="text" id="quickSuppName" class="form-control rounded-3" required>
|
||||
</div>
|
||||
<div class="col-md-6">
|
||||
<label class="form-label small fw-bold">{% trans "Contact Person" %}</label>
|
||||
<input type="text" id="quickSuppContact" class="form-control rounded-3">
|
||||
</div>
|
||||
<div class="col-md-6">
|
||||
<label class="form-label small fw-bold">{% trans "Phone" %}</label>
|
||||
<input type="text" id="quickSuppPhone" class="form-control rounded-3">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="modal-footer border-0">
|
||||
<button type="button" class="btn btn-light rounded-3" data-bs-dismiss="modal">{% trans "Cancel" %}</button>
|
||||
<button type="button" class="btn btn-primary rounded-3 px-4" id="saveQuickSupplier">{% trans "Save" %}</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Import Modal -->
|
||||
<div class="modal fade" id="importModal" tabindex="-1" aria-hidden="true">
|
||||
<div class="modal-dialog">
|
||||
<div class="modal-content rounded-4 border-0 shadow">
|
||||
<div class="modal-header border-0 pb-0">
|
||||
<h5 class="modal-title fw-bold">{% trans "Import Items from Excel" %}</h5>
|
||||
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
|
||||
</div>
|
||||
<form action="{% url 'import_products' %}" method="POST" enctype="multipart/form-data">
|
||||
{% csrf_token %}
|
||||
<div class="modal-body">
|
||||
<div class="alert alert-info rounded-3 small">
|
||||
<i class="bi bi-info-circle me-2"></i>
|
||||
{% trans "Excel file should have these columns in order:" %}<br>
|
||||
<strong>{% trans "Name (Eng), Name (Ar), SKU, Cost Price, Sale Price" %}</strong>
|
||||
</div>
|
||||
<div class="mb-3">
|
||||
<label class="form-label small fw-bold">{% trans "Select Excel File (.xlsx)" %}</label>
|
||||
<input type="file" name="excel_file" class="form-control rounded-3" accept=".xlsx" required>
|
||||
</div>
|
||||
<p class="text-muted small">
|
||||
{% trans "Note: If SKU exists, the item will be updated. Otherwise, a new item will be created in the 'General' category." %}
|
||||
</p>
|
||||
</div>
|
||||
<div class="modal-footer border-0">
|
||||
<button type="button" class="btn btn-light rounded-3" data-bs-dismiss="modal">{% trans "Cancel" %}</button>
|
||||
<button type="submit" class="btn btn-success rounded-3 px-4">{% trans "Start Import" %}</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Add Category Modal -->
|
||||
<div class="modal fade" id="addCategoryModal" tabindex="-1" aria-hidden="true">
|
||||
<div class="modal-dialog">
|
||||
@ -663,4 +810,95 @@
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
document.addEventListener('DOMContentLoaded', function() {
|
||||
// Suggest SKU
|
||||
const suggestBtn = document.getElementById('suggestSkuBtn');
|
||||
if (suggestBtn) {
|
||||
suggestBtn.addEventListener('click', function() {
|
||||
fetch('{% url "suggest_sku" %}')
|
||||
.then(response => response.json())
|
||||
.then(data => {
|
||||
document.getElementById('skuInput').value = data.sku;
|
||||
})
|
||||
.catch(error => console.error('Error fetching SKU:', error));
|
||||
});
|
||||
}
|
||||
|
||||
// Quick Add Category
|
||||
document.getElementById('saveQuickCategory').addEventListener('click', function() {
|
||||
const nameEn = document.getElementById('quickCatNameEn').value;
|
||||
const nameAr = document.getElementById('quickCatNameAr').value;
|
||||
if (!nameEn || !nameAr) return alert('Please fill all fields');
|
||||
|
||||
fetch('{% url "add_category_ajax" %}', {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({ name_en: nameEn, name_ar: nameAr })
|
||||
})
|
||||
.then(response => response.json())
|
||||
.then(data => {
|
||||
if (data.success) {
|
||||
const select = document.getElementById('categorySelect');
|
||||
const option = new Option(data.name_en + ' | ' + data.name_ar, data.id, true, true);
|
||||
select.add(option);
|
||||
bootstrap.Modal.getInstance(document.getElementById('quickAddCategoryModal')).hide();
|
||||
} else {
|
||||
alert('Error: ' + data.error);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
// Quick Add Unit
|
||||
document.getElementById('saveQuickUnit').addEventListener('click', function() {
|
||||
const nameEn = document.getElementById('quickUnitNameEn').value;
|
||||
const nameAr = document.getElementById('quickUnitNameAr').value;
|
||||
const shortName = document.getElementById('quickUnitShortName').value;
|
||||
if (!nameEn || !nameAr || !shortName) return alert('Please fill all fields');
|
||||
|
||||
fetch('{% url "add_unit_ajax" %}', {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({ name_en: nameEn, name_ar: nameAr, short_name: shortName })
|
||||
})
|
||||
.then(response => response.json())
|
||||
.then(data => {
|
||||
if (data.success) {
|
||||
const select = document.getElementById('unitSelect');
|
||||
const option = new Option(data.name_en + ' | ' + data.name_ar, data.id, true, true);
|
||||
select.add(option);
|
||||
bootstrap.Modal.getInstance(document.getElementById('quickAddUnitModal')).hide();
|
||||
} else {
|
||||
alert('Error: ' + data.error);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
// Quick Add Supplier
|
||||
document.getElementById('saveQuickSupplier').addEventListener('click', function() {
|
||||
const name = document.getElementById('quickSuppName').value;
|
||||
const contact = document.getElementById('quickSuppContact').value;
|
||||
const phone = document.getElementById('quickSuppPhone').value;
|
||||
if (!name) return alert('Please fill supplier name');
|
||||
|
||||
fetch('{% url "add_supplier_ajax" %}', {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({ name: name, contact_person: contact, phone: phone })
|
||||
})
|
||||
.then(response => response.json())
|
||||
.then(data => {
|
||||
if (data.success) {
|
||||
const select = document.getElementById('supplierSelect');
|
||||
const option = new Option(data.name, data.id, true, true);
|
||||
select.add(option);
|
||||
bootstrap.Modal.getInstance(document.getElementById('quickAddSupplierModal')).hide();
|
||||
} else {
|
||||
alert('Error: ' + data.error);
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
</script>
|
||||
{% endblock %}
|
||||
@ -59,20 +59,25 @@ urlpatterns = [
|
||||
path('suppliers/add/', views.add_supplier, name='add_supplier'),
|
||||
path('suppliers/edit/<int:pk>/', views.edit_supplier, name='edit_supplier'),
|
||||
path('suppliers/delete/<int:pk>/', views.delete_supplier, name='delete_supplier'),
|
||||
path('api/add-supplier-ajax/', views.add_supplier_ajax, name='add_supplier_ajax'),
|
||||
|
||||
# Inventory
|
||||
path('inventory/suggest-sku/', views.suggest_sku, name='suggest_sku'),
|
||||
path('inventory/add/', views.add_product, name='add_product'),
|
||||
path('inventory/edit/<int:pk>/', views.edit_product, name='edit_product'),
|
||||
path('inventory/delete/<int:pk>/', views.delete_product, name='delete_product'),
|
||||
path('inventory/barcodes/', views.barcode_labels, name='barcode_labels'),
|
||||
path('inventory/import/', views.import_products, name='import_products'),
|
||||
|
||||
# Categories
|
||||
path('inventory/category/add/', views.add_category, name='add_category'),
|
||||
path('inventory/category/edit/<int:pk>/', views.edit_category, name='edit_category'),
|
||||
path('inventory/category/delete/<int:pk>/', views.delete_category, name='delete_category'),
|
||||
path('api/add-category-ajax/', views.add_category_ajax, name='add_category_ajax'),
|
||||
|
||||
# Units
|
||||
path('inventory/unit/add/', views.add_unit, name='add_unit'),
|
||||
path('inventory/unit/edit/<int:pk>/', views.edit_unit, name='edit_unit'),
|
||||
path('inventory/unit/delete/<int:pk>/', views.delete_unit, name='delete_unit'),
|
||||
path('api/add-unit-ajax/', views.add_unit_ajax, name='add_unit_ajax'),
|
||||
]
|
||||
165
core/views.py
165
core/views.py
@ -1,3 +1,5 @@
|
||||
import random
|
||||
import string
|
||||
from django.shortcuts import render, get_object_or_404, redirect
|
||||
from django.db.models import Sum, Count, F
|
||||
from django.db.models.functions import TruncDate, TruncMonth
|
||||
@ -15,6 +17,7 @@ from datetime import timedelta
|
||||
from django.utils import timezone
|
||||
from django.contrib import messages
|
||||
from django.utils.text import slugify
|
||||
import openpyxl
|
||||
|
||||
def index(request):
|
||||
"""
|
||||
@ -709,6 +712,17 @@ def delete_supplier(request, pk):
|
||||
messages.success(request, "Supplier deleted successfully!")
|
||||
return redirect('suppliers')
|
||||
|
||||
|
||||
def suggest_sku(request):
|
||||
"""
|
||||
API endpoint to suggest a unique SKU.
|
||||
"""
|
||||
while True:
|
||||
# Generate a random 8-digit number
|
||||
sku = "".join(random.choices(string.digits, k=8))
|
||||
if not Product.objects.filter(sku=sku).exists():
|
||||
return JsonResponse({"sku": sku})
|
||||
|
||||
def add_product(request):
|
||||
if request.method == 'POST':
|
||||
name_en = request.POST.get('name_en')
|
||||
@ -717,6 +731,11 @@ def add_product(request):
|
||||
unit_id = request.POST.get('unit')
|
||||
supplier_id = request.POST.get('supplier')
|
||||
sku = request.POST.get('sku')
|
||||
if not sku:
|
||||
while True:
|
||||
sku = ''.join(random.choices(string.digits, k=8))
|
||||
if not Product.objects.filter(sku=sku).exists():
|
||||
break
|
||||
cost_price = request.POST.get('cost_price', 0)
|
||||
price = request.POST.get('price', 0)
|
||||
vat = request.POST.get('vat', 0)
|
||||
@ -839,3 +858,149 @@ def barcode_labels(request):
|
||||
products = Product.objects.filter(is_active=True).order_by('name_en')
|
||||
context = {'products': products}
|
||||
return render(request, 'core/barcode_labels.html', context)
|
||||
|
||||
def import_products(request):
|
||||
"""
|
||||
Import products from an Excel (.xlsx) file.
|
||||
Expected columns: Name (Eng), Name (Ar), SKU, Cost Price, Sale Price
|
||||
"""
|
||||
if request.method == 'POST' and request.FILES.get('excel_file'):
|
||||
excel_file = request.FILES['excel_file']
|
||||
|
||||
if not excel_file.name.endswith('.xlsx'):
|
||||
messages.error(request, "Please upload a valid .xlsx file.")
|
||||
return redirect('inventory')
|
||||
|
||||
try:
|
||||
wb = openpyxl.load_workbook(excel_file)
|
||||
sheet = wb.active
|
||||
|
||||
# Get or create a default category
|
||||
default_category, _ = Category.objects.get_or_create(
|
||||
name_en="General",
|
||||
defaults={'name_ar': "عام", 'slug': 'general'}
|
||||
)
|
||||
|
||||
count = 0
|
||||
updated_count = 0
|
||||
errors = []
|
||||
|
||||
# Skip header row (min_row=2)
|
||||
for i, row in enumerate(sheet.iter_rows(min_row=2, values_only=True), start=2):
|
||||
if not any(row): continue # Skip empty rows
|
||||
|
||||
# Unpack columns with fallbacks for safety
|
||||
# Format: name_en, name_ar, sku, cost_price, sale_price
|
||||
name_en = str(row[0]).strip() if row[0] else None
|
||||
name_ar = str(row[1]).strip() if len(row) > 1 and row[1] else name_en
|
||||
sku = str(row[2]).strip() if len(row) > 2 and row[2] else None
|
||||
cost_price = row[3] if len(row) > 3 and row[3] is not None else 0
|
||||
sale_price = row[4] if len(row) > 4 and row[4] is not None else 0
|
||||
|
||||
if not name_en:
|
||||
errors.append(f"Row {i}: Missing English Name. Skipped.")
|
||||
continue
|
||||
|
||||
if not sku:
|
||||
# Generate unique SKU if missing
|
||||
while True:
|
||||
sku = "".join(random.choices(string.digits, k=8))
|
||||
if not Product.objects.filter(sku=sku).exists():
|
||||
break
|
||||
|
||||
product, created = Product.objects.update_or_create(
|
||||
sku=sku,
|
||||
defaults={
|
||||
'name_en': name_en,
|
||||
'name_ar': name_ar,
|
||||
'cost_price': cost_price,
|
||||
'price': sale_price,
|
||||
'category': default_category,
|
||||
'is_active': True
|
||||
}
|
||||
)
|
||||
|
||||
if created:
|
||||
count += 1
|
||||
else:
|
||||
updated_count += 1
|
||||
|
||||
if count > 0 or updated_count > 0:
|
||||
msg = f"Import completed: {count} new items added"
|
||||
if updated_count > 0:
|
||||
msg += f", {updated_count} items updated"
|
||||
messages.success(request, msg)
|
||||
|
||||
if errors:
|
||||
for error in errors:
|
||||
messages.warning(request, error)
|
||||
|
||||
except Exception as e:
|
||||
messages.error(request, f"Error processing file: {str(e)}")
|
||||
|
||||
return redirect('inventory')
|
||||
|
||||
@csrf_exempt
|
||||
def add_category_ajax(request):
|
||||
if request.method == 'POST':
|
||||
try:
|
||||
data = json.loads(request.body)
|
||||
name_en = data.get('name_en')
|
||||
name_ar = data.get('name_ar')
|
||||
if not name_en or not name_ar:
|
||||
return JsonResponse({'success': False, 'error': 'Missing names'}, status=400)
|
||||
|
||||
slug = slugify(name_en)
|
||||
category = Category.objects.create(name_en=name_en, name_ar=name_ar, slug=slug)
|
||||
return JsonResponse({
|
||||
'success': True,
|
||||
'id': category.id,
|
||||
'name_en': category.name_en,
|
||||
'name_ar': category.name_ar
|
||||
})
|
||||
except Exception as e:
|
||||
return JsonResponse({'success': False, 'error': str(e)}, status=400)
|
||||
return JsonResponse({'success': False, 'error': 'Invalid request'}, status=405)
|
||||
|
||||
@csrf_exempt
|
||||
def add_unit_ajax(request):
|
||||
if request.method == 'POST':
|
||||
try:
|
||||
data = json.loads(request.body)
|
||||
name_en = data.get('name_en')
|
||||
name_ar = data.get('name_ar')
|
||||
short_name = data.get('short_name')
|
||||
if not name_en or not name_ar or not short_name:
|
||||
return JsonResponse({'success': False, 'error': 'Missing fields'}, status=400)
|
||||
|
||||
unit = Unit.objects.create(name_en=name_en, name_ar=name_ar, short_name=short_name)
|
||||
return JsonResponse({
|
||||
'success': True,
|
||||
'id': unit.id,
|
||||
'name_en': unit.name_en,
|
||||
'name_ar': unit.name_ar
|
||||
})
|
||||
except Exception as e:
|
||||
return JsonResponse({'success': False, 'error': str(e)}, status=400)
|
||||
return JsonResponse({'success': False, 'error': 'Invalid request'}, status=405)
|
||||
|
||||
@csrf_exempt
|
||||
def add_supplier_ajax(request):
|
||||
if request.method == 'POST':
|
||||
try:
|
||||
data = json.loads(request.body)
|
||||
name = data.get('name')
|
||||
contact_person = data.get('contact_person', '')
|
||||
phone = data.get('phone', '')
|
||||
if not name:
|
||||
return JsonResponse({'success': False, 'error': 'Missing name'}, status=400)
|
||||
|
||||
supplier = Supplier.objects.create(name=name, contact_person=contact_person, phone=phone)
|
||||
return JsonResponse({
|
||||
'success': True,
|
||||
'id': supplier.id,
|
||||
'name': supplier.name
|
||||
})
|
||||
except Exception as e:
|
||||
return JsonResponse({'success': False, 'error': str(e)}, status=400)
|
||||
return JsonResponse({'success': False, 'error': 'Invalid request'}, status=405)
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user