Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Sprint 134 - Staging to Test-Production(V15.1.3) #3701

Merged
merged 26 commits into from
Oct 12, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
26 commits
Select commit Hold shift + click to select a range
8180cdc
marked site and supervisor field mandatory depending on project type
ibtesam-onefm Oct 1, 2024
288e9fe
Merge pull request #3675 from ONE-F-M/version-15
pjamsheer Oct 1, 2024
9591c2e
Merge pull request #3676 from ONE-F-M/188337383
Talleyrand333 Oct 2, 2024
84195d0
use gpt-4o as openai model
Talleyrand333 Oct 3, 2024
ab57d97
link knowledge base chatbot to openai
Talleyrand333 Oct 6, 2024
967de50
Merge pull request #3678 from ONE-F-M/188329899
NoBoneZ Oct 6, 2024
d9a0625
minor update to api
Talleyrand333 Oct 6, 2024
9fb3b90
Minor update to params
Talleyrand333 Oct 6, 2024
8e416a5
Merge pull request #3679 from ONE-F-M/188329899
NoBoneZ Oct 6, 2024
945dbf2
fixes
yusuffGoodie Oct 6, 2024
c7b118e
attendance-marking-before-employee-joining-date
yusuffGoodie Oct 6, 2024
275f76c
fixes
yusuffGoodie Oct 7, 2024
f0ca0c8
Made changes to lumina
Talleyrand333 Oct 7, 2024
38d6878
Merge pull request #3686 from ONE-F-M/188329899
NoBoneZ Oct 7, 2024
30aa4b2
Merge pull request #3684 from ONE-F-M/attendance-marking-before-emplo…
Talleyrand333 Oct 8, 2024
b9a0863
removed redundant method
Talleyrand333 Oct 8, 2024
1e0d866
Merge pull request #3681 from ONE-F-M/contracts-end-email-not-send
NoBoneZ Oct 8, 2024
0048ee4
Merge pull request #3689 from ONE-F-M/188329899
ibtesam-onefm Oct 8, 2024
ea3a34b
Add Customer Confirmation Copy field
Talleyrand333 Oct 9, 2024
6592b41
Lumina Finetuning
Talleyrand333 Oct 9, 2024
f91a3fa
Merge pull request #3692 from ONE-F-M/188329899
Talleyrand333 Oct 9, 2024
63db2fb
Merge pull request #3691 from ONE-F-M/188393943
NoBoneZ Oct 9, 2024
c2d3dcd
Merge pull request #3695 from ONE-F-M/version-15
pjamsheer Oct 10, 2024
12e600c
chore: v15_1_3 change log
pjamsheer Oct 10, 2024
9ebbaf3
Merge pull request #3698 from ONE-F-M/change_log
pjamsheer Oct 10, 2024
a43bc66
Merge pull request #3697 from ONE-F-M/staging
pjamsheer Oct 10, 2024
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
2 changes: 1 addition & 1 deletion one_fm/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@
from one_fm.permissions import get_custom_user_permissions


__version__ = '15.1.2'
__version__ = '15.1.3'

user_permission.get_user_permissions = get_custom_user_permissions
StockController.make_batches = make_batches_with_supplier_batch_id
Expand Down
11 changes: 11 additions & 0 deletions one_fm/change_log/v15/v15_1_3.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
# Version 15.1.3 Release Notes

### Feature Update
- Interview Question fetch in the order provided in Template
- Client Confirmation copy attachment in Sales Invoice
- Shows external projects only in MoM
- More space in interview feedback answer field
- Client Confirmation copy attachment in Sales Invoice

### Bug Fixes
- Remove attendance creation for today joined employees
240 changes: 153 additions & 87 deletions one_fm/one_fm/custom/sales_invoice.json

Large diffs are not rendered by default.

2 changes: 2 additions & 0 deletions one_fm/one_fm/sales_invoice_custom.py
Original file line number Diff line number Diff line change
Expand Up @@ -941,6 +941,8 @@ def calculate_total_working_days(project = None, item_code = None, first_day =No
return total_working_day

def before_submit_sales_invoice(doc, method):
if not doc.custom_client_confirmation_copy:
frappe.throw('Please Attach Client Confirmation Copy')
if doc.contracts:
is_po_for_invoice = frappe.db.get_value('Contracts', doc.contracts, 'is_po_for_invoice')
if is_po_for_invoice == 1 and not doc.po:
Expand Down
102 changes: 52 additions & 50 deletions one_fm/operations/doctype/contracts/contracts.py
Original file line number Diff line number Diff line change
Expand Up @@ -1028,56 +1028,58 @@ def send_contract_reminders(is_scheduled_event=True):
Args:
is_scheduled_event -> Boolean (Default True) If method is triggered from anywhere else than the scheduled event, Pass "False" to avoid email trigger check from "ONEFM General Setting"
"""

contracts_due_internal_notification = frappe.get_all("Contracts",{'contract_end_internal_notification_date':getdate()},['contract_end_internal_notification',\
'contract_end_internal_notification_date','engagement_type','contract_termination_decision_period','contract_termination_decision_period_date','name','start_date','end_date','duration','client'])
contracts_due_termination_notification = frappe.get_all("Contracts",{'contract_termination_decision_period_date':getdate()},['contract_end_internal_notification',\
'contract_end_internal_notification_date','engagement_type','contract_termination_decision_period','contract_termination_decision_period_date','name','start_date','end_date','duration','client'])

relevant_roles = ["Finance Manager",'Legal Manager','Projects Manager','Operations Manager']
active_users = frappe.get_all("User",{'enabled':1})
active_users_ = [i.name for i in active_users] if active_users else []
active_users_.remove("Administrator")
relevant_users = frappe.get_all("Has Role",{'role':['IN',relevant_roles],'parent':['IN',active_users_]},['distinct parent'])
users = [i.parent for i in relevant_users]
if contracts_due_internal_notification:
contracts_due_internal_notification_list = [[i.contract_termination_decision_period,i.contract_end_internal_notification,\
get_date_str(i.contract_termination_decision_period_date),i.name,get_date_str(i.start_date),get_date_str(i.contract_end_internal_notification_date),\
get_date_str(i.end_date),i.duration,i.client,i.engagement_type, i.contract] for i in contracts_due_internal_notification]
for each in contracts_due_internal_notification_list:
context = {"project": each[8],
"contract_end_internal_notif_period": each[1],
"start_date": each[4],
"engagement_type": each[9],
"contract_end_internal_notif_date": each[5],
"contract_termination_decision_period": each[0],
"contract_termination_decision_date": each[2],
"end_date": each[6],
"duration": each[7],
"document_id": each[3],
"link": frappe.utils.get_url_to_form("Contracts",each[3]),
"attachment": frappe.utils.get_url(each[10]) if each[10] else None}
msg = frappe.render_template('one_fm/templates/emails/contracts_reminder.html', context=context)
sendemail(recipients=[users], subject="Expiring Contracts", content=msg, is_scheduler_email=is_scheduled_event)
if contracts_due_termination_notification:
contracts_due_termination_notification_list = [[i.contract_termination_decision_period,i.contract_end_internal_notification,\
get_date_str(i.contract_termination_decision_period_date),i.name,get_date_str(i.start_date),get_date_str(i.contract_end_internal_notification_date),\
get_date_str(i.end_date),i.duration,i.client,i.engagement_type, i.contract] for i in contracts_due_termination_notification]
for each in contracts_due_termination_notification_list:
context = {"project": each[8],
"contract_end_internal_notif_period": each[1],
"start_date": each[4],
"engagement_type": each[9],
"contract_end_internal_notif_date": each[5],
"contract_termination_decision_period": each[0],
"contract_termination_decision_date": each[2],
"end_date": each[6],
"duration": each[7],
"document_id": each[3],
"link": frappe.utils.get_url_to_form("Contracts",each[3]),
"attachment": frappe.utils.get_url(each[10]) if each[10] else None}
msg = frappe.render_template('one_fm/templates/emails/contracts_reminder.html', context=context)
sendemail(recipients=[users], subject="Expiring Contracts", content=msg,is_scheduler_email=is_scheduled_event)
try:
contracts_due_internal_notification = frappe.get_all("Contracts",{'contract_end_internal_notification_date':getdate()},['contract_end_internal_notification',\
'contract_end_internal_notification_date','engagement_type','contract_termination_decision_period','contract_termination_decision_period_date','name','start_date','end_date','duration','client'])
contracts_due_termination_notification = frappe.get_all("Contracts",{'contract_termination_decision_period_date':getdate()},['contract_end_internal_notification',\
'contract_end_internal_notification_date','engagement_type','contract_termination_decision_period','contract_termination_decision_period_date','name','start_date','end_date','duration','client'])

relevant_roles = ["Finance Manager",'Legal Manager','Projects Manager','Operations Manager']
active_users = frappe.get_all("User",{'enabled':1})
active_users_ = [i.name for i in active_users] if active_users else []
active_users_.remove("Administrator")
relevant_users = frappe.get_all("Has Role",{'role':['IN',relevant_roles],'parent':['IN',active_users_]},['distinct parent'])
users = [i.parent for i in relevant_users]
if contracts_due_internal_notification:
contracts_due_internal_notification_list = [[i.contract_termination_decision_period,i.contract_end_internal_notification,\
get_date_str(i.contract_termination_decision_period_date),i.name,get_date_str(i.start_date),get_date_str(i.contract_end_internal_notification_date),\
get_date_str(i.end_date),i.duration,i.client,i.engagement_type, i.contract] for i in contracts_due_internal_notification]
for each in contracts_due_internal_notification_list:
context = {"project": each[8],
"contract_end_internal_notif_period": each[1],
"start_date": each[4],
"engagement_type": each[9],
"contract_end_internal_notif_date": each[5],
"contract_termination_decision_period": each[0],
"contract_termination_decision_date": each[2],
"end_date": each[6],
"duration": each[7],
"document_id": each[3],
"link": frappe.utils.get_url_to_form("Contracts",each[3]),
"attachment": frappe.utils.get_url(each[10]) if each[10] else None}
msg = frappe.render_template('one_fm/templates/emails/contracts_reminder.html', context=context)
sendemail(recipients=users, subject="Expiring Contracts", content=msg, is_scheduler_email=is_scheduled_event)
if contracts_due_termination_notification:
contracts_due_termination_notification_list = [[i.contract_termination_decision_period,i.contract_end_internal_notification,\
get_date_str(i.contract_termination_decision_period_date),i.name,get_date_str(i.start_date),get_date_str(i.contract_end_internal_notification_date),\
get_date_str(i.end_date),i.duration,i.client,i.engagement_type, i.contract] for i in contracts_due_termination_notification]
for each in contracts_due_termination_notification_list:
context = {"project": each[8],
"contract_end_internal_notif_period": each[1],
"start_date": each[4],
"engagement_type": each[9],
"contract_end_internal_notif_date": each[5],
"contract_termination_decision_period": each[0],
"contract_termination_decision_date": each[2],
"end_date": each[6],
"duration": each[7],
"document_id": each[3],
"link": frappe.utils.get_url_to_form("Contracts",each[3]),
"attachment": frappe.utils.get_url(each[10]) if each[10] else None}
msg = frappe.render_template('one_fm/templates/emails/contracts_reminder.html', context=context)
sendemail(recipients=users, subject="Expiring Contracts", content=msg,is_scheduler_email=is_scheduled_event)
except Exception as e:
frappe.log_error(e)

@frappe.whitelist()
def renew_contracts_by_termination_date():
Expand Down
4 changes: 3 additions & 1 deletion one_fm/operations/doctype/mom/mom.json
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@
"fieldtype": "Link",
"hidden": 1,
"label": "Site",
"mandatory_depends_on": "eval:doc.project_type == 'External'",
"options": "Operations Site"
},
{
Expand Down Expand Up @@ -199,6 +200,7 @@
"fieldname": "supervisor",
"fieldtype": "Link",
"label": "Supervisor",
"mandatory_depends_on": "eval:doc.project_type == 'External'",
"options": "Employee"
},
{
Expand All @@ -216,7 +218,7 @@
],
"is_submittable": 1,
"links": [],
"modified": "2024-09-30 14:17:34.273265",
"modified": "2024-10-01 12:49:10.048427",
"modified_by": "Administrator",
"module": "Operations",
"name": "MOM",
Expand Down
2 changes: 2 additions & 0 deletions one_fm/overrides/attendance.py
Original file line number Diff line number Diff line change
Expand Up @@ -553,6 +553,7 @@ def mark_daily_attendance(start_date, end_date):
"{owner}", "{creation}", "{creation}", "{i.description}"
),"""

today = getdate()
# Mark DayOff Attendance
#Find Employees with no schedule but have Day Off in the company holiday. Mainly for head office employees
day_off_no_schedule = frappe.db.sql(f"""
Expand All @@ -566,6 +567,7 @@ def mark_daily_attendance(start_date, end_date):
AND '{start_date}' BETWEEN hl.from_date AND hl.to_date
AND e.status='Active'
AND e.name NOT IN (SELECT employee from `tabEmployee Schedule`es where es.date = '{start_date}' AND es.employee_availability='Day Off')
AND e.date_of_joining < '{today}'
""",
as_dict=1)

Expand Down
8 changes: 4 additions & 4 deletions one_fm/public/faq/js/chatgpt.js
Original file line number Diff line number Diff line change
Expand Up @@ -44,13 +44,13 @@ function generateResponse(prompt){
// Here you can add your answer-generating code
if(prompt){
frappe.call({
method: 'one_fm.www.knowledge_base.chatgpt.get_completion',
args: {'prompt': prompt},
method: 'one_fm.wiki_chat_bot.main.ask_question',
args: {'question': prompt},
callback: function(r) {
console.log(r)

if(r.message != 'None') {
$('#chat-bubble').hide();
addMessage("received", r.message);
addMessage("received", r.data.answer);
}
else{
$('#chat-bubble').hide();
Expand Down
49 changes: 38 additions & 11 deletions one_fm/wiki_chat_bot/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,21 +2,21 @@
import json

import frappe
from llama_index.core import SimpleDirectoryReader,PromptHelper,VectorStoreIndex
from langchain.llms import OpenAI
from llama_index.core import SimpleDirectoryReader,PromptHelper,VectorStoreIndex,PromptTemplate
from llama_index.llms.openai import OpenAI
from llama_index.embeddings.openai import OpenAIEmbedding
from llama_index.core import StorageContext, load_index_from_storage

from one_fm.api.v1.utils import response



from one_fm.api.v1.utils import response

def create_vector_index():
try:
os.environ["OPENAI_API_KEY"] = frappe.local.conf.CHATGPT_APIKEY
docs = SimpleDirectoryReader(get_folder_path()).load_data()
vector_index = VectorStoreIndex.from_documents(docs)

vector_index.storage_context.persist(persist_dir="vector_index.json")
embedding_model = OpenAIEmbedding(model_name="gpt-4o-mini")
vector_index = VectorStoreIndex.from_documents(docs,embedding=embedding_model)
vector_index.storage_context.persist(persist_dir="vector_index")
return vector_index
except:
frappe.log_error(frappe.get_traceback(), "Error while adding to bot memory(Chat-BOT)")
Expand All @@ -28,10 +28,37 @@ def ask_question(question: str = None):
os.environ["OPENAI_API_KEY"] = frappe.local.conf.CHATGPT_APIKEY
if not question:
return response("Bad Request !", 400, error="Question can not be empty")
storage_context = StorageContext.from_defaults(persist_dir="vector_index.json")
storage_context = StorageContext.from_defaults(persist_dir="vector_index")
index = load_index_from_storage(storage_context)

query_engine = index.as_query_engine()
prompt_template_str = (
"Context information is below.\n"
"---------------------\n"
"{context_str}\n"
"---------------------\n"
"Given the context information and not prior knowledge, "
"You do not need to introduce yourself or say who you are when you are not asked directly\n"
"You are an AI assistant called Lumina.\n"
"You Work for One Faciities Management, A company with it's Headquarters in Kuwait\n"
"Whenever Lumina does not find the required data,ask the user to upload the most updated data to enable you answer the question appropriately\n"
"Respond to the user in the same language they use"
"Query: {query_str}\n"
"Answer: "
)
refine_prompt_str = (
"We have the opportunity to refine the original answer "
"(only if needed) with some more context below.\n"
"------------\n"
"If you did not respond to the question in the same language it was asked,translate your answer to the same language as the question unless the preferred languaged was specified in the query\n"
"------------\n"
"Given the new context, refine the original answer to better "
"answer the question: {query_str}. "

"Original Answer: {existing_answer}"
)
text_qa_template = PromptTemplate(prompt_template_str)
refined_text_qa_template = PromptTemplate(refine_prompt_str)
llm = OpenAI(model="gpt-4o-mini")
query_engine = index.as_query_engine(llm=llm,text_qa_template=text_qa_template,refine_template=refined_text_qa_template)
answer = query_engine.query(question)
return response(message="Success", status_code=200, data={"question": question, "answer": answer.response})
except Exception as e:
Expand Down