Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions api/urls.py
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,7 @@
path('item-edit', views.itemEdit, name='itemEdit'),
path('item-delete', views.itemDelete, name='itemDelete'),
path('item-export', views.itemExport, name='itemExport'),
path('item-import', views.itemImport, name='itemImport'),

path('store-list', views.storeList, name='storeList'),
path('store-add', views.storeAdd, name='storeAdd'),
Expand Down
99 changes: 87 additions & 12 deletions api/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
from django.contrib.auth.hashers import make_password, check_password
from datetime import datetime, timedelta
from django.utils.timezone import now
from openpyxl import Workbook
from openpyxl import Workbook, load_workbook
from django.db import transaction
from django.db.models import Q
from django.conf import settings
Expand All @@ -29,6 +29,7 @@
from fpdf import FPDF
from django.db.models import Avg, Count, Min, Sum
from fractions import Fraction
import pandas as pd
from django.contrib.auth.models import Permission


Expand Down Expand Up @@ -2171,11 +2172,12 @@ def itemExport(request):
ws['C1'] = "Item Category"
ws['D1'] = "UOM"
ws['E1'] = "Price"
ws['F1'] = "HSN Code"

# Rows can also be appended
for each in page_items:
ws.append([each.name, each.item_type.name,
each.item_type.item_category.name, each.uom.name, each.price])
each.item_type.item_category.name, each.uom.name, each.price, each.hsn_code])

# Save the file
wb.save(settings.MEDIA_ROOT + '/reports/' + tmpname)
Expand All @@ -2201,10 +2203,10 @@ def itemExport(request):

with open(os.path.join(directory_path, tmpname), 'w', newline='') as csvfile:
writer = csv.writer(csvfile)
writer.writerow(["Name", "Item Type", "Item Category", "UOM", "Price"])
writer.writerow(["Name", "Item Type", "Item Category", "UOM", "Price", "HSN Code"])
for item in page_items:
writer.writerow(
[item.name, item.item_type.name, item.item_type.item_category.name, item.uom.name, item.price])
[item.name, item.item_type.name, item.item_type.item_category.name, item.uom.name, item.price, item.hsn_code])

os.chmod(settings.MEDIA_ROOT + '/reports/' + tmpname, 0o777)
return JsonResponse({
Expand All @@ -2225,11 +2227,12 @@ def itemExport(request):
# Add a header row with bold text
pdf.set_font("Arial", size=9, style='B') # Set font style to bold
pdf.cell(9, 10, txt="S.No.", border=1, align='C') # Add S.No. column
pdf.cell(65, 10, txt="Name", border=1, align='C')
pdf.cell(43, 10, txt="Item Type", border=1, align='C')
pdf.cell(43, 10, txt="Item Category", border=1, align='C')
pdf.cell(20, 10, txt="UOM", border=1, align='C')
pdf.cell(55, 10, txt="Name", border=1, align='C')
pdf.cell(38, 10, txt="Item Type", border=1, align='C')
pdf.cell(38, 10, txt="Item Category", border=1, align='C')
pdf.cell(18, 10, txt="UOM", border=1, align='C')
pdf.cell(20, 10, txt="Price", border=1, align='C')
pdf.cell(20, 10, txt="HSN Code", border=1, align='C')
pdf.set_font("Arial", size=9) # Reset font style to normal
pdf.ln(10) # Move to the next line

Expand All @@ -2240,12 +2243,13 @@ def itemExport(request):
counter = 1 # Counter for serial numbers
for item in page_items:
pdf.cell(9, 10, txt=str(counter), border=1, align='C') # Add S.No. for each row
pdf.cell(65, 10, txt=item.name, border=1)
pdf.cell(43, 10, txt=item.item_type.name, border=1)
pdf.cell(43, 10, txt=item.item_type.item_category.name, border=1)
pdf.cell(20, 10, txt=item.uom.name, border=1)
pdf.cell(55, 10, txt=item.name, border=1)
pdf.cell(38, 10, txt=item.item_type.name, border=1)
pdf.cell(38, 10, txt=item.item_type.item_category.name, border=1)
pdf.cell(18, 10, txt=item.uom.name, border=1)
# Right align price for each data row
pdf.cell(20, 10, txt=str(item.price), align='R', border=1)
pdf.cell(20, 10, txt=item.hsn_code if item.hsn_code else "", border=1)
pdf.ln(10)
counter += 1 # Increment counter for next row

Expand All @@ -2264,6 +2268,77 @@ def itemExport(request):
})


@api_view(['POST'])
def itemImport(request):
context = {}
if request.FILES.get('file'):
excel = request.FILES['file']
# trying to process files without error
try:
df = pd.read_excel(excel)
df.columns = [col.strip().lower() for col in df.columns]
for index, row in df.iterrows():
# trying to fetch required cells from
try:
name = row['name']
item_type_name = row['item type']
item_category_name = row['item category']
uom_name = row['uom']
price = row['price']
hsn_code = row['hsn code']

# Skip the row if any required field is empty
if not all([name, item_type_name, item_category_name, uom_name, price, hsn_code]):
continue # Skip this row and move to the next one

if not models.Item.objects.filter(name__iexact=name).exists():
if (
models.Item_Type.objects.filter(name__iexact=item_type_name).exists()
and models.Item_Category.objects.filter(name__iexact=item_category_name).exists()
and models.Uom.objects.filter(name__iexact=uom_name).exists()
):
try:
with transaction.atomic():
obj = models.Item(
name=name,
item_type=models.Item_Type.objects.get(name__iexact=item_type_name),
uom=models.Uom.objects.get(name__iexact=uom_name),
price=Decimal(price),
hsn_code=hsn_code
)
obj.save()
transaction.commit()
context.update({
'status': 200,
'message': "Items Created Successfully."
})
except Exception:
context.update({
'status': 568,
'message': "Items cannot be created something wrong"
})
transaction.rollback()

except KeyError as e:
# Handle missing columns
context.update({
'status': 568,
'message': "Required column missing"
})
return JsonResponse(context)
except Exception as e:
context.update({
'status': 568,
'message': "Error processing file"
})
else:
context.update({
'status': 568,
'message': "File has not been uploaded"
})
return JsonResponse(context)


@api_view(['GET'])
@permission_classes([IsAuthenticated])
def storeList(request):
Expand Down
Binary file modified media/reports/Item.pdf
Binary file not shown.
Binary file not shown.
10 changes: 9 additions & 1 deletion requirements.txt
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
APScheduler==3.10.4
asgiref==3.7.2
cffi==1.16.0
chardet==5.2.0
cryptography==41.0.5
Django==4.2.6
django-crontab==0.7.1
django-environ==0.11.2
Expand All @@ -10,12 +13,17 @@ docopt==0.6.2
et-xmlfile==1.1.0
fpdf==1.7.2
num2words==0.5.13
numpy==2.0.1
openpyxl==3.1.2
pandas==2.2.2
pillow==10.2.0
protobuf==3.20.3
pycparser==2.21
PyJWT==2.8.0
PyMySQL==1.1.0
python-dateutil==2.9.0.post0
pytz==2023.3.post1
setuptools==68.2.2
reportlab==4.1.0
six==1.16.0
sqlparse==0.4.4
tzdata==2023.3
Expand Down
39 changes: 38 additions & 1 deletion templates/portal/Item/list.html
Original file line number Diff line number Diff line change
Expand Up @@ -114,7 +114,16 @@ <h6 class="card-header-title tx-13 mb-0">{{parent_page_title}} {{page_title}}</h
<a href="{% url 'superuser:itemAdd' %}" class="mr-3"><i class="fa fa-plus"></i></a>
{% endif %}
{% if request.user.is_superuser == 1 or 'view_item'|get_session_permission:request is not None %}
<a href="javascript:void(0);" url="{% url 'api:itemExport' %}?&keyword={{request.GET.keyword}}" class="mr-3 excel_download"><i class="fa fa-download"></i></a>
<!-- <a href="javascript:void(0);"
url="{% url 'api:itemExport' %}?&keyword={{request.GET.keyword}}"
class="mr-3">
<i class="fa fa-upload"></i>
</a> -->
<a href="javascript:$('#fileInput').click();" class="mr-3">
<i class="fa fa-upload"></i>
</a>

<input type="file" id="fileInput" style="display: none;" accept=".xlsx" />
{% endif %}
<a href="" class="mr-3"><i class="ti-reload"></i></a>
<!-- <div class="dropdown" data-toggle="dropdown">
Expand Down Expand Up @@ -431,5 +440,33 @@ <h6 class="card-header-title tx-13 mb-0">{{parent_page_title}} {{page_title}}</h

})

$(document).on("change", "#fileInput", function() {
var formData = new FormData();
formData.append('file', $('#fileInput')[0].files[0]);
$.ajax({
url: "{% url 'api:itemImport' %}",
type: 'POST',
data: formData,
headers: {
'Authorization': getCookieValue("accessToken"),
},
processData: false, // Prevent jQuery from processing the data
contentType: false,
success: function(response) {
if (response.status === 200) {
alert('File successfully uploaded and items created.');
location.reload();
}
else {
alert('Error: ' + response.message);
}
$('#fileInput').val('');
},
error: function(xhr, status, error) {
// Handle error
alert('Error uploading file:', error);
}
});
});
</script>
{% endblock %}