@ -0,0 +1,47 @@ |
|||
.. image:: https://img.shields.io/badge/license-AGPL--3-blue.svg |
|||
:target: https://www.gnu.org/licenses/agpl-3.0-standalone.html |
|||
:alt: License: AGPL-3 |
|||
|
|||
Hospital Management Odoo 17 |
|||
=========================== |
|||
This Module helps to manage day to day activities of a hospital. |
|||
|
|||
Configuration |
|||
============= |
|||
Install python-barcode (pip install python-barcode) |
|||
|
|||
License |
|||
------- |
|||
Affero General Public License, Version 3 (AGPL v3). |
|||
(https://www.gnu.org/licenses/lgpl-3.0-standalone.html) |
|||
|
|||
Company |
|||
------- |
|||
* `Cybrosys Techno Solutions <https://cybrosys.com/>`__ |
|||
|
|||
Credits |
|||
------- |
|||
* Developer:(V17) Subina, |
|||
Contact: odoo@cybrosys.com |
|||
|
|||
Contacts |
|||
-------- |
|||
* Mail Contact : odoo@cybrosys.com |
|||
* Website : https://cybrosys.com |
|||
|
|||
Bug Tracker |
|||
----------- |
|||
Bugs are tracked on GitHub Issues. In case of trouble, please check there if your issue has already been reported. |
|||
|
|||
Maintainer |
|||
========== |
|||
.. image:: https://cybrosys.com/images/logo.png |
|||
:target: https://cybrosys.com |
|||
|
|||
This module is maintained by Cybrosys Technologies. |
|||
|
|||
For support and more information, please visit `Our Website <https://cybrosys.com/>`__ |
|||
|
|||
Further information |
|||
=================== |
|||
HTML Description: `<static/description/index.html>`__ |
@ -0,0 +1,23 @@ |
|||
# -*- coding: utf-8 -*- |
|||
################################################################################ |
|||
# |
|||
# Cybrosys Technologies Pvt. Ltd. |
|||
# |
|||
# Copyright (C) 2024-TODAY Cybrosys Technologies(<https://www.cybrosys.com>). |
|||
# Author: Subina P (odoo@cybrosys.com) |
|||
# |
|||
# You can modify it under the terms of the GNU AFFERO |
|||
# GENERAL PUBLIC LICENSE (AGPL v3), Version 3. |
|||
# |
|||
# This program is distributed in the hope that it will be useful, |
|||
# but WITHOUT ANY WARRANTY; without even the implied warranty of |
|||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|||
# GNU AFFERO GENERAL PUBLIC LICENSE (AGPL v3) for more details. |
|||
# |
|||
# You should have received a copy of the GNU AFFERO GENERAL PUBLIC LICENSE |
|||
# (AGPL v3) along with this program. |
|||
# If not, see <http://www.gnu.org/licenses/>. |
|||
# |
|||
################################################################################ |
|||
from . import controllers |
|||
from . import models |
@ -0,0 +1,112 @@ |
|||
# -*- coding: utf-8 -*- |
|||
################################################################################ |
|||
# |
|||
# Cybrosys Technologies Pvt. Ltd. |
|||
# |
|||
# Copyright (C) 2024-TODAY Cybrosys Technologies(<https://www.cybrosys.com>). |
|||
# Author: Subina P (odoo@cybrosys.com) |
|||
# |
|||
# You can modify it under the terms of the GNU AFFERO |
|||
# GENERAL PUBLIC LICENSE (AGPL v3), Version 3. |
|||
# |
|||
# This program is distributed in the hope that it will be useful, |
|||
# but WITHOUT ANY WARRANTY; without even the implied warranty of |
|||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|||
# GNU AFFERO GENERAL PUBLIC LICENSE (AGPL v3) for more details. |
|||
# |
|||
# You should have received a copy of the GNU AFFERO GENERAL PUBLIC LICENSE |
|||
# (AGPL v3) along with this program. |
|||
# If not, see <http://www.gnu.org/licenses/>. |
|||
# |
|||
################################################################################ |
|||
{ |
|||
"name": "Hospital Management Odoo 17", |
|||
"version": "17.0.1.0.0", |
|||
"category": "Industries", |
|||
"summary": """This Module Helps to Manage Patients Records, Doctors Details, |
|||
Lab Management , Employee Management etc.""", |
|||
"description": """The hospital management module can be used to handle |
|||
the day-to-day activities of the hospital. Managing patient scheduling, |
|||
making patient ID cards, creating patient lab test results, and adding |
|||
doctors, patients, prescriptions, vaccines, etc. are all made easier |
|||
with the help of this module. This app offers a different dashboards for |
|||
different users.""", |
|||
"author": "Cybrosys Techno Solutions", |
|||
"company": "Cybrosys Techno Solutions", |
|||
"maintainer": "Cybrosys Techno Solutions", |
|||
"website": "https://www.cybrosys.com", |
|||
"depends": ["website", "hr", "stock", "sale_management"], |
|||
"data": [ |
|||
"security/base_hospital_management_groups.xml", |
|||
"security/doctor_allocation_security.xml", |
|||
"security/doctor_slot_security.xml", |
|||
"security/patient_lab_test_security.xml", |
|||
"security/ir.model.access.csv", |
|||
"data/ir_sequence_data.xml", |
|||
"data/ir_cron_data.xml", |
|||
"data/website_data.xml", |
|||
"views/menu_views.xml", |
|||
"views/inpatient_surgery_views.xml", |
|||
"views/hospital_bed_views.xml", |
|||
"views/blood_bank_views.xml", |
|||
"views/contra_indication_views.xml", |
|||
"views/booking_success_templates.xml", |
|||
"views/hospital_building_views.xml", |
|||
"views/hospital_degree_views.xml", |
|||
"views/doctor_allocation_views.xml", |
|||
"views/hr_employee_views.xml", |
|||
"views/hospital_inpatient_views.xml", |
|||
"views/hospital_insurance_views.xml", |
|||
"views/hospital_laboratory_views.xml", |
|||
"views/patient_lab_test_views.xml", |
|||
"views/lab_test_views.xml", |
|||
"views/lab_test_result_views.xml", |
|||
"views/medicine_brand_views.xml", |
|||
"views/menu_views.xml", |
|||
"views/hospital_outpatient_views.xml", |
|||
"views/res_partner_views.xml", |
|||
"views/patient_portal_templates.xml", |
|||
"views/hospital_vaccination_views.xml", |
|||
"views/product_template_views.xml", |
|||
"views/room_facility_views.xml", |
|||
"views/patient_card_templates.xml", |
|||
"views/booking_success_templates.xml", |
|||
"views/doctor_specialization_views.xml", |
|||
"views/hospital_pharmacy_views.xml", |
|||
"views/hospital_ward_views.xml", |
|||
"views/patient_booking_templates.xml", |
|||
"views/patient_room_views.xml", |
|||
"views/lab_test_line_views.xml", |
|||
"report/res_partner_reports.xml", |
|||
"report/lab_test_line_reports.xml", |
|||
], |
|||
"demo": ["demo/hr_job_demo.xml"], |
|||
"assets": { |
|||
"web.assets_frontend": [ |
|||
"base_hospital_management/static/src/js/prescription.js", |
|||
"base_hospital_management/static/src/js/website_page.js", |
|||
], |
|||
"web.assets_backend": [ |
|||
"base_hospital_management/static/src/css/doctor_dashboard.css", |
|||
"base_hospital_management/static/src/css/reception_dashboard.css", |
|||
"base_hospital_management/static/src/css/lab_dashboard.css", |
|||
"base_hospital_management/static/src/css/pharmacy_dashboard.css", |
|||
"base_hospital_management/static/src/xml/lab_dashboard_templates.xml", |
|||
"base_hospital_management/static/src/xml/doctor_dashboard_templates.xml", |
|||
"base_hospital_management/static/src/js/lab_dashboard.js", |
|||
"base_hospital_management/static/src/js/doctor_dashboard.js", |
|||
"base_hospital_management/static/src/xml/pharmacy_orderlines.xml", |
|||
"base_hospital_management/static/src/js/pharmacy_orderlines.js", |
|||
"base_hospital_management/static/src/xml/pharmacy_dashboard_templates.xml", |
|||
"base_hospital_management/static/src/js/pharmacy_dashboard.js", |
|||
"base_hospital_management/static/src/xml/reception_dashboard_templates.xml", |
|||
"base_hospital_management/static/src/js/reception_dashboard.js", |
|||
], |
|||
}, |
|||
"external_dependencies": {"python": ["python-barcode"]}, |
|||
"images": ["static/description/banner.jpg"], |
|||
"license": "AGPL-3", |
|||
"installable": True, |
|||
"auto_install": False, |
|||
"application": True, |
|||
} |
@ -0,0 +1,24 @@ |
|||
# -*- coding: utf-8 -*- |
|||
################################################################################ |
|||
# |
|||
# Cybrosys Technologies Pvt. Ltd. |
|||
# |
|||
# Copyright (C) 2024-TODAY Cybrosys Technologies(<https://www.cybrosys.com>). |
|||
# Author: Subina P (odoo@cybrosys.com) |
|||
# |
|||
# You can modify it under the terms of the GNU AFFERO |
|||
# GENERAL PUBLIC LICENSE (AGPL v3), Version 3. |
|||
# |
|||
# This program is distributed in the hope that it will be useful, |
|||
# but WITHOUT ANY WARRANTY; without even the implied warranty of |
|||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|||
# GNU AFFERO GENERAL PUBLIC LICENSE (AGPL v3) for more details. |
|||
# |
|||
# You should have received a copy of the GNU AFFERO GENERAL PUBLIC LICENSE |
|||
# (AGPL v3) along with this program. |
|||
# If not, see <http://www.gnu.org/licenses/>. |
|||
# |
|||
################################################################################ |
|||
from . import patient_booking |
|||
from . import portal |
|||
from . import view_portal |
@ -0,0 +1,78 @@ |
|||
# -*- coding: utf-8 -*- |
|||
################################################################################ |
|||
# |
|||
# Cybrosys Technologies Pvt. Ltd. |
|||
# |
|||
# Copyright (C) 2024-TODAY Cybrosys Technologies(<https://www.cybrosys.com>). |
|||
# Author: Subina P (odoo@cybrosys.com) |
|||
# |
|||
# You can modify it under the terms of the GNU AFFERO |
|||
# GENERAL PUBLIC LICENSE (AGPL v3), Version 3. |
|||
# |
|||
# This program is distributed in the hope that it will be useful, |
|||
# but WITHOUT ANY WARRANTY; without even the implied warranty of |
|||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|||
# GNU AFFERO GENERAL PUBLIC LICENSE (AGPL v3) for more details. |
|||
# |
|||
# You should have received a copy of the GNU AFFERO GENERAL PUBLIC LICENSE |
|||
# (AGPL v3) along with this program. |
|||
# If not, see <http://www.gnu.org/licenses/>. |
|||
# |
|||
################################################################################ |
|||
from odoo import fields, http |
|||
from odoo.http import request |
|||
|
|||
|
|||
class PatientBooking(http.Controller): |
|||
"""Class for patient booking""" |
|||
|
|||
@http.route('/patient_booking', type='http', auth="public", website=True) |
|||
def patient_booking(self): |
|||
"""Function for patient booking from website.""" |
|||
if request.env.user._is_public(): |
|||
return request.redirect('/web/login') |
|||
values = { |
|||
'user': request.env.user.name, |
|||
'date': fields.date.today() |
|||
} |
|||
return request.render( |
|||
"base_hospital_management.patient_booking_form", values) |
|||
|
|||
@http.route('/patient_booking/success', type='http', |
|||
website=True, csrf=False) |
|||
def patient_booking_submit(self, **kw): |
|||
"""Function for submitting the patient booking""" |
|||
if request.env.user.partner_id.patient_seq in ['New', 'User', |
|||
'Employee']: |
|||
request.env.user.partner_id.sudo().write( |
|||
{'patient_seq': request.env['ir.sequence'].sudo().next_by_code( |
|||
'patient.sequence')}) or 'New' |
|||
op = request.env['hospital.outpatient'].sudo().create({ |
|||
'patient_id': request.env.user.partner_id.id, |
|||
'doctor_id': int(kw.get("doctor-name")), |
|||
'op_date': kw.get("date"), |
|||
'reason': kw.get("reason") |
|||
}) |
|||
op.sudo().action_confirm() |
|||
return request.redirect('/my/home') |
|||
|
|||
@http.route('/patient_booking/get_doctors', type='json', auth="public", |
|||
website=True) |
|||
def update_doctors(self, **kw): |
|||
"""Method for fetching doctor allocation for the selected date""" |
|||
domain = [('date', '=', kw.get('selected_date'))] |
|||
departments = [] |
|||
doctors = [] |
|||
if kw.get('department'): |
|||
domain.append( |
|||
('doctor_id.department_id.id', '=', kw.get('department'))) |
|||
allocation = request.env['doctor.allocation'].sudo().search(domain) |
|||
for rec in allocation: |
|||
if request.env.user.partner_id not in rec.mapped( |
|||
'op_ids.patient_id'): |
|||
doctors.append({'id': rec.id, 'name': rec.name}) |
|||
if ({'id': rec.department_id.id, 'name': rec.department_id.name} |
|||
not in departments): |
|||
departments.append({'id': rec.department_id.id, |
|||
'name': rec.department_id.name}) |
|||
return {'doctors': doctors, 'departments': departments} |
@ -0,0 +1,44 @@ |
|||
# -*- coding: utf-8 -*- |
|||
################################################################################ |
|||
# |
|||
# Cybrosys Technologies Pvt. Ltd. |
|||
# |
|||
# Copyright (C) 2024-TODAY Cybrosys Technologies(<https://www.cybrosys.com>). |
|||
# Author: Subina P (odoo@cybrosys.com) |
|||
# |
|||
# You can modify it under the terms of the GNU AFFERO |
|||
# GENERAL PUBLIC LICENSE (AGPL v3), Version 3. |
|||
# |
|||
# This program is distributed in the hope that it will be useful, |
|||
# but WITHOUT ANY WARRANTY; without even the implied warranty of |
|||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|||
# GNU AFFERO GENERAL PUBLIC LICENSE (AGPL v3) for more details. |
|||
# |
|||
# You should have received a copy of the GNU AFFERO GENERAL PUBLIC LICENSE |
|||
# (AGPL v3) along with this program. |
|||
# If not, see <http://www.gnu.org/licenses/>. |
|||
# |
|||
################################################################################ |
|||
from odoo.http import request |
|||
from odoo.addons.portal.controllers.portal import CustomerPortal |
|||
|
|||
|
|||
class WebsiteCustomerPortal(CustomerPortal): |
|||
"""Class for inheriting _prepare_home_portal_values function """ |
|||
|
|||
def _prepare_home_portal_values(self, counters): |
|||
"""Function for updating the counts of vaccinations, lab tests and op |
|||
of portal user""" |
|||
values = super()._prepare_home_portal_values(counters) |
|||
if 'vaccination_count' in counters: |
|||
values['vaccination_count'] = request.env[ |
|||
'hospital.vaccination'].sudo(). \ |
|||
search_count([('patient_id.user_ids', '=', request.uid)]) |
|||
if 'lab_test_count' in counters: |
|||
values['lab_test_count'] = request.env['patient.lab.test'].sudo(). \ |
|||
search_count([('patient_id.user_ids', '=', request.uid)]) |
|||
if 'op_count' in counters: |
|||
values['op_count'] = request.env[ |
|||
'hospital.outpatient'].sudo().search_count( |
|||
[('patient_id.user_ids', '=', request.uid)]) |
|||
return values |
@ -0,0 +1,129 @@ |
|||
# -*- coding: utf-8 -*- |
|||
################################################################################ |
|||
# |
|||
# Cybrosys Technologies Pvt. Ltd. |
|||
# |
|||
# Copyright (C) 2024-TODAY Cybrosys Technologies(<https://www.cybrosys.com>). |
|||
# Author: Subina P (odoo@cybrosys.com) |
|||
# |
|||
# You can modify it under the terms of the GNU AFFERO |
|||
# GENERAL PUBLIC LICENSE (AGPL v3), Version 3. |
|||
# |
|||
# This program is distributed in the hope that it will be useful, |
|||
# but WITHOUT ANY WARRANTY; without even the implied warranty of |
|||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|||
# GNU AFFERO GENERAL PUBLIC LICENSE (AGPL v3) for more details. |
|||
# |
|||
# You should have received a copy of the GNU AFFERO GENERAL PUBLIC LICENSE |
|||
# (AGPL v3) along with this program. |
|||
# If not, see <http://www.gnu.org/licenses/>. |
|||
# |
|||
################################################################################ |
|||
from odoo import http |
|||
from odoo.http import request |
|||
|
|||
|
|||
class ViewPortal(http.Controller): |
|||
"""Class holding portal view methods""" |
|||
|
|||
@http.route('/my/vaccinations', type='http', auth="public", website=True) |
|||
def portal_my_vaccine(self, **kw): |
|||
"""Function for rendering vaccination details of portal user""" |
|||
v_list = [] |
|||
for rec in request.env['hospital.vaccination'].sudo().search( |
|||
[('patient_id.user_ids.id', '=', request.uid)]): |
|||
request.env.cr.execute( |
|||
f"""SELECT id FROM ir_attachment WHERE res_id = {rec.id} |
|||
and res_model='hospital.vaccination' """) |
|||
attachment_id = False |
|||
attachment = request.env.cr.dictfetchall() |
|||
if attachment: |
|||
attachment_id = attachment[0]['id'] |
|||
data = { |
|||
'id': rec.id, |
|||
'name': rec.name, |
|||
'vaccine_date': rec.vaccine_date, |
|||
'dose': rec.dose, |
|||
'vaccine_product_id': rec.vaccine_product_id.name, |
|||
'vaccine_price': rec.vaccine_price, |
|||
'attachment_id': attachment_id |
|||
} |
|||
v_list.append(data) |
|||
values = { |
|||
'vaccinations': v_list, |
|||
'page_name': 'vaccination' |
|||
} |
|||
return request.render("base_hospital_management.portal_my_vaccines", |
|||
values) |
|||
|
|||
@http.route(['/my/tests'], type='http', auth="public", website=True) |
|||
def portal_my_tests(self, **kw): |
|||
"""Function for rendering tests of portal user""" |
|||
tests_list = [] |
|||
for rec in request.env['patient.lab.test'].sudo().search( |
|||
[('patient_id.user_ids', '=', request.uid)]): |
|||
request.env['account.move'].sudo().search( |
|||
[('ref', '=', rec.test_id.name) |
|||
], limit=1) |
|||
data = { |
|||
'id': rec.id, |
|||
'name': rec.test_id.name, |
|||
'date': rec.date |
|||
} |
|||
tests_list.append(data) |
|||
values = { |
|||
'tests': tests_list, |
|||
'page_name': 'lab_test' |
|||
} |
|||
return request.render("base_hospital_management.portal_my_tests", |
|||
values) |
|||
|
|||
@http.route('/my/tests/<int:test_id>', type="http", auth="public", |
|||
website=True) |
|||
def tests_view(self, test_id): |
|||
"""Function for rendering test results of portal user""" |
|||
result_list = [] |
|||
all_test = request.env['patient.lab.test'].sudo().browse(test_id) |
|||
test_result_ids = request.env['lab.test.result'].sudo().search( |
|||
[('id', 'in', all_test.result_ids.ids)]) |
|||
for rec in test_result_ids: |
|||
query = f"""SELECT id FROM ir_attachment WHERE res_id = {rec.id} |
|||
and res_model='lab.test.result' """ |
|||
request.env.cr.execute(query) |
|||
attachment_id = False |
|||
attachment = request.env.cr.dictfetchall() |
|||
if attachment: |
|||
attachment_id = attachment[0]['id'] |
|||
result_list.append({ |
|||
'id': rec.id, |
|||
'name': rec.test_id.name, |
|||
'result': rec.result, |
|||
'price': rec.price, |
|||
'attachment_id': attachment_id, |
|||
}) |
|||
values = { |
|||
'all_test_id': all_test.id, |
|||
'results': result_list, |
|||
'page_name': 'test_results' |
|||
} |
|||
return request.render( |
|||
"base_hospital_management.portal_my_tests_results", values) |
|||
|
|||
@http.route('/my/op', type='http', auth="public", |
|||
website=True) |
|||
def portal_my_op(self, **kw): |
|||
"""Function for rendering prescriptions of portal user""" |
|||
op = request.env['hospital.outpatient'].sudo().search_read( |
|||
[('patient_id.user_ids.id', '=', request.uid)], |
|||
['op_reference', 'op_date', 'doctor_id', 'slot', |
|||
'prescription_ids']) |
|||
for record in op: |
|||
hours = int(record['slot']) |
|||
minutes = int((record['slot'] - hours) * 60) |
|||
record['slot'] = '{:02d}:{:02d}'.format(hours, minutes) |
|||
values = { |
|||
'op': op, |
|||
'page_name': 'op' |
|||
} |
|||
return request.render( |
|||
"base_hospital_management.portal_my_op", values) |
@ -0,0 +1,15 @@ |
|||
<?xml version="1.0" encoding="utf-8"?> |
|||
<odoo> |
|||
<data noupdate="1"> |
|||
<!-- Scheduled action for checking blood bank availability--> |
|||
<record id="ir_cron_scheduler_blood_availability" model="ir.cron"> |
|||
<field name="name">Blood Bank Availability</field> |
|||
<field name="model_id" ref="model_blood_bank"/> |
|||
<field name="state">code</field> |
|||
<field name="code">model.action_change_availability()</field> |
|||
<field name="interval_number">3</field> |
|||
<field name="interval_type">months</field> |
|||
<field name="numbercall">-1</field> |
|||
</record> |
|||
</data> |
|||
</odoo> |
@ -0,0 +1,74 @@ |
|||
<?xml version="1.0" encoding="utf-8"?> |
|||
<odoo> |
|||
<data noupdate="1"> |
|||
<!-- Blood Bank sequence--> |
|||
<record id="blood_bank_sequence" model="ir.sequence"> |
|||
<field name="name">Blood Bank Sequence</field> |
|||
<field name="code">blood.bank</field> |
|||
<field name="prefix">BB/</field> |
|||
<field name="padding">3</field> |
|||
<field name="number_next">1</field> |
|||
<field name="number_increment">1</field> |
|||
</record> |
|||
<!-- Building sequence generator--> |
|||
<record id="building_sequence" model="ir.sequence"> |
|||
<field name="name">Building Sequence</field> |
|||
<field name="code">building.sequence</field> |
|||
<field name="prefix">BC/</field> |
|||
<field name="padding">3</field> |
|||
<field name="number_next">1</field> |
|||
<field name="number_increment">1</field> |
|||
</record> |
|||
<!-- Inpatient sequence generator--> |
|||
<record id="inpatient_sequence" model="ir.sequence"> |
|||
<field name="name">Inpatient sequence</field> |
|||
<field name="code">hospital.inpatient</field> |
|||
<field name="prefix">IN/PAT</field> |
|||
<field name="padding">3</field> |
|||
<field name="number_next">1</field> |
|||
<field name="number_increment">1</field> |
|||
</record> |
|||
<!-- Lab test sequence generator--> |
|||
<record id="seq_lab_test_line" model="ir.sequence"> |
|||
<field name="name">Lab Test Sequence</field> |
|||
<field name="code">lab.test.sequence</field> |
|||
<field name="prefix">LB/TS/</field> |
|||
<field name="padding">3</field> |
|||
<field name="number_next">1</field> |
|||
<field name="number_increment">1</field> |
|||
</record> |
|||
<!-- Lab test draft sequence--> |
|||
<record id="seq_hospital_draft_lab_test" model="ir.sequence"> |
|||
<field name="name">Lab Test Draft Sequence</field> |
|||
<field name="code">lab_tests.draft.sequence</field> |
|||
<field name="prefix">LB/DR/</field> |
|||
<field name="padding">3</field> |
|||
<field name="number_next">1</field> |
|||
<field name="number_increment">1</field> |
|||
</record> |
|||
<!-- Lab sequence generator--> |
|||
<record id="lab_sequence" model="ir.sequence"> |
|||
<field name="name">Laboratory Sequence</field> |
|||
<field name="code">laboratory.sequence</field> |
|||
<field name="prefix">LAB</field> |
|||
<field name="padding">3</field> |
|||
</record> |
|||
<!-- Patient sequence generator--> |
|||
<record id="patient_sequence" model="ir.sequence"> |
|||
<field name="name">Patient sequence</field> |
|||
<field name="code">patient.sequence</field> |
|||
<field name="prefix">PAT</field> |
|||
<field name="padding">3</field> |
|||
<field name="number_next">1</field> |
|||
<field name="number_increment">1</field> |
|||
</record> |
|||
<!-- Vaccination sequence generator--> |
|||
<record id="vaccination_sequence" |
|||
model="ir.sequence"> |
|||
<field name="name">Vaccination Sequence</field> |
|||
<field name="code">vaccination.sequence</field> |
|||
<field name="prefix">VAC</field> |
|||
<field name="padding">3</field> |
|||
</record> |
|||
</data> |
|||
</odoo> |
@ -0,0 +1,12 @@ |
|||
<?xml version="1.0" encoding="utf-8"?> |
|||
<odoo> |
|||
<data noupdate="1"> |
|||
<!-- Booking menu in Website--> |
|||
<record id="website_menu_patient_booking" model="website.menu"> |
|||
<field name="name">Booking</field> |
|||
<field name="url">/patient_booking</field> |
|||
<field name="parent_id" ref="website.main_menu"/> |
|||
<field name="sequence" type="int">50</field> |
|||
</record> |
|||
</data> |
|||
</odoo> |
@ -0,0 +1,24 @@ |
|||
<?xml version="1.0" encoding="utf-8"?> |
|||
<odoo> |
|||
<data noupdate="1"> |
|||
<!-- Adding job positions to demo data --> |
|||
<record id="job_position_doctor" model="hr.job"> |
|||
<field name="name">Doctor</field> |
|||
</record> |
|||
<record id="job_position_nurse" model="hr.job"> |
|||
<field name="name">Nurse</field> |
|||
</record> |
|||
<record id="job_position_receptionist" model="hr.job"> |
|||
<field name="name">Receptionist</field> |
|||
</record> |
|||
<record id="job_position_pharmacist" model="hr.job"> |
|||
<field name="name">Pharmacist</field> |
|||
</record> |
|||
<record id="job_position_staff" model="hr.job"> |
|||
<field name="name">Staff</field> |
|||
</record> |
|||
<record id="job_position_lab_technician" model="hr.job"> |
|||
<field name="name">Lab Technician</field> |
|||
</record> |
|||
</data> |
|||
</odoo> |
@ -0,0 +1,7 @@ |
|||
## Module <base_hospital_management> |
|||
|
|||
#### 03.06.2024 |
|||
#### Version 17.0.1.0.0 |
|||
#### ADD |
|||
|
|||
- Initial commit for Hospital Management Odoo 17 |
@ -0,0 +1,58 @@ |
|||
# -*- coding: utf-8 -*- |
|||
################################################################################ |
|||
# |
|||
# Cybrosys Technologies Pvt. Ltd. |
|||
# |
|||
# Copyright (C) 2024-TODAY Cybrosys Technologies(<https://www.cybrosys.com>). |
|||
# Author: Subina P (odoo@cybrosys.com) |
|||
# |
|||
# You can modify it under the terms of the GNU AFFERO |
|||
# GENERAL PUBLIC LICENSE (AGPL v3), Version 3. |
|||
# |
|||
# This program is distributed in the hope that it will be useful, |
|||
# but WITHOUT ANY WARRANTY; without even the implied warranty of |
|||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|||
# GNU AFFERO GENERAL PUBLIC LICENSE (AGPL v3) for more details. |
|||
# |
|||
# You should have received a copy of the GNU AFFERO GENERAL PUBLIC LICENSE |
|||
# (AGPL v3) along with this program. |
|||
# If not, see <http://www.gnu.org/licenses/>. |
|||
# |
|||
################################################################################ |
|||
from . import account_payment_register |
|||
from . import blood_bank |
|||
from . import blood_donation |
|||
from . import contra_indication |
|||
from . import doctor_allocation |
|||
from . import doctor_round |
|||
from . import doctor_slot |
|||
from . import doctor_specialization |
|||
from . import hospital_bed |
|||
from . import hospital_building |
|||
from . import hospital_degree |
|||
from . import hospital_family |
|||
from . import hospital_inpatient |
|||
from . import hospital_insurance |
|||
from . import hospital_laboratory |
|||
from . import hospital_outpatient |
|||
from . import hospital_pharmacy |
|||
from . import hospital_vaccination |
|||
from . import hospital_ward |
|||
from . import hr_employee |
|||
from . import inpatient_payment |
|||
from . import inpatient_surgery |
|||
from . import ir_attachment |
|||
from . import lab_medicine_line |
|||
from . import lab_test |
|||
from . import lab_test_line |
|||
from . import lab_test_result |
|||
from . import medicine_brand |
|||
from . import nursing_plan |
|||
from . import patient_lab_test |
|||
from . import patient_room |
|||
from . import pharmacy_medicine |
|||
from . import prescription_line |
|||
from . import product_template |
|||
from . import res_partner |
|||
from . import res_users |
|||
from . import room_facility |
@ -0,0 +1,42 @@ |
|||
# -*- coding: utf-8 -*- |
|||
################################################################################ |
|||
# |
|||
# Cybrosys Technologies Pvt. Ltd. |
|||
# |
|||
# Copyright (C) 2024-TODAY Cybrosys Technologies(<https://www.cybrosys.com>). |
|||
# Author: Subina P (odoo@cybrosys.com) |
|||
# |
|||
# You can modify it under the terms of the GNU AFFERO |
|||
# GENERAL PUBLIC LICENSE (AGPL v3), Version 3. |
|||
# |
|||
# This program is distributed in the hope that it will be useful, |
|||
# but WITHOUT ANY WARRANTY; without even the implied warranty of |
|||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|||
# GNU AFFERO GENERAL PUBLIC LICENSE (AGPL v3) for more details. |
|||
# |
|||
# You should have received a copy of the GNU AFFERO GENERAL PUBLIC LICENSE |
|||
# (AGPL v3) along with this program. |
|||
# If not, see <http://www.gnu.org/licenses/>. |
|||
# |
|||
################################################################################ |
|||
from odoo import api, models |
|||
|
|||
|
|||
class AccountPaymentRegister(models.TransientModel): |
|||
""" |
|||
Adding inpatient field to invoicing model. |
|||
""" |
|||
_inherit = "account.payment.register" |
|||
|
|||
@api.model |
|||
def create(self, vals_list): |
|||
"""Create records to inpatient payment""" |
|||
self.env['inpatient.payment'].sudo().create({ |
|||
'name': vals_list['communication'], |
|||
'subtotal': vals_list['amount'], |
|||
'inpatient_id': self.env['hospital.inpatient'].sudo().search([( |
|||
'patient_id', '=', vals_list['partner_id'])], |
|||
order='create_date desc', limit=1).id, |
|||
'date': vals_list['payment_date'] |
|||
}) |
|||
return super().create(vals_list) |
@ -0,0 +1,101 @@ |
|||
# -*- coding: utf-8 -*- |
|||
################################################################################ |
|||
# |
|||
# Cybrosys Technologies Pvt. Ltd. |
|||
# |
|||
# Copyright (C) 2024-TODAY Cybrosys Technologies(<https://www.cybrosys.com>). |
|||
# Author: Subina P (odoo@cybrosys.com) |
|||
# |
|||
# You can modify it under the terms of the GNU AFFERO |
|||
# GENERAL PUBLIC LICENSE (AGPL v3), Version 3. |
|||
# |
|||
# This program is distributed in the hope that it will be useful, |
|||
# but WITHOUT ANY WARRANTY; without even the implied warranty of |
|||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|||
# GNU AFFERO GENERAL PUBLIC LICENSE (AGPL v3) for more details. |
|||
# |
|||
# You should have received a copy of the GNU AFFERO GENERAL PUBLIC LICENSE |
|||
# (AGPL v3) along with this program. |
|||
# If not, see <http://www.gnu.org/licenses/>. |
|||
# |
|||
################################################################################ |
|||
from odoo import api, fields, models |
|||
|
|||
|
|||
class BloodBank(models.Model): |
|||
"""Class holding Blood bank details""" |
|||
_name = 'blood.bank' |
|||
_description = "Blood Bank" |
|||
|
|||
partner_id = fields.Many2one('res.partner', |
|||
string='Donor Name', |
|||
domain=[('patient_seq', 'not in', |
|||
['New', 'Employee', 'User'])], |
|||
help='Name of the blood donor', |
|||
required=True) |
|||
name = fields.Char(string='Sequence', |
|||
help='Sequence number indicating the blood bank', |
|||
index=True, |
|||
default=lambda self: 'New') |
|||
date = fields.Date(string='Date', help='Blood donating date', |
|||
default=fields.Date.today()) |
|||
blood_type = fields.Selection([('a_positive', 'A+'), |
|||
('a_negative', 'A-'), |
|||
('b_positive', 'B+'), ('b_negative', 'B-'), |
|||
('o_positive', 'O+'), ('o_negative', '0-'), |
|||
('ab_positive', 'AB+'), |
|||
('ab_negative', 'AB-')], |
|||
string='Blood Group', |
|||
help='Choose your blood group', required=True, |
|||
group_expand='_group_expand_states') |
|||
blood_donation_ids = fields.One2many('blood.donation', |
|||
'blood_bank_id', |
|||
string='Contra Indications', |
|||
help='Lists all the ' |
|||
'contraindications') |
|||
state = fields.Selection([('avail', 'Available'), |
|||
('not', 'Unavailable')], |
|||
string='State', help='State of the blood donation', |
|||
readonly=True, default="avail") |
|||
assigned_patient_id = fields.Many2one('res.partner', |
|||
string='Receiver', |
|||
domain=[('patient_seq', 'not in', |
|||
['New', 'Employee', |
|||
'User'])], |
|||
help='Choose the patient to whom ' |
|||
'blood is donating') |
|||
|
|||
@api.model |
|||
def create(self, vals): |
|||
"""Function for creating blood sequence number""" |
|||
if vals.get('name', 'New') == 'New': |
|||
vals['name'] = self.env['ir.sequence'].next_by_code( |
|||
'blood.bank') or 'New' |
|||
return super().create(vals) |
|||
|
|||
@api.onchange('partner_id') |
|||
def _onchange_partner_id(self): |
|||
"""Function for listing all contra indications""" |
|||
self.blood_donation_ids = False |
|||
self.sudo().write({ |
|||
'blood_donation_ids': [(0, 0, { |
|||
'questions': rec.blood_donation_question}) |
|||
for rec in |
|||
self.env['contra.indication'].sudo().search( |
|||
[])]}) |
|||
|
|||
def _group_expand_states(self, states, domain, order): |
|||
"""Method for expanding all blood groups in kanban view""" |
|||
return [key for key, val in type(self).blood_type.selection] |
|||
|
|||
def action_blood_available(self): |
|||
"""Change the state to unavailable""" |
|||
self.sudo().write({ |
|||
'state': 'not' |
|||
}) |
|||
|
|||
def action_change_availability(self): |
|||
"""Cron action for changing the state of the record""" |
|||
for rec in self.sudo().search([]): |
|||
if rec.date <= fields.Date.subtract(fields.Date.today(), months=1): |
|||
rec.state = 'avail' |
@ -0,0 +1,38 @@ |
|||
# -*- coding: utf-8 -*- |
|||
################################################################################ |
|||
# |
|||
# Cybrosys Technologies Pvt. Ltd. |
|||
# |
|||
# Copyright (C) 2024-TODAY Cybrosys Technologies(<https://www.cybrosys.com>). |
|||
# Author: Subina P (odoo@cybrosys.com) |
|||
# |
|||
# You can modify it under the terms of the GNU AFFERO |
|||
# GENERAL PUBLIC LICENSE (AGPL v3), Version 3. |
|||
# |
|||
# This program is distributed in the hope that it will be useful, |
|||
# but WITHOUT ANY WARRANTY; without even the implied warranty of |
|||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|||
# GNU AFFERO GENERAL PUBLIC LICENSE (AGPL v3) for more details. |
|||
# |
|||
# You should have received a copy of the GNU AFFERO GENERAL PUBLIC LICENSE |
|||
# (AGPL v3) along with this program. |
|||
# If not, see <http://www.gnu.org/licenses/>. |
|||
# |
|||
################################################################################ |
|||
from odoo import fields, models |
|||
|
|||
|
|||
class BloodDonation(models.Model): |
|||
"""Class holding blood donation details""" |
|||
_name = 'blood.donation' |
|||
_description = 'Blood Donation' |
|||
_rec_name = 'questions' |
|||
|
|||
questions = fields.Text(string='Contra Indications', |
|||
help='Contraindications of the blood donor') |
|||
is_true = fields.Boolean(string='Is True', |
|||
help='True for contraindications') |
|||
blood_bank_id = fields.Many2one('blood.bank', |
|||
string='Blood Bank', |
|||
help='Blood bank corresponding to the ' |
|||
'donor') |
@ -0,0 +1,33 @@ |
|||
# -*- coding: utf-8 -*- |
|||
################################################################################ |
|||
# |
|||
# Cybrosys Technologies Pvt. Ltd. |
|||
# |
|||
# Copyright (C) 2024-TODAY Cybrosys Technologies(<https://www.cybrosys.com>). |
|||
# Author: Subina P (odoo@cybrosys.com) |
|||
# |
|||
# You can modify it under the terms of the GNU AFFERO |
|||
# GENERAL PUBLIC LICENSE (AGPL v3), Version 3. |
|||
# |
|||
# This program is distributed in the hope that it will be useful, |
|||
# but WITHOUT ANY WARRANTY; without even the implied warranty of |
|||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|||
# GNU AFFERO GENERAL PUBLIC LICENSE (AGPL v3) for more details. |
|||
# |
|||
# You should have received a copy of the GNU AFFERO GENERAL PUBLIC LICENSE |
|||
# (AGPL v3) along with this program. |
|||
# If not, see <http://www.gnu.org/licenses/>. |
|||
# |
|||
################################################################################ |
|||
from odoo import fields, models |
|||
|
|||
|
|||
class ContraIndication(models.Model): |
|||
"""Class holding the contra indications""" |
|||
_name = 'contra.indication' |
|||
_description = 'Contra Indication' |
|||
_rec_name = 'blood_donation_question' |
|||
|
|||
blood_donation_question = fields.Text(string='Contra Indications', |
|||
help='Contra indications of the ' |
|||
'blood donor') |
@ -0,0 +1,220 @@ |
|||
# -*- coding: utf-8 -*- |
|||
################################################################################ |
|||
# |
|||
# Cybrosys Technologies Pvt. Ltd. |
|||
# |
|||
# Copyright (C) 2024-TODAY Cybrosys Technologies(<https://www.cybrosys.com>). |
|||
# Author: Subina P (odoo@cybrosys.com) |
|||
# |
|||
# You can modify it under the terms of the GNU AFFERO |
|||
# GENERAL PUBLIC LICENSE (AGPL v3), Version 3. |
|||
# |
|||
# This program is distributed in the hope that it will be useful, |
|||
# but WITHOUT ANY WARRANTY; without even the implied warranty of |
|||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|||
# GNU AFFERO GENERAL PUBLIC LICENSE (AGPL v3) for more details. |
|||
# |
|||
# You should have received a copy of the GNU AFFERO GENERAL PUBLIC LICENSE |
|||
# (AGPL v3) along with this program. |
|||
# If not, see <http://www.gnu.org/licenses/>. |
|||
# |
|||
################################################################################ |
|||
from odoo import api, fields, models |
|||
from odoo.exceptions import ValidationError |
|||
|
|||
|
|||
class DoctorAllocation(models.Model): |
|||
"""Class holding doctor allocations""" |
|||
_name = 'doctor.allocation' |
|||
_description = 'Doctor Allocation' |
|||
|
|||
doctor_id = fields.Many2one('hr.employee', string="Doctor", |
|||
help='Name of the doctor', |
|||
domain=[('job_id.name', '=', 'Doctor')]) |
|||
name = fields.Char(string="Name", readonly=True, default='New', |
|||
help='Name of the allocation') |
|||
department_id = fields.Many2one(string='Department', |
|||
help='Department of the doctor', |
|||
related='doctor_id.department_id') |
|||
op_ids = fields.One2many('hospital.outpatient', |
|||
'doctor_id', |
|||
string='Booking', |
|||
help='Patient booking belongs to this ' |
|||
'allocation') |
|||
company_id = fields.Many2one('res.company', string='Company', |
|||
default=lambda self: self.env.company.id, |
|||
help='Indicates the company') |
|||
is_doctor = fields.Boolean(string='Is Doctor', help='True for doctors.') |
|||
date = fields.Date(string='Date', |
|||
help='Indicate the allocated date for a doctor', |
|||
default=fields.Date.today()) |
|||
work_to = fields.Float(string='Work To', required=True, |
|||
help='Allocation time ending time in 24 hrs format') |
|||
work_from = fields.Float(string='Work From', required=True, |
|||
help='Allocation time starting time in 24 hrs ' |
|||
'format') |
|||
time_avg = fields.Float(string='Duration', help="Average Consultation time " |
|||
"per Patient in minutes", |
|||
readonly=False, |
|||
related='doctor_id.time_avg') |
|||
patient_type = fields.Selection([('inpatient', 'Inpatient'), |
|||
('outpatient', 'Outpatient')], |
|||
string='Patient Type', |
|||
help='Indicates the type of patient') |
|||
patient_limit = fields.Integer(string='Limit Patient', |
|||
help='Maximum number of patients allowed ' |
|||
'per allocation', store=True, |
|||
compute='_compute_patient_limit', ) |
|||
patient_count = fields.Integer(string='Patient Count', |
|||
help='Number of patient under ' |
|||
'this allocation', |
|||
compute='_compute_patient_count') |
|||
slot_remaining = fields.Integer(string='Slots Remaining', |
|||
help='Number of slots remaining in this' |
|||
' allocation', store=True, |
|||
compute='_compute_slot_remaining') |
|||
latest_slot = fields.Float(string='Available Slot', |
|||
help='Indicates the latest available slot') |
|||
state = fields.Selection( |
|||
[('draft', 'Draft'), ('confirm', 'Confirmed'), |
|||
('cancel', 'Cancelled')], |
|||
default='draft', string='State', help='State of Doctor allocation') |
|||
|
|||
@api.model |
|||
def create(self, vals): |
|||
"""Method for creating name""" |
|||
work_from_hr = int(vals['work_from']) |
|||
work_from_min = int((vals['work_from'] - work_from_hr) * 60) |
|||
work_from = "{:02d}:{:02d}".format(work_from_hr, work_from_min) |
|||
work_to_hr = int(vals['work_to']) |
|||
work_to_min = int((vals['work_to'] - work_to_hr) * 60) |
|||
work_to = "{:02d}:{:02d}".format(work_to_hr, work_to_min) |
|||
doctor_group = self.env.ref( |
|||
'base_hospital_management.base_hospital_management_group_doctor') |
|||
if doctor_group in self.env.user.groups_id: |
|||
default_doctor_id = self.env['hr.employee'].sudo().search( |
|||
[('user_id', '=', self.env.user.id)], limit=1) |
|||
if default_doctor_id: |
|||
vals[ |
|||
'name'] = (default_doctor_id.name + ': ' + work_from + '-' |
|||
+ work_to) |
|||
else: |
|||
vals['name'] = self.env['hr.employee'].sudo().browse( |
|||
vals['doctor_id']).name + ': ' + work_from + '-' + work_to |
|||
return super().create(vals) |
|||
|
|||
@api.onchange('work_from', 'work_to') |
|||
def _onchange_work_from(self): |
|||
"""Method for calculating name""" |
|||
if self.work_from and self.work_to: |
|||
work_from_hr = int(self.work_from) |
|||
work_from_min = int((self.work_from - work_from_hr) * 60) |
|||
work_from = "{:02d}:{:02d}".format(work_from_hr, work_from_min) |
|||
work_to_hr = int(self.work_to) |
|||
work_to_min = int((self.work_to - work_to_hr) * 60) |
|||
work_to = "{:02d}:{:02d}".format(work_to_hr, work_to_min) |
|||
self.name = str(self.doctor_id.name) + ': ' + work_from + '-' + work_to |
|||
|
|||
@api.model |
|||
def default_get(self, doctor_id): |
|||
"""Method for making doctor field readonly and applying default value |
|||
for doctor login""" |
|||
res = super().default_get(doctor_id) |
|||
doctor_group = self.env.ref( |
|||
'base_hospital_management.base_hospital_management_group_doctor') |
|||
if doctor_group in self.env.user.groups_id: |
|||
default_doctor_id = self.env['hr.employee'].sudo().search( |
|||
[('user_id', '=', self.env.user.id)], limit=1) |
|||
if default_doctor_id: |
|||
res['doctor_id'] = default_doctor_id.id |
|||
res['is_doctor'] = True |
|||
self.is_doctor = True |
|||
else: |
|||
self.is_doctor = False |
|||
res['is_doctor'] = False |
|||
return res |
|||
|
|||
@api.constrains('work_from', 'work_to', 'date') |
|||
def _check_overlap(self): |
|||
"""Method for checking overlapping""" |
|||
for allocation in self: |
|||
if allocation.work_from >= allocation.work_to: |
|||
raise ValidationError("Work From must be less than Work To.") |
|||
overlapping_allocations = self.sudo().search([ |
|||
('id', '!=', allocation.id), |
|||
('date', '=', allocation.date), |
|||
('doctor_id', '=', allocation.doctor_id.id), |
|||
'|', |
|||
'&', ('work_from', '<=', allocation.work_from), |
|||
('work_to', '>=', allocation.work_from), |
|||
'&', ('work_from', '<=', allocation.work_to), |
|||
('work_to', '>=', allocation.work_to) |
|||
]) |
|||
if overlapping_allocations: |
|||
raise ValidationError( |
|||
"Overlap detected with another doctor allocation on the " |
|||
"same date.") |
|||
|
|||
@api.depends('work_from', 'work_to', 'time_avg') |
|||
def _compute_patient_limit(self): |
|||
"""Method for computing patient limit""" |
|||
for record in self: |
|||
if (record.work_from and record.work_to and record.time_avg |
|||
and record.time_avg > 0): |
|||
patient_slots = int( |
|||
(record.work_to - record.work_from) / record.time_avg) |
|||
if patient_slots <= 0: |
|||
raise ValidationError( |
|||
"Work From must be less than Work To.") |
|||
else: |
|||
record.patient_limit = patient_slots |
|||
else: |
|||
record.patient_limit = 10 |
|||
|
|||
@api.depends('op_ids') |
|||
def _compute_patient_count(self): |
|||
"""Method for computing patient count""" |
|||
for rec in self: |
|||
rec.patient_count = len(rec.op_ids) |
|||
|
|||
@api.depends('op_ids', 'patient_count', 'patient_limit') |
|||
def _compute_slot_remaining(self): |
|||
"""Method for computing slot remaining""" |
|||
for rec in self: |
|||
rec.slot_remaining = rec.patient_limit - rec.patient_count |
|||
|
|||
def action_get_patient_booking(self): |
|||
"""Returns form view of bed""" |
|||
return { |
|||
'name': "Patient Booking", |
|||
'type': 'ir.actions.act_window', |
|||
'view_mode': 'tree,form', |
|||
'res_model': 'hospital.outpatient', |
|||
'domain': [('id', 'in', self.op_ids.ids)], |
|||
'context': {'create': False} |
|||
} |
|||
|
|||
def action_confirm_allocation(self): |
|||
"""Confirmation of allocation""" |
|||
self.state = 'confirm' |
|||
|
|||
def action_cancel_allocation(self): |
|||
"""Method for cancelling a allocation""" |
|||
self.state = 'cancel' |
|||
|
|||
@api.model |
|||
def get_allocation_lines(self): |
|||
"""Returns allocated hour details to display on the dashboard""" |
|||
data_list = [] |
|||
allocated_hour = self.sudo().search([ |
|||
('doctor_id.user_id', '=', self.env.user.id) |
|||
]) |
|||
for rec in allocated_hour: |
|||
data_list.append({ |
|||
'date': rec.date, |
|||
'name': rec.name, |
|||
'patient_type': rec.patient_type, |
|||
'patient_limit': rec.patient_limit, |
|||
'patient_count': rec.patient_count |
|||
}) |
|||
return data_list |
@ -0,0 +1,39 @@ |
|||
# -*- coding: utf-8 -*- |
|||
################################################################################ |
|||
# |
|||
# Cybrosys Technologies Pvt. Ltd. |
|||
# |
|||
# Copyright (C) 2024-TODAY Cybrosys Technologies(<https://www.cybrosys.com>). |
|||
# Author: Subina P (odoo@cybrosys.com) |
|||
# |
|||
# You can modify it under the terms of the GNU AFFERO |
|||
# GENERAL PUBLIC LICENSE (AGPL v3), Version 3. |
|||
# |
|||
# This program is distributed in the hope that it will be useful, |
|||
# but WITHOUT ANY WARRANTY; without even the implied warranty of |
|||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|||
# GNU AFFERO GENERAL PUBLIC LICENSE (AGPL v3) for more details. |
|||
# |
|||
# You should have received a copy of the GNU AFFERO GENERAL PUBLIC LICENSE |
|||
# (AGPL v3) along with this program. |
|||
# If not, see <http://www.gnu.org/licenses/>. |
|||
# |
|||
################################################################################ |
|||
from odoo import fields, models |
|||
|
|||
|
|||
class DoctorRound(models.Model): |
|||
"""Class holding doctor round details""" |
|||
_name = 'doctor.round' |
|||
_description = "Doctor Rounds" |
|||
|
|||
admission_id = fields.Many2one('hospital.inpatient', |
|||
string='Patient', |
|||
help='Choose the patient') |
|||
doctor_id = fields.Many2one('hr.employee', |
|||
domain=[('job_id.name', '=', 'Doctor')], |
|||
string='Doctor', help='Choose your doctor') |
|||
date = fields.Datetime(string='Visit Time', help='Choose the visit time ' |
|||
'of doctor') |
|||
status = fields.Char(string='Status', help='Status of doctor rounds') |
|||
notes = fields.Text(string='Note', help='Notes regarding the rounds') |
@ -0,0 +1,128 @@ |
|||
# -*- coding: utf-8 -*- |
|||
################################################################################ |
|||
# |
|||
# Cybrosys Technologies Pvt. Ltd. |
|||
# |
|||
# Copyright (C) 2024-TODAY Cybrosys Technologies(<https://www.cybrosys.com>). |
|||
# Author: Subina P (odoo@cybrosys.com) |
|||
# |
|||
# You can modify it under the terms of the GNU AFFERO |
|||
# GENERAL PUBLIC LICENSE (AGPL v3), Version 3. |
|||
# |
|||
# This program is distributed in the hope that it will be useful, |
|||
# but WITHOUT ANY WARRANTY; without even the implied warranty of |
|||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|||
# GNU AFFERO GENERAL PUBLIC LICENSE (AGPL v3) for more details. |
|||
# |
|||
# You should have received a copy of the GNU AFFERO GENERAL PUBLIC LICENSE |
|||
# (AGPL v3) along with this program. |
|||
# If not, see <http://www.gnu.org/licenses/>. |
|||
# |
|||
################################################################################ |
|||
from odoo import fields, models |
|||
|
|||
|
|||
class DoctorSlot(models.Model): |
|||
"""Model for handling a doctor's slot for surgery""" |
|||
_name = 'doctor.slot' |
|||
_description = "Doctor Slot" |
|||
_inherit = ["mail.thread", "mail.activity.mixin"] |
|||
|
|||
doctor_id = fields.Many2one('hr.employee', string="Doctor", |
|||
help='Doctors name', |
|||
domain=[('job_id.name', '=', 'Doctor')]) |
|||
date_start = fields.Datetime(default=fields.Date.today(), string='Date', |
|||
help='Date of surgery') |
|||
patient_id = fields.Many2one('res.partner', |
|||
domain=[('patient_seq', 'not in', |
|||
['New', 'Employee', 'User'])], |
|||
string='Patient', help='Name of the patient') |
|||
name = fields.Char(string='Surgery', help='Name of surgery') |
|||
state = fields.Selection([('confirmed', 'Confirmed'), |
|||
('cancel', 'Cancel'), |
|||
('done', 'Done'), |
|||
('draft', 'Draft')], default='draft', |
|||
string='State', help='State of the slot') |
|||
time = fields.Float(string='Time', help='Time of surgery') |
|||
hours_to_take = fields.Float(string='Duration', |
|||
help='Time duration for the surgery') |
|||
company_id = fields.Many2one('res.company', string='Company', |
|||
default=lambda self: self.env.company.id) |
|||
|
|||
def hospital_inpatient_confirm(self): |
|||
"""Inpatient confirmation from Doctor's dashboard""" |
|||
data_list = [] |
|||
for rec in self.env['doctor.slot'].sudo().search( |
|||
[('doctor_id.user_id', '=', self.env.user.id), |
|||
('state', '=', 'confirmed')]): |
|||
data_list.append({ |
|||
'id': rec.id, |
|||
'planned_date': rec.date_start, |
|||
'patient_id': rec.patient_id.name, |
|||
'name': rec.name, |
|||
'state': rec.state |
|||
}) |
|||
return data_list |
|||
|
|||
def hospital_inpatient_cancel(self): |
|||
"""Inpatients cancellation from Doctor's dashboard""" |
|||
data_list = [] |
|||
for rec in self.env['doctor.slot'].sudo().search( |
|||
[('doctor_id.user_id', '=', self.env.user.id), |
|||
('state', '=', 'cancel')]): |
|||
data_list.append({ |
|||
'id': rec.id, |
|||
'planned_date': rec.date_start, |
|||
'patient_id': rec.patient_id.name, |
|||
'name': rec.name, |
|||
'state': rec.state |
|||
}) |
|||
return data_list |
|||
|
|||
def hospital_inpatient_done(self): |
|||
"""Inpatient done function from doctor's dashboard""" |
|||
data_list = [] |
|||
for rec in self.env['doctor.slot'].sudo().search( |
|||
[('doctor_id.user_id', '=', self.env.user.id), |
|||
('state', '=', 'done')]): |
|||
data_list.append({ |
|||
'id': rec.id, |
|||
'planned_date': rec.date_start, |
|||
'patient_id': rec.patient_id.name, |
|||
'name': rec.name, |
|||
'state': rec.state |
|||
}) |
|||
return data_list |
|||
|
|||
def action_get_doctor_slot(self): |
|||
"""Function for returning doctor's slot to doctor's dashboard""" |
|||
data_list = [] |
|||
for rec in self.sudo().search( |
|||
[('doctor_id.user_id', '=', self.env.user.id), |
|||
('state', '=', 'draft')]): |
|||
data_list.append({ |
|||
'id': rec.id, |
|||
'planned_date': rec.date_start, |
|||
'patient_id': rec.patient_id.patient_seq, |
|||
'name': rec.name, |
|||
'state': rec.state |
|||
}) |
|||
return data_list |
|||
|
|||
def action_confirm(self): |
|||
"""Function for confirming a slot""" |
|||
self.sudo().write({ |
|||
'state': 'confirmed' |
|||
}) |
|||
|
|||
def action_cancel(self): |
|||
"""Function for cancelling a slot""" |
|||
self.sudo().write({ |
|||
'state': 'cancel' |
|||
}) |
|||
|
|||
def action_done(self): |
|||
"""Function for change the state to done""" |
|||
self.sudo().write({ |
|||
'state': 'done' |
|||
}) |
@ -0,0 +1,32 @@ |
|||
# -*- coding: utf-8 -*- |
|||
################################################################################ |
|||
# |
|||
# Cybrosys Technologies Pvt. Ltd. |
|||
# |
|||
# Copyright (C) 2024-TODAY Cybrosys Technologies(<https://www.cybrosys.com>). |
|||
# Author: Subina P (odoo@cybrosys.com) |
|||
# |
|||
# You can modify it under the terms of the GNU AFFERO |
|||
# GENERAL PUBLIC LICENSE (AGPL v3), Version 3. |
|||
# |
|||
# This program is distributed in the hope that it will be useful, |
|||
# but WITHOUT ANY WARRANTY; without even the implied warranty of |
|||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|||
# GNU AFFERO GENERAL PUBLIC LICENSE (AGPL v3) for more details. |
|||
# |
|||
# You should have received a copy of the GNU AFFERO GENERAL PUBLIC LICENSE |
|||
# (AGPL v3) along with this program. |
|||
# If not, see <http://www.gnu.org/licenses/>. |
|||
# |
|||
################################################################################ |
|||
from odoo import fields, models |
|||
|
|||
|
|||
class DoctorSpecialization(models.Model): |
|||
"""Class holding doctor's specializations""" |
|||
_name = 'doctor.specialization' |
|||
_description = 'Doctor Specialization' |
|||
_rec_name = 'specialization' |
|||
|
|||
specialization = fields.Char(string="Specialization", |
|||
help='Specify the name of specialization') |
@ -0,0 +1,59 @@ |
|||
# -*- coding: utf-8 -*- |
|||
################################################################################ |
|||
# |
|||
# Cybrosys Technologies Pvt. Ltd. |
|||
# |
|||
# Copyright (C) 2024-TODAY Cybrosys Technologies(<https://www.cybrosys.com>). |
|||
# Author: Subina P (odoo@cybrosys.com) |
|||
# |
|||
# You can modify it under the terms of the GNU AFFERO |
|||
# GENERAL PUBLIC LICENSE (AGPL v3), Version 3. |
|||
# |
|||
# This program is distributed in the hope that it will be useful, |
|||
# but WITHOUT ANY WARRANTY; without even the implied warranty of |
|||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|||
# GNU AFFERO GENERAL PUBLIC LICENSE (AGPL v3) for more details. |
|||
# |
|||
# You should have received a copy of the GNU AFFERO GENERAL PUBLIC LICENSE |
|||
# (AGPL v3) along with this program. |
|||
# If not, see <http://www.gnu.org/licenses/>. |
|||
# |
|||
################################################################################ |
|||
from odoo import fields, models |
|||
|
|||
|
|||
class HospitalBed(models.Model): |
|||
"""Class holding hospital bed details""" |
|||
_name = 'hospital.bed' |
|||
_description = 'Beds' |
|||
|
|||
_sql_constraints = [('unique_room', 'unique (name)', |
|||
'Bed number should be unique!')] |
|||
name = fields.Char(string="Bed Number", help='Indicates the unique ' |
|||
'number for a bed', |
|||
required=True) |
|||
bed_type = fields.Selection([('gatch', 'Gatch Bed'), |
|||
('electric', 'Electric'), |
|||
('stretcher', 'Stretcher'), |
|||
('low', 'Low Bed'), |
|||
('air', 'Low Air Loss'), |
|||
('circo', 'Circo Electric'), |
|||
('clinitron', 'Clinitron'), |
|||
], string="Type", help='Type of bed') |
|||
note = fields.Text(string="Notes", help='Notes regarding bed') |
|||
ward_id = fields.Many2one('hospital.ward', string="Ward", |
|||
help='Indicates the ward to which the bed' |
|||
' belongs to') |
|||
room_id = fields.Many2one('patient.room', string="Room", |
|||
help='Indicates the room to which the bed' |
|||
' belongs to') |
|||
currency_id = fields.Many2one('res.currency', string='Currency', |
|||
help='Currency in which bed rent calculates', |
|||
default=lambda self: |
|||
self.env.user.company_id.currency_id.id, |
|||
required=True) |
|||
bed_rent = fields.Monetary(string='Rent', help="The charge for the bed") |
|||
state = fields.Selection([('avail', 'Available'), ('not', 'Unavailable')], |
|||
string='State', readonly=True, |
|||
help='State of the bed', |
|||
default="avail") |
@ -0,0 +1,87 @@ |
|||
# -*- coding: utf-8 -*- |
|||
################################################################################ |
|||
# |
|||
# Cybrosys Technologies Pvt. Ltd. |
|||
# |
|||
# Copyright (C) 2024-TODAY Cybrosys Technologies(<https://www.cybrosys.com>). |
|||
# Author: Subina P (odoo@cybrosys.com) |
|||
# |
|||
# You can modify it under the terms of the GNU AFFERO |
|||
# GENERAL PUBLIC LICENSE (AGPL v3), Version 3. |
|||
# |
|||
# This program is distributed in the hope that it will be useful, |
|||
# but WITHOUT ANY WARRANTY; without even the implied warranty of |
|||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|||
# GNU AFFERO GENERAL PUBLIC LICENSE (AGPL v3) for more details. |
|||
# |
|||
# You should have received a copy of the GNU AFFERO GENERAL PUBLIC LICENSE |
|||
# (AGPL v3) along with this program. |
|||
# If not, see <http://www.gnu.org/licenses/>. |
|||
# |
|||
################################################################################ |
|||
from odoo import api, fields, models |
|||
|
|||
|
|||
class HospitalBuilding(models.Model): |
|||
"""Class containing field and functions related to hospital building""" |
|||
_name = 'hospital.building' |
|||
_description = 'Buildings' |
|||
|
|||
notes = fields.Text(string='Notes', help='Notes regarding the building') |
|||
name = fields.Char(string='Block Code', |
|||
help='Code for uniquely identifying a block', |
|||
copy=False, readonly=True, index=True, |
|||
default=lambda self: 'New') |
|||
phone = fields.Char(string='Phone', |
|||
help='Phone number for contact the building') |
|||
mobile = fields.Char(string='Mobile', |
|||
help='Mobile number for contact the building') |
|||
email = fields.Char(string='Email', help='Email of the building') |
|||
room_count = fields.Integer(string="Rooms", |
|||
help='Number of rooms in the building', |
|||
compute="_compute_room_count") |
|||
ward_count = fields.Integer(string="Wards", |
|||
help='Number of wards in the building', |
|||
compute="_compute_ward_count") |
|||
|
|||
@api.model |
|||
def create(self, vals): |
|||
"""Create building sequence""" |
|||
if vals.get('name', 'New') == 'New': |
|||
vals['name'] = self.env['ir.sequence'].next_by_code( |
|||
'building.sequence') or 'New' |
|||
return super().create(vals) |
|||
|
|||
def _compute_room_count(self): |
|||
"""Calculates room_count in a building""" |
|||
for rec in self: |
|||
rec.room_count = self.env['patient.room'].sudo().search_count([( |
|||
'building_id', '=', rec.id)]) |
|||
|
|||
def _compute_ward_count(self): |
|||
"""Counting wards in the building""" |
|||
for rec in self: |
|||
rec.ward_count = self.env['hospital.ward'].sudo().search_count([( |
|||
'building_id', '=', rec.id)]) |
|||
|
|||
def get_room_count(self): |
|||
"""Smart button action for viewing all rooms in a building""" |
|||
return { |
|||
'name': 'Room', |
|||
'domain': [('building_id', '=', self.id)], |
|||
'type': 'ir.actions.act_window', |
|||
'res_model': 'patient.room', |
|||
'view_mode': 'tree,form', |
|||
'context': {'create': False}, |
|||
} |
|||
|
|||
def get_ward_count(self): |
|||
"""Smart button action for viewing all wards in a building""" |
|||
return { |
|||
'name': 'Wards', |
|||
'domain': [('building_id', '=', self.id)], |
|||
'type': 'ir.actions.act_window', |
|||
'res_model': 'hospital.ward', |
|||
'view_mode': 'tree,form', |
|||
'context': {'create': False}, |
|||
} |
@ -0,0 +1,30 @@ |
|||
# -*- coding: utf-8 -*- |
|||
################################################################################ |
|||
# |
|||
# Cybrosys Technologies Pvt. Ltd. |
|||
# |
|||
# Copyright (C) 2024-TODAY Cybrosys Technologies(<https://www.cybrosys.com>). |
|||
# Author: Subina P (odoo@cybrosys.com) |
|||
# |
|||
# You can modify it under the terms of the GNU AFFERO |
|||
# GENERAL PUBLIC LICENSE (AGPL v3), Version 3. |
|||
# |
|||
# This program is distributed in the hope that it will be useful, |
|||
# but WITHOUT ANY WARRANTY; without even the implied warranty of |
|||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|||
# GNU AFFERO GENERAL PUBLIC LICENSE (AGPL v3) for more details. |
|||
# |
|||
# You should have received a copy of the GNU AFFERO GENERAL PUBLIC LICENSE |
|||
# (AGPL v3) along with this program. |
|||
# If not, see <http://www.gnu.org/licenses/>. |
|||
# |
|||
################################################################################ |
|||
from odoo import fields, models |
|||
|
|||
|
|||
class HospitalDegree(models.Model): |
|||
"""Class holding degree details of Doctor""" |
|||
_name = 'hospital.degree' |
|||
_description = 'Degree' |
|||
|
|||
name = fields.Char(string="Degree", help='Degree of the staff') |
@ -0,0 +1,39 @@ |
|||
# -*- coding: utf-8 -*- |
|||
################################################################################ |
|||
# |
|||
# Cybrosys Technologies Pvt. Ltd. |
|||
# |
|||
# Copyright (C) 2024-TODAY Cybrosys Technologies(<https://www.cybrosys.com>). |
|||
# Author: Subina P (odoo@cybrosys.com) |
|||
# |
|||
# You can modify it under the terms of the GNU AFFERO |
|||
# GENERAL PUBLIC LICENSE (AGPL v3), Version 3. |
|||
# |
|||
# This program is distributed in the hope that it will be useful, |
|||
# but WITHOUT ANY WARRANTY; without even the implied warranty of |
|||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|||
# GNU AFFERO GENERAL PUBLIC LICENSE (AGPL v3) for more details. |
|||
# |
|||
# You should have received a copy of the GNU AFFERO GENERAL PUBLIC LICENSE |
|||
# (AGPL v3) along with this program. |
|||
# If not, see <http://www.gnu.org/licenses/>. |
|||
# |
|||
################################################################################ |
|||
from odoo import fields, models |
|||
|
|||
|
|||
class HospitalFamily(models.Model): |
|||
"""Class holding hospital family details""" |
|||
_name = 'hospital.family' |
|||
_description = 'Hospital Family' |
|||
|
|||
name = fields.Char(string="Name", help='Name of family member') |
|||
relation = fields.Char(string="Relation", help='Relation with the patient') |
|||
age = fields.Integer(string="Age", help='Age of family member') |
|||
deceased = fields.Selection([('yes', 'Yes'), ('no', 'NO')], |
|||
string="Diseased", help='Specify whether the ' |
|||
'family member is ' |
|||
'alive or not') |
|||
family_id = fields.Many2one('res.partner', |
|||
string="Family ID", help='Choose the family ' |
|||
'member') |
@ -0,0 +1,484 @@ |
|||
# -*- coding: utf-8 -*- |
|||
################################################################################ |
|||
# |
|||
# Cybrosys Technologies Pvt. Ltd. |
|||
# |
|||
# Copyright (C) 2024-TODAY Cybrosys Technologies(<https://www.cybrosys.com>). |
|||
# Author: Subina P (odoo@cybrosys.com) |
|||
# |
|||
# You can modify it under the terms of the GNU AFFERO |
|||
# GENERAL PUBLIC LICENSE (AGPL v3), Version 3. |
|||
# |
|||
# This program is distributed in the hope that it will be useful, |
|||
# but WITHOUT ANY WARRANTY; without even the implied warranty of |
|||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|||
# GNU AFFERO GENERAL PUBLIC LICENSE (AGPL v3) for more details. |
|||
# |
|||
# You should have received a copy of the GNU AFFERO GENERAL PUBLIC LICENSE |
|||
# (AGPL v3) along with this program. |
|||
# If not, see <http://www.gnu.org/licenses/>. |
|||
# |
|||
################################################################################ |
|||
import datetime |
|||
from odoo import api, fields, models |
|||
|
|||
|
|||
class HospitalInpatient(models.Model): |
|||
"""Class holding inpatient details""" |
|||
_name = 'hospital.inpatient' |
|||
_description = 'Inpatient' |
|||
_inherit = ['mail.thread.cc', 'mail.activity.mixin'] |
|||
|
|||
patient_id = fields.Many2one('res.partner', string="Patient", |
|||
domain=[('patient_seq', 'not in', |
|||
['New', 'Employee', 'User'])], |
|||
required=True, help='Choose the patient') |
|||
name = fields.Char(string="Sequence Number", store=True, |
|||
copy=False, readonly=True, index=True, |
|||
help='Sequence number of inpatient for uniquely ' |
|||
'identifying', |
|||
default=lambda self: 'New') |
|||
reason = fields.Text( |
|||
string="Reason For Admission", |
|||
help="Current reason for hospitalization of the patient") |
|||
bed_id = fields.Many2one('hospital.bed', string='Bed', |
|||
help='Choose the bed') |
|||
room_id = fields.Many2one('patient.room', string='Room', |
|||
help='Choose the room to which patient admitted' |
|||
' to') |
|||
building_id = fields.Many2one( |
|||
'hospital.building', related='room_id.building_id', |
|||
string="Block", help='Name of the block') |
|||
room_building_id = fields.Many2one( |
|||
'hospital.building', related='room_id.building_id', |
|||
string="Room Building", |
|||
help='Name of the building to which room belongs to') |
|||
ward_id = fields.Many2one('hospital.ward', |
|||
related='bed_id.ward_id', |
|||
string='Ward', |
|||
help='Ward to which the bed belongs to') |
|||
type_admission = fields.Selection([('emergency', |
|||
'Emergency Admission'), |
|||
('routine', 'Routine Admission')], |
|||
string="Admission Type", |
|||
help='The type of admission', |
|||
required=True) |
|||
attending_doctor_id = fields.Many2one('hr.employee', |
|||
string="Attending Doctor", |
|||
required=True, |
|||
help='Name of attending doctor', |
|||
domain=[ |
|||
('job_id.name', '=', 'Doctor')]) |
|||
operating_doctor_id = fields.Many2one('hr.employee', |
|||
string="Operating Doctor", |
|||
help='Name of operating doctor', |
|||
domain=[ |
|||
('job_id.name', '=', 'Doctor')]) |
|||
hosp_date = fields.Date(string="Admission Date", |
|||
help='Date of hospitalisation', |
|||
default=fields.Date.today()) |
|||
discharge_date = fields.Date(string="Discharge Date", |
|||
help='Date of discharge', copy=False) |
|||
condition = fields.Text( |
|||
string="Condition Before Hospitalization", |
|||
help="The condition of the patient before he/she is admitted to" |
|||
" the hospital") |
|||
nursing_plan_ids = fields.One2many('nursing.plan', |
|||
'admission_id', |
|||
string='Nursing Plan', |
|||
help='Nursing plan of the inpatient') |
|||
active = fields.Boolean(string='Active', default=True, |
|||
help='True for active inpatients') |
|||
doctor_round_ids = fields.One2many('doctor.round', |
|||
'admission_id', |
|||
string='Doctor Rounds', |
|||
help='Doctor rounds of the patient') |
|||
discharge_plan = fields.Text(string="Discharge Plan", |
|||
help='Discharge plan of the inpatient') |
|||
notes = fields.Text(string="Notes", help='Notes regarding the inpatient') |
|||
bed_rent = fields.Monetary(string='Rent Per Day', related='bed_id.bed_rent', |
|||
help='Rent for the bed') |
|||
currency_id = fields.Many2one('res.currency', string='Currency', |
|||
help='Currency in which rent is calculating', |
|||
default=lambda self: self.env.user.company_id |
|||
.currency_id.id) |
|||
state = fields.Selection([('draft', 'Draft'), |
|||
('reserve', 'Reserved'), |
|||
('admit', 'Admitted'), ('invoice', 'Invoiced'), |
|||
('dis', 'Discharge')], |
|||
string='State', readonly=True, |
|||
help='State of inpatient', |
|||
default="draft") |
|||
bed_rent_amount = fields.Monetary(string="Total Bed Rent", |
|||
help='Total rent ' |
|||
'for stayed ' |
|||
'days', |
|||
compute='_compute_bed_rent_amount', |
|||
copy=False) |
|||
invoice_id = fields.Many2one('account.move', string='Invoice', |
|||
help='Invoice id of the inpatient', copy=False) |
|||
admit_days = fields.Integer(string='Days', |
|||
help='Number of days the inpatient admitted', |
|||
compute='_compute_admit_days', |
|||
copy=False) |
|||
bed_type = fields.Selection([('gatch', 'Gatch Bed'), |
|||
('electric', 'Electric'), |
|||
('stretcher', 'Stretcher'), |
|||
('low', 'Low Bed'), |
|||
('air', 'Low Air Loss'), |
|||
('circo', 'Circo Electric'), |
|||
('clinitron', 'Clinitron'), |
|||
], string="Bed Type", |
|||
help='Indicates the type of bed') |
|||
is_ward = fields.Selection([('ward', 'Ward'), ('room', 'Room')], |
|||
string='Room/Ward', |
|||
help='Choose where the patient is admitted to') |
|||
payment_ids = fields.One2many('inpatient.payment', |
|||
'inpatient_id', |
|||
string='Payment Details', |
|||
help='Payment details of the patient') |
|||
is_invoice = fields.Boolean(string='Is Invoice', |
|||
help='View invoice button will be visible if ' |
|||
'this field is true') |
|||
prescription_ids = fields.One2many('prescription.line', |
|||
'inpatient_id', |
|||
string='Prescription', |
|||
help='Medical prescriptions of patient') |
|||
enable_outpatient = fields.Boolean(string='Prescription History', |
|||
help='If checked, the prescription ' |
|||
'history of the patient will be ' |
|||
'added') |
|||
lab_test_ids = fields.One2many('patient.lab.test', |
|||
'inpatient_id', |
|||
string='Lab Test', |
|||
help='Lab tests of the inpatient') |
|||
test_count = fields.Integer(string='Test Created', |
|||
help='Number of tests of the inpatient', |
|||
compute='_compute_test_count') |
|||
test_ids = fields.One2many('patient.lab.test', |
|||
'inpatient_id', string='Test Line', |
|||
help='Details of the lab test') |
|||
surgery_ids = fields.One2many('inpatient.surgery', |
|||
'inpatient_id', |
|||
string='Surgery/Operation', |
|||
help='Surgery details of the patient') |
|||
room_rent = fields.Monetary(string='Rent per day', help='Rent for the room', |
|||
related='room_id.rent') |
|||
room_rent_amount = fields.Monetary(string="Total Room Rent", |
|||
compute='_compute_room_rent_amount', |
|||
help='Total rent for the room', |
|||
copy=False) |
|||
|
|||
@api.model |
|||
def create(self, vals): |
|||
"""Sequence number generation""" |
|||
if vals.get('name', 'New') == 'New': |
|||
vals['name'] = self.env['ir.sequence'].next_by_code( |
|||
'hospital.inpatient') or 'New' |
|||
return super().create(vals) |
|||
|
|||
@api.depends('test_ids') |
|||
def _compute_test_count(self): |
|||
"""Method for computing test count""" |
|||
self.test_count = self.env['lab.test.line'].sudo().search_count( |
|||
[('id', 'in', self.test_ids.ids)]) |
|||
|
|||
def _compute_admit_days(self): |
|||
"""Method for computing admit days""" |
|||
if self.hosp_date: |
|||
if self.discharge_date: |
|||
self.admit_days = (self.discharge_date - self.hosp_date + |
|||
datetime.timedelta(days=1)).days |
|||
else: |
|||
self.admit_days = (fields.date.today() - self.hosp_date + |
|||
datetime.timedelta(days=1)).days |
|||
|
|||
@api.depends('hosp_date', 'discharge_date', |
|||
'admit_days', 'room_id') |
|||
def _compute_room_rent_amount(self): |
|||
"""Method for computing room rent amount""" |
|||
if self.hosp_date: |
|||
if self.discharge_date: |
|||
self.admit_days = (self.discharge_date - self.hosp_date + |
|||
datetime.timedelta(days=1)).days |
|||
self.room_rent_amount = self.room_id.rent * self.admit_days |
|||
else: |
|||
self.admit_days = (fields.date.today() - self.hosp_date + |
|||
datetime.timedelta(days=1)).days |
|||
self.room_rent_amount = self.room_id.rent * self.admit_days |
|||
self.room_rent_amount = self.room_id.rent * self.admit_days |
|||
|
|||
@api.depends('hosp_date', 'discharge_date', 'room_rent_amount', |
|||
'admit_days') |
|||
def _compute_bed_rent_amount(self): |
|||
"""Method for computing bed rent amount""" |
|||
if self.hosp_date: |
|||
if self.discharge_date: |
|||
self.admit_days = (self.discharge_date - self.hosp_date + |
|||
datetime.timedelta(days=1)).days |
|||
self.bed_rent_amount = self.bed_id.bed_rent * self.admit_days |
|||
else: |
|||
self.admit_days = (fields.date.today() - self.hosp_date + |
|||
datetime.timedelta(days=1)).days |
|||
self.bed_rent_amount = self.bed_id.bed_rent * self.admit_days |
|||
else: |
|||
self.bed_rent_amount = self.bed_id.bed_rent |
|||
|
|||
@api.onchange('enable_outpatient') |
|||
def _onchange_enable_outpatient(self): |
|||
"""Method for adding prescription lines of patient""" |
|||
self.prescription_ids = False |
|||
if self.enable_outpatient: |
|||
outpatient_id = self.env['hospital.outpatient'].sudo().search( |
|||
[('patient_id', '=', self.patient_id.id)]) |
|||
self.sudo().write({ |
|||
'prescription_ids': [(0, 0, { |
|||
'medicine_id': rec.medicine_id.id, |
|||
'quantity': rec.quantity, |
|||
'no_intakes': rec.no_intakes, |
|||
'note': rec.note, |
|||
'time': rec.time, |
|||
}) for rec in outpatient_id.prescription_ids] |
|||
}) |
|||
|
|||
@api.onchange('bed_type') |
|||
def _onchange_bed_type(self): |
|||
"""Method for filtering beds according to the bed type""" |
|||
return {'domain': { |
|||
'bed_id': [ |
|||
('bed_type', '=', self.bed_type), |
|||
('state', '=', 'avail') |
|||
], 'room_id': [ |
|||
('bed_type', '=', self.bed_type), |
|||
('state', '=', 'avail') |
|||
]}} |
|||
|
|||
def action_view_invoice(self): |
|||
"""Method for viewing Invoice""" |
|||
self.ensure_one() |
|||
return { |
|||
'name': 'inpatient Invoice', |
|||
'view_mode': 'tree,form', |
|||
'res_model': 'account.move', |
|||
'type': 'ir.actions.act_window', |
|||
'domain': [('ref', '=', self.name)], |
|||
'context': "{'create':False}" |
|||
} |
|||
|
|||
def action_view_tests(self): |
|||
"""Returns all lab tests""" |
|||
return { |
|||
'name': 'Lab Tests', |
|||
'res_model': 'patient.lab.test', |
|||
'view_mode': 'tree,form', |
|||
'type': 'ir.actions.act_window', |
|||
'domain': [('inpatient_id', '=', self.id)] |
|||
} |
|||
|
|||
def action_create_lab_test(self): |
|||
"""Function for creating lab test""" |
|||
return { |
|||
'name': 'Create Lab Test', |
|||
'res_model': 'lab.test.line', |
|||
'view_mode': 'form', |
|||
'views': [[False, 'form']], |
|||
'target': 'current', |
|||
'type': 'ir.actions.act_window', |
|||
'context': { |
|||
'default_patient_id': self.patient_id.id, |
|||
'default_doctor_id': self.attending_doctor_id.id, |
|||
'default_patient_type': 'inpatient', |
|||
'default_ip_id': self.id |
|||
} |
|||
} |
|||
|
|||
def action_view_test(self): |
|||
"""View test details""" |
|||
return { |
|||
'name': 'Created Tests', |
|||
'res_model': 'lab.test.line', |
|||
'view_mode': 'tree,form', |
|||
'target': 'current', |
|||
'type': 'ir.actions.act_window', |
|||
'domain': [ |
|||
('patient_type', '=', 'inpatient'), |
|||
('ip_id', '=', self.id) |
|||
] |
|||
} |
|||
|
|||
def action_reserve(self): |
|||
"""Method for inpatient reservation""" |
|||
if self.bed_id: |
|||
self.bed_id.state = 'not' |
|||
if self.room_id: |
|||
self.room_id.state = 'reserve' |
|||
self.sudo().write({ |
|||
'state': "reserve" |
|||
}) |
|||
|
|||
def action_admit(self): |
|||
"""Method for patient admission""" |
|||
if self.bed_id: |
|||
self.bed_id.state = 'not' |
|||
if self.room_id: |
|||
self.room_id.state = 'not' |
|||
self.sudo().write({ |
|||
'state': "admit" |
|||
}) |
|||
|
|||
def action_discharge(self): |
|||
"""Method for patient discharge""" |
|||
if self.bed_id: |
|||
self.bed_id.state = 'avail' |
|||
if self.room_id: |
|||
self.room_id.state = 'avail' |
|||
self.sudo().write({ |
|||
'state': "dis" |
|||
}) |
|||
self.active = False |
|||
|
|||
def action_invoice(self): |
|||
"""Method for creating invoice""" |
|||
self.is_invoice = True |
|||
self.state = 'invoice' |
|||
inv_line_list = [] |
|||
invoice = self.env['account.move.line'].sudo().search( |
|||
[('move_id.partner_id', '=', self.patient_id.id), |
|||
('move_id.state', '=', 'draft'), |
|||
('group_tax_id', '=', False), |
|||
('date_maturity', '=', False), |
|||
('move_id.move_type', '=', 'out_invoice')]) |
|||
for rec in self: |
|||
if rec.bed_rent_amount: |
|||
inv_line_list.append((0, 0, {'name': 'Room/Bed Rent Amount', |
|||
'price_unit': rec.bed_rent_amount, |
|||
'quantity': rec.admit_days, |
|||
})) |
|||
elif rec.room_rent_amount: |
|||
inv_line_list.append((0, 0, {'name': 'Room/Bed Rent Amount', |
|||
'price_unit': rec.room_rent_amount, |
|||
'quantity': rec.admit_days, |
|||
})) |
|||
for line in rec.payment_ids: |
|||
inv_line_list.append((0, 0, {'name': line.name, |
|||
'price_unit': line.subtotal, |
|||
'quantity': 1, |
|||
'tax_ids': line.tax_ids |
|||
})) |
|||
for line in self.test_ids: |
|||
if not line.invoice_id: |
|||
inv_line_list.append((0, 0, { |
|||
'name': line.test_id.name, |
|||
'price_unit': line.total_price, |
|||
'quantity': 1 |
|||
})) |
|||
for line in self.prescription_ids: |
|||
inv_line_list.append((0, 0, { |
|||
'name': line.medicine_id.name, |
|||
'price_unit': line.medicine_id.list_price, |
|||
'quantity': line.quantity |
|||
})) |
|||
if invoice: |
|||
for line in invoice.read( |
|||
['name', 'price_unit', 'quantity']): |
|||
inv_line_list.append((0, 0, {'name': line['name'], |
|||
'price_unit': line[ |
|||
'price_unit'], |
|||
'quantity': line['quantity']})) |
|||
move = self.env['account.move'].sudo().create({ |
|||
'move_type': 'out_invoice', |
|||
'date': fields.Date.today(), |
|||
'ref': self.name, |
|||
'invoice_date': fields.Date.today(), |
|||
'partner_id': self.patient_id.id, |
|||
'line_ids': inv_line_list |
|||
}) |
|||
self.invoice_id = move.id |
|||
for rec in invoice: |
|||
rec.move_id.button_cancel() |
|||
return { |
|||
'name': 'Invoice', |
|||
'res_model': 'account.move', |
|||
'view_mode': 'form', |
|||
'view_Id': self.env.ref('account.view_move_form').id, |
|||
'context': "{'move_type':'out_invoice'}", |
|||
'type': 'ir.actions.act_window', |
|||
'res_id': move.id |
|||
} |
|||
|
|||
def create_new_in_patient(self, domain): |
|||
"""Create in-patient from receptionist dashboard""" |
|||
if domain: |
|||
patient = self.env['hospital.inpatient'].sudo().search( |
|||
[('patient_id', '=', domain['patient_id'])]) |
|||
if patient: |
|||
return 'Patient already exists' |
|||
else: |
|||
self.sudo().create({ |
|||
'patient_id': domain['patient_id'], |
|||
'reason': domain['reason_of_admission'], |
|||
'type_admission': domain['admission_type'], |
|||
'attending_doctor_id': domain['attending_doctor_id'], |
|||
}) |
|||
|
|||
def fetch_inpatient(self, domain): |
|||
"""Returns inpatient details to display on the doctor's dashboard""" |
|||
if domain: |
|||
return self.env['hospital.inpatient'].sudo().search( |
|||
['|', '|', '|', '|', ('name', 'ilike', domain), |
|||
('patient_id.name', 'ilike', domain), |
|||
('hosp_date', 'ilike', domain), |
|||
('discharge_date', 'ilike', domain), |
|||
('state', 'ilike', domain)]).read( |
|||
['name', 'patient_id', 'ward_id', 'bed_id', |
|||
'hosp_date', 'discharge_date', 'type_admission', |
|||
'attending_doctor_id', |
|||
'state']) |
|||
else: |
|||
return self.env['hospital.inpatient'].sudo().search_read( |
|||
fields=['name', 'patient_id', 'ward_id', 'bed_id', 'hosp_date', |
|||
'discharge_date', 'attending_doctor_id', 'state']) |
|||
|
|||
def action_print_prescription(self): |
|||
"""Method for printing prescription""" |
|||
data = False |
|||
p_list = [] |
|||
for rec in self.prescription_ids: |
|||
p_list.append({ |
|||
'medicine': rec.medicine_id.name, |
|||
'intake': rec.no_intakes, |
|||
'time': rec.time.capitalize(), |
|||
'quantity': rec.quantity, |
|||
'note': rec.note.capitalize(), |
|||
}) |
|||
data = { |
|||
'datas': p_list, |
|||
'date': fields.date.today(), |
|||
'patient_name': self.patient_id.name, |
|||
'doctor_name': self.attending_doctor_id.name, |
|||
} |
|||
return self.env.ref( |
|||
'base_hospital_management.action_report_patient_prescription'). \ |
|||
report_action(self, data=data) |
|||
|
|||
@api.model |
|||
def hospital_inpatient_list(self): |
|||
"""Returns list of inpatients to doctor's dashboard""" |
|||
patient_list = [] |
|||
patients = self.sudo().search([]) |
|||
patient_type = {'emergency': 'Emergency Admission', |
|||
'routine': 'Routine Admission'} |
|||
for rec in patients: |
|||
patient_list.append({ |
|||
'id': rec.id, |
|||
'name': rec.name, |
|||
'patient_id': rec.patient_id.name, |
|||
'bed_id': rec.bed_id.name, |
|||
'ward_id': rec.ward_id.ward_no, |
|||
'room_id': rec.room_id, |
|||
'hosp_date': rec.hosp_date, |
|||
'attending_doctor_id': rec.attending_doctor_id._origin.name, |
|||
'admission_type': patient_type[rec.type_admission], |
|||
'discharge_date': rec.discharge_date |
|||
}) |
|||
return patient_list |
@ -0,0 +1,38 @@ |
|||
# -*- coding: utf-8 -*- |
|||
################################################################################ |
|||
# |
|||
# Cybrosys Technologies Pvt. Ltd. |
|||
# |
|||
# Copyright (C) 2024-TODAY Cybrosys Technologies(<https://www.cybrosys.com>). |
|||
# Author: Subina P (odoo@cybrosys.com) |
|||
# |
|||
# You can modify it under the terms of the GNU AFFERO |
|||
# GENERAL PUBLIC LICENSE (AGPL v3), Version 3. |
|||
# |
|||
# This program is distributed in the hope that it will be useful, |
|||
# but WITHOUT ANY WARRANTY; without even the implied warranty of |
|||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|||
# GNU AFFERO GENERAL PUBLIC LICENSE (AGPL v3) for more details. |
|||
# |
|||
# You should have received a copy of the GNU AFFERO GENERAL PUBLIC LICENSE |
|||
# (AGPL v3) along with this program. |
|||
# If not, see <http://www.gnu.org/licenses/>. |
|||
# |
|||
################################################################################ |
|||
from odoo import fields, models |
|||
|
|||
|
|||
class HospitalInsurance(models.Model): |
|||
"""Class holding insurance details""" |
|||
_name = 'hospital.insurance' |
|||
_description = 'Hospital Insurance' |
|||
|
|||
name = fields.Char(string='Provider', help='Name of the insurance provider') |
|||
currency_id = fields.Many2one('res.currency', string='Currency', |
|||
help='Currency in which insurance will be ' |
|||
'calculated', |
|||
default=lambda self: self.env.user.company_id |
|||
.currency_id.id, |
|||
required=True) |
|||
total_coverage = fields.Monetary(string='Total Coverage', |
|||
help='Total coverage of the insurance') |
@ -0,0 +1,65 @@ |
|||
# -*- coding: utf-8 -*- |
|||
################################################################################ |
|||
# |
|||
# Cybrosys Technologies Pvt. Ltd. |
|||
# |
|||
# Copyright (C) 2024-TODAY Cybrosys Technologies(<https://www.cybrosys.com>). |
|||
# Author: Subina P (odoo@cybrosys.com) |
|||
# |
|||
# You can modify it under the terms of the GNU AFFERO |
|||
# GENERAL PUBLIC LICENSE (AGPL v3), Version 3. |
|||
# |
|||
# This program is distributed in the hope that it will be useful, |
|||
# but WITHOUT ANY WARRANTY; without even the implied warranty of |
|||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|||
# GNU AFFERO GENERAL PUBLIC LICENSE (AGPL v3) for more details. |
|||
# |
|||
# You should have received a copy of the GNU AFFERO GENERAL PUBLIC LICENSE |
|||
# (AGPL v3) along with this program. |
|||
# If not, see <http://www.gnu.org/licenses/>. |
|||
# |
|||
################################################################################ |
|||
from odoo import api, fields, models |
|||
|
|||
|
|||
class HospitalLaboratory(models.Model): |
|||
"""Class holding laboratory details""" |
|||
_name = 'hospital.laboratory' |
|||
_description = 'Hospital Laboratory' |
|||
|
|||
notes = fields.Text(string='Notes', help='Notes regarding the laboratory') |
|||
image_130 = fields.Image(max_width=128, max_height=128, string='Image', |
|||
help='Image of the laboratory') |
|||
phone = fields.Char(string='Phone', help='Phone number of laboratory') |
|||
mobile = fields.Char(string='Mobile', help='Mobile number of' |
|||
' laboratory') |
|||
email = fields.Char(string='Email', help='Email of the laboratory') |
|||
street = fields.Char(string='Street', help='Street name of lab') |
|||
street2 = fields.Char(string='Street2', help='Street2 name of lab') |
|||
zip = fields.Char(string='Zip', help='Zip code of lab') |
|||
city = fields.Char(string='City', help="City of lab") |
|||
state_id = fields.Many2one("res.country.state", |
|||
string='State', |
|||
help='State of lab') |
|||
country_id = fields.Many2one('res.country', |
|||
related='state_id.country_id', |
|||
string='Country', |
|||
help='Country name of lab') |
|||
note = fields.Text(string='Note', help='Notes regarding lab') |
|||
name = fields.Char(string='Lab Sequence', help='Sequence number for lab', |
|||
copy=False, |
|||
readonly=True, index=1, default=lambda self: 'New') |
|||
technician_id = fields.Many2one('hr.employee', |
|||
string="Lab in charge", |
|||
domain=[ |
|||
('job_title', '=', 'Lab Technician')], |
|||
help='Name of the lab technician who has ' |
|||
'the in charge') |
|||
|
|||
@api.model |
|||
def create(self, vals): |
|||
"""Method for creating lab sequence number""" |
|||
if vals.get('name', 'New') == 'New': |
|||
vals['name'] = self.env['ir.sequence'].next_by_code( |
|||
'laboratory.sequence') or 'New' |
|||
return super().create(vals) |
@ -0,0 +1,317 @@ |
|||
# -*- coding: utf-8 -*- |
|||
################################################################################ |
|||
# |
|||
# Cybrosys Technologies Pvt. Ltd. |
|||
# |
|||
# Copyright (C) 2024-TODAY Cybrosys Technologies(<https://www.cybrosys.com>). |
|||
# Author: Subina P (odoo@cybrosys.com) |
|||
# |
|||
# You can modify it under the terms of the GNU AFFERO |
|||
# GENERAL PUBLIC LICENSE (AGPL v3), Version 3. |
|||
# |
|||
# This program is distributed in the hope that it will be useful, |
|||
# but WITHOUT ANY WARRANTY; without even the implied warranty of |
|||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|||
# GNU AFFERO GENERAL PUBLIC LICENSE (AGPL v3) for more details. |
|||
# |
|||
# You should have received a copy of the GNU AFFERO GENERAL PUBLIC LICENSE |
|||
# (AGPL v3) along with this program. |
|||
# If not, see <http://www.gnu.org/licenses/>. |
|||
# |
|||
################################################################################ |
|||
import base64 |
|||
from odoo import api, fields, models |
|||
from odoo.exceptions import ValidationError |
|||
|
|||
|
|||
class HospitalOutpatient(models.Model): |
|||
"""Class holding Outpatient details""" |
|||
_name = 'hospital.outpatient' |
|||
_description = 'Hospital Outpatient' |
|||
_rec_name = 'op_reference' |
|||
_inherit = 'mail.thread' |
|||
_order = 'op_date desc' |
|||
|
|||
op_reference = fields.Char(string="OP Reference", readonly=True, |
|||
default='New', |
|||
help='Op reference number of the patient') |
|||
patient_id = fields.Many2one('res.partner', |
|||
domain=[('patient_seq', 'not in', |
|||
['New', 'Employee', 'User'])], |
|||
string='Patient ID', help='Id of the patient', |
|||
required=True) |
|||
doctor_id = fields.Many2one('doctor.allocation', |
|||
string='Doctor', |
|||
help='Select the doctor', |
|||
required=True, |
|||
domain=[('slot_remaining', '>', 0), |
|||
('date', '=', fields.date.today()), |
|||
('state', '=', 'confirm')]) |
|||
op_date = fields.Date(default=fields.Date.today(), string='Date', |
|||
help='Date of OP') |
|||
reason = fields.Text(string='Reason', help='Reason for visiting hospital') |
|||
test_count = fields.Integer(string='Test Created', |
|||
help='Number of tests created for the patient', |
|||
compute='_compute_test_count') |
|||
test_ids = fields.One2many('lab.test.line', 'op_id', |
|||
string='Tests', |
|||
help='Tests for the patient') |
|||
state = fields.Selection( |
|||
[('draft', 'Draft'), ('op', 'OP'), ('inpatient', 'In Patient'), |
|||
('invoice', 'Invoiced'), ('cancel', 'Canceled')], |
|||
default='draft', string='State', help='State of the outpatient') |
|||
prescription_ids = fields.One2many('prescription.line', |
|||
'outpatient_id', |
|||
string='Prescription', |
|||
help='Prescription for the patient') |
|||
invoiced = fields.Boolean(default=False, string='Invoiced', |
|||
help='True for invoiced') |
|||
invoice_id = fields.Many2one('account.move', copy=False, |
|||
string='Invoice', |
|||
help='Invoice of the patient') |
|||
attachment_id = fields.Many2one('ir.attachment', |
|||
string='Attachment', |
|||
help='Attachments related to the' |
|||
' outpatient') |
|||
active = fields.Boolean(string='Active', help='True for active patients', |
|||
default=True) |
|||
slot = fields.Float(string='Slot', help='Slot for the patient', |
|||
copy=False, readonly=True) |
|||
is_sale_created = fields.Boolean(string='Sale Created', |
|||
help='True if sale order created') |
|||
|
|||
@api.model |
|||
def create(self, vals): |
|||
"""Op number generator""" |
|||
if vals.get('op_reference', 'New') == 'New': |
|||
last_op = self.search([ |
|||
('doctor_id', '=', vals.get('doctor_id')), |
|||
('op_reference', '!=', 'New'), |
|||
], order='create_date desc', limit=1) |
|||
if last_op: |
|||
last_number = int(last_op.op_reference[2:]) |
|||
new_number = last_number + 1 |
|||
vals['op_reference'] = f'OP{str(new_number).zfill(3)}' |
|||
else: |
|||
vals['op_reference'] = 'OP001' |
|||
if self.search([ |
|||
('patient_id', '=', vals['patient_id']), |
|||
('doctor_id', '=', vals['doctor_id']) |
|||
]): |
|||
raise ValidationError( |
|||
'An OP already exists for this patient under the specified ' |
|||
'allocation') |
|||
return super().create(vals) |
|||
|
|||
@api.depends('test_ids') |
|||
def _compute_test_count(self): |
|||
"""Computes the value of test count""" |
|||
self.test_count = len(self.test_ids.ids) |
|||
|
|||
@api.onchange('op_date') |
|||
def _onchange_op_date(self): |
|||
"""Method for updating the doamil of doctor_id""" |
|||
self.doctor_id = False |
|||
return {'domain': {'doctor_id': [('slot_remaining', '>', 0), |
|||
('date', '=', self.op_date), |
|||
('state', '=', 'confirm'), ( |
|||
'patient_type', 'in', |
|||
[False, 'outpatient'])]}} |
|||
|
|||
@api.model |
|||
def action_row_click_data(self, op_reference): |
|||
"""Returns data to be displayed on clicking op row""" |
|||
op_record = self.env['hospital.outpatient'].sudo().search( |
|||
[('op_reference', '=', op_reference), |
|||
('active', 'in', [True, False])]) |
|||
op_data = [op_reference, op_record.patient_id.patient_seq, |
|||
op_record.patient_id.name, str(op_record.op_date), |
|||
op_record.slot, op_record.reason, |
|||
op_record.doctor_id.doctor_id.name, |
|||
op_record.is_sale_created] |
|||
medicines = [] |
|||
for rec in op_record.prescription_ids: |
|||
medicines.append( |
|||
[rec.medicine_id.name, rec.no_intakes, rec.time, rec.note, |
|||
rec.quantity, rec.medicine_id.id]) |
|||
return { |
|||
'op_data': op_data, |
|||
'medicines': medicines |
|||
} |
|||
|
|||
@api.model |
|||
def create_medicine_sale_order(self, order_id): |
|||
"""Method for creating sale order for medicines""" |
|||
order = self.sudo().search([('op_reference', 'ilike', order_id)]) |
|||
sale_order = self.env['sale.order'].sudo().create({ |
|||
'partner_id': order.patient_id.id, |
|||
}) |
|||
for i in order.prescription_ids: |
|||
self.env['sale.order.line'].sudo().create({ |
|||
'product_id': i.medicine_id.id, |
|||
'product_uom_qty': i.quantity, |
|||
'order': sale_order.id, |
|||
}) |
|||
self.create_invoice() |
|||
|
|||
@api.model |
|||
def create_file(self, rec_id): |
|||
"""Method for creating prescription""" |
|||
record = self.env['hospital.outpatient'].sudo().browse(rec_id) |
|||
p_list = [] |
|||
data = False |
|||
for rec in record.prescription_ids: |
|||
p_list.append({ |
|||
'medicine': rec.medicine_id.name, |
|||
'intake': rec.no_intakes, |
|||
'time': rec.time.capitalize(), |
|||
'quantity': rec.quantity, |
|||
'note': rec.note.capitalize() if rec.note else '', |
|||
}) |
|||
data = { |
|||
'datas': p_list, |
|||
'date': record.op_date, |
|||
'patient_name': record.patient_id.name, |
|||
'doctor_name': record.doctor_id.doctor_id.name, |
|||
} |
|||
pdf = self.env['ir.actions.report'].sudo()._render_qweb_pdf( |
|||
'base_hospital_management.action_report_patient_prescription', |
|||
rec_id, data=data) |
|||
record.attachment_id = self.env['ir.attachment'].sudo().create({ |
|||
'datas': base64.b64encode(pdf[0]), |
|||
'name': "Prescription", |
|||
'type': 'binary', |
|||
'res_model': 'hospital.outpatient', |
|||
'res_id': rec_id, |
|||
}) |
|||
return { |
|||
'url': f'/web/content' |
|||
f'/{record.attachment_id.id}?download=true&' |
|||
f';access_token=', |
|||
} |
|||
|
|||
@api.model |
|||
def create_new_out_patient(self, kw): |
|||
"""Create out patient from receptionist dashboard""" |
|||
if kw['id']: |
|||
partner = self.env['res.partner'].sudo().search( |
|||
['|', ('barcode', '=', kw['id']), |
|||
('phone', '=', kw['op_phone'])]) |
|||
self.sudo().create({ |
|||
'patient_id': partner.id, |
|||
'op_date': kw['date'], |
|||
'reason': kw['reason'], |
|||
'slot': kw['slot'], |
|||
'doctor_id': kw['doctor'], |
|||
}) |
|||
|
|||
def action_create_lab_test(self): |
|||
"""Button action for creating a lab test""" |
|||
return { |
|||
'name': 'Create Lab Test', |
|||
'res_model': 'lab.test.line', |
|||
'view_mode': 'form', |
|||
'views': [[False, 'form']], |
|||
'target': 'current', |
|||
'type': 'ir.actions.act_window', |
|||
'context': { |
|||
'default_patient_id': self.patient_id.id, |
|||
'default_doctor_id': self.doctor_id.id, |
|||
'default_patient_type': 'outpatient', |
|||
'default_op_id': self.id |
|||
} |
|||
} |
|||
|
|||
def action_view_test(self): |
|||
"""Method for viewing all lab tests""" |
|||
return { |
|||
'name': 'Created Tests', |
|||
'res_model': 'lab.test.line', |
|||
'view_mode': 'tree,form', |
|||
'target': 'current', |
|||
'type': 'ir.actions.act_window', |
|||
'domain': [ |
|||
('patient_type', '=', 'outpatient'), |
|||
('op_id', '=', self.id) |
|||
] |
|||
} |
|||
|
|||
def action_convert_to_inpatient(self): |
|||
"""Converts an outpatient to inpatient""" |
|||
self.state = 'inpatient' |
|||
return { |
|||
'name': 'Convert to Inpatient', |
|||
'res_model': 'hospital.inpatient', |
|||
'view_mode': 'form', |
|||
'target': 'current', |
|||
'type': 'ir.actions.act_window', |
|||
'context': { |
|||
'default_patient_id': self.patient_id.id, |
|||
'default_attending_doctor_id': self.doctor_id.doctor_id.id, |
|||
} |
|||
} |
|||
|
|||
def action_op_cancel(self): |
|||
"""Button action for cancelling an op""" |
|||
self.state = 'cancel' |
|||
|
|||
def action_confirm(self): |
|||
"""Button action for confirming an op""" |
|||
if self.doctor_id.latest_slot == 0: |
|||
self.slot = self.doctor_id.work_from |
|||
else: |
|||
self.slot = self.doctor_id.latest_slot + self.doctor_id.time_avg |
|||
self.doctor_id.latest_slot = self.slot |
|||
self.state = 'op' |
|||
|
|||
def create_invoice(self): |
|||
"""Method for creating invoice""" |
|||
self.state = 'invoice' |
|||
self.invoice_id = self.env['account.move'].sudo().create({ |
|||
'move_type': 'out_invoice', |
|||
'date': fields.Date.today(), |
|||
'invoice_date': fields.Date.today(), |
|||
'partner_id': self.patient_id.id, |
|||
'invoice_line_ids': [( |
|||
0, 0, { |
|||
'name': 'Consultation fee', |
|||
'quantity': 1, |
|||
'price_unit': self.doctor_id.doctor_id.consultancy_charge, |
|||
} |
|||
)] |
|||
}) |
|||
self.invoiced = True |
|||
|
|||
def action_view_invoice(self): |
|||
"""Method for viewing invoice""" |
|||
return { |
|||
'name': 'Invoice', |
|||
'domain': [('id', '=', self.invoice_id.id)], |
|||
'type': 'ir.actions.act_window', |
|||
'res_model': 'account.move', |
|||
'view_mode': 'tree,form', |
|||
'context': {'create': False}, |
|||
} |
|||
|
|||
def action_print_prescription(self): |
|||
"""Method for printing prescription""" |
|||
data = False |
|||
p_list = [] |
|||
for rec in self.prescription_ids: |
|||
datas = { |
|||
'medicine': rec.medicine_id.name, |
|||
'intake': rec.no_intakes, |
|||
'time': rec.time.capitalize(), |
|||
'quantity': rec.quantity, |
|||
'note': rec.note.capitalize(), |
|||
} |
|||
p_list.append(datas) |
|||
data = { |
|||
'datas': p_list, |
|||
'date': self.op_date, |
|||
'patient_name': self.patient_id.name, |
|||
'doctor_name': self.doctor_id.doctor_id.name, |
|||
} |
|||
return self.env.ref( |
|||
'base_hospital_management.action_report_patient_prescription'). \ |
|||
report_action(self, data=data) |
@ -0,0 +1,156 @@ |
|||
# -*- coding: utf-8 -*- |
|||
################################################################################ |
|||
# |
|||
# Cybrosys Technologies Pvt. Ltd. |
|||
# |
|||
# Copyright (C) 2024-TODAY Cybrosys Technologies(<https://www.cybrosys.com>). |
|||
# Author: Subina P (odoo@cybrosys.com) |
|||
# |
|||
# You can modify it under the terms of the GNU AFFERO |
|||
# GENERAL PUBLIC LICENSE (AGPL v3), Version 3. |
|||
# |
|||
# This program is distributed in the hope that it will be useful, |
|||
# but WITHOUT ANY WARRANTY; without even the implied warranty of |
|||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|||
# GNU AFFERO GENERAL PUBLIC LICENSE (AGPL v3) for more details. |
|||
# |
|||
# You should have received a copy of the GNU AFFERO GENERAL PUBLIC LICENSE |
|||
# (AGPL v3) along with this program. |
|||
# If not, see <http://www.gnu.org/licenses/>. |
|||
# |
|||
################################################################################ |
|||
from odoo import api, fields, models |
|||
|
|||
|
|||
class HospitalPharmacy(models.Model): |
|||
"""Class holding Pharmacy details.""" |
|||
_name = 'hospital.pharmacy' |
|||
_description = 'Pharmacy' |
|||
|
|||
name = fields.Char(string="Name", help='Name of the pharmacy', |
|||
required=True) |
|||
pharmacist_id = fields.Many2one('hr.employee', |
|||
string="Pharmacist", |
|||
help='Name of the pharmacist', |
|||
domain=[ |
|||
('job_id.name', '=', 'Pharmacist')]) |
|||
phone = fields.Char(string='Phone', help='Phone number of the pharmacy') |
|||
mobile = fields.Char(string='Mobile', help='Mobile number of the pharmacy') |
|||
email = fields.Char(string='Email', help='Email of the pharmacy') |
|||
street = fields.Char(string='Street', help='Street of pharmacy') |
|||
street2 = fields.Char(string='Street2', help='Street2 of pharmacy') |
|||
zip = fields.Char(string='Zip', help='Zip code of pharmacy') |
|||
city = fields.Char(string='City', help='City of pharmacy') |
|||
state_id = fields.Many2one("res.country.state", string='State', |
|||
help='State of pharmacy') |
|||
country_id = fields.Many2one('res.country', string='Country', |
|||
help='Country of pharmacy') |
|||
notes = fields.Text(string='Notes', help='Notes regarding pharmacy') |
|||
image_129 = fields.Image(string='Image', help='Image of pharmacy', |
|||
max_width=128, max_height=128) |
|||
active = fields.Boolean(string='Active', help='True for active pharmacy', |
|||
default=True) |
|||
medicine_ids = fields.One2many('pharmacy.medicine', |
|||
'pharmacy_id', |
|||
string='Pharmacy', |
|||
help='Indicates the medicines in the ' |
|||
'pharmacy') |
|||
sales_team_id = fields.Many2one('crm.team', string='Sales Team', |
|||
help='Choose the sales-team for the' |
|||
' pharmacy') |
|||
|
|||
@api.model |
|||
def create(self, vals): |
|||
"""Method for creating CRM team""" |
|||
team_id = self.env['crm.team'].sudo().create({ |
|||
'name': vals['name'] + ' Pharmacy Team', |
|||
'company_id': False, |
|||
'user_id': self.env.uid |
|||
}) |
|||
vals['sales_team_id'] = team_id.id |
|||
return super().create(vals) |
|||
|
|||
@api.model |
|||
def create_sale_order(self, kwargs): |
|||
"""Creating sale order from pharmacy dashboard""" |
|||
if 'op' not in kwargs.keys(): |
|||
patient_id = self.env['res.partner'].sudo().search( |
|||
[('name', '=', kwargs['name']), ('email', '=', kwargs['email'])]) |
|||
else: |
|||
patient_id = self.env['hospital.outpatient'].sudo().search( |
|||
[('op_reference', '=', kwargs['op'])]).patient_id |
|||
if not patient_id: |
|||
patient_id = self.env['res.partner'].sudo().create({ |
|||
'name': kwargs['name'], |
|||
'email': kwargs['email'], |
|||
}) |
|||
pharmacy_sale_order = self.env['sale.order'].sudo().create({ |
|||
'partner_id': patient_id.id, |
|||
}) |
|||
for rec in kwargs['products']: |
|||
pharmacy_sale_order.sudo().write({ |
|||
'order_line': [(0, 0, { |
|||
'product_id': self.env['product.product'].search([('product_tmpl_id', '=', int(rec['product']))]).id, |
|||
'product_uom_qty': float(rec['qty']), |
|||
'price_unit': float(rec['price']) if 'price' in rec.keys() else |
|||
self.env['product.product'].search([('product_tmpl_id', '=', int(rec['product']))]).list_price |
|||
})] |
|||
}) |
|||
pharmacy_sale_order.action_confirm() |
|||
if 'op' in kwargs.keys(): |
|||
self.env['hospital.outpatient'].sudo().search( |
|||
[('op_reference', '=', kwargs['op'])]).write( |
|||
{ |
|||
'is_sale_created': True |
|||
}) |
|||
return {'invoice_id': pharmacy_sale_order.id, 'invoice': pharmacy_sale_order.name} |
|||
|
|||
@api.model |
|||
def company_currency(self): |
|||
"""Currency symbol of current company""" |
|||
return self.env.user.company_id.currency_id.symbol |
|||
|
|||
@api.model |
|||
def tax_amount(self, kw): |
|||
"""Amount in tax of selected product in pharmacy""" |
|||
return { |
|||
'amount': self.env['account.tax'].sudo().browse(kw).amount |
|||
} |
|||
|
|||
def action_get_inventory(self): |
|||
"""Inventory adjustment for medicine""" |
|||
med_list = [] |
|||
for med in self.medicine_ids.product_id: |
|||
for product in self.env['product.product'].sudo().search([]): |
|||
if med.id == product.product_tmpl_id.id: |
|||
med_list.append(product.id) |
|||
return { |
|||
'name': 'medicine', |
|||
'domain': ['&', ('product_id', 'in', med_list), |
|||
('location_id.usage', '=', 'internal')], |
|||
'type': 'ir.actions.act_window', |
|||
'res_model': 'stock.quant', |
|||
'view_id': self.env.ref( |
|||
'stock.view_stock_quant_tree_inventory_editable').id, |
|||
'view_mode': 'tree', |
|||
} |
|||
|
|||
def action_get_sale_order(self): |
|||
"""Sale order view of medicine""" |
|||
return { |
|||
'name': 'Sales', |
|||
'res_model': 'sale.order', |
|||
'view_mode': 'tree,form', |
|||
'domain': [('team_id', '=', self.sales_team_id.id)], |
|||
'type': 'ir.actions.act_window', |
|||
'context': {'default_team_id': self.sales_team_id.id} |
|||
} |
|||
|
|||
def fetch_sale_orders(self): |
|||
"""Method to fetch all sale orders for displaying on pharmacy |
|||
dashboard""" |
|||
return self.env['sale.order'].search_read( |
|||
[('partner_id.patient_seq', 'not in', ['New', 'Employee', |
|||
'User'])], |
|||
fields=['name', 'create_date', 'partner_id', 'amount_total', |
|||
'state']) |
@ -0,0 +1,155 @@ |
|||
# -*- coding: utf-8 -*- |
|||
################################################################################ |
|||
# |
|||
# Cybrosys Technologies Pvt. Ltd. |
|||
# |
|||
# Copyright (C) 2024-TODAY Cybrosys Technologies(<https://www.cybrosys.com>). |
|||
# Author: Subina P (odoo@cybrosys.com) |
|||
# |
|||
# You can modify it under the terms of the GNU AFFERO |
|||
# GENERAL PUBLIC LICENSE (AGPL v3), Version 3. |
|||
# |
|||
# This program is distributed in the hope that it will be useful, |
|||
# but WITHOUT ANY WARRANTY; without even the implied warranty of |
|||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|||
# GNU AFFERO GENERAL PUBLIC LICENSE (AGPL v3) for more details. |
|||
# |
|||
# You should have received a copy of the GNU AFFERO GENERAL PUBLIC LICENSE |
|||
# (AGPL v3) along with this program. |
|||
# If not, see <http://www.gnu.org/licenses/>. |
|||
# |
|||
################################################################################ |
|||
from datetime import timedelta |
|||
from odoo import api, fields, models |
|||
|
|||
|
|||
class HospitalVaccination(models.Model): |
|||
"""Class holding Vaccination details""" |
|||
_name = 'hospital.vaccination' |
|||
_description = "Vaccination Details" |
|||
_order = 'name desc' |
|||
|
|||
name = fields.Char(string='Vaccination Reference', copy=False, |
|||
readonly=True, index=True, help='Name of vaccination', |
|||
default=lambda self: 'New') |
|||
patient_id = fields.Many2one('res.partner', |
|||
domain=[('patient_seq', 'not in', |
|||
['New', 'Employee', 'User'])], |
|||
required=True, |
|||
string="Patient", help='Choose the patient') |
|||
vaccine_date = fields.Date(string='Vaccination Date', help='Date of ' |
|||
'vaccination', |
|||
default=fields.Date.today()) |
|||
dose = fields.Float(string='Dose', help='Dose of the vaccine') |
|||
vaccine_product_id = fields.Many2one('product.template', |
|||
domain="[('vaccine_ok', '=', True)]", |
|||
string="Vaccine", help='Choose the ' |
|||
'vaccine', |
|||
required=True) |
|||
vaccine_price = fields.Float(related='vaccine_product_id.list_price', |
|||
string="Price", help='Price of vaccine') |
|||
sale_order_id = fields.Many2one('sale.order', |
|||
string='Sale Order', |
|||
help='Sale order for the vaccine') |
|||
sold = fields.Boolean(string='Sold', help='True if sale order created') |
|||
certificate = fields.Binary(string="Certificate", help='Vaccination ' |
|||
'certificate') |
|||
attachment_id = fields.Many2one('ir.attachment', |
|||
string='Attachment', |
|||
help='Attachments added to the vaccination') |
|||
recurring_vaccine = fields.Boolean(string='Recurring Vaccine', |
|||
help='True for recurring vaccinations') |
|||
total_vaccine = fields.Integer(string="Total Dose", |
|||
help='Total number of vaccines') |
|||
next_vaccine_days = fields.Integer(string="Next Vaccine (In Days)", |
|||
help='The number of days to next ' |
|||
'vaccine') |
|||
next_vaccine = fields.Date(string="Next Vaccination Date", |
|||
help='Date of next ' |
|||
'vaccine', |
|||
readonly=True) |
|||
|
|||
@api.model |
|||
def create(self, vals): |
|||
"""Inherits create method for creating the vaccination sequence""" |
|||
if vals.get('name', 'New') == 'New': |
|||
vals['name'] = self.env['ir.sequence'].next_by_code( |
|||
'vaccination.sequence') or 'New' |
|||
return super().create(vals) |
|||
|
|||
@api.onchange('next_vaccine_days') |
|||
def _onchange_next_vaccine_days(self): |
|||
"""Method for updating the field next_vaccine according to the value |
|||
of next_vaccine_days""" |
|||
if self.next_vaccine_days: |
|||
self.sudo().write({'next_vaccine': fields.Date.today() + timedelta( |
|||
self.next_vaccine_days)}) |
|||
|
|||
def action_create_so(self): |
|||
"""Method for creating the sale order for vaccines""" |
|||
product_id = self.env['product.product'].sudo().search([ |
|||
('product_tmpl_id', '=', self.vaccine_product_id.id) |
|||
]) |
|||
sale = self.env['sale.order'].search([ |
|||
('partner_id.id', '=', self.patient_id.id), |
|||
('state', '=', 'draft')], limit=1) |
|||
if sale: |
|||
sale.sudo().write({ |
|||
'order_line': [( |
|||
0, 0, { |
|||
'product_id': product_id[0].id, |
|||
'name': self.vaccine_product_id.name, |
|||
'price_unit': self.vaccine_price, |
|||
'product_uom_qty': self.dose |
|||
} |
|||
)] |
|||
}) |
|||
else: |
|||
sale = self.env['sale.order'].sudo().create({ |
|||
'partner_id': self.patient_id.id, |
|||
'date_order': fields.Date.today(), |
|||
'order_line': [(0, 0, { |
|||
'product_id': product_id[0].id, |
|||
'name': self.vaccine_product_id.name, |
|||
'price_unit': self.vaccine_price, |
|||
'product_uom_qty': self.dose |
|||
})] |
|||
}) |
|||
self.sold = True |
|||
self.sale_order_id = sale.id |
|||
|
|||
def get_sale_order(self): |
|||
"""Smart button action for viewing corresponding sale orders""" |
|||
return { |
|||
'name': 'Sale order', |
|||
'res_model': 'sale.order', |
|||
'view_mode': 'form', |
|||
'type': 'ir.actions.act_window', |
|||
'res_id': self.sale_order_id.id |
|||
} |
|||
|
|||
@api.model |
|||
def fetch_vaccination_data(self, **kwargs): |
|||
"""Method for fetching vaccine data""" |
|||
data = self.sudo().search(kwargs['domain']) |
|||
context = [] |
|||
for rec in data: |
|||
self.env.cr.execute( |
|||
f"""SELECT id FROM ir_attachment WHERE |
|||
res_id = {rec.id} and res_model='hospital.vaccination' """) |
|||
attachment_id = False |
|||
attachment = self.env.cr.dictfetchall() |
|||
if attachment: |
|||
attachment_id = attachment[0]['id'] |
|||
context.append({ |
|||
'id': rec.id, |
|||
'name': rec.name, |
|||
'patient_id': [rec.patient_id.id, |
|||
rec.patient_id.name], |
|||
'vaccine_product_id': rec.vaccine_product_id.name, |
|||
'vaccine_price': rec.vaccine_price, |
|||
'attachment_id': attachment_id, |
|||
'view_id': self.env['ir.ui.view'].sudo().search([ |
|||
('name', '=', 'hospital.vaccination.view.form')]).id |
|||
}) |
|||
return context |
@ -0,0 +1,76 @@ |
|||
# -*- coding: utf-8 -*- |
|||
################################################################################ |
|||
# |
|||
# Cybrosys Technologies Pvt. Ltd. |
|||
# |
|||
# Copyright (C) 2024-TODAY Cybrosys Technologies(<https://www.cybrosys.com>). |
|||
# Author: Subina P (odoo@cybrosys.com) |
|||
# |
|||
# You can modify it under the terms of the GNU AFFERO |
|||
# GENERAL PUBLIC LICENSE (AGPL v3), Version 3. |
|||
# |
|||
# This program is distributed in the hope that it will be useful, |
|||
# but WITHOUT ANY WARRANTY; without even the implied warranty of |
|||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|||
# GNU AFFERO GENERAL PUBLIC LICENSE (AGPL v3) for more details. |
|||
# |
|||
# You should have received a copy of the GNU AFFERO GENERAL PUBLIC LICENSE |
|||
# (AGPL v3) along with this program. |
|||
# If not, see <http://www.gnu.org/licenses/>. |
|||
# |
|||
################################################################################ |
|||
from odoo import api, fields, models |
|||
|
|||
|
|||
class HospitalWard(models.Model): |
|||
"""Class holding Ward details""" |
|||
_name = 'hospital.ward' |
|||
_description = 'Hospital Ward' |
|||
_rec_name = 'ward_no' |
|||
|
|||
ward_no = fields.Char(string="Name", |
|||
required=True, help='Number of the ward') |
|||
building_id = fields.Many2one('hospital.building', |
|||
string="Block", help='The building to ' |
|||
'which the ward ' |
|||
'corresponds to') |
|||
floor_no = fields.Integer(string="Floor No.", help='The floor to ' |
|||
'which the ward ' |
|||
'corresponds to') |
|||
note = fields.Text(string="Note", help='Note regarding the ward') |
|||
bed_count = fields.Integer(string="Count", compute="_compute_bed_count", |
|||
help='The bed count') |
|||
nurse_ids = fields.Many2many('hr.employee', string='Nurses', |
|||
domain="[('job_id','=','Nurse')]", |
|||
help='Nurses corresponds to the ward') |
|||
ward_facilities_ids = fields.Many2many('room.facility', |
|||
string='Facilities', |
|||
help='Facilities corresponds to ' |
|||
'ward.') |
|||
_sql_constraints = [('unique_ward', 'unique (ward_no)', |
|||
'Ward number should be unique!')] |
|||
|
|||
def _compute_bed_count(self): |
|||
"""Method for computing bed count""" |
|||
for rec in self: |
|||
rec.bed_count = rec.env['hospital.bed'].sudo().search_count([( |
|||
'ward_id', '=', rec.ward_no)]) |
|||
|
|||
@api.onchange('building_id') |
|||
def _onchange_building_id(self): |
|||
"""Returns domain for the field bed_id""" |
|||
return {'domain': { |
|||
'bed_id': [ |
|||
('ward_id', '=', self.id), |
|||
]}} |
|||
|
|||
def action_get_open_bed(self): |
|||
"""Returns form view of bed""" |
|||
return { |
|||
'name': 'Bed', |
|||
'domain': [('ward_id', '=', self.ward_no)], |
|||
'type': 'ir.actions.act_window', |
|||
'res_model': 'hospital.bed', |
|||
'view_mode': 'tree', |
|||
'context': {'create': False}, |
|||
} |
@ -0,0 +1,100 @@ |
|||
# -*- coding: utf-8 -*- |
|||
################################################################################ |
|||
# |
|||
# Cybrosys Technologies Pvt. Ltd. |
|||
# |
|||
# Copyright (C) 2024-TODAY Cybrosys Technologies(<https://www.cybrosys.com>). |
|||
# Author: Subina P (odoo@cybrosys.com) |
|||
# |
|||
# You can modify it under the terms of the GNU AFFERO |
|||
# GENERAL PUBLIC LICENSE (AGPL v3), Version 3. |
|||
# |
|||
# This program is distributed in the hope that it will be useful, |
|||
# but WITHOUT ANY WARRANTY; without even the implied warranty of |
|||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|||
# GNU AFFERO GENERAL PUBLIC LICENSE (AGPL v3) for more details. |
|||
# |
|||
# You should have received a copy of the GNU AFFERO GENERAL PUBLIC LICENSE |
|||
# (AGPL v3) along with this program. |
|||
# If not, see <http://www.gnu.org/licenses/>. |
|||
# |
|||
################################################################################ |
|||
from odoo import fields, models, _ |
|||
from odoo.exceptions import ValidationError |
|||
|
|||
|
|||
class HrEmployee(models.Model): |
|||
"""Inherited to add more fields and functions""" |
|||
_inherit = 'hr.employee' |
|||
|
|||
doctor = fields.Boolean(string='Doctor', help='True for Doctors') |
|||
currency_id = fields.Many2one('res.currency', string='Currency', |
|||
help='Currency in which consultation fee ' |
|||
'is calculating', |
|||
default=lambda self: self.env.user.company_id |
|||
.currency_id.id, |
|||
required=True) |
|||
coach_id = fields.Many2one('hr.employee', string='Coach', |
|||
help='Name of the coach') |
|||
consultancy_charge = fields.Monetary(string="Consultation Charge", |
|||
help='Charge for consultation') |
|||
consultancy_type = fields.Selection([('resident', 'Residential'), |
|||
('special', 'Specialist')], |
|||
string="Consultation Type", |
|||
help='Select the type of Consultation') |
|||
time_avg = fields.Float(string='Average Time for a Patient', |
|||
help="Average Consultation time " |
|||
"per Patient in minutes") |
|||
degree_ids = fields.Many2many('hospital.degree', |
|||
string="Degree", |
|||
help='Degrees of staff') |
|||
pharmacy_id = fields.Many2one('hospital.pharmacy', |
|||
string="Pharmacy", |
|||
help='Name of the pharmacy') |
|||
specialization_ids = fields.Many2many('doctor.specialization', |
|||
string="Specialization", |
|||
help="Doctors specialization for" |
|||
" an area") |
|||
|
|||
def action_create_user(self): |
|||
"""Updating employee field of res user to true""" |
|||
self.ensure_one() |
|||
if self.user_id: |
|||
raise ValidationError(_("This employee already has an user.")) |
|||
return { |
|||
'name': _('Create User'), |
|||
'type': 'ir.actions.act_window', |
|||
'res_model': 'res.users', |
|||
'view_mode': 'form', |
|||
'view_id': self.env.ref('hr.view_users_simple_form').id, |
|||
'target': 'new', |
|||
'context': { |
|||
'default_create_employee_id': self.id, |
|||
'default_name': self.name, |
|||
'default_phone': self.work_phone, |
|||
'default_mobile': self.mobile_phone, |
|||
'default_login': self.work_email, |
|||
'default_employee': True |
|||
} |
|||
} |
|||
|
|||
def _inverse_work_contact_details(self): |
|||
"""Override to prevent creating patient while creating a staff""" |
|||
for employee in self: |
|||
if not employee.work_contact_id: |
|||
employee.work_contact_id = self.env[ |
|||
'res.partner'].sudo().create( |
|||
{ |
|||
'email': employee.work_email, |
|||
'mobile': employee.mobile_phone, |
|||
'name': employee.name, |
|||
'image_1920': employee.image_1920, |
|||
'company_id': employee.company_id.id, |
|||
'patient_seq': 'Employee' |
|||
}) |
|||
else: |
|||
employee.work_contact_id.sudo().write({ |
|||
'email': employee.work_email, |
|||
'mobile': employee.mobile_phone, |
|||
'patient_seq': 'Employee' |
|||
}) |
@ -0,0 +1,37 @@ |
|||
# -*- coding: utf-8 -*- |
|||
################################################################################ |
|||
# |
|||
# Cybrosys Technologies Pvt. Ltd. |
|||
# |
|||
# Copyright (C) 2024-TODAY Cybrosys Technologies(<https://www.cybrosys.com>). |
|||
# Author: Subina P (odoo@cybrosys.com) |
|||
# |
|||
# You can modify it under the terms of the GNU AFFERO |
|||
# GENERAL PUBLIC LICENSE (AGPL v3), Version 3. |
|||
# |
|||
# This program is distributed in the hope that it will be useful, |
|||
# but WITHOUT ANY WARRANTY; without even the implied warranty of |
|||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|||
# GNU AFFERO GENERAL PUBLIC LICENSE (AGPL v3) for more details. |
|||
# |
|||
# You should have received a copy of the GNU AFFERO GENERAL PUBLIC LICENSE |
|||
# (AGPL v3) along with this program. |
|||
# If not, see <http://www.gnu.org/licenses/>. |
|||
# |
|||
################################################################################ |
|||
from odoo import fields, models |
|||
|
|||
|
|||
class InpatientPayment(models.Model): |
|||
"""Class holding Payment details of Inpatient""" |
|||
_name = 'inpatient.payment' |
|||
_description = "Inpatient Payments" |
|||
|
|||
name = fields.Char(string='Name', help='Name of payment') |
|||
subtotal = fields.Float(string='Subtotal', help='Total payment') |
|||
inpatient_id = fields.Many2one('hospital.inpatient', |
|||
string='Inpatient', |
|||
help='Inpatient related to the payment') |
|||
date = fields.Datetime(string='Date', help="Date of payment") |
|||
tax_ids = fields.Many2many('account.tax', string='Tax', |
|||
help='Tax for the test') |
@ -0,0 +1,90 @@ |
|||
# -*- coding: utf-8 -*- |
|||
################################################################################ |
|||
# |
|||
# Cybrosys Technologies Pvt. Ltd. |
|||
# |
|||
# Copyright (C) 2024-TODAY Cybrosys Technologies(<https://www.cybrosys.com>). |
|||
# Author: Subina P (odoo@cybrosys.com) |
|||
# |
|||
# You can modify it under the terms of the GNU AFFERO |
|||
# GENERAL PUBLIC LICENSE (AGPL v3), Version 3. |
|||
# |
|||
# This program is distributed in the hope that it will be useful, |
|||
# but WITHOUT ANY WARRANTY; without even the implied warranty of |
|||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|||
# GNU AFFERO GENERAL PUBLIC LICENSE (AGPL v3) for more details. |
|||
# |
|||
# You should have received a copy of the GNU AFFERO GENERAL PUBLIC LICENSE |
|||
# (AGPL v3) along with this program. |
|||
# If not, see <http://www.gnu.org/licenses/>. |
|||
# |
|||
################################################################################ |
|||
from odoo import api, fields, models |
|||
|
|||
|
|||
class InpatientSurgery(models.Model): |
|||
"""Class holding Surgery details""" |
|||
_name = 'inpatient.surgery' |
|||
_inherit = ["mail.thread", "mail.activity.mixin"] |
|||
_description = 'Inpatient Surgery' |
|||
|
|||
date = fields.Date(dafault=fields.date.today(), string='Date', |
|||
help='Date of adding surgery') |
|||
planned_date = fields.Datetime(string='Planned Date', |
|||
help='Planned date for surgery', |
|||
required=True) |
|||
name = fields.Char(string='Name', help='Name of the surgery', |
|||
required=True) |
|||
doctor_id = fields.Many2one('hr.employee', |
|||
string="Operating Doctor", |
|||
domain=[('job_id.name', '=', 'Doctor')], |
|||
help='Doctor responsible for the surgery', |
|||
required=True) |
|||
inpatient_id = fields.Many2one('hospital.inpatient', |
|||
string='Inpatient',required=True, |
|||
help='Inpatient to whom surgery is added') |
|||
hours_to_take = fields.Float(string='Duration', |
|||
help='Time duration for the surgery') |
|||
company_id = fields.Many2one('res.company', string='Company', |
|||
default=lambda self: self.env.company.id) |
|||
state = fields.Selection([('draft', 'Draft'), ('confirmed', 'Confirmed'), |
|||
('done', 'Done'), ('cancel', 'Cancel'), |
|||
], default='draft', |
|||
string='State', help='State of the slot') |
|||
|
|||
def action_confirm(self): |
|||
"""Function for confirming a surgery""" |
|||
self.sudo().write({ |
|||
'state': 'confirmed' |
|||
}) |
|||
|
|||
def action_cancel(self): |
|||
"""Function for cancelling a surgery""" |
|||
self.sudo().write({ |
|||
'state': 'cancel' |
|||
}) |
|||
|
|||
def action_done(self): |
|||
"""Function for change the state to surgery""" |
|||
self.sudo().write({ |
|||
'state': 'done' |
|||
}) |
|||
|
|||
@api.model |
|||
def get_doctor_slot(self): |
|||
"""Function for returning surgery details to doctor's dashboard""" |
|||
data_list = [] |
|||
state = {'confirmed': 'Confirmed', |
|||
'cancel': 'Cancel', |
|||
'done': 'Done', |
|||
'draft': 'Draft'} |
|||
for rec in self.sudo().search( |
|||
[('doctor_id.user_id', '=', self.env.user.id)]): |
|||
data_list.append({ |
|||
'id': rec.id, |
|||
'planned_date': rec.planned_date, |
|||
'patient_id': rec.inpatient_id.patient_id.name, |
|||
'surgery_name': rec.name, |
|||
'state': state[rec.state] |
|||
}) |
|||
return data_list |
@ -0,0 +1,33 @@ |
|||
# -*- coding: utf-8 -*- |
|||
################################################################################ |
|||
# |
|||
# Cybrosys Technologies Pvt. Ltd. |
|||
# |
|||
# Copyright (C) 2024-TODAY Cybrosys Technologies(<https://www.cybrosys.com>). |
|||
# Author: Subina P (odoo@cybrosys.com) |
|||
# |
|||
# You can modify it under the terms of the GNU AFFERO |
|||
# GENERAL PUBLIC LICENSE (AGPL v3), Version 3. |
|||
# |
|||
# This program is distributed in the hope that it will be useful, |
|||
# but WITHOUT ANY WARRANTY; without even the implied warranty of |
|||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|||
# GNU AFFERO GENERAL PUBLIC LICENSE (AGPL v3) for more details. |
|||
# |
|||
# You should have received a copy of the GNU AFFERO GENERAL PUBLIC LICENSE |
|||
# (AGPL v3) along with this program. |
|||
# If not, see <http://www.gnu.org/licenses/>. |
|||
# |
|||
################################################################################ |
|||
from odoo import api, models |
|||
|
|||
|
|||
class IrAttachment(models.Model): |
|||
"""Inherited for making the attachments public""" |
|||
_inherit = 'ir.attachment' |
|||
|
|||
@api.model |
|||
def create(self, vals): |
|||
"""Inherited to make the attachments public""" |
|||
vals['public'] = True |
|||
return super().create(vals) |
@ -0,0 +1,54 @@ |
|||
# -*- coding: utf-8 -*- |
|||
################################################################################ |
|||
# |
|||
# Cybrosys Technologies Pvt. Ltd. |
|||
# |
|||
# Copyright (C) 2024-TODAY Cybrosys Technologies(<https://www.cybrosys.com>). |
|||
# Author: Subina P (odoo@cybrosys.com) |
|||
# |
|||
# You can modify it under the terms of the GNU AFFERO |
|||
# GENERAL PUBLIC LICENSE (AGPL v3), Version 3. |
|||
# |
|||
# This program is distributed in the hope that it will be useful, |
|||
# but WITHOUT ANY WARRANTY; without even the implied warranty of |
|||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|||
# GNU AFFERO GENERAL PUBLIC LICENSE (AGPL v3) for more details. |
|||
# |
|||
# You should have received a copy of the GNU AFFERO GENERAL PUBLIC LICENSE |
|||
# (AGPL v3) along with this program. |
|||
# If not, see <http://www.gnu.org/licenses/>. |
|||
# |
|||
################################################################################ |
|||
from odoo import api, fields, models |
|||
|
|||
|
|||
class LabMedicineLine(models.Model): |
|||
"""Class holding Lab medicines""" |
|||
_name = 'lab.medicine.line' |
|||
_description = 'Lab Medicine Line' |
|||
|
|||
lab_test_id = fields.Many2one('patient.lab.test', |
|||
string='Lab Test Line', |
|||
help='Lab test corresponds to the medicine') |
|||
test_id = fields.Many2one('lab.test', string='Test', |
|||
help='Test corresponds to medicine') |
|||
medicine_id = fields.Many2one('product.template', |
|||
domain="['|', ('medicine_ok', '=', True)," |
|||
"('vaccine_ok', '=', True)" |
|||
"]", required=True, string='Medicine', |
|||
help='Medicine for the lab test') |
|||
quantity = fields.Integer(string='Quantity', default=1, |
|||
help='Quantity of medicine') |
|||
qty_available = fields.Float(string='Available', help='Available quantity', |
|||
related='medicine_id.qty_available') |
|||
price = fields.Float(string='Price', help='Price for the medicine', |
|||
related='medicine_id.list_price') |
|||
sub_total = fields.Float(string='Subtotal', |
|||
help='Total cost of the medicine', |
|||
compute='_compute_sub_total') |
|||
|
|||
@api.depends('quantity', 'price') |
|||
def _compute_sub_total(self): |
|||
"""Method for computing total amount""" |
|||
for rec in self: |
|||
rec.sub_total = rec.price * rec.quantity |
@ -0,0 +1,47 @@ |
|||
# -*- coding: utf-8 -*- |
|||
################################################################################ |
|||
# |
|||
# Cybrosys Technologies Pvt. Ltd. |
|||
# |
|||
# Copyright (C) 2024-TODAY Cybrosys Technologies(<https://www.cybrosys.com>). |
|||
# Author: Subina P (odoo@cybrosys.com) |
|||
# |
|||
# You can modify it under the terms of the GNU AFFERO |
|||
# GENERAL PUBLIC LICENSE (AGPL v3), Version 3. |
|||
# |
|||
# This program is distributed in the hope that it will be useful, |
|||
# but WITHOUT ANY WARRANTY; without even the implied warranty of |
|||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|||
# GNU AFFERO GENERAL PUBLIC LICENSE (AGPL v3) for more details. |
|||
# |
|||
# You should have received a copy of the GNU AFFERO GENERAL PUBLIC LICENSE |
|||
# (AGPL v3) along with this program. |
|||
# If not, see <http://www.gnu.org/licenses/>. |
|||
# |
|||
################################################################################ |
|||
from odoo import fields, models |
|||
|
|||
|
|||
class LabTest(models.Model): |
|||
"""Class holding lab test details""" |
|||
_name = 'lab.test' |
|||
_description = 'Laboratory Test' |
|||
|
|||
name = fields.Char(string='Test', help='Name of the test') |
|||
patient_lead = fields.Float(string='Result Within', |
|||
help='Time taken to get the result') |
|||
price = fields.Monetary(string='Price', help="The cost for the test") |
|||
currency_id = fields.Many2one('res.currency', string='Currency', |
|||
default=lambda self: |
|||
self.env.user.company_id.currency_id.id, |
|||
required=True, help='Currency in which ' |
|||
'payments will be done') |
|||
tax_ids = fields.Many2many('account.tax', string='Tax', |
|||
help='Tax for the test') |
|||
medicine_ids = fields.One2many('lab.medicine.line', |
|||
'test_id', |
|||
string='Medicines', |
|||
help='Medicines used for the test') |
|||
test_type = fields.Selection( |
|||
[('range', 'Range'), ('objective', 'Objective')], |
|||
string='Type', required=True, help='Type of test') |
@ -0,0 +1,126 @@ |
|||
# -*- coding: utf-8 -*- |
|||
################################################################################ |
|||
# |
|||
# Cybrosys Technologies Pvt. Ltd. |
|||
# |
|||
# Copyright (C) 2024-TODAY Cybrosys Technologies(<https://www.cybrosys.com>). |
|||
# Author: Subina P (odoo@cybrosys.com) |
|||
# |
|||
# You can modify it under the terms of the GNU AFFERO |
|||
# GENERAL PUBLIC LICENSE (AGPL v3), Version 3. |
|||
# |
|||
# This program is distributed in the hope that it will be useful, |
|||
# but WITHOUT ANY WARRANTY; without even the implied warranty of |
|||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|||
# GNU AFFERO GENERAL PUBLIC LICENSE (AGPL v3) for more details. |
|||
# |
|||
# You should have received a copy of the GNU AFFERO GENERAL PUBLIC LICENSE |
|||
# (AGPL v3) along with this program. |
|||
# If not, see <http://www.gnu.org/licenses/>. |
|||
# |
|||
################################################################################ |
|||
from odoo import api, fields, models, _ |
|||
from odoo.exceptions import UserError |
|||
|
|||
|
|||
class LabTestLine(models.Model): |
|||
"""Class holing lab test line details""" |
|||
_name = "lab.test.line" |
|||
_description = "Lab Test Line" |
|||
|
|||
name = fields.Char(string='Test Sequence', required=True, |
|||
copy=False, readonly=True, index=True, |
|||
default=lambda self: 'New', help='Name of lab test line') |
|||
patient_id = fields.Many2one('res.partner', string='Patient', |
|||
help='Choose the patient', |
|||
domain=[('patient_seq', 'not in', |
|||
['New', 'Employee', 'User'])]) |
|||
doctor_id = fields.Many2one('hr.employee', string='Doctor', |
|||
help='Choose the doctor', |
|||
domain=[('job_id.name', '=', 'Doctor')]) |
|||
date = fields.Date(default=fields.Date.today(), string='Date', |
|||
help='Date of test') |
|||
test_ids = fields.Many2many('lab.test', string='Test', |
|||
help='All the tests') |
|||
patient_type = fields.Selection(selection=[ |
|||
('inpatient', 'Inpatient'), ('outpatient', 'Outpatient') |
|||
], required=True, string='Patient Type', help='Choose the patient type') |
|||
op_id = fields.Many2one('hospital.outpatient', string='OP Number', |
|||
help='ID of outpatient') |
|||
ip_id = fields.Many2one('hospital.inpatient', string='Inpatient ID', |
|||
help='ID of inpatient') |
|||
state = fields.Selection(selection=[ |
|||
('draft', 'Draft'), ('created', 'created') |
|||
], default='draft', string='State', help='State of the record') |
|||
|
|||
@api.model |
|||
def create(self, vals): |
|||
"""Sequence generation""" |
|||
if vals.get('name', 'New') == 'New': |
|||
vals['name'] = self.env['ir.sequence'].next_by_code( |
|||
'lab_tests.draft.sequence') or 'New' |
|||
return super().create(vals) |
|||
|
|||
def action_confirm(self): |
|||
"""Method for confirming the test""" |
|||
if not self.test_ids: |
|||
raise UserError(_('You need to add a test before posting.')) |
|||
self.state = 'created' |
|||
self.env['patient.lab.test'].sudo().create({ |
|||
'patient_id': self.patient_id.id, |
|||
'test_id': self.id, |
|||
'patient_type': self.patient_type, |
|||
'state': 'draft', |
|||
'test_ids': self.test_ids.ids, |
|||
}) |
|||
|
|||
@api.model |
|||
def action_get_patient_data(self, rec_id): |
|||
"""Method for fetching patient data""" |
|||
data = self.env['lab.test.line'].sudo().browse(rec_id) |
|||
if data: |
|||
patient_data = { |
|||
'id': rec_id, |
|||
'name': data.patient_id.name, |
|||
'unique': data.patient_id.patient_seq, |
|||
'email': data.patient_id.email, |
|||
'phone': data.patient_id.phone, |
|||
'dob': data.patient_id.date_of_birth, |
|||
'image_1920': data.patient_id.image_1920, |
|||
'gender': data.patient_id.gender, |
|||
'status': data.patient_id.marital_status, |
|||
'doctor': data.doctor_id.name, |
|||
'patient_type': data.patient_type.capitalize(), |
|||
'ticket': data.op_id.op_reference |
|||
if data.patient_type == 'outpatient' else data.ip_id.name, |
|||
'test_data': [] |
|||
} |
|||
if data.patient_id.blood_group: |
|||
blood_caps = data.patient_id.blood_group.capitalize() |
|||
patient_data['blood_group'] = blood_caps + str( |
|||
data.patient_id.rh_type), |
|||
for test in data.test_ids: |
|||
hours = int(test.patient_lead) |
|||
minutes = int((test.patient_lead - hours) * 60) |
|||
patient_data['test_data'].append({ |
|||
'id': test.id, |
|||
'name': test.name, |
|||
'patient_lead': "{:02d}:{:02d}".format(hours, minutes), |
|||
'price': test.price, |
|||
}) |
|||
return patient_data |
|||
|
|||
@api.model |
|||
def create_lab_tests(self, data): |
|||
"""Method for creating lab tests""" |
|||
test = self.env['lab.test.line'].sudo().browse(data) |
|||
test.state = 'created' |
|||
self.env['patient.lab.test'].sudo().create({ |
|||
'patient_id': test.patient_id.id, |
|||
'test_id': test.id, |
|||
'patient_type': test.patient_type.lower(), |
|||
'state': 'draft', |
|||
}) |
|||
return { |
|||
'message': 'success', |
|||
} |
@ -0,0 +1,91 @@ |
|||
# -*- coding: utf-8 -*- |
|||
################################################################################ |
|||
# |
|||
# Cybrosys Technologies Pvt. Ltd. |
|||
# |
|||
# Copyright (C) 2024-TODAY Cybrosys Technologies(<https://www.cybrosys.com>). |
|||
# Author: Subina P (odoo@cybrosys.com) |
|||
# |
|||
# You can modify it under the terms of the GNU AFFERO |
|||
# GENERAL PUBLIC LICENSE (AGPL v3), Version 3. |
|||
# |
|||
# This program is distributed in the hope that it will be useful, |
|||
# but WITHOUT ANY WARRANTY; without even the implied warranty of |
|||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|||
# GNU AFFERO GENERAL PUBLIC LICENSE (AGPL v3) for more details. |
|||
# |
|||
# You should have received a copy of the GNU AFFERO GENERAL PUBLIC LICENSE |
|||
# (AGPL v3) along with this program. |
|||
# If not, see <http://www.gnu.org/licenses/>. |
|||
# |
|||
################################################################################ |
|||
from odoo import api, fields, models |
|||
|
|||
|
|||
class LabTestResult(models.Model): |
|||
"""Class holding lab test result""" |
|||
_name = 'lab.test.result' |
|||
_description = 'Lab Test Result' |
|||
_rec_name = 'test_id' |
|||
|
|||
patient_id = fields.Many2one('res.partner', string='Patient', |
|||
domain=[('patient_seq', 'not in', |
|||
['New', 'Employee', 'User'])], |
|||
help='Patient for whom the test has been done') |
|||
result = fields.Char(string='Result', help='Result of the test') |
|||
normal = fields.Char(string='Normal', help="The normal rate of the test") |
|||
uom_id = fields.Many2one('uom.uom', string='Unit', |
|||
help='Unit of the normal and result value') |
|||
parent_id = fields.Many2one('patient.lab.test', string='Tests', |
|||
help='The tests for which the result' |
|||
' corresponds to') |
|||
test_id = fields.Many2one('lab.test', string="Test Name", |
|||
help='Name of the test') |
|||
attachment = fields.Binary(string='Result', help='Result document') |
|||
currency_id = fields.Many2one('res.currency', |
|||
related='test_id.currency_id', |
|||
string='Currency', |
|||
help='Currency in which payments to be done') |
|||
price = fields.Monetary(string='Cost', help='Cost for the test', |
|||
related='test_id.price') |
|||
tax_ids = fields.Many2many('account.tax', string='Tax', |
|||
help='Tax for the test') |
|||
state = fields.Selection(selection=[('processing', 'Processing'), |
|||
('published', 'Published')], |
|||
string='State', help='State of the result', |
|||
default='processing', compute='_compute_state') |
|||
|
|||
@api.depends('attachment') |
|||
def _compute_state(self): |
|||
"""Method for computing the state of result based on attachment""" |
|||
for rec in self: |
|||
if rec.attachment: |
|||
rec.state = 'published' |
|||
else: |
|||
rec.state = 'processing' |
|||
|
|||
@api.model |
|||
def print_test_results(self): |
|||
"""Method for printing rest result""" |
|||
data = self.sudo().search([]) |
|||
context = [] |
|||
for rec in data: |
|||
self.env.cr.execute( |
|||
f"""SELECT id FROM ir_attachment WHERE res_id = {rec.id} |
|||
and res_model='lab.test.result' """) |
|||
attachment_id = False |
|||
attachment = self.env.cr.dictfetchall() |
|||
if attachment: |
|||
attachment_id = attachment[0]['id'] |
|||
context.append({ |
|||
'id': rec.id, |
|||
'parent_id': rec.parent_id.test_id.name, |
|||
'patient_id': [rec.parent_id.patient_id.id, |
|||
rec.parent_id.patient_id.name], |
|||
'test_id': rec.test_id.name, |
|||
'attachment_id': attachment_id, |
|||
'normal': rec.normal, |
|||
'result': rec.result, |
|||
'unit': rec.uom_id.name if rec.uom_id else '' |
|||
}) |
|||
return context |
@ -0,0 +1,34 @@ |
|||
# -*- coding: utf-8 -*- |
|||
################################################################################ |
|||
# |
|||
# Cybrosys Technologies Pvt. Ltd. |
|||
# |
|||
# Copyright (C) 2024-TODAY Cybrosys Technologies(<https://www.cybrosys.com>). |
|||
# Author: Subina P (odoo@cybrosys.com) |
|||
# |
|||
# You can modify it under the terms of the GNU AFFERO |
|||
# GENERAL PUBLIC LICENSE (AGPL v3), Version 3. |
|||
# |
|||
# This program is distributed in the hope that it will be useful, |
|||
# but WITHOUT ANY WARRANTY; without even the implied warranty of |
|||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|||
# GNU AFFERO GENERAL PUBLIC LICENSE (AGPL v3) for more details. |
|||
# |
|||
# You should have received a copy of the GNU AFFERO GENERAL PUBLIC LICENSE |
|||
# (AGPL v3) along with this program. |
|||
# If not, see <http://www.gnu.org/licenses/>. |
|||
# |
|||
################################################################################ |
|||
from odoo import fields, models |
|||
|
|||
|
|||
class MedicineBrand(models.Model): |
|||
"""Model holding all medicine brands""" |
|||
_name = 'medicine.brand' |
|||
_description = 'Medicine Brand' |
|||
|
|||
name = fields.Char(string="Brand", help='Name of the brand') |
|||
medicine_ids = fields.One2many('product.template', |
|||
'medicine_brand_id', |
|||
string='Medicine', |
|||
help='All medicines belongs to this brand') |
@ -0,0 +1,36 @@ |
|||
# -*- coding: utf-8 -*- |
|||
################################################################################ |
|||
# |
|||
# Cybrosys Technologies Pvt. Ltd. |
|||
# |
|||
# Copyright (C) 2024-TODAY Cybrosys Technologies(<https://www.cybrosys.com>). |
|||
# Author: Subina P (odoo@cybrosys.com) |
|||
# |
|||
# You can modify it under the terms of the GNU AFFERO |
|||
# GENERAL PUBLIC LICENSE (AGPL v3), Version 3. |
|||
# |
|||
# This program is distributed in the hope that it will be useful, |
|||
# but WITHOUT ANY WARRANTY; without even the implied warranty of |
|||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|||
# GNU AFFERO GENERAL PUBLIC LICENSE (AGPL v3) for more details. |
|||
# |
|||
# You should have received a copy of the GNU AFFERO GENERAL PUBLIC LICENSE |
|||
# (AGPL v3) along with this program. |
|||
# If not, see <http://www.gnu.org/licenses/>. |
|||
# |
|||
################################################################################ |
|||
from odoo import fields, models |
|||
|
|||
|
|||
class NursingPlan(models.Model): |
|||
"""Class holding nursing plan""" |
|||
_name = 'nursing.plan' |
|||
_description = "Nursing Plan" |
|||
|
|||
admission_id = fields.Many2one('hospital.inpatient', |
|||
string='Patient', |
|||
help='Name of the inpatient') |
|||
date = fields.Datetime(string='Visit Time', help='Date and time of visit') |
|||
status = fields.Char(string='Status', |
|||
help='Physical condition of the patient') |
|||
notes = fields.Text(string='Note', help='You can add the notes here') |
@ -0,0 +1,308 @@ |
|||
# -*- coding: utf-8 -*- |
|||
################################################################################ |
|||
# |
|||
# Cybrosys Technologies Pvt. Ltd. |
|||
# |
|||
# Copyright (C) 2024-TODAY Cybrosys Technologies(<https://www.cybrosys.com>). |
|||
# Author: Subina P (odoo@cybrosys.com) |
|||
# |
|||
# You can modify it under the terms of the GNU AFFERO |
|||
# GENERAL PUBLIC LICENSE (AGPL v3), Version 3. |
|||
# |
|||
# This program is distributed in the hope that it will be useful, |
|||
# but WITHOUT ANY WARRANTY; without even the implied warranty of |
|||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|||
# GNU AFFERO GENERAL PUBLIC LICENSE (AGPL v3) for more details. |
|||
# |
|||
# You should have received a copy of the GNU AFFERO GENERAL PUBLIC LICENSE |
|||
# (AGPL v3) along with this program. |
|||
# If not, see <http://www.gnu.org/licenses/>. |
|||
# |
|||
################################################################################ |
|||
from odoo import api, fields, models |
|||
|
|||
|
|||
class PatientLabTest(models.Model): |
|||
"""Class holding Patient lab test details""" |
|||
_name = 'patient.lab.test' |
|||
_description = 'Patient Lab Test' |
|||
_rec_name = 'test_id' |
|||
|
|||
test_id = fields.Many2one('lab.test.line', string='Test', |
|||
help='Name of the test') |
|||
patient_id = fields.Many2one('res.partner', string="Patient", |
|||
domain=[('patient_seq', 'not in', |
|||
['New', 'Employee', 'User'])], |
|||
required=True, help='Choose the patient') |
|||
patient_type = fields.Selection(selection=[ |
|||
('inpatient', 'Inpatient'), ('outpatient', 'Outpatient') |
|||
], related='test_id.patient_type', string='Type', |
|||
help='Choose the type of patient') |
|||
test_ids = fields.Many2many('lab.test', |
|||
related='test_id.test_ids', string='Tests', |
|||
help='All the tests added for the patient') |
|||
date = fields.Date(string='Date', help='Date of test', |
|||
default=fields.Date.today()) |
|||
total_price = fields.Float(string='Price', help='Total price for the test') |
|||
currency_id = fields.Many2one('res.currency', string='Currency', |
|||
help='Currency in which lab test amount will' |
|||
' be calculated', |
|||
default=lambda self: self.env.user.company_id |
|||
.currency_id.id, |
|||
required=True) |
|||
state = fields.Selection([('draft', 'Draft'), |
|||
('test', 'Test In Progress'), |
|||
('completed', 'Completed')], |
|||
string='State', readonly=True, |
|||
help='State of test', |
|||
default="draft") |
|||
result_ids = fields.One2many('lab.test.result', |
|||
'parent_id', |
|||
string="Result", help='Results of the test') |
|||
medicine_ids = fields.One2many('lab.medicine.line', |
|||
'lab_test_id', |
|||
string='Medicine', |
|||
compute='_compute_medicine_ids', |
|||
readonly=False, |
|||
help='Medicines needed for the test') |
|||
notes = fields.Text(string='Notes', help='Notes regarding the test') |
|||
lab_id = fields.Many2one('hospital.laboratory', string='Lab', |
|||
help='Lab in which test is doing') |
|||
invoice_id = fields.Many2one('account.move', string='Invoice', |
|||
help='Invoice for the test', copy=False) |
|||
order = fields.Integer(string='Sale Order', |
|||
help='Number of sale orders for vaccines and ' |
|||
'medicines', |
|||
copy=False) |
|||
started = fields.Boolean(string='Test Started', |
|||
help='True if the test has been started', |
|||
copy=False) |
|||
invoiced = fields.Boolean(string='Invoiced', |
|||
help='True if the test has been invoiced', |
|||
copy=False) |
|||
sold = fields.Boolean(string='Sold', |
|||
help='If true, sale order smart button will be ' |
|||
'visible ', copy=False) |
|||
company_id = fields.Many2one('res.company', string='Company', |
|||
default=lambda self: self.env.company.id) |
|||
invoice_count = fields.Integer(string='Invoice ' |
|||
'Count', |
|||
compute='_compute_invoice_count', |
|||
help='Total number of invoices for this ' |
|||
'patient lab test.') |
|||
sale_count = fields.Integer(string='Sale ' |
|||
'Count', |
|||
compute='_compute_sale_count', |
|||
help='Total number of sale orders for this ' |
|||
'patient lab test.') |
|||
inpatient_id = fields.Many2one('hospital.inpatient', |
|||
string='Inpatient', |
|||
help='Choose the inpatient') |
|||
|
|||
@api.depends('test_id') |
|||
def _compute_medicine_ids(self): |
|||
"""Method for computing medicine_ids""" |
|||
for record in self: |
|||
record.medicine_ids = self.test_ids.medicine_ids |
|||
|
|||
def _compute_invoice_count(self): |
|||
"""Method for computing invoice_count""" |
|||
for record in self: |
|||
record.invoice_count = self.env['account.move'].sudo().search_count( |
|||
['|', ( |
|||
'ref', '=', record.test_id.name), ('payment_reference', '=', |
|||
record.test_id.name)]) |
|||
|
|||
def _compute_sale_count(self): |
|||
"""Method for computing sale_count""" |
|||
for record in self: |
|||
record.sale_count = self.env['sale.order'].sudo().search_count([( |
|||
'reference', '=', record.test_id.name)]) |
|||
|
|||
@api.model |
|||
def action_get_patient_data(self, rec_id): |
|||
"""Returns data to the lab dashboard""" |
|||
data = self.sudo().browse(rec_id) |
|||
if data: |
|||
patient_data = { |
|||
'id': rec_id, |
|||
'sequence': data.test_id.name, |
|||
'name': data.patient_id.name, |
|||
'unique': data.patient_id.patient_seq, |
|||
'email': data.patient_id.email, |
|||
'phone': data.patient_id.phone, |
|||
'dob': data.patient_id.date_of_birth, |
|||
'image_1920': data.patient_id.image_1920, |
|||
'gender': data.patient_id.gender, |
|||
'status': data.patient_id.marital_status, |
|||
'doctor': data.test_id.doctor_id.name, |
|||
'patient_type': data.patient_type.capitalize(), |
|||
'state': data.state, |
|||
'invoiced': data.invoiced, |
|||
'ticket': data.test_id.op_id.op_reference |
|||
if data.patient_type == 'outpatient' |
|||
else data.test_id.patient_id.patient_seq, |
|||
'test_data': [], |
|||
'medicine': [], |
|||
'result_ids': [], |
|||
} |
|||
if data.patient_id.blood_group: |
|||
blood_caps = data.patient_id.blood_group.capitalize() |
|||
patient_data['blood_group'] = blood_caps + str( |
|||
data.patient_id.rh_type), |
|||
for test in data.test_ids: |
|||
patient_data['test_data'].append({ |
|||
'id': test.id, |
|||
'name': test.name, |
|||
'patient_lead': test.patient_lead, |
|||
'price': test.price, |
|||
}) |
|||
for medicine in data.medicine_ids: |
|||
patient_data['medicine'].append({ |
|||
'id': medicine.medicine_id.id, |
|||
'name': medicine.medicine_id.name, |
|||
'quantity': medicine.quantity |
|||
}) |
|||
for result in data.result_ids: |
|||
patient_data['result_ids'].append({ |
|||
'id': result.id, |
|||
'name': result.test_id.name, |
|||
'result': result.result, |
|||
'normal': result.normal, |
|||
'uom_id': result.uom_id.name, |
|||
'attachment': result.attachment, |
|||
'cost': result.price, |
|||
'state': result.state |
|||
}) |
|||
return patient_data |
|||
|
|||
@api.model |
|||
def start_test(self, rec_id): |
|||
"""Method for creating lab tests from lab dashboard""" |
|||
data = self.sudo().browse(rec_id) |
|||
data.state = 'test' |
|||
data.started = True |
|||
med_list = data.medicine_ids.ids |
|||
for rec in data.test_ids: |
|||
medicine_ids = [item for item in rec.medicine_ids.ids] |
|||
data.sudo().write({ |
|||
'result_ids': [(0, 0, { |
|||
'patient_id': data.patient_id.id, |
|||
'test_id': rec.id, |
|||
'tax_ids': rec.tax_ids.ids |
|||
})] |
|||
}) |
|||
[med_list.append(i) for i in medicine_ids] |
|||
data.medicine_ids = med_list |
|||
|
|||
@api.model |
|||
def test_end(self, rec_id): |
|||
"""Method for ending test from lab dashboard""" |
|||
data = self.sudo().browse(rec_id) |
|||
data.state = 'completed' |
|||
|
|||
@api.model |
|||
def create_invoice(self, rec_id): |
|||
"""Method for creating invoice""" |
|||
data = self.sudo().browse(rec_id) |
|||
order_lines = [] |
|||
partner_id = data.patient_id.id |
|||
if data.medicine_ids: |
|||
for rec in data.medicine_ids: |
|||
order_lines.append((0, 0, { |
|||
'product_id': self.env['product.product'].sudo().search([ |
|||
('product_tmpl_id', '=', rec.medicine_id.id)]).id, |
|||
'name': rec.medicine_id.name, |
|||
'price_unit': rec.price, |
|||
'product_uom_qty': rec.quantity, |
|||
})) |
|||
sale_order = self.env['sale.order'].sudo().create({ |
|||
'partner_id': partner_id, |
|||
'date_order': fields.Date.today(), |
|||
'reference': data.test_id.name, |
|||
'order_line': order_lines |
|||
}) |
|||
data.sold = True |
|||
data.order = sale_order.id |
|||
invoice_id = self.env['account.move'].sudo().search( |
|||
[('ref', '=', data.test_id.name) |
|||
], limit=1) |
|||
if not invoice_id: |
|||
invoice_id = self.env['account.move'].sudo().create({ |
|||
'move_type': 'out_invoice', |
|||
'partner_id': partner_id, |
|||
'invoice_date': fields.Date.today(), |
|||
'date': fields.Date.today(), |
|||
'ref': data.test_id.name |
|||
}) |
|||
for rec in data.result_ids: |
|||
invoice_id.sudo().write({ |
|||
'invoice_line_ids': [( |
|||
0, 0, { |
|||
'quantity': 1, |
|||
'name': rec.test_id.name, |
|||
'price_unit': rec.price, |
|||
'tax_ids': rec.tax_ids.ids, |
|||
'price_subtotal': rec.price, |
|||
} |
|||
)] |
|||
}) |
|||
data.invoiced = True |
|||
data.invoice_id = invoice_id.id |
|||
|
|||
def action_test_end(self): |
|||
"""Button action for test end""" |
|||
self.state = 'completed' |
|||
|
|||
def action_start_test(self): |
|||
"""Button action for start test""" |
|||
self.start_test(self.id) |
|||
|
|||
def action_create_invoice(self): |
|||
"""Button action for creating invoice""" |
|||
self.create_invoice(self.id) |
|||
|
|||
def action_view_invoice(self): |
|||
"""Method for viewing invoice from the smart button""" |
|||
return { |
|||
'name': 'Invoice', |
|||
'type': 'ir.actions.act_window', |
|||
'res_model': 'account.move', |
|||
'view_mode': 'tree,form', |
|||
"context": {"create": False, 'default_move_type': 'out_invoice'}, |
|||
'domain': [('id', '=', self.invoice_id.id)] |
|||
} |
|||
|
|||
def action_view_sale_order(self): |
|||
"""Method for viewing sale order from the smart button""" |
|||
sale_order = self.env['sale.order'].sudo().search( |
|||
[('partner_id', '=', self.patient_id.id)], limit=1) |
|||
return { |
|||
'name': 'Sale order', |
|||
'res_model': 'sale.order', |
|||
'view_mode': 'form', |
|||
'type': 'ir.actions.act_window', |
|||
'res_id': sale_order.id |
|||
} |
|||
|
|||
def print_lab_tests(self): |
|||
"""Method for printing the lab test result""" |
|||
test_list = [] |
|||
for rec in self.result_ids: |
|||
datas = { |
|||
'test': rec.test_id.test, |
|||
'normal': rec.normal, |
|||
'uom_id': rec.uom_id.name, |
|||
'result': rec.result, |
|||
'cost': rec.price, |
|||
'currency': self.env.company.currency_id.symbol |
|||
} |
|||
test_list.append(datas) |
|||
data = { |
|||
'datas': test_list, |
|||
'date': self.date, |
|||
'patient_name': self.patient_id.name, |
|||
'doctor_name': self.test_id.doctor_id.name |
|||
} |
|||
return self.env.ref( |
|||
'base_hospital_management.action_report_patient_lab_tests').report_action(self, data=data) |
@ -0,0 +1,67 @@ |
|||
# -*- coding: utf-8 -*- |
|||
################################################################################ |
|||
# |
|||
# Cybrosys Technologies Pvt. Ltd. |
|||
# |
|||
# Copyright (C) 2024-TODAY Cybrosys Technologies(<https://www.cybrosys.com>). |
|||
# Author: Subina P (odoo@cybrosys.com) |
|||
# |
|||
# You can modify it under the terms of the GNU AFFERO |
|||
# GENERAL PUBLIC LICENSE (AGPL v3), Version 3. |
|||
# |
|||
# This program is distributed in the hope that it will be useful, |
|||
# but WITHOUT ANY WARRANTY; without even the implied warranty of |
|||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|||
# GNU AFFERO GENERAL PUBLIC LICENSE (AGPL v3) for more details. |
|||
# |
|||
# You should have received a copy of the GNU AFFERO GENERAL PUBLIC LICENSE |
|||
# (AGPL v3) along with this program. |
|||
# If not, see <http://www.gnu.org/licenses/>. |
|||
# |
|||
################################################################################ |
|||
from odoo import fields, models |
|||
|
|||
|
|||
class PatientRoom(models.Model): |
|||
"""Class holding Patient room details""" |
|||
_name = 'patient.room' |
|||
_description = 'Patient Room' |
|||
|
|||
name = fields.Char(string="Name", help='The name of room', required=True) |
|||
currency_id = fields.Many2one('res.currency', string='Currency', |
|||
default=lambda self: self.env.user.company_id |
|||
.currency_id.id, |
|||
required=True, help='Currency in which ' |
|||
'payments will be done') |
|||
building_id = fields.Many2one('hospital.building', |
|||
string="Block Name", |
|||
required=True, help='Building to which ' |
|||
'the room corresponds ' |
|||
'to') |
|||
nurse_ids = fields.Many2many('hr.employee', string='Nurses', |
|||
domain="[('job_id.name','=','Nurse')]", |
|||
help='Nurses of the room') |
|||
bed_type = fields.Selection([('gatch', 'Gatch Bed'), |
|||
('electric', 'Electric'), |
|||
('stretcher', 'Stretcher'), |
|||
('low', 'Low Bed'), |
|||
('air', 'Low Air Loss'), |
|||
('circo', 'Circo Electric'), |
|||
('clinitron', 'Clinitron'), |
|||
], string="Bed Type", help='Select the type ' |
|||
'of bed') |
|||
rent = fields.Monetary(string='Rent', help='Rent for the room') |
|||
state = fields.Selection([('avail', 'Available'), |
|||
('reserve', 'Reserve'), |
|||
('not', 'Unavailable'), ], |
|||
string='State', readonly=True, |
|||
default="avail", help='State of room') |
|||
room_facilities_ids = fields.Many2many('room.facility', |
|||
string='Facilities', |
|||
help='Facilities of room') |
|||
floor_no = fields.Integer(string="Floor No.", help='The floor to ' |
|||
'which the room ' |
|||
'corresponds to') |
|||
|
|||
_sql_constraints = [('unique_room', 'unique (name)', |
|||
'Room number should be unique!')] |
@ -0,0 +1,42 @@ |
|||
# -*- coding: utf-8 -*- |
|||
################################################################################ |
|||
# |
|||
# Cybrosys Technologies Pvt. Ltd. |
|||
# |
|||
# Copyright (C) 2024-TODAY Cybrosys Technologies(<https://www.cybrosys.com>). |
|||
# Author: Subina P (odoo@cybrosys.com) |
|||
# |
|||
# You can modify it under the terms of the GNU AFFERO |
|||
# GENERAL PUBLIC LICENSE (AGPL v3), Version 3. |
|||
# |
|||
# This program is distributed in the hope that it will be useful, |
|||
# but WITHOUT ANY WARRANTY; without even the implied warranty of |
|||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|||
# GNU AFFERO GENERAL PUBLIC LICENSE (AGPL v3) for more details. |
|||
# |
|||
# You should have received a copy of the GNU AFFERO GENERAL PUBLIC LICENSE |
|||
# (AGPL v3) along with this program. |
|||
# If not, see <http://www.gnu.org/licenses/>. |
|||
# |
|||
################################################################################ |
|||
from odoo import fields, models |
|||
|
|||
|
|||
class PharmacyMedicine(models.Model): |
|||
"""Class holding Pharmacy medicine details""" |
|||
_name = 'pharmacy.medicine' |
|||
_description = 'pharmacy Medicine' |
|||
_rec_name = 'product_id' |
|||
|
|||
product_id = fields.Many2one('product.template', |
|||
string='Medicine', |
|||
help='Name of medicine', |
|||
domain="[('medicine_ok', '=', True)]") |
|||
pharmacy_id = fields.Many2one('hospital.pharmacy', |
|||
string='Pharmacy', |
|||
help='Name of pharmacy') |
|||
qty_available = fields.Float(related='product_id.qty_available', |
|||
string='Available Quantity', |
|||
help='The quantity of product available') |
|||
list_price = fields.Float(related='product_id.list_price', string='Price', |
|||
help='Price of the medicine') |
@ -0,0 +1,65 @@ |
|||
# -*- coding: utf-8 -*- |
|||
################################################################################ |
|||
# |
|||
# Cybrosys Technologies Pvt. Ltd. |
|||
# |
|||
# Copyright (C) 2024-TODAY Cybrosys Technologies(<https://www.cybrosys.com>). |
|||
# Author: Subina P (odoo@cybrosys.com) |
|||
# |
|||
# You can modify it under the terms of the GNU AFFERO |
|||
# GENERAL PUBLIC LICENSE (AGPL v3), Version 3. |
|||
# |
|||
# This program is distributed in the hope that it will be useful, |
|||
# but WITHOUT ANY WARRANTY; without even the implied warranty of |
|||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|||
# GNU AFFERO GENERAL PUBLIC LICENSE (AGPL v3) for more details. |
|||
# |
|||
# You should have received a copy of the GNU AFFERO GENERAL PUBLIC LICENSE |
|||
# (AGPL v3) along with this program. |
|||
# If not, see <http://www.gnu.org/licenses/>. |
|||
# |
|||
################################################################################ |
|||
from odoo import fields, models |
|||
|
|||
|
|||
class PrescriptionLine(models.Model): |
|||
"""Class holding prescription line details""" |
|||
_name = 'prescription.line' |
|||
_description = 'Prescription Lines' |
|||
_rec_name = 'prescription_id' |
|||
|
|||
prescription_id = fields.Many2one('hospital.prescription', |
|||
string='Prescription', |
|||
help='Name of the prescription') |
|||
medicine_id = fields.Many2one('product.template', domain=[ |
|||
'|', ('medicine_ok', '=', True), ('vaccine_ok', '=', True)], |
|||
string='Medicine', required=True, |
|||
help='Medicines or vaccines') |
|||
quantity = fields.Integer(string='Quantity', required=True, |
|||
help="The number of medicines for the time " |
|||
"period") |
|||
no_intakes = fields.Float(string='Intakes', required=True, |
|||
help="How much medicine want to take") |
|||
time = fields.Selection( |
|||
[('once', 'Once in a day'), ('twice', 'Twice in a Day'), |
|||
('thrice', 'Thrice in a day'), ('morning', 'In Morning'), |
|||
('noon', 'In Noon'), ('evening', 'In Evening')], string='Time', |
|||
required=True, |
|||
help='The interval for medicine intake') |
|||
note = fields.Selection( |
|||
[('before', 'Before Food'), ('after', 'After Food')], |
|||
string='Before/ After Food', |
|||
help='Whether the medicine to be taken before or after food') |
|||
inpatient_id = fields.Many2one('hospital.inpatient', |
|||
string='Inpatient', |
|||
help='The inpatient corresponds to the ' |
|||
'prescription line') |
|||
outpatient_id = fields.Many2one('hospital.outpatient', |
|||
string='Outpatient', |
|||
help='The outpatient corresponds to the ' |
|||
'prescription line') |
|||
res_partner_id = fields.Many2one('res.partner', |
|||
string='Patient', |
|||
help='The outpatient corresponds to the ' |
|||
'prescription line', |
|||
related='outpatient_id.patient_id') |
@ -0,0 +1,57 @@ |
|||
# -*- coding: utf-8 -*- |
|||
################################################################################ |
|||
# |
|||
# Cybrosys Technologies Pvt. Ltd. |
|||
# |
|||
# Copyright (C) 2024-TODAY Cybrosys Technologies(<https://www.cybrosys.com>). |
|||
# Author: Subina P (odoo@cybrosys.com) |
|||
# |
|||
# You can modify it under the terms of the GNU AFFERO |
|||
# GENERAL PUBLIC LICENSE (AGPL v3), Version 3. |
|||
# |
|||
# This program is distributed in the hope that it will be useful, |
|||
# but WITHOUT ANY WARRANTY; without even the implied warranty of |
|||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|||
# GNU AFFERO GENERAL PUBLIC LICENSE (AGPL v3) for more details. |
|||
# |
|||
# You should have received a copy of the GNU AFFERO GENERAL PUBLIC LICENSE |
|||
# (AGPL v3) along with this program. |
|||
# If not, see <http://www.gnu.org/licenses/>. |
|||
# |
|||
################################################################################ |
|||
from odoo import api, fields, models |
|||
|
|||
|
|||
class ProductTemplate(models.Model): |
|||
"""Inherited to add more fields and functions""" |
|||
_inherit = 'product.template' |
|||
|
|||
medicine_ok = fields.Boolean(string='Medicine', help='True for medicines') |
|||
vaccine_ok = fields.Boolean(string="Vaccine", help='True for vaccines') |
|||
pharmacy_id = fields.Many2one('hospital.pharmacy', |
|||
string='Pharmacy', |
|||
help='Name of the pharmacy') |
|||
medicine_brand_id = fields.Many2one('medicine.brand', |
|||
string='Brand', |
|||
help='Indicates the brand of medicine ' |
|||
'or vaccine') |
|||
|
|||
@api.model |
|||
def action_get_medicine_data(self): |
|||
"""Returns medicine list to the pharmacy dashboard""" |
|||
medicines = [] |
|||
for rec in self.env['product.template'].sudo().search( |
|||
[('medicine_ok', '=', True)]): |
|||
medicines.append( |
|||
[rec.name, rec.list_price, rec.qty_available, rec.image_1920, rec.id]) |
|||
return medicines |
|||
|
|||
@api.model |
|||
def action_get_vaccine_data(self): |
|||
"""Returns vaccine list to the pharmacy dashboard""" |
|||
vaccines = [] |
|||
for rec in self.env['product.template'].sudo().search( |
|||
[('vaccine_ok', '=', True)]): |
|||
vaccines.append( |
|||
[rec.name, rec.list_price, rec.qty_available, rec.image_1920]) |
|||
return vaccines |
@ -0,0 +1,584 @@ |
|||
# -*- coding: utf-8 -*- |
|||
################################################################################ |
|||
# |
|||
# Cybrosys Technologies Pvt. Ltd. |
|||
# |
|||
# Copyright (C) 2024-TODAY Cybrosys Technologies(<https://www.cybrosys.com>). |
|||
# Author: Subina P (odoo@cybrosys.com) |
|||
# |
|||
# You can modify it under the terms of the GNU AFFERO |
|||
# GENERAL PUBLIC LICENSE (AGPL v3), Version 3. |
|||
# |
|||
# This program is distributed in the hope that it will be useful, |
|||
# but WITHOUT ANY WARRANTY; without even the implied warranty of |
|||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|||
# GNU AFFERO GENERAL PUBLIC LICENSE (AGPL v3) for more details. |
|||
# |
|||
# You should have received a copy of the GNU AFFERO GENERAL PUBLIC LICENSE |
|||
# (AGPL v3) along with this program. |
|||
# If not, see <http://www.gnu.org/licenses/>. |
|||
# |
|||
################################################################################ |
|||
import math |
|||
import re |
|||
import base64 |
|||
from datetime import date |
|||
from barcode import EAN13 |
|||
from barcode.writer import ImageWriter |
|||
from dateutil.relativedelta import * |
|||
from odoo import api, fields, models |
|||
|
|||
|
|||
class ResPartner(models.Model): |
|||
"""Inherited to add more fields and functions""" |
|||
_inherit = 'res.partner' |
|||
_description = 'Hospital Patients' |
|||
|
|||
date_of_birth = fields.Date(string='Date of Birth', |
|||
help='Date of birth of the patient') |
|||
blood_group = fields.Selection(string='Blood Group', |
|||
help='Blood group of the patient', |
|||
selection=[('a', 'A'), ('b', 'B'), |
|||
('o', 'O'), ('ab', 'AB')]) |
|||
rh_type = fields.Selection(selection=[('-', '-ve'), ('+', '+ve')], |
|||
string='RH Type', |
|||
help='Rh type of the blood group') |
|||
gender = fields.Selection(selection=[ |
|||
('male', 'Male'), ('female', 'Female'), ('other', 'Other') |
|||
], string='Gender', help='Gender of the patient') |
|||
marital_status = fields.Selection(selection=[ |
|||
('married', 'Married'), ('unmarried', 'Unmarried'), ('widow', 'Widow'), |
|||
('widower', 'Widower'), ('divorcee', 'Divorcee') |
|||
], string='Marital Status', help='Marital status of patient') |
|||
is_alive = fields.Selection( |
|||
string='Status', |
|||
selection=[('alive', 'Alive'), ('dead', 'Dead')], |
|||
default='alive', help='True for alive patient') |
|||
patient_seq = fields.Char(string='Patient No.', |
|||
help='Sequence number of the patient', copy=False, |
|||
readonly=True, index=True, |
|||
default=lambda self: 'New') |
|||
notes = fields.Html(string='Note', help='Notes regarding the notes', |
|||
sanitize_style=True) |
|||
patient_profession = fields.Char(string="Profession", |
|||
help="Profession of patient") |
|||
doctor_id = fields.Many2one('hr.employee', |
|||
domain=[('job_id.name', '=', 'Doctor')], |
|||
string="Family Doctor", |
|||
help='Family doctor of the patient') |
|||
barcode = fields.Char(string='Barcode', help='Barcode for the patient') |
|||
barcode_png = fields.Binary(string='Barcode PNG', |
|||
help='Image file of the barcode', readonly=True) |
|||
group = fields.Selection(selection=[ |
|||
('hindu', 'Hindu'), ('muslim', 'Muslim'), ('christian', 'Christian')], |
|||
string="Ethnic Group", help="Specify your religion") |
|||
risk = fields.Text(string="Genetic Risks", |
|||
help='Genetic risks of the patient') |
|||
insurance_id = fields.Many2one('hospital.insurance', |
|||
string="Insurance", |
|||
help="Patient insurance") |
|||
unique_id = fields.Char(string='Unique ID', |
|||
help="Unique identifier to fetch " |
|||
"patient insurance data") |
|||
family_ids = fields.One2many('hospital.family', |
|||
'family_id', |
|||
string="Family ID", help='Family of a patient') |
|||
lab_test_ids = fields.One2many('patient.lab.test', |
|||
'patient_id', |
|||
string='Lab Test', |
|||
help='Lab tests for the patient') |
|||
prescription_ids = fields.One2many('prescription.line', |
|||
'res_partner_id', |
|||
string='Prescription', |
|||
help='Prescription for patient') |
|||
economic_level = fields.Selection(selection=[ |
|||
('low', 'Lower Class'), ('middle', 'Middle Class'), |
|||
('upper', 'Upper Class')], string="Socioeconomic", |
|||
help="Specify your economic status") |
|||
education_level = fields.Selection(selection=[ |
|||
('post', 'Post Graduation'), ('graduation', 'Graduation'), |
|||
('pre', 'Pre Graduation')], string="Education Level", |
|||
help="Education status of patient") |
|||
house_level = fields.Selection(selection=[ |
|||
('good', 'Good'), ('bad', 'Bad'), ('poor', 'Poor')], |
|||
string="House Condition", help="Specify your house's condition") |
|||
work_home = fields.Boolean(string='Work At Home', |
|||
help='True if you are working from home') |
|||
hours_outside = fields.Integer(string='Hours Stay Outside Home', |
|||
help="Specify how many hours you stay away " |
|||
"from home") |
|||
hostile = fields.Boolean(string='Hostile Area', |
|||
help="Specify your house in a friendly " |
|||
"neighbourhood ") |
|||
income = fields.Monetary(string='Income', help="The in come of patient") |
|||
currency_id = fields.Many2one('res.currency', string='Currency', |
|||
help='Currency in which invoices and payments' |
|||
' will be generated', |
|||
default=lambda self: self.env.user.company_id |
|||
.currency_id.id, required=True) |
|||
sanitary = fields.Boolean('Sanitary Sewers', |
|||
help="A sewer or sewer system for carrying off " |
|||
"wastewater, waste matter from a residence," |
|||
" business, etc") |
|||
running = fields.Boolean(string='Running Water', |
|||
help="water that comes into a building through " |
|||
"pipes. A cabin with hot and cold running " |
|||
"water.") |
|||
electricity = fields.Boolean(string='Electricity', |
|||
help='True if you have electricity') |
|||
gas = fields.Boolean(string='Gas Supply', |
|||
help='True if you have gas supply') |
|||
trash = fields.Boolean(string='Trash Collection', |
|||
help='True if you have trash collection') |
|||
home_phone = fields.Boolean(string='Telephone', |
|||
help='True if you have telephone') |
|||
tv = fields.Boolean(string='Television', help='True if you have television') |
|||
internet = fields.Boolean(string='Internet', |
|||
help='True if you have internet') |
|||
help = fields.Selection([('yes', 'Yes'), ('no', 'No')], |
|||
string="Family Help", |
|||
help="Specify whether your family is willing " |
|||
"to help or not") |
|||
discussion = fields.Selection([('yes', 'Yes'), ('no', 'No')], |
|||
string="Family Discussion ", |
|||
help="Specify your family have a good " |
|||
"discussion at home ") |
|||
ability = fields.Selection([('very', 'Very good'), ('good', 'Good'), |
|||
('bad', 'Bad'), ('poor', 'Poor')], |
|||
string="Family Ability", |
|||
help="family status of the patient") |
|||
time_sharing = fields.Selection([('yes', 'Yes'), ('no', 'No')], |
|||
string=" Family Time Sharing ", |
|||
help="Specify your family share time " |
|||
"at home ") |
|||
affection = fields.Selection([('very', 'Very good'), |
|||
('good', 'Good'), |
|||
('bad', 'Bad'), ('poor', 'Poor')], |
|||
string="Family Affection ", |
|||
help="Specify your family's affection ") |
|||
single = fields.Boolean(string='Single Parent Family', |
|||
help='Whether single parent family or not') |
|||
violence = fields.Boolean(string='Domestic Violence', |
|||
help='True if you are facing any domestic ' |
|||
'violence') |
|||
children = fields.Boolean(string='Working Children', |
|||
help='Do you have working children') |
|||
abuse = fields.Boolean(string='Sexual Abuse', |
|||
help='Do you faced any sexual abuse') |
|||
drug = fields.Boolean(string='Drug Addiction', |
|||
help='Do you have drug addiction') |
|||
withdrawal = fields.Boolean(string='Withdrawal', |
|||
help='Do you faced any withdrawal symptoms') |
|||
in_prison = fields.Boolean(string='Has Been In Prison', |
|||
help='True if you had been in prison') |
|||
current_prison = fields.Boolean(string='Currently In Prison', |
|||
help='True if you are in prison currently') |
|||
relative_prison = fields.Boolean(string='Relative In Prison', |
|||
help='True if any of your relative is ' |
|||
'in prison') |
|||
hospital_vaccination_ids = fields.One2many( |
|||
'hospital.vaccination', 'patient_id', |
|||
string='Vaccination', help='Vaccination details of ' |
|||
'patient') |
|||
fertile = fields.Boolean(string='Fertile', help="""Capable of developing |
|||
into a complete organism; |
|||
fertilized. Capable of supporting |
|||
plant life; favorable to the |
|||
growth of crops and plants.""") |
|||
menarche_age = fields.Integer(string='Menarche Age', help="""The first |
|||
menstrual period in a female adolescent""") |
|||
pause = fields.Boolean(string='Menopause', help="""Menopause is a point in |
|||
time 12 months after a woman's last period""") |
|||
pause_age = fields.Integer(string='Menopause Age', |
|||
help='Age at which menopause occurred') |
|||
pap = fields.Boolean(string='PAP Test', |
|||
help=""" |
|||
A procedure in which a small brush is used to gently |
|||
remove cells from the surface of the cervix and the |
|||
area around it so they can be checked under a |
|||
microscope for cervical cancer or cell changes that |
|||
may lead to cervical cancer.""") |
|||
colposcopy = fields.Boolean(string='Colposcopy', help=""" test to take a |
|||
closer look at your cervix""") |
|||
self = fields.Boolean(string='Self breast examination', |
|||
help="A breast self-exam for breast awareness is " |
|||
"in inspection " |
|||
"of your breasts that women do on your own") |
|||
mommography = fields.Boolean(string='Mommography', |
|||
help="Mammograms can be used to look for " |
|||
"breast cancer") |
|||
last_pap = fields.Date(string="Last PAP Test", |
|||
help='The date on which last PAP test has been done') |
|||
last_col = fields.Date(string="Last Colposcopy", |
|||
help='The date on which last colposcopy has been ' |
|||
'done') |
|||
deceased = fields.Boolean(string='Deceased during 1st week', |
|||
help='The family member deceased during first ' |
|||
'week') |
|||
grandiva = fields.Boolean(string='Grandiva', help='True for grandiva') |
|||
alive = fields.Boolean(string='Born Alive', help='Whether born alive or ' |
|||
'not') |
|||
premature = fields.Integer(string='Premature', |
|||
help="Premature birth is birth that happens too" |
|||
"soon, before 37 weeks of pregnancy") |
|||
abortions = fields.Integer(string='No Of Abortions', help='Number of ' |
|||
'abortions of ' |
|||
'patient') |
|||
exercise = fields.Boolean(string='Exercise', help='True if patient doing ' |
|||
'exercise regularly') |
|||
minute = fields.Integer(string='Minute/Day', help='The duration of ' |
|||
'exercise per day') |
|||
|
|||
day_sleep = fields.Boolean(string='Sleeps At Daytime', help='True if ' |
|||
'sleeps at ' |
|||
'daytime') |
|||
sleep_hrs = fields.Integer(string='Sleep Hours', help='Duration of sleep') |
|||
meals = fields.Integer(string='Meals/Day', help='Number of meals per day') |
|||
alone = fields.Boolean(string='Eat Alone', help='True if eats alone') |
|||
coffee = fields.Boolean(string='Coffee', help='True if you have a habit ' |
|||
'of drinking coffee') |
|||
cup = fields.Integer(string='Cups/Day', help='Number of cups of coffee ' |
|||
'per day') |
|||
drink = fields.Boolean(string='Soft Drink', help='True if you drinks soft ' |
|||
'drinks') |
|||
salt = fields.Boolean(string='Salt', help='True if you use salt') |
|||
diet = fields.Boolean(string='Currently On Diet', help='True if you are ' |
|||
'on diet currently') |
|||
smoke = fields.Boolean(string='Smoker', help='True for smoker') |
|||
ex_smoke = fields.Boolean(string='Ex-Smoker', help='True for ex-smoker') |
|||
age_start = fields.Integer(string='Age of Started Smoking', |
|||
help='Age on which you started your smoking') |
|||
cigarettes = fields.Integer(string='Cigarettes/Day', |
|||
help='Number of cigarettes per day') |
|||
passive = fields.Boolean(string='Passive Smoker', |
|||
help='True for passive smokers') |
|||
age_quit = fields.Integer(string='Age of Quitting', |
|||
help='Age at which you quit your smoking habit') |
|||
alcoholic = fields.Boolean(string='Alcoholic', help='True for alcoholics') |
|||
ex_alcoholic = fields.Boolean(string='Ex-Alcoholic', help='True for ex- ' |
|||
'alcoholics') |
|||
age_start_alco = fields.Integer(string='Age to Start Drinking', |
|||
help='Age at which you started your ' |
|||
'drinking habit') |
|||
beer = fields.Integer(string='Beer/Day', |
|||
help='Number of beers per day') |
|||
liquor = fields.Integer(string='Liquor/Day', |
|||
help='Liquors per day') |
|||
wine = fields.Integer(string='Wine/Day', |
|||
help='Number of wines per day') |
|||
age_quit_alcoholic = fields.Integer(string='Age Of Quitting', |
|||
help='Age at which you started your ' |
|||
'drinking habit') |
|||
drugs = fields.Boolean(string='Drug User', help='True for drug users') |
|||
ex_drugs = fields.Boolean(string='Ex-Drug User', help='True for Ex drug ' |
|||
'user') |
|||
iv_user = fields.Boolean(string='IV Drug User', help='True for IV drug ' |
|||
'user') |
|||
age_start_drug = fields.Integer(string='Age to Start Using Drugs', |
|||
help='Age at which you started using drug') |
|||
age_quit_drug = fields.Integer(string='Drug Quitting Age', help='Age of ' |
|||
'quitting ' |
|||
'drug') |
|||
orientation = fields.Selection([('straight', 'Straight'), |
|||
('homo', 'Homosexual'), |
|||
('trans', 'Trans-Gender')], |
|||
string="Orientation") |
|||
age_sex = fields.Integer(string="Age of First Encounter", |
|||
help='Age of first sex encounter') |
|||
partners = fields.Integer(string="No of Partners", |
|||
help='Number of sex partners') |
|||
anti = fields.Selection( |
|||
[('pills', 'Contraceptive Pills'), ('ring', 'Contraceptive Ring'), |
|||
('injection', 'Contraceptive Injection')], |
|||
string="Contraceptive Methods", help='Choose your contraceptive method') |
|||
oral = fields.Boolean(string='Oral Sex', help=("uttered by the mouth or in " |
|||
"words")) |
|||
anal = fields.Boolean(string='Anal Sex', help="True if you are " |
|||
"encountering anal sex") |
|||
prostitute = fields.Boolean(string='Prostitute', help='True for ' |
|||
'prostitutes') |
|||
prostitute_sex = fields.Boolean(string='Sex With Prostitute', |
|||
help='True if you are encountered sex ' |
|||
'with prostitute') |
|||
sex_notes = fields.Text(string='Notes', help='Write down the notes') |
|||
rider = fields.Boolean(string='Motorcycle Rider', help='True for ' |
|||
'motorcycle riders') |
|||
helmet = fields.Boolean(string='Uses Helmet', |
|||
help='True if you regularly use helmet') |
|||
laws = fields.Boolean(string='Obey Traffic Laws', |
|||
help='True if you obey traffic rules') |
|||
revision = fields.Boolean(string='Car Revision', help='True if car ' |
|||
'revision is done') |
|||
belt = fields.Boolean(string='Seat Belt', |
|||
help='True if you uses seat belt regularly') |
|||
safety = fields.Boolean(string='Car Child Safety', |
|||
help='True if you have car child safety') |
|||
home = fields.Boolean(string='Home Safety', help='True for home safety') |
|||
occupation = fields.Char(string='Occupation', help='Your occupation') |
|||
|
|||
@api.model |
|||
def create(self, vals): |
|||
"""Inherits create function for sequence generation""" |
|||
if vals.get('patient_seq', 'New') == 'New': |
|||
vals['patient_seq'] = self.env['ir.sequence'].next_by_code( |
|||
'patient.sequence') or 'New' |
|||
return super().create(vals) |
|||
|
|||
def action_view_invoice(self): |
|||
"""Returns patient invoice""" |
|||
self.ensure_one() |
|||
return { |
|||
'name': 'Patient Invoice', |
|||
'view_mode': 'tree,form', |
|||
'res_model': 'account.move', |
|||
'type': 'ir.actions.act_window', |
|||
'domain': [('partner_id', '=', self.id)], |
|||
'context': "{'create':False}" |
|||
} |
|||
|
|||
def name_get(self): |
|||
"""Returns the patient name""" |
|||
result = [] |
|||
for rec in self: |
|||
result.append((rec.id, f'{rec.patient_seq} - {rec.name}')) |
|||
return result |
|||
|
|||
def alive_status(self): |
|||
"""Function for setting the value of is_alive field""" |
|||
if self.is_alive == 'alive': |
|||
self.is_alive = 'dead' |
|||
else: |
|||
self.is_alive = 'alive' |
|||
|
|||
def action_schedule(self): |
|||
"""Returns form view of hospital appointment wizard""" |
|||
return { |
|||
'type': 'ir.actions.act_window', |
|||
'res_model': 'hospital.outpatient', |
|||
'view_type': 'form', |
|||
'view_mode': 'form', |
|||
'target': 'new', |
|||
'views': [[False, 'form']], |
|||
'context': { |
|||
'default_patient_id': self.id |
|||
} |
|||
} |
|||
|
|||
@api.model |
|||
def ean_checksum(self, eancode): |
|||
"""Returns the checksum of an ean string of length 13, returns -1 if |
|||
the string has the wrong length""" |
|||
if len(eancode) != 13: |
|||
return -1 |
|||
odd_sum = 0 |
|||
even_sum = 0 |
|||
ean_value = eancode |
|||
reverse_value = ean_value[::-1] |
|||
final_ean = reverse_value[1:] |
|||
for i in range(len(final_ean)): |
|||
if i % 2 == 0: |
|||
odd_sum += int(final_ean[i]) |
|||
else: |
|||
even_sum += int(final_ean[i]) |
|||
total = (odd_sum * 3) + even_sum |
|||
check = int(10 - math.ceil(total % 10.0)) % 10 |
|||
return check |
|||
|
|||
def check_ean(eancode): |
|||
"""Returns True if eancode is a valid ean13 string, or null""" |
|||
if not eancode: |
|||
return True |
|||
if len(eancode) != 13: |
|||
return False |
|||
int(eancode) |
|||
return eancode.ean_checksum(eancode) == int(eancode[-1]) |
|||
|
|||
def generate_ean(self, ean): |
|||
"""Creates and returns a valid ean13 from an invalid one""" |
|||
if not ean: |
|||
return "0000000000000" |
|||
ean = re.sub("[A-Za-z]", "0", ean) |
|||
ean = re.sub("[^0-9]", "", ean) |
|||
ean = ean[:13] |
|||
if len(ean) < 13: |
|||
ean = ean + '0' * (13 - len(ean)) |
|||
return ean[:-1] + str(self.ean_checksum(ean)) |
|||
|
|||
def action_generate_patient_card(self): |
|||
"""Method for generating the patient card""" |
|||
current_age = 0 |
|||
gender_caps = '' |
|||
blood_caps = '' |
|||
if not self.barcode: |
|||
ean = self.sudo().generate_ean(str(self.id)) |
|||
self.sudo().write({'barcode': ean}) |
|||
number = self.barcode |
|||
my_code = EAN13(number, writer=ImageWriter()) |
|||
my_code.save("code") |
|||
with open('code.png', 'rb') as f: |
|||
self.sudo().write({ |
|||
'barcode_png': base64.b64encode(f.read()) |
|||
}) |
|||
if self.gender: |
|||
gender_caps = self.gender.capitalize() |
|||
if self.blood_group: |
|||
blood_caps = self.blood_group.capitalize() |
|||
if self.date_of_birth: |
|||
today = date.today() |
|||
dob = self.date_of_birth |
|||
current_age = relativedelta(today, dob).years |
|||
company = self.env['res.company'].sudo().search( |
|||
[('id', '=', self.env.context['allowed_company_ids'])]) |
|||
data = { |
|||
'name': self.name, |
|||
'code': self.patient_seq, |
|||
'age': current_age, |
|||
'gender': gender_caps, |
|||
'dob': self.date_of_birth, |
|||
'blood': blood_caps + str(self.rh_type), |
|||
'street': self.street, |
|||
'street2': self.street2, |
|||
'state': self.state_id.name, |
|||
'country': self.country_id.name, |
|||
'city': self.city, |
|||
'phone': self.phone, |
|||
'image': self.sudo().read(['image_1920'])[0], |
|||
'barcode': self.sudo().read(['barcode_png'])[0], |
|||
'company_name': company.name, |
|||
'company_street': company.street, |
|||
'company_street2': company.street2, |
|||
'company_city': company.city, |
|||
'company_state': company.state_id.name, |
|||
'company_zip': company.zip, |
|||
} |
|||
return self.env.ref( |
|||
'base_hospital_management.action_report_patient_card' |
|||
).report_action(None, data=data) |
|||
|
|||
@api.model |
|||
def reception_op_barcode(self, kw): |
|||
"""Returns a patient based on the barcode""" |
|||
values = { |
|||
'name': '', |
|||
'date_of_birth': '', |
|||
'phone': '', |
|||
'blood_group': '', |
|||
'gender': '', |
|||
} |
|||
if kw['patient_data']: |
|||
patient = self.sudo().search( |
|||
['|', ('id', '=', kw['patient_data']), |
|||
('phone', '=', kw['patient_data'])]) |
|||
if patient: |
|||
values = { |
|||
'name': patient.name, |
|||
'date_of_birth': patient.date_of_birth, |
|||
'phone': patient.phone, |
|||
'blood_group': patient.blood_group, |
|||
'gender': patient.gender, |
|||
} |
|||
return values |
|||
|
|||
@api.model |
|||
def reception_op_phone(self, phone): |
|||
"""Returns a patient details having the phone number""" |
|||
patient_phone = self.sudo().search( |
|||
[('phone', '=', phone['patient-phone'])]) |
|||
return { |
|||
'patient_seq': patient_phone.patient_seq, |
|||
'name': patient_phone.name, |
|||
'date_of_birth': patient_phone.date_of_birth, |
|||
'blood_group': patient_phone.blood_group, |
|||
'gender': patient_phone.gender, |
|||
} |
|||
|
|||
@api.model |
|||
def action_get_patient_data(self, patient_id): |
|||
"""Method which returns patient details""" |
|||
data = self.sudo().search([ |
|||
'|', ('patient_seq', '=', patient_id), |
|||
('barcode', '=', patient_id) |
|||
]) |
|||
patient_history = [] |
|||
for rec in self.env['hospital.outpatient'].sudo().search( |
|||
[('patient_id', '=', data.id)]): |
|||
patient_history.append( |
|||
[rec.op_reference, str(rec.op_date), |
|||
rec.doctor_id.doctor_id.name]) |
|||
values = { |
|||
'name': data.name, |
|||
'unique': data.patient_seq, |
|||
'email': data.email, |
|||
'phone': data.phone, |
|||
'dob': data.date_of_birth, |
|||
'image_1920': data.image_1920, |
|||
'status': data.marital_status, |
|||
'history': patient_history, |
|||
} |
|||
if not data.name: |
|||
values['name'] = 'Patient Not Found' |
|||
if not data.patient_seq: |
|||
values['unique'] = '' |
|||
if data.blood_group: |
|||
blood_caps = data.blood_group.capitalize() |
|||
values['blood_group'] = blood_caps + str(data.rh_type) |
|||
else: |
|||
values['blood_group'] = '' |
|||
if data.gender: |
|||
gender_caps = data.gender.capitalize() |
|||
values['gender'] = gender_caps |
|||
else: |
|||
values['gender'] = '' |
|||
return values |
|||
|
|||
@api.model |
|||
def create_sale_order_pharmacy(self, order): |
|||
"""Method for creating sale order for medicines""" |
|||
medicine = [] |
|||
op_record = self.env['hospital.outpatient'].sudo().search( |
|||
[('op_reference', '=', order), '|', |
|||
('active', 'in', [False, True])]) |
|||
for rec in op_record.prescription_ids: |
|||
medicine.append([rec.medicine_id.id, rec.quantity]) |
|||
sale_order_pharmacy = self.env['sale.order'].sudo().create({ |
|||
'partner_id': op_record.patient_id.id, |
|||
}) |
|||
for new in medicine: |
|||
self.env['sale.order.line'].sudo().create({ |
|||
'product_id': new[0], |
|||
'product_uom_qty': new[1], |
|||
'order_id': sale_order_pharmacy.id, |
|||
}) |
|||
|
|||
@api.model |
|||
def create_patient(self, post): |
|||
"""Method for creating a patient""" |
|||
if post and not post['patient_id']: |
|||
patient = self.sudo().search([('name', '=', post['op_name'])]) |
|||
if not patient: |
|||
|
|||
patient = self.sudo().create({ |
|||
'name': post['op_name'], |
|||
'blood_group': post['op_blood_group'], |
|||
'gender': post['op_gender'] |
|||
}) |
|||
if 'op_dob' in post.keys(): |
|||
patient.sudo().write({'date_of_birth': post['op_dob']}) |
|||
else: |
|||
patient = self.sudo().search([('id', '=', post['patient_id'])]) |
|||
out_patient = self.env['hospital.outpatient'].sudo().search([('patient_id','=', patient.id)]) |
|||
if not out_patient: |
|||
self.env['hospital.outpatient'].sudo().create({ |
|||
'patient_id': patient.id, |
|||
'op_date': post['date'], |
|||
'reason': post['reason'], |
|||
'slot': post['slot'], |
|||
'doctor_id': self.env['doctor.allocation'].sudo().browse( |
|||
post['doctor']).id |
|||
}) |
|||
|
|||
@api.model |
|||
def fetch_patient_data(self): |
|||
"""Method for returning patient data""" |
|||
return self.sudo().search_read( |
|||
[('patient_seq', 'not in', ['New', 'Employee', 'User'])]) |
@ -0,0 +1,35 @@ |
|||
# -*- coding: utf-8 -*- |
|||
################################################################################ |
|||
# |
|||
# Cybrosys Technologies Pvt. Ltd. |
|||
# |
|||
# Copyright (C) 2024-TODAY Cybrosys Technologies(<https://www.cybrosys.com>). |
|||
# Author: Subina P (odoo@cybrosys.com) |
|||
# |
|||
# You can modify it under the terms of the GNU AFFERO |
|||
# GENERAL PUBLIC LICENSE (AGPL v3), Version 3. |
|||
# |
|||
# This program is distributed in the hope that it will be useful, |
|||
# but WITHOUT ANY WARRANTY; without even the implied warranty of |
|||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|||
# GNU AFFERO GENERAL PUBLIC LICENSE (AGPL v3) for more details. |
|||
# |
|||
# You should have received a copy of the GNU AFFERO GENERAL PUBLIC LICENSE |
|||
# (AGPL v3) along with this program. |
|||
# If not, see <http://www.gnu.org/licenses/>. |
|||
# |
|||
################################################################################ |
|||
from odoo import api, models |
|||
|
|||
|
|||
class ResUsers(models.Model): |
|||
"""Inherited to prevent creating patients while creating users""" |
|||
_inherit = 'res.users' |
|||
|
|||
@api.model_create_multi |
|||
def create(self, vals_list): |
|||
"""Override to add patient_seq to the partners created from users""" |
|||
users = super().create(vals_list) |
|||
for user in users: |
|||
user.partner_id.patient_seq = 'User' |
|||
return users |
@ -0,0 +1,30 @@ |
|||
# -*- coding: utf-8 -*- |
|||
################################################################################ |
|||
# |
|||
# Cybrosys Technologies Pvt. Ltd. |
|||
# |
|||
# Copyright (C) 2024-TODAY Cybrosys Technologies(<https://www.cybrosys.com>). |
|||
# Author: Subina P (odoo@cybrosys.com) |
|||
# |
|||
# You can modify it under the terms of the GNU AFFERO |
|||
# GENERAL PUBLIC LICENSE (AGPL v3), Version 3. |
|||
# |
|||
# This program is distributed in the hope that it will be useful, |
|||
# but WITHOUT ANY WARRANTY; without even the implied warranty of |
|||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|||
# GNU AFFERO GENERAL PUBLIC LICENSE (AGPL v3) for more details. |
|||
# |
|||
# You should have received a copy of the GNU AFFERO GENERAL PUBLIC LICENSE |
|||
# (AGPL v3) along with this program. |
|||
# If not, see <http://www.gnu.org/licenses/>. |
|||
# |
|||
################################################################################ |
|||
from odoo import fields, models |
|||
|
|||
|
|||
class RoomFacility(models.Model): |
|||
"""Class holding room facilities""" |
|||
_name = 'room.facility' |
|||
_description = 'Room Facility' |
|||
|
|||
name = fields.Char(string="Facilities", help='Name of room facility') |
@ -0,0 +1,66 @@ |
|||
<?xml version="1.0" encoding="utf-8"?> |
|||
<odoo> |
|||
<!-- Patient lab test report action--> |
|||
<record id="action_report_patient_lab_tests" model="ir.actions.report"> |
|||
<field name="name">Patient Lab Tests</field> |
|||
<field name="model">lab.test.line</field> |
|||
<field name="report_type">qweb-pdf</field> |
|||
<field name="report_name"> |
|||
base_hospital_management.report_patient_lab_tests |
|||
</field> |
|||
<field name="report_file"> |
|||
base_hospital_management.report_patient_lab_tests |
|||
</field> |
|||
<field name="binding_model_id" ref="model_lab_test_line"/> |
|||
<field name="binding_type">report</field> |
|||
</record> |
|||
<!-- Patient lab test report template--> |
|||
<template id="report_patient_lab_tests"> |
|||
<t t-call="web.html_container"> |
|||
<t t-call="web.external_layout"> |
|||
<center> |
|||
<h1>Lab Tests</h1> |
|||
</center> |
|||
<div> |
|||
<strong>Date :</strong> |
|||
<span t-esc="date"/> |
|||
</div> |
|||
<div> |
|||
<strong>Patient's Name :</strong> |
|||
<span t-esc="patient_id"/> |
|||
</div> |
|||
<div> |
|||
<strong>Doctor Name :</strong> |
|||
<span t-esc="doctor_name"/> |
|||
</div> |
|||
<table class="table table-striped"> |
|||
<tr> |
|||
<th>Test</th> |
|||
<th>Normal</th> |
|||
<th>Unit</th> |
|||
<th>Result</th> |
|||
<th>Price Including Tax</th> |
|||
</tr> |
|||
<tr t-foreach="datas" t-as="line" style="text-align:center"> |
|||
<td> |
|||
<span t-esc="line['name']"/> |
|||
</td> |
|||
<td> |
|||
<span t-esc="line['normal']"/> |
|||
</td> |
|||
<td> |
|||
<span t-esc="line['uom_id']"/> |
|||
</td> |
|||
<td> |
|||
<span t-esc="line['result']"/> |
|||
</td> |
|||
<td> |
|||
<t t-esc="line['currency']"/> |
|||
<span t-esc="line['cost']"/> |
|||
</td> |
|||
</tr> |
|||
</table> |
|||
</t> |
|||
</t> |
|||
</template> |
|||
</odoo> |
@ -0,0 +1,208 @@ |
|||
<?xml version="1.0" encoding="utf-8"?> |
|||
<odoo> |
|||
<!--Patient prescription report --> |
|||
<record id="action_report_patient_prescription" model="ir.actions.report"> |
|||
<field name="name">Patient Prescription</field> |
|||
<field name="model">res.partner</field> |
|||
<field name="report_type">qweb-pdf</field> |
|||
<field name="report_name">base_hospital_management.patient_prescription_report</field> |
|||
<field name="report_file">base_hospital_management.patient_prescription_report</field> |
|||
<field name="binding_model_id" ref="model_res_partner"/> |
|||
<field name="binding_type">report</field> |
|||
</record> |
|||
<!-- Patient prescription report template--> |
|||
<template id="patient_prescription_report"> |
|||
<t t-call="web.html_container"> |
|||
<t t-call="web.external_layout"> |
|||
<center> |
|||
<h1>Doctor Prescription</h1></center> |
|||
<div> |
|||
<strong>Date :</strong> |
|||
<span t-esc="date"/> |
|||
</div> |
|||
<div> |
|||
<strong>Patient's Name :</strong> |
|||
<span t-esc="patient_name"/> |
|||
</div> |
|||
<div> |
|||
<strong>Doctor :</strong> |
|||
<span t-esc="doctor_name"/> |
|||
</div> |
|||
<table class="table"> |
|||
<thead> |
|||
<tr style="text-align:left"> |
|||
<th>SL.No</th> |
|||
<th>Medicine</th> |
|||
<th>Intake</th> |
|||
<th>Time</th> |
|||
<th>Quantity</th> |
|||
<th>Before/ After Food</th> |
|||
</tr> |
|||
</thead> |
|||
<t t-set="i" t-value="0"/> |
|||
<tbody> |
|||
<center> |
|||
<tr t-foreach="datas" t-as="line"> |
|||
<td> |
|||
<t t-set="i" t-value="i + 1"/> |
|||
<span t-esc="i"/> |
|||
</td> |
|||
<td> |
|||
<span t-esc="line['medicine']"/> |
|||
</td> |
|||
<td> |
|||
<span t-esc="line['intake']"/> |
|||
</td> |
|||
<td> |
|||
<span t-esc="line['time']"/> |
|||
</td> |
|||
<td> |
|||
<span t-esc="line['quantity']"/> |
|||
</td> |
|||
<td> |
|||
<span t-esc="line['note']"/> |
|||
</td> |
|||
</tr> |
|||
</center> |
|||
</tbody> |
|||
</table> |
|||
</t> |
|||
</t> |
|||
</template> |
|||
<!--Report paper format--> |
|||
<record id="paperformat_patient" model="report.paperformat"> |
|||
<field name="name">Custom Paper</field> |
|||
<field name="default" eval="True"/> |
|||
<field name="format">custom</field> |
|||
<field name="page_height">55</field> |
|||
<field name="page_width">30</field> |
|||
<field name="orientation">Landscape</field> |
|||
<field name="margin_top">1.00</field> |
|||
<field name="margin_bottom">1.00</field> |
|||
<field name="margin_left">0.00</field> |
|||
<field name="margin_right">1.00</field> |
|||
<field name="header_line" eval="False"/> |
|||
<field name="header_spacing">35</field> |
|||
<field name="dpi">125</field> |
|||
</record> |
|||
<!-- Patient card report action--> |
|||
<record id="action_report_patient_card" model="ir.actions.report"> |
|||
<field name="name">Patient Card</field> |
|||
<field name="model">res.partner</field> |
|||
<field name="report_type">qweb-pdf</field> |
|||
<field name="report_name">base_hospital_management.patient_card_report</field> |
|||
<field name="report_file">base_hospital_management.patient_card_report</field> |
|||
<field name="binding_model_id" ref="model_res_partner"/> |
|||
<field name="paperformat_id" |
|||
ref="base_hospital_management.paperformat_patient"/> |
|||
<field name="binding_type">report</field> |
|||
</record> |
|||
<!-- Patient card template--> |
|||
<template id="patient_card_report"> |
|||
<t t-call="web.html_container"> |
|||
<section> |
|||
<div style="width: 500px; height: 260px; border: 2px black solid; |
|||
border-radius: 5px;"> |
|||
<div class="container" |
|||
style="width: 500px; height: 50px; background-color:red"> |
|||
<span> |
|||
<i class="fa fa-wave-pulse" style="color:black;"/> |
|||
</span> |
|||
<h1 style="margin-left: 150px; padding-top: 10px; color:white; border-radius: 10px;"> |
|||
Patient Card |
|||
</h1> |
|||
<div class="page"> |
|||
<h1 style="margin-left: 15px;"> |
|||
<t t-esc="name"/> |
|||
<br/> |
|||
<label style="font-size: 18px;"> |
|||
<b>Code : |
|||
<t t-esc="code"/> |
|||
</b> |
|||
</label> |
|||
</h1> |
|||
<p style="margin-left: 15px;"> |
|||
<label> |
|||
<b>Gender :</b> |
|||
<t t-esc="gender"/> |
|||
</label> |
|||
<br/> |
|||
<label> |
|||
<b>Age :</b> |
|||
<t t-esc="age"/> |
|||
</label> |
|||
<br/> |
|||
<label> |
|||
<b>DOB :</b> |
|||
<t t-esc="dob"/> |
|||
</label> |
|||
<br/> |
|||
<label> |
|||
<b>Blood Group :</b> |
|||
<t t-esc="blood"/> |
|||
<br/> |
|||
</label> |
|||
<label> |
|||
<b>Phone :</b> |
|||
<t t-esc="phone"/> |
|||
</label> |
|||
<br/> |
|||
<label style="position:absolute; left:350px; top:100px;"> |
|||
<img t-attf-src="data:image/png;base64,{{image['image_1920']}}" |
|||
style="max-height: 130px; max-width: 130px;"/> |
|||
</label> |
|||
<br/> |
|||
</p> |
|||
</div> |
|||
</div> |
|||
</div> |
|||
</section> |
|||
<section> |
|||
<div class="container" |
|||
style="margin-top:50px"> |
|||
<div style="width: 500px; height: 250px; border: 2px black |
|||
solid; border-radius: 5px;"> |
|||
<div style="margin-left: 10px; margin-top: 10px;"> |
|||
<span style="padding-top:5px padding-top:5px"> |
|||
<b>Address:</b> |
|||
<br/> |
|||
<t t-esc="street"/> |
|||
<br/> |
|||
<t t-esc="street2"/> |
|||
<br/> |
|||
<t t-esc='city'/> |
|||
<t t-esc='state'/> |
|||
<br/> |
|||
<t t-esc='country'/> |
|||
<br/> |
|||
<br/> |
|||
</span> |
|||
<span style="padding-top:5px padding-top:5px"> |
|||
<b> |
|||
<t t-esc="company_name"/> |
|||
</b> |
|||
<br/> |
|||
<t t-esc="company_street"/> |
|||
<br/> |
|||
<t t-esc="company_street2"/> |
|||
<br/> |
|||
<t t-esc='company_city'/> |
|||
<t t-esc='company_state'/> |
|||
<br/> |
|||
<t t-esc='company_zip'/> |
|||
<br/> |
|||
<br/> |
|||
</span> |
|||
</div> |
|||
<div> |
|||
<img style="max-height: 150px; max-width: 180px; |
|||
position:absolute; left:310px; top:290px;" |
|||
t-attf-src="data:image/gif;base64, |
|||
{{barcode['barcode_png']}}"/> |
|||
</div> |
|||
</div> |
|||
</div> |
|||
</section> |
|||
</t> |
|||
</template> |
|||
</odoo> |
@ -0,0 +1,42 @@ |
|||
<?xml version="1.0" encoding="utf-8"?> |
|||
<odoo> |
|||
<!-- Hospital Management access category--> |
|||
<record id="base_hospital_management_access" model="ir.module.category"> |
|||
<field name="name">Hospital Management</field> |
|||
<field name="description">User access levels for Hospital Management |
|||
</field> |
|||
<field name="sequence">10</field> |
|||
</record> |
|||
<!--Lab Assistant access group--> |
|||
<record id="base_hospital_management_group_lab_assistant" |
|||
model="res.groups"> |
|||
<field name="name">Lab Assistant</field> |
|||
<field name="category_id" ref="base_hospital_management_access"/> |
|||
</record> |
|||
<!--Pharmacist access group--> |
|||
<record id="base_hospital_management_group_pharmacist" model="res.groups"> |
|||
<field name="name">Pharmacist</field> |
|||
<field name="category_id" ref="base_hospital_management_access"/> |
|||
</record> |
|||
<!-- Nurse access group--> |
|||
<record id="base_hospital_management_group_nurse" model="res.groups"> |
|||
<field name="name">Nurse</field> |
|||
<field name="category_id" ref="base_hospital_management_access"/> |
|||
</record> |
|||
<!--Doctor access group--> |
|||
<record id="base_hospital_management_group_doctor" model="res.groups"> |
|||
<field name="name">Doctor</field> |
|||
<field name="category_id" ref="base_hospital_management_access"/> |
|||
</record> |
|||
<!--Receptionist access group--> |
|||
<record id="base_hospital_management_group_receptionist" model="res.groups"> |
|||
<field name="name">Receptionist</field> |
|||
<field name="category_id" ref="base_hospital_management_access"/> |
|||
</record> |
|||
<!--Manager access group--> |
|||
<record id="base_hospital_management_group_manager" |
|||
model="res.groups"> |
|||
<field name="name">Manager</field> |
|||
<field name="category_id" ref="base_hospital_management_access"/> |
|||
</record> |
|||
</odoo> |
@ -0,0 +1,33 @@ |
|||
<?xml version="1.0" encoding="utf-8"?> |
|||
<odoo> |
|||
<data noupdate="1"> |
|||
<!-- Record rule of group doctor to access doctor allocation records--> |
|||
<record id="doctor_allocation_rule_doctor" model="ir.rule"> |
|||
<field name="name">Doctor Allocation Rule Doctor</field> |
|||
<field name="model_id" ref="model_doctor_allocation"/> |
|||
<field name="domain_force"> |
|||
[('doctor_id.user_id','=',user.id)] |
|||
</field> |
|||
<field name="groups" |
|||
eval="[(4, ref('base_hospital_management.base_hospital_management_group_doctor'))]"/> |
|||
</record> |
|||
<!-- Record rule of group doctor to access manager allocation records--> |
|||
<record id="doctor_allocation_rule_manager" model="ir.rule"> |
|||
<field name="name">Doctor Allocation Rule Manager</field> |
|||
<field name="model_id" ref="model_doctor_allocation"/> |
|||
<field name="domain_force"> |
|||
[(1,'=',1)] |
|||
</field> |
|||
<field name="groups" |
|||
eval="[(4, ref('base_hospital_management.base_hospital_management_group_manager'))]"/> |
|||
</record> |
|||
<!-- Multi company rule for doctor allocation records--> |
|||
<record id="doctor_allocation_rule_company" model="ir.rule"> |
|||
<field name="name">Doctor Allocation Rule Company</field> |
|||
<field name="model_id" ref="model_doctor_slot"/> |
|||
<field name="domain_force"> |
|||
['|',('company_id','=',False),('company_id', 'in', company_ids)] |
|||
</field> |
|||
</record> |
|||
</data> |
|||
</odoo> |
@ -0,0 +1,25 @@ |
|||
<?xml version="1.0" encoding="utf-8"?> |
|||
<odoo> |
|||
<data noupdate="1"> |
|||
<!-- Record rule of group doctor to access doctor slot records--> |
|||
<record id="doctor_slot_rule_doctor" model="ir.rule"> |
|||
<field name="name">Doctor Slot Rule Doctor</field> |
|||
<field name="model_id" ref="model_doctor_slot"/> |
|||
<field name="domain_force"> |
|||
[('doctor_id.user_id','=',user.id)] |
|||
</field> |
|||
<field name="groups" |
|||
eval="[(4, ref('base_hospital_management.base_hospital_management_group_doctor'))]"/> |
|||
</record> |
|||
<!-- Multi company rule for doctor slot records--> |
|||
<record id="doctor_slot_rule_company" model="ir.rule"> |
|||
<field name="name">Doctor Slot Rule Company</field> |
|||
<field name="model_id" ref="model_doctor_slot"/> |
|||
<field name="domain_force"> |
|||
['|',('company_id','=',False),('company_id', 'in', company_ids)] |
|||
</field> |
|||
<field name="groups" |
|||
eval="[(4, ref('base_hospital_management.base_hospital_management_group_doctor'))]"/> |
|||
</record> |
|||
</data> |
|||
</odoo> |
|
@ -0,0 +1,23 @@ |
|||
<?xml version="1.0" encoding="utf-8"?> |
|||
<odoo> |
|||
<data noupdate="1"> |
|||
<!-- Record rule of group doctor to access patient booking records--> |
|||
<record id="patient_booking_rule_doctor" model="ir.rule"> |
|||
<field name="name">Patient Booking Rule Doctor</field> |
|||
<field name="model_id" ref="model_patient_booking"/> |
|||
<field name="domain_force"> |
|||
[('doctor_id.doctor_id.user_id','=',user.id)] |
|||
</field> |
|||
<field name="groups" |
|||
eval="[(4, ref('base_hospital_management.base_hospital_management_group_doctor'))]"/> |
|||
</record> |
|||
<!-- Multi company rule for doctor allocation records--> |
|||
<record id="patient_booking_rule_company" model="ir.rule"> |
|||
<field name="name">Patient Booking Rule Company</field> |
|||
<field name="model_id" ref="model_patient_booking"/> |
|||
<field name="domain_force"> |
|||
['|',('company_id','=',False),('company_id', 'in', company_ids)] |
|||
</field> |
|||
</record> |
|||
</data> |
|||
</odoo> |
@ -0,0 +1,24 @@ |
|||
<?xml version="1.0" encoding="utf-8"?> |
|||
<odoo> |
|||
<data noupdate="1"> |
|||
<!--Record rule of group lab assistant to access patient lab test |
|||
records--> |
|||
<record id="patient_lab_test_rule_lab_assistant" model="ir.rule"> |
|||
<field name="name">Patient Lab Test Rule Lab Assistant</field> |
|||
<field name="model_id" ref="model_patient_lab_test"/> |
|||
<field name="domain_force"> |
|||
['|','|',('lab_id.technician_id.user_id','=',user.id),('lab_id.technician_id.user_id','=',False),('lab_id','=',False)] |
|||
</field> |
|||
<field name="groups" |
|||
eval="[(4, ref('base_hospital_management.base_hospital_management_group_lab_assistant'))]"/> |
|||
</record> |
|||
<!--Multi company rule for patient lab test records--> |
|||
<record id="patient_lab_test_rule_company" model="ir.rule"> |
|||
<field name="name">Patient Lab Test Rule Company</field> |
|||
<field name="model_id" ref="model_patient_lab_test"/> |
|||
<field name="domain_force"> |
|||
['|',('company_id','=',False),('company_id', 'in', company_ids)] |
|||
</field> |
|||
</record> |
|||
</data> |
|||
</odoo> |
After Width: | Height: | Size: 36 KiB |
After Width: | Height: | Size: 3.6 KiB |
After Width: | Height: | Size: 310 B |
After Width: | Height: | Size: 1.3 KiB |
After Width: | Height: | Size: 1.4 KiB |
After Width: | Height: | Size: 576 B |
After Width: | Height: | Size: 733 B |
After Width: | Height: | Size: 911 B |
After Width: | Height: | Size: 1.1 KiB |
After Width: | Height: | Size: 1.1 KiB |
After Width: | Height: | Size: 1.2 KiB |
After Width: | Height: | Size: 673 B |
After Width: | Height: | Size: 11 KiB |
After Width: | Height: | Size: 878 B |
After Width: | Height: | Size: 653 B |
After Width: | Height: | Size: 905 B |
After Width: | Height: | Size: 839 B |
After Width: | Height: | Size: 427 B |
After Width: | Height: | Size: 627 B |
After Width: | Height: | Size: 1.2 KiB |
After Width: | Height: | Size: 988 B |
After Width: | Height: | Size: 1.2 KiB |
After Width: | Height: | Size: 80 KiB |
After Width: | Height: | Size: 1.5 KiB |
After Width: | Height: | Size: 1.1 KiB |
After Width: | Height: | Size: 1.9 KiB |
After Width: | Height: | Size: 1.1 KiB |
After Width: | Height: | Size: 2.1 KiB |
After Width: | Height: | Size: 4.4 KiB |
After Width: | Height: | Size: 3.2 KiB |
After Width: | Height: | Size: 589 B |
After Width: | Height: | Size: 3.4 KiB |
After Width: | Height: | Size: 565 B |
After Width: | Height: | Size: 1.7 KiB |
After Width: | Height: | Size: 2.3 KiB |
After Width: | Height: | Size: 967 B |
After Width: | Height: | Size: 26 KiB |
After Width: | Height: | Size: 1.6 KiB |
After Width: | Height: | Size: 43 KiB |
After Width: | Height: | Size: 1.4 KiB |
After Width: | Height: | Size: 3.8 KiB |
After Width: | Height: | Size: 4.0 KiB |