diff --git a/library_management/__init__.py b/library_management/__init__.py index e69de29..b5cb49c 100644 --- a/library_management/__init__.py +++ b/library_management/__init__.py @@ -0,0 +1 @@ +__version__ = '0.0.1' diff --git a/library_management/library_management/doctype/library_books/__init__.py b/library_management/library_management/doctype/library_books/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/library_management/library_management/doctype/library_books/library_books.js b/library_management/library_management/doctype/library_books/library_books.js new file mode 100644 index 0000000..46fb929 --- /dev/null +++ b/library_management/library_management/doctype/library_books/library_books.js @@ -0,0 +1,8 @@ +// Copyright (c) 2025, Frappe and contributors +// For license information, please see license.txt + +// frappe.ui.form.on("Library Books", { +// refresh(frm) { + +// }, +// }); diff --git a/library_management/library_management/doctype/library_books/library_books.json b/library_management/library_management/doctype/library_books/library_books.json new file mode 100644 index 0000000..e7ccd61 --- /dev/null +++ b/library_management/library_management/doctype/library_books/library_books.json @@ -0,0 +1,189 @@ +{ + "actions": [], + "allow_import": 1, + "allow_rename": 1, + "autoname": "B.######", + "creation": "2025-04-24 16:17:30.685181", + "doctype": "DocType", + "engine": "InnoDB", + "field_order": [ + "isbn", + "book_name", + "accession_number", + "author", + "status", + "branch", + "column_break_pxyi", + "pages", + "publisher", + "language", + "price", + "source_of_book", + "image", + "column_break_frzw", + "quantity", + "available_quantity", + "bill_no_and_date", + "call_no", + "edition", + "year_of_publication", + "remarks", + "take_home" + ], + "fields": [ + { + "fieldname": "isbn", + "fieldtype": "Data", + "in_list_view": 1, + "label": "ISBN", + "reqd": 1 + }, + { + "fieldname": "book_name", + "fieldtype": "Data", + "in_list_view": 1, + "label": "Book Name", + "reqd": 1 + }, + { + "fieldname": "accession_number", + "fieldtype": "Data", + "label": "Accession Number" + }, + { + "fieldname": "author", + "fieldtype": "Data", + "in_list_view": 1, + "label": "Author", + "reqd": 1 + }, + { + "fieldname": "status", + "fieldtype": "Select", + "in_list_view": 1, + "label": "Status", + "options": "Active\nInactive\nDiscontinued", + "reqd": 1 + }, + { + "fieldname": "branch", + "fieldtype": "Link", + "label": "Branch", + "options": "School", + "reqd": 1 + }, + { + "fieldname": "column_break_pxyi", + "fieldtype": "Column Break" + }, + { + "fieldname": "pages", + "fieldtype": "Data", + "label": "Pages" + }, + { + "fieldname": "publisher", + "fieldtype": "Data", + "label": "Publisher" + }, + { + "fieldname": "language", + "fieldtype": "Data", + "label": "Language" + }, + { + "fieldname": "price", + "fieldtype": "Data", + "label": "Price" + }, + { + "fieldname": "source_of_book", + "fieldtype": "Data", + "label": "Source of Book" + }, + { + "fieldname": "image", + "fieldtype": "Attach Image", + "label": "Image", + "options": "image" + }, + { + "fieldname": "column_break_frzw", + "fieldtype": "Column Break" + }, + { + "fieldname": "quantity", + "fieldtype": "Int", + "label": "Quantity", + "reqd": 1 + }, + { + "fieldname": "available_quantity", + "fieldtype": "Int", + "label": "Available Quantity", + "reqd": 1 + }, + { + "fieldname": "bill_no_and_date", + "fieldtype": "Data", + "label": "Bill No. and Date" + }, + { + "fieldname": "call_no", + "fieldtype": "Data", + "label": "Call No." + }, + { + "fieldname": "edition", + "fieldtype": "Data", + "label": "Edition" + }, + { + "fieldname": "year_of_publication", + "fieldtype": "Data", + "label": "Year of Publication" + }, + { + "fieldname": "remarks", + "fieldtype": "Data", + "label": "Remarks" + }, + { + "default": "0", + "fieldname": "take_home", + "fieldtype": "Check", + "label": "Take Home", + "reqd": 1 + } + ], + "grid_page_length": 50, + "image_field": "image", + "index_web_pages_for_search": 1, + "links": [], + "modified": "2025-04-24 16:43:54.038751", + "modified_by": "Administrator", + "module": "Library Management", + "name": "Library Books", + "naming_rule": "Expression (old style)", + "owner": "Administrator", + "permissions": [ + { + "create": 1, + "delete": 1, + "email": 1, + "export": 1, + "print": 1, + "read": 1, + "report": 1, + "role": "System Manager", + "share": 1, + "write": 1 + } + ], + "row_format": "Dynamic", + "show_title_field_in_link": 1, + "sort_field": "modified", + "sort_order": "DESC", + "states": [], + "title_field": "book_name" +} \ No newline at end of file diff --git a/library_management/library_management/doctype/library_books/library_books.py b/library_management/library_management/doctype/library_books/library_books.py new file mode 100644 index 0000000..086c2ac --- /dev/null +++ b/library_management/library_management/doctype/library_books/library_books.py @@ -0,0 +1,9 @@ +# Copyright (c) 2025, Frappe and contributors +# For license information, please see license.txt + +# import frappe +from frappe.model.document import Document + + +class LibraryBooks(Document): + pass diff --git a/library_management/library_management/doctype/library_books/test_library_books.py b/library_management/library_management/doctype/library_books/test_library_books.py new file mode 100644 index 0000000..d19c8d2 --- /dev/null +++ b/library_management/library_management/doctype/library_books/test_library_books.py @@ -0,0 +1,9 @@ +# Copyright (c) 2025, Frappe and Contributors +# See license.txt + +# import frappe +from frappe.tests.utils import FrappeTestCase + + +class TestLibraryBooks(FrappeTestCase): + pass diff --git a/library_management/library_management/doctype/library_books_student_table/__init__.py b/library_management/library_management/doctype/library_books_student_table/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/library_management/library_management/doctype/library_books_student_table/library_books_student_table.json b/library_management/library_management/doctype/library_books_student_table/library_books_student_table.json new file mode 100644 index 0000000..091188f --- /dev/null +++ b/library_management/library_management/doctype/library_books_student_table/library_books_student_table.json @@ -0,0 +1,108 @@ +{ + "actions": [], + "allow_rename": 1, + "creation": "2025-04-24 16:57:59.073601", + "doctype": "DocType", + "editable_grid": 1, + "engine": "InnoDB", + "field_order": [ + "book_id", + "book_name", + "author", + "reference_number", + "column_break_dsnf", + "book_issue_date", + "book_return_date", + "reading_period", + "column_break_vyxp", + "book_status", + "due__days", + "take_home" + ], + "fields": [ + { + "fieldname": "book_id", + "fieldtype": "Data", + "in_list_view": 1, + "label": "Book ID", + "options": "Library Books" + }, + { + "fieldname": "book_name", + "fieldtype": "Data", + "in_list_view": 1, + "label": "Book Name", + "options": "Article" + }, + { + "fieldname": "author", + "fieldtype": "Data", + "label": "Author" + }, + { + "fieldname": "reference_number", + "fieldtype": "Data", + "in_list_view": 1, + "label": "Reference Number" + }, + { + "fieldname": "column_break_dsnf", + "fieldtype": "Column Break" + }, + { + "fieldname": "book_issue_date", + "fieldtype": "Date", + "in_list_view": 1, + "label": "Book Issue Date" + }, + { + "fieldname": "book_return_date", + "fieldtype": "Date", + "in_list_view": 1, + "label": "Book Return Date" + }, + { + "fieldname": "reading_period", + "fieldtype": "Data", + "in_list_view": 1, + "label": "Reading Period" + }, + { + "fieldname": "column_break_vyxp", + "fieldtype": "Column Break" + }, + { + "fieldname": "book_status", + "fieldtype": "Select", + "in_list_view": 1, + "label": "Book Status" + }, + { + "fieldname": "due__days", + "fieldtype": "Data", + "in_list_view": 1, + "label": "Due Days" + }, + { + "default": "0", + "fieldname": "take_home", + "fieldtype": "Check", + "in_list_view": 1, + "label": "Take Home" + } + ], + "grid_page_length": 50, + "index_web_pages_for_search": 1, + "istable": 1, + "links": [], + "modified": "2025-04-24 17:04:10.903916", + "modified_by": "Administrator", + "module": "Library Management", + "name": "Library Books Student Table", + "owner": "Administrator", + "permissions": [], + "row_format": "Dynamic", + "sort_field": "modified", + "sort_order": "DESC", + "states": [] +} \ No newline at end of file diff --git a/library_management/library_management/doctype/library_books_student_table/library_books_student_table.py b/library_management/library_management/doctype/library_books_student_table/library_books_student_table.py new file mode 100644 index 0000000..afd5de7 --- /dev/null +++ b/library_management/library_management/doctype/library_books_student_table/library_books_student_table.py @@ -0,0 +1,9 @@ +# Copyright (c) 2025, Frappe and contributors +# For license information, please see license.txt + +# import frappe +from frappe.model.document import Document + + +class LibraryBooksStudentTable(Document): + pass diff --git a/library_management/library_management/doctype/library_transactions/__init__.py b/library_management/library_management/doctype/library_transactions/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/library_management/library_management/doctype/library_transactions/library_transactions.js b/library_management/library_management/doctype/library_transactions/library_transactions.js new file mode 100644 index 0000000..c366d46 --- /dev/null +++ b/library_management/library_management/doctype/library_transactions/library_transactions.js @@ -0,0 +1,8 @@ +// Copyright (c) 2025, Frappe and contributors +// For license information, please see license.txt + +// frappe.ui.form.on("Library Transactions", { +// refresh(frm) { + +// }, +// }); diff --git a/library_management/library_management/doctype/library_transactions/library_transactions.json b/library_management/library_management/doctype/library_transactions/library_transactions.json new file mode 100644 index 0000000..f3a9f02 --- /dev/null +++ b/library_management/library_management/doctype/library_transactions/library_transactions.json @@ -0,0 +1,173 @@ +{ + "actions": [], + "allow_rename": 1, + "autoname": "format:{student_ref} {name} {#####}", + "creation": "2025-04-24 16:44:54.204848", + "doctype": "DocType", + "engine": "InnoDB", + "field_order": [ + "student_details_section", + "student", + "classs", + "column_break_mtqw", + "student_ref", + "branch", + "book_transaction_details_section", + "isbn", + "book_name", + "accession_number", + "column_break_nplj", + "author", + "publisher", + "return_date", + "quantity_available", + "column_break_duyr", + "date_of_issue", + "reading_period", + "due_days", + "book_status", + "take_home" + ], + "fields": [ + { + "fieldname": "student_details_section", + "fieldtype": "Section Break", + "label": "Student Details" + }, + { + "fieldname": "student", + "fieldtype": "Link", + "in_list_view": 1, + "label": "Student", + "options": "Student", + "reqd": 1 + }, + { + "fieldname": "classs", + "fieldtype": "Data", + "label": "Class" + }, + { + "fieldname": "column_break_mtqw", + "fieldtype": "Column Break" + }, + { + "fieldname": "student_ref", + "fieldtype": "Data", + "label": "Student Reference Number" + }, + { + "fieldname": "branch", + "fieldtype": "Data", + "label": "Branch" + }, + { + "fieldname": "book_transaction_details_section", + "fieldtype": "Section Break", + "label": "Book Transaction Details" + }, + { + "fieldname": "isbn", + "fieldtype": "Data", + "in_list_view": 1, + "label": "ISBN", + "reqd": 1 + }, + { + "fieldname": "book_name", + "fieldtype": "Data", + "in_list_view": 1, + "label": "Book Name", + "reqd": 1 + }, + { + "fieldname": "accession_number", + "fieldtype": "Data", + "label": "Accession Number" + }, + { + "fieldname": "column_break_nplj", + "fieldtype": "Column Break" + }, + { + "fieldname": "author", + "fieldtype": "Data", + "label": "Author" + }, + { + "fieldname": "publisher", + "fieldtype": "Data", + "label": "Publisher" + }, + { + "fieldname": "return_date", + "fieldtype": "Date", + "in_list_view": 1, + "label": "Return Date", + "reqd": 1 + }, + { + "fieldname": "quantity_available", + "fieldtype": "Data", + "label": "Quantity Available" + }, + { + "fieldname": "column_break_duyr", + "fieldtype": "Column Break" + }, + { + "fieldname": "date_of_issue", + "fieldtype": "Date", + "label": "Date of Issue" + }, + { + "fieldname": "reading_period", + "fieldtype": "Data", + "label": "Reading Period" + }, + { + "fieldname": "due_days", + "fieldtype": "Data", + "label": "Due Days" + }, + { + "fieldname": "book_status", + "fieldtype": "Select", + "label": "Book Status", + "options": "READING\nRETURNED\nLOST" + }, + { + "default": "0", + "fieldname": "take_home", + "fieldtype": "Check", + "label": "Take Home" + } + ], + "grid_page_length": 50, + "index_web_pages_for_search": 1, + "links": [], + "modified": "2025-04-24 16:56:44.908131", + "modified_by": "Administrator", + "module": "Library Management", + "name": "Library Transactions", + "naming_rule": "Expression", + "owner": "Administrator", + "permissions": [ + { + "create": 1, + "delete": 1, + "email": 1, + "export": 1, + "print": 1, + "read": 1, + "report": 1, + "role": "System Manager", + "share": 1, + "write": 1 + } + ], + "row_format": "Dynamic", + "sort_field": "modified", + "sort_order": "DESC", + "states": [] +} \ No newline at end of file diff --git a/library_management/library_management/doctype/library_transactions/library_transactions.py b/library_management/library_management/doctype/library_transactions/library_transactions.py new file mode 100644 index 0000000..a2c3db9 --- /dev/null +++ b/library_management/library_management/doctype/library_transactions/library_transactions.py @@ -0,0 +1,174 @@ +# Copyright (c) 2025, Frappe and contributors +# For license information, please see license.txt + +# import frappe +from frappe.model.document import Document + + +class LibraryTransactions(Document): + pass + +''' +# Copyright (c) 2025, Frappe and contributors +# For license information, please see license.txt + +import frappe +from frappe.model.document import Document +from frappe.utils import getdate + +class LibraryTransactions(Document): + def on_update(self): + update_period_and_due_days(self, 'on_update') + + def on_submit(self): + update_period_and_due_days(self, 'on_submit') + + def on_change(self): + if self.isbn or self.accession_number: + fetch_book_details(self, 'on_change') + + def after_save(self): + validate_library_transaction(self, 'after_save') + + +# Function to update the reading_period and due_days +def update_period_and_due_days(doc, method): + date_of_issue = doc.date_of_issue + return_date = doc.return_date + book_status = doc.book_status + + if date_of_issue and return_date: + # Calculate the difference in days between return date and issue date + days_difference = getdate(return_date) - getdate(date_of_issue) + doc.reading_period = f"{days_difference.days + 1} days" # Include both start and end date + + if book_status == 'READING' and return_date: + today = getdate() + days_since_return = today - getdate(return_date) + doc.due_days = f"{max(days_since_return.days + 1, 0)} days" # Calculate due days + + doc.save() + + +# Function to fetch book details from Library Books based on ISBN or Accession Number +def fetch_book_details(doc, method): + # Fetch data from Library Books based on ISBN or Accession Number + if doc.isbn: + filters = {'isbn': doc.isbn} + elif doc.accession_number: + filters = {'accession_number': doc.accession_number} + else: + return + + book = frappe.get_all('Library Books', filters=filters, fields=["book_name", "accession_number", "author", "publisher", "avail_quantity", "take_home", "branch"]) + + if book: + book = book[0] # Fetch the first result + doc.book_name = book.get("book_name") + doc.accession_number = book.get("accession_number") + doc.quantity_available = book.get("avail_quantity") + doc.author = book.get("author") + doc.publisher = book.get("publisher") + doc.take_home = book.get("take_home") + doc.branch = book.get("branch") + doc.save() + else: + frappe.msgprint(__('No matching book found for the provided ISBN or Accession Number.')) + + +# Function to validate library transaction (book issuance) +def validate_library_transaction(doc, method): + reference_number = doc.student_ref + class_name = doc.classs + student_name = doc.student + isbn = doc.isbn + accession_number = doc.accession_number + + if reference_number and class_name and student_name and (isbn or accession_number): + # Fetch all library transactions except the current document + all_library_transactions = frappe.get_all('Library Transactions', + filters={ + 'classs': class_name, + 'student_ref': reference_number, + 'isbn': isbn, + 'student': student_name, + 'book_status': doc.book_status, + 'return_date': doc.return_date, + 'name': ('!=', doc.name) + }) + + if all_library_transactions: + frappe.throw("Same book cannot be taken repeatedly at a time.") + + # Fetch Program Enrollment document for the student and class + program_enrollment = frappe.get_doc("Program Enrollment", {"student": student_name, "program": class_name}) + if program_enrollment: + if program_enrollment.custom_library_membership: + student_doc = frappe.get_doc("Student", {"reference_number": reference_number, "program": class_name}) + if student_doc: + # Count the number of books issued by reference_number + issued_books_count = frappe.db.count("Library Transactions", + filters={"student_ref": reference_number, + "classs": class_name, + "book_status": ("!=", "RETURNED")}) + if issued_books_count > 2: + frappe.throw("Only three books are allowed to be issued at a time.") + + # Update custom_number_of_books_issued with the count of issued books + student_doc.custom_number_of_books_issued = issued_books_count + + # Fetch library details for the student + library_details = frappe.get_all("Library Transactions", + filters={"student_ref": reference_number, "classs": class_name}, + fields=["book_name", "author", "date_of_issue", "return_date", "take_home", + "reading_period", "due_days", "book_status"]) + + if library_details: + student_doc.set("custom_books", []) + update = False + for detail in library_details: + if detail.get("take_home") == 1: + # Use ISBN or accession_number to fetch book details + book_filters = {"isbn": isbn} if isbn else {"accession_number": accession_number} + book_details = frappe.get_all("Library Books", filters=book_filters, + fields=["name", "book_name", "avail_quantity", "author", "publisher", "take_home"], + limit_page_length=1) + + if book_details: + book_details = book_details[0] # Get the first result + current_quantity = int(book_details.get('avail_quantity', 0) or 0) + if doc.book_status == "READING": + if current_quantity < 0: + frappe.throw("Book is out of stock.") + if not update: + book_details['avail_quantity'] = current_quantity - 1 + update = True + elif doc.book_status == "RETURNED": + if not update: + book_details['avail_quantity'] = current_quantity + 1 + frappe.msgprint("Book quantity updated") + update = True + + frappe.get_doc("Library Books", book_details['name']).update({"avail_quantity": book_details['avail_quantity']}).save() + + # Append book details to custom_books + library_book = student_doc.append("custom_library_books", {}) + library_book.book_name = book_details['book_name'] + library_book.author = detail.get("author") + library_book.date_of_issue = detail.get("date_of_issue") + library_book.return_date = detail.get("return_date") + library_book.take_home = detail.get("take_home") + library_book.reading_period = detail.get("reading_period") + library_book.due_days = detail.get("due_days") + library_book.book_status = detail.get("book_status") + + student_doc.save() + frappe.msgprint("Library book details updated in Student document.") + else: + frappe.throw("Student document not found for the given reference number.") + else: + frappe.throw("Student is not allowed to issue library books.") + else: + frappe.throw("Program Enrollment not found for the student and class.") + else: + frappe.throw("Reference number, class, student, or book details not found in the newly added Library Transaction record.")''' diff --git a/library_management/library_management/doctype/library_transactions/test_library_transactions.py b/library_management/library_management/doctype/library_transactions/test_library_transactions.py new file mode 100644 index 0000000..273abb0 --- /dev/null +++ b/library_management/library_management/doctype/library_transactions/test_library_transactions.py @@ -0,0 +1,9 @@ +# Copyright (c) 2025, Frappe and Contributors +# See license.txt + +# import frappe +from frappe.tests.utils import FrappeTestCase + + +class TestLibraryTransactions(FrappeTestCase): + pass