Browse Source

Nov 13: [ADD] Initial commit 'dental_clinical_management'

pull/254/merge
Cybrosys Technologies 6 months ago
parent
commit
0bf0b1b474
  1. 50
      dental_clinical_management/README.rst
  2. 24
      dental_clinical_management/__init__.py
  3. 81
      dental_clinical_management/__manifest__.py
  4. 23
      dental_clinical_management/controllers/__init__.py
  5. 148
      dental_clinical_management/controllers/dental_clinic.py
  6. 74
      dental_clinical_management/controllers/patient_portal.py
  7. 15
      dental_clinical_management/data/dental_department_data.xml
  8. 18
      dental_clinical_management/data/dental_specialist_data.xml
  9. 26
      dental_clinical_management/data/dental_time_shift_data.xml
  10. 26
      dental_clinical_management/data/dental_treatment_data.xml
  11. 15
      dental_clinical_management/data/insurance_company_data.xml
  12. 19
      dental_clinical_management/data/ir_sequence.xml
  13. 26
      dental_clinical_management/data/medical_questions_data.xml
  14. 30
      dental_clinical_management/data/medicine_frequency_data.xml
  15. 15
      dental_clinical_management/data/treatment_category_data.xml
  16. 17
      dental_clinical_management/data/website_menu.xml
  17. 6
      dental_clinical_management/doc/RELEASE_NOTES.md
  18. 34
      dental_clinical_management/models/__init__.py
  19. 132
      dental_clinical_management/models/dental_appointment.py
  20. 85
      dental_clinical_management/models/dental_doctor.py
  21. 36
      dental_clinical_management/models/dental_medicine.py
  22. 129
      dental_clinical_management/models/dental_patients.py
  23. 224
      dental_clinical_management/models/dental_prescription.py
  24. 31
      dental_clinical_management/models/dental_specialist.py
  25. 54
      dental_clinical_management/models/dental_time_shift.py
  26. 36
      dental_clinical_management/models/dental_treatment.py
  27. 33
      dental_clinical_management/models/insurance_company.py
  28. 38
      dental_clinical_management/models/medical_questionnaire.py
  29. 53
      dental_clinical_management/models/medical_questions.py
  30. 34
      dental_clinical_management/models/medicine_frequency.py
  31. 30
      dental_clinical_management/models/treatment_category.py
  32. 108
      dental_clinical_management/report/dental_appointment_card.xml
  33. 17
      dental_clinical_management/report/dental_prescription_report.xml
  34. 120
      dental_clinical_management/report/dental_prescription_templates.xml
  35. 27
      dental_clinical_management/security/dental_clinical_management_groups.xml
  36. 33
      dental_clinical_management/security/dental_clinical_management_security.xml
  37. 27
      dental_clinical_management/security/ir.model.access.csv
  38. BIN
      dental_clinical_management/static/description/assets/icons/check.png
  39. BIN
      dental_clinical_management/static/description/assets/icons/chevron.png
  40. BIN
      dental_clinical_management/static/description/assets/icons/cogs.png
  41. BIN
      dental_clinical_management/static/description/assets/icons/consultation.png
  42. BIN
      dental_clinical_management/static/description/assets/icons/ecom-black.png
  43. BIN
      dental_clinical_management/static/description/assets/icons/education-black.png
  44. BIN
      dental_clinical_management/static/description/assets/icons/hotel-black.png
  45. BIN
      dental_clinical_management/static/description/assets/icons/license.png
  46. BIN
      dental_clinical_management/static/description/assets/icons/lifebuoy.png
  47. BIN
      dental_clinical_management/static/description/assets/icons/manufacturing-black.png
  48. BIN
      dental_clinical_management/static/description/assets/icons/pos-black.png
  49. BIN
      dental_clinical_management/static/description/assets/icons/puzzle.png
  50. BIN
      dental_clinical_management/static/description/assets/icons/restaurant-black.png
  51. BIN
      dental_clinical_management/static/description/assets/icons/service-black.png
  52. BIN
      dental_clinical_management/static/description/assets/icons/trading-black.png
  53. BIN
      dental_clinical_management/static/description/assets/icons/training.png
  54. BIN
      dental_clinical_management/static/description/assets/icons/update.png
  55. BIN
      dental_clinical_management/static/description/assets/icons/user.png
  56. BIN
      dental_clinical_management/static/description/assets/icons/wrench.png
  57. BIN
      dental_clinical_management/static/description/assets/misc/categories.png
  58. BIN
      dental_clinical_management/static/description/assets/misc/check-box.png
  59. BIN
      dental_clinical_management/static/description/assets/misc/compass.png
  60. BIN
      dental_clinical_management/static/description/assets/misc/corporate.png
  61. BIN
      dental_clinical_management/static/description/assets/misc/customer-support.png
  62. BIN
      dental_clinical_management/static/description/assets/misc/cybrosys-logo.png
  63. BIN
      dental_clinical_management/static/description/assets/misc/features.png
  64. BIN
      dental_clinical_management/static/description/assets/misc/logo.png
  65. BIN
      dental_clinical_management/static/description/assets/misc/pictures.png
  66. BIN
      dental_clinical_management/static/description/assets/misc/pie-chart.png
  67. BIN
      dental_clinical_management/static/description/assets/misc/right-arrow.png
  68. BIN
      dental_clinical_management/static/description/assets/misc/star.png
  69. BIN
      dental_clinical_management/static/description/assets/misc/support.png
  70. BIN
      dental_clinical_management/static/description/assets/misc/whatsapp.png
  71. BIN
      dental_clinical_management/static/description/assets/modules/1.png
  72. BIN
      dental_clinical_management/static/description/assets/modules/2.jpg
  73. BIN
      dental_clinical_management/static/description/assets/modules/3.png
  74. BIN
      dental_clinical_management/static/description/assets/modules/4.png
  75. BIN
      dental_clinical_management/static/description/assets/modules/5.jpg
  76. BIN
      dental_clinical_management/static/description/assets/modules/6.png
  77. BIN
      dental_clinical_management/static/description/assets/screenshots/1.png
  78. BIN
      dental_clinical_management/static/description/assets/screenshots/10.png
  79. BIN
      dental_clinical_management/static/description/assets/screenshots/11.png
  80. BIN
      dental_clinical_management/static/description/assets/screenshots/12.png
  81. BIN
      dental_clinical_management/static/description/assets/screenshots/13.png
  82. BIN
      dental_clinical_management/static/description/assets/screenshots/14.png
  83. BIN
      dental_clinical_management/static/description/assets/screenshots/15.png
  84. BIN
      dental_clinical_management/static/description/assets/screenshots/16.png
  85. BIN
      dental_clinical_management/static/description/assets/screenshots/17.png
  86. BIN
      dental_clinical_management/static/description/assets/screenshots/18.png
  87. BIN
      dental_clinical_management/static/description/assets/screenshots/19.png
  88. BIN
      dental_clinical_management/static/description/assets/screenshots/2.png
  89. BIN
      dental_clinical_management/static/description/assets/screenshots/20.png
  90. BIN
      dental_clinical_management/static/description/assets/screenshots/21.png
  91. BIN
      dental_clinical_management/static/description/assets/screenshots/22.png
  92. BIN
      dental_clinical_management/static/description/assets/screenshots/23.png
  93. BIN
      dental_clinical_management/static/description/assets/screenshots/24.png
  94. BIN
      dental_clinical_management/static/description/assets/screenshots/25.png
  95. BIN
      dental_clinical_management/static/description/assets/screenshots/26.png
  96. BIN
      dental_clinical_management/static/description/assets/screenshots/27.png
  97. BIN
      dental_clinical_management/static/description/assets/screenshots/28.png
  98. BIN
      dental_clinical_management/static/description/assets/screenshots/29.png
  99. BIN
      dental_clinical_management/static/description/assets/screenshots/3.png
  100. BIN
      dental_clinical_management/static/description/assets/screenshots/30.png

50
dental_clinical_management/README.rst

@ -0,0 +1,50 @@
.. 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
Dental Clinic Management
========================
Dental Clinic Management is to manage the entire Dental Clinic.
Configuration
=============
* No additional configuration required
License
-------
GNU AFFERO GENERAL PUBLIC LICENSE v3.0 (AGPL-3)
(https://www.gnu.org/licenses/agpl-3.0-standalone.html)
Company
-------
* `Cybrosys Techno Solutions <https://cybrosys.com/>`__
Credits
-------
* Developer: (V17) Kailas Krishna,
(V16) Nihala KP
(V15) Nihala KP
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>`__

24
dental_clinical_management/__init__.py

@ -0,0 +1,24 @@
# -*- coding: utf-8 -*-
################################################################################
#
# Cybrosys Technologies Pvt. Ltd.
#
# Copyright (C) 2024-TODAY Cybrosys Technologies(<https://www.cybrosys.com>).
# Author: Cybrosys Techno Solutions(<https://www.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
from . import wizard

81
dental_clinical_management/__manifest__.py

@ -0,0 +1,81 @@
# -*- coding: utf-8 -*-
################################################################################
#
# Cybrosys Technologies Pvt. Ltd.
#
# Copyright (C) 2024-TODAY Cybrosys Technologies(<https://www.cybrosys.com>).
# Author: Cybrosys Techno Solutions(<https://www.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': 'Dental Clinic Management',
'version': '15.0.1.0.0',
'category': 'Industries',
'summary': """Dental Clinic Management is to manage the entire dental clinic.""",
'description': """Dental Clinic Management software, dental clinics can
enhance efficiency, improve patient care, optimize resource utilization,
and maintain smooth operations.""",
'author': 'Cybrosys Techno Solutions',
'company': 'Cybrosys Techno Solutions',
'maintainer': 'Cybrosys Techno Solutions',
'website': "https://www.cybrosys.com",
'depends': ['hr', 'website', 'mail', 'sale_management', 'purchase',
'stock'],
'assets': {
'web.assets_frontend': [
"/dental_clinical_management/static/src/js/dental_clinic.js"
]
},
'data': [
'security/dental_clinical_management_groups.xml',
'security/dental_clinical_management_security.xml',
'security/ir.model.access.csv',
'data/ir_sequence.xml',
'data/dental_department_data.xml',
'data/dental_specialist_data.xml',
'data/treatment_category_data.xml',
'data/dental_treatment_data.xml',
'data/medical_questions_data.xml',
'data/insurance_company_data.xml',
'data/medicine_frequency_data.xml',
'data/dental_time_shift_data.xml',
'data/website_menu.xml',
'views/dental_time_shift_views.xml',
'views/dental_department_views.xml',
'views/dental_doctor_views.xml',
'views/dental_patients_views.xml',
'views/dental_prescription_views.xml',
'views/dental_medicine_views.xml',
'views/dental_specialist_views.xml',
'views/dental_treatment_views.xml',
'views/insurance_company_views.xml',
'views/medicine_frequency_views.xml',
'views/medical_questions_views.xml',
'views/treatment_category_views.xml',
'views/dental_appointment_views.xml',
'views/patient_portal_template.xml',
'views/dental_clinic_template.xml',
'report/dental_appointment_card.xml',
'report/dental_prescription_templates.xml',
'report/dental_prescription_report.xml',
'wizard/xray_report_views.xml',
'views/dental_clinical_management_menu.xml',
],
'images': ['static/description/banner.png'],
'license': 'AGPL-3',
'installable': True,
'auto_install': False,
'application': True,
}

23
dental_clinical_management/controllers/__init__.py

@ -0,0 +1,23 @@
# -*- coding: utf-8 -*-
################################################################################
#
# Cybrosys Technologies Pvt. Ltd.
#
# Copyright (C) 2024-TODAY Cybrosys Technologies(<https://www.cybrosys.com>).
# Author: Cybrosys Techno Solutions(<https://www.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 dental_clinic
from . import patient_portal

148
dental_clinical_management/controllers/dental_clinic.py

@ -0,0 +1,148 @@
# -*- coding: utf-8 -*-
################################################################################
#
# Cybrosys Technologies Pvt. Ltd.
#
# Copyright (C) 2024-TODAY Cybrosys Technologies(<https://www.cybrosys.com>).
# Author: Cybrosys Techno Solutions(<https://www.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.exceptions import UserError
from odoo import _, http
from odoo.http import Controller, request, route
class DentalClinic(Controller):
"""Controller for a dental clinic website that allows users to view clinic
details and schedule appointments online."""
@route('/dental_doctor', auth='public', website=True)
def dental_clinic(self):
"""Renders the dental clinic page with patient, specialist,
and doctor information. This method retrieves the current user's
partner ID as the patient ID, fetches all records from the
`dental.specialist` model, and all records from the `hr.employee`
model to display on the dental clinic webpage."""
patient_id = request.env.user.partner_id
specialised_id = request.env['dental.specialist'].sudo().search([])
doctor_id = request.env['hr.employee'].sudo().search([])
return request.render(
'dental_clinical_management.website_dental_template',
{'patient_id': patient_id,
'specialised_id': specialised_id,
'doctor_id': doctor_id})
@route('/create/appointment', auth='public', website=True)
def create_appointment(self, **kw):
"""To create a new appointment from website"""
appointment_exists = request.env['dental.appointment'].sudo().search(
[('patient_id', '=', int(kw.get('patient'))),
('doctor_id', '=', int(kw.get('doctor'))),
('date', '=', kw.get('date')),
('shift_id', '=', int(kw.get('time_shift')))])
if appointment_exists:
return request.render(
'dental_clinical_management.website_dental_scheduled_template',
)
if len(kw.get('time_shift')) == 0:
raise UserError(_('Doctor Does not have the available appointment'))
else:
patient_appointment = request.env[
'dental.appointment'].sudo().create({
'patient_id': kw.get('patient'),
'patient_phone': kw.get('phone'),
'patient_age': kw.get('age'),
'specialist_id': kw.get('specialization', False),
'doctor_id': kw.get('doctor'),
'shift_id': kw.get('time_shift'),
'date': kw.get('date'),
})
return request.redirect(
f'/success_appointment?token={patient_appointment.token_no}'
f'&doctor_id={patient_appointment.doctor_id}'
f'&sequence_no={patient_appointment.sequence_no}')
@route('/success_appointment', auth='public', website=True)
def success_appointment(self, **kwargs):
"""Return when appointment creation is success"""
return request.render(
'dental_clinical_management.website_rental_success_template',
{'token': kwargs})
@http.route('/dental_clinic/appointment_card/<token>',
type='http', auth="public", website=True)
def appointment_card(self, token):
"""To download the appointment card for patients for doctor's
appointment"""
appointment = request.env['dental.appointment'].sudo().search(
[('sequence_no', '=', token)])
if not appointment.exists():
return request.not_found()
data = {
'website': True,
'token': appointment.token_no,
'doctor': appointment.doctor_id.name,
'specialised': appointment.specialist_id.name,
'appointment_time': appointment.shift_id.name,
'date': appointment.date,
}
report_action = request.env.ref(
'dental_clinical_management.action_appointment_card')
pdf_content, _ = report_action.sudo()._render_qweb_pdf(
'dental_clinical_management.appointment_card', data=data)
pdf_http_headers = [('Content-Type', 'application/pdf'),
('Content-Length', len(pdf_content))]
return request.make_response(pdf_content, headers=pdf_http_headers)
@route('/patient_details', type="json", auth='public', website=True)
def get_patient_details(self, patient_id):
"""Retrieve and return details of a specific patient by their ID.
This method accesses the `res.partner` model, retrieves a patient
record by the given ID, and returns selected fields of the patient
such as phone number and age.
Args:
patient_id (int): The unique identifier of the patient."""
patient = request.env['res.partner'].sudo().browse(int(patient_id))
return patient.read(fields=['phone', 'patient_age'])
@route('/specialised_doctors', type="json", auth='public', website=True)
def get_specialised_doctors(self, specialised_id):
"""To get the list of doctors based on their specialisation"""
domain = []
if specialised_id:
domain = [('specialised_in_id', '=', int(specialised_id))]
doctors = request.env['hr.employee'].sudo().search_read(domain,
["name"])
return doctors
@route('/doctors_shifts', type="json", auth='public', website=True)
def get_doctors_shifts(self, doctor_id):
"""To get the particular doctor time slots"""
doctors_shift = request.env['hr.employee'].sudo().browse(
int(doctor_id)).time_shift_ids
time_shifts = [{"id": rec.id, "name": rec.name} for rec in
doctors_shift]
return time_shifts
@route('/all_doctors', auth='public', website=True)
def get_all_doctors(self):
"""To list all the doctors"""
doctor_id = request.env['hr.employee'].sudo().search([])
return request.render('dental_clinical_management.website_all_doctors',
{'doctor_ids': doctor_id})

74
dental_clinical_management/controllers/patient_portal.py

@ -0,0 +1,74 @@
# -*- coding: utf-8 -*-
################################################################################
#
# Cybrosys Technologies Pvt. Ltd.
#
# Copyright (C) 2024-TODAY Cybrosys Technologies(<https://www.cybrosys.com>).
# Author: Cybrosys Techno Solutions(<https://www.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
from odoo.addons.portal.controllers import portal
class PatientPortal(portal.CustomerPortal):
"""Provide portal access for patients to view their treatment
details, prescriptions, and invoices."""
def _prepare_home_portal_values(self, counters):
"""Extends the base method to include the count of dental prescriptions
in the returned dictionary if requested.
Args:
counters (list): A list of strings indicating which counts to
include in the response."""
values = super()._prepare_home_portal_values(counters)
if 'prescriptions_count' in counters:
prescriptions_count = request.env[
'dental.prescription'].sudo().search_count([])
values['prescriptions_count'] = prescriptions_count
return values
@http.route(['/my/prescriptions'], type='http', auth="user", website=True)
def portal_my_prescriptions(self, **kwargs):
"""Renders the prescriptions page for the logged-in user based on
their role. Managers see all prescriptions, doctors see their own,
and patients see their own prescriptions."""
if (request.env.ref(
'dental_clinical_management.group_dental_manager') in
request.env.user.groups_id):
domain = []
elif (request.env.ref(
'dental_clinical_management.group_dental_doctor') in
request.env.user.groups_id):
domain = [('prescribed_doctor_id', '=',
request.env.user.partner_id.employee_ids.id)]
else:
domain = [('patient_id', '=', request.env.user.partner_id.id)]
prescriptions = request.env['dental.prescription'].sudo().search(domain)
return request.render(
"dental_clinical_management.portal_my_prescriptions",
{'prescriptions': prescriptions, 'page_name': 'prescriptions'})
@http.route(['/view/prescriptions/<int:id>'],
type='http', auth="public", website=True)
def view_prescriptions(self, id):
"""View prescriptions based on the provided ID.
:param id: The ID of the prescription to view.
:return: Rendered template with prescription details."""
prescription = request.env['dental.prescription'].browse(id)
return request.render(
'dental_clinical_management.prescription_portal_template',
{'prescription_details': prescription, 'page_name': 'prescription'})

15
dental_clinical_management/data/dental_department_data.xml

@ -0,0 +1,15 @@
<?xml version="1.0" encoding="utf-8"?>
<odoo>
<data noupdate="1">
<!-- Dental department data -->
<record model="hr.department" id="clinical_department">
<field name="name">Clinical Department</field>
</record>
<record model="hr.department" id="telehealth_department">
<field name="name">Telehealth Department</field>
</record>
<record model="hr.department" id="quality_assurance">
<field name="name">Quality Assurance</field>
</record>
</data>
</odoo>

18
dental_clinical_management/data/dental_specialist_data.xml

@ -0,0 +1,18 @@
<?xml version="1.0" encoding="utf-8"?>
<odoo>
<data noupdate="1">
<!-- Data for dental specialist -->
<record model="dental.specialist" id="orthodontist_specialist">
<field name="name">Orthodontist</field>
<field name="code">ORTHO</field>
</record>
<record model="dental.specialist" id="periodontist_specialist">
<field name="name">Periodontist</field>
<field name="code">PEROD</field>
</record>
<record model="dental.specialist" id="endodontist_specialist">
<field name="name">Endodontist</field>
<field name="code">ENDO</field>
</record>
</data>
</odoo>

26
dental_clinical_management/data/dental_time_shift_data.xml

@ -0,0 +1,26 @@
<?xml version="1.0" encoding="utf-8"?>
<odoo>
<data noupdate="1">
<!-- Data for dental time shift -->
<record model="dental.time.shift" id="shift_morning">
<field name="shift_type">morning</field>
<field name="start_time">06</field>
<field name="end_time">09</field>
</record>
<record model="dental.time.shift" id="shift_evening">
<field name="shift_type">evening</field>
<field name="start_time">17</field>
<field name="end_time">20</field>
</record>
<record model="dental.time.shift" id="shift_day">
<field name="shift_type">day</field>
<field name="start_time">10</field>
<field name="end_time">12</field>
</record>
<record model="dental.time.shift" id="shift_night">
<field name="shift_type">night</field>
<field name="start_time">20</field>
<field name="end_time">22</field>
</record>
</data>
</odoo>

26
dental_clinical_management/data/dental_treatment_data.xml

@ -0,0 +1,26 @@
<?xml version="1.0" encoding="utf-8"?>
<odoo>
<data noupdate="1">
<!-- Dental treatment data -->
<record model="dental.treatment" id="treatment_teeth_whitening">
<field name="name">Teeth Whitening</field>
<field name="treatment_categ_id" ref="cosmetic_dentistry"/>
</record>
<record model="dental.treatment" id="treatment_gum_contouring">
<field name="name">Gum Contouring</field>
<field name="treatment_categ_id" ref="cosmetic_dentistry"/>
</record>
<record model="dental.treatment" id="treatment_dental_fillings">
<field name="name">Dental Fillings</field>
<field name="treatment_categ_id" ref="restorative_dentistry"/>
</record>
<record model="dental.treatment" id="treatment_dental_cleanings">
<field name="name">Dental Cleanings</field>
<field name="treatment_categ_id" ref="preventive_dentistry"/>
</record>
<record model="dental.treatment" id="treatment_check_ups">
<field name="name">Routine Check-ups and Examinations</field>
<field name="treatment_categ_id" ref="preventive_dentistry"/>
</record>
</data>
</odoo>

15
dental_clinical_management/data/insurance_company_data.xml

@ -0,0 +1,15 @@
<?xml version="1.0" encoding="utf-8"?>
<odoo>
<data noupdate="1">
<!-- Insurance company data -->
<record model="insurance.company" id="insurance_company_star_health">
<field name="name">Star Health and Allied Insurance</field>
</record>
<record model="insurance.company" id="insurance_company_max_bupa">
<field name="name">Max Bupa Health Insurance</field>
</record>
<record model="insurance.company" id="insurance_company_unitedhealth">
<field name="name">UnitedHealth Group</field>
</record>
</data>
</odoo>

19
dental_clinical_management/data/ir_sequence.xml

@ -0,0 +1,19 @@
<?xml version="1.0" encoding="utf-8"?>
<odoo noupdate="1">
<!-- Sequence for Prescription -->
<record id="seq_dental_prescription" model="ir.sequence">
<field name="name">Dental Prescription</field>
<field name="code">dental.prescriptions</field>
<field name="prefix">PRN</field>
<field name="padding">3</field>
<field name="company_id" eval="False"/>
</record>
<!-- Sequence for Appointment -->
<record id="seq_dental_appointment" model="ir.sequence">
<field name="name">Dental Appointment</field>
<field name="code">dental.appointment</field>
<field name="prefix">DAP</field>
<field name="padding">5</field>
<field name="company_id" eval="False"/>
</record>
</odoo>

26
dental_clinical_management/data/medical_questions_data.xml

@ -0,0 +1,26 @@
<?xml version="1.0" encoding="utf-8"?>
<odoo>
<data noupdate="1">
<record model="medical.questions" id="medical_question_procedure">
<field name="question">Have you ever had any dental procedures
before?
</field>
</record>
<record model="medical.questions" id="medical_question_concerns">
<field name="question">Do you have any dental concerns or issues?
</field>
</record>
<record model="medical.questions" id="medical_question_brush">
<field name="question">How often do you brush your teeth?</field>
</record>
<record model="medical.questions" id="medical_question_tobacco">
<field name="question">Do you smoke or use any tobacco products?
</field>
</record>
<record model="medical.questions" id="medical_question_checkup">
<field name="question">When was your last dental check up and
cleaning?
</field>
</record>
</data>
</odoo>

30
dental_clinical_management/data/medicine_frequency_data.xml

@ -0,0 +1,30 @@
<?xml version="1.0" encoding="utf-8"?>
<odoo>
<data noupdate="1">
<!-- Medical Frequency data -->
<record model="medicine.frequency" id="medicine_frequency_bd">
<field name="code">BD</field>
<field name="medicament_frequency">Twice a day</field>
</record>
<record model="medicine.frequency" id="medicine_frequency_od">
<field name="code">OD</field>
<field name="medicament_frequency">Once in a day</field>
</record>
<record model="medicine.frequency" id="medicine_frequency_tds">
<field name="code">TDS</field>
<field name="medicament_frequency">Three times a day</field>
</record>
<record model="medicine.frequency" id="medicine_frequency_qds">
<field name="code">QDS</field>
<field name="medicament_frequency">Four times a day</field>
</record>
<record model="medicine.frequency" id="medicine_frequency_hs">
<field name="code">HS</field>
<field name="medicament_frequency">Bed Time</field>
</record>
<record model="medicine.frequency" id="medicine_frequency_pc">
<field name="code">PC</field>
<field name="medicament_frequency">Before Meals</field>
</record>
</data>
</odoo>

15
dental_clinical_management/data/treatment_category_data.xml

@ -0,0 +1,15 @@
<?xml version="1.0" encoding="utf-8"?>
<odoo>
<data noupdate="1">
<!-- Data for treatment category -->
<record model="treatment.category" id="preventive_dentistry">
<field name="name">Preventive Dentistry</field>
</record>
<record model="treatment.category" id="restorative_dentistry">
<field name="name">Restorative Dentistry</field>
</record>
<record model="treatment.category" id="cosmetic_dentistry">
<field name="name">Cosmetic Dentistry</field>
</record>
</data>
</odoo>

17
dental_clinical_management/data/website_menu.xml

@ -0,0 +1,17 @@
<?xml version="1.0" encoding="utf-8"?>
<odoo>
<!-- Appointment Menu in website -->
<record id="appointment_menu" model="website.menu">
<field name="name">Appointment</field>
<field name="url">/dental_doctor</field>
<field name="parent_id" ref="website.main_menu"/>
<field name="sequence" type="int">11</field>
</record>
<!-- Doctors Menu in website -->
<record id="doctors_menu" model="website.menu">
<field name="name">Doctors</field>
<field name="url">/all_doctors</field>
<field name="parent_id" ref="website.main_menu"/>
<field name="sequence" type="int">12</field>
</record>
</odoo>

6
dental_clinical_management/doc/RELEASE_NOTES.md

@ -0,0 +1,6 @@
## Module <dental_clinical_management>
#### 02.11.2024
#### Version 15.0.1.0.0
#### ADD
- Initial commit for Dental Clinic Management

34
dental_clinical_management/models/__init__.py

@ -0,0 +1,34 @@
# -*- coding: utf-8 -*-
################################################################################
#
# Cybrosys Technologies Pvt. Ltd.
#
# Copyright (C) 2024-TODAY Cybrosys Technologies(<https://www.cybrosys.com>).
# Author: Cybrosys Techno Solutions(<https://www.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 dental_appointment
from . import dental_doctor
from . import dental_medicine
from . import dental_patients
from . import dental_prescription
from . import dental_specialist
from . import dental_time_shift
from . import dental_treatment
from . import insurance_company
from . import medical_questionnaire
from . import medical_questions
from . import medicine_frequency
from . import treatment_category

132
dental_clinical_management/models/dental_appointment.py

@ -0,0 +1,132 @@
# -*- coding: utf-8 -*-
################################################################################
#
# Cybrosys Technologies Pvt. Ltd.
#
# Copyright (C) 2024-TODAY Cybrosys Technologies(<https://www.cybrosys.com>).
# Author: Cybrosys Techno Solutions(<https://www.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 DentalAppointment(models.Model):
"""Patient dental appointment details"""
_name = 'dental.appointment'
_description = "Dental Appointment for patients"
_inherit = "mail.thread"
_rec_name = 'sequence_no'
sequence_no = fields.Char(string='Sequence No', readonly=True,
default=lambda self: _('New'),
copy=False,
help="Sequence number of appointment")
token_no = fields.Integer(string='Token No', copy=False,
readonly=True,
help="Token number of the appointments")
patient_id = fields.Many2one('res.partner',
string="Patient Name",
domain="[('is_patient', '=', True)]",
copy=False,
required=True,
help="Add the patient")
patient_phone = fields.Char(related="patient_id.phone", string="Phone",
help="Phone number of the patient")
patient_age = fields.Integer(related="patient_id.patient_age", string="Age",
help="Age of the patient")
specialist_id = fields.Many2one('dental.specialist',
string="Doctors Department",
help='Choose the doctors department')
doctor_ids = fields.Many2many('hr.employee',
compute='_compute_doctor_ids',
string="Doctors Data", help="Doctors Data")
doctor_id = fields.Many2one('hr.employee', string="Doctor",
required=True,
domain="[('id', 'in', doctor_ids)]",
help="Name the of the doctor")
time_shift_ids = fields.Many2many('dental.time.shift',
string="Time Shift",
help="Choose the time shift",
compute='_compute_time_shifts')
shift_id = fields.Many2one('dental.time.shift',
string="Booking Time",
domain="[('id','in',time_shift_ids)]",
help="Choose the time shift")
date = fields.Date(string="Date", required=True,
default=fields.date.today(),
help="Date when to take appointment for doctor")
reason = fields.Text(string="Please describe the reason",
help="Just explain about the reason to take doctor "
"appointment")
state = fields.Selection([('draft', 'Draft'),
('new', 'New Appointment'),
('done', 'Prescribed'),
('cancel', 'Cancel')],
default="draft",
string="State", help="state of the appointment")
@api.model
def create(self, vals):
"""Function declared for creating sequence Number for Appointments"""
if vals.get('sequence_no', _('New')) == _('New'):
vals['sequence_no'] = self.env['ir.sequence'].next_by_code(
'dental.appointment') or _('New')
last_token = self.search(
[('doctor_id', '=', int(vals['doctor_id'])),
('date', '=', vals['date']),
('shift_id', '=', int(vals['shift_id']))],
order='id desc', limit=1)
vals['token_no'] = last_token.token_no + 1 if last_token else 1
res = super(DentalAppointment, self).create(vals)
res.state = 'new'
return res
def action_create_appointment(self):
"""Change the state of the appointment while click create button"""
self.state = 'new'
@api.depends('doctor_id')
def _compute_time_shifts(self):
"""To get the doctors time shift"""
for record in self:
record.time_shift_ids = self.env['dental.time.shift'].search(
[('id', 'in', record.doctor_id.time_shift_ids.ids)]).ids
@api.depends('specialist_id')
def _compute_doctor_ids(self):
"""Searching for doctors based on there specialization"""
for record in self:
if record.specialist_id:
record.doctor_ids = self.env['hr.employee'].search(
[('specialised_in_id', '=', record.specialist_id.id)]).ids
else:
record.doctor_ids = self.env['hr.employee'].search([]).ids
def action_cancel(self):
"""Change the state of the appointment while click cancel button"""
self.state = 'cancel'
def action_prescription(self):
"""Created the action for view the prescriptions
of 'done' state appointments"""
return {
'type': 'ir.actions.act_window',
'target': 'inline',
'name': 'Prescription',
'view_mode': 'form',
'res_model': 'dental.prescription',
'res_id': self.env['dental.prescription'].search([
('appointment_id', '=', self.id)], limit=1).id,
}

85
dental_clinical_management/models/dental_doctor.py

@ -0,0 +1,85 @@
# -*- coding: utf-8 -*-
################################################################################
#
# Cybrosys Technologies Pvt. Ltd.
#
# Copyright (C) 2024-TODAY Cybrosys Technologies(<https://www.cybrosys.com>).
# Author: Cybrosys Techno Solutions(<https://www.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 DentalDoctor(models.Model):
"""To add the doctors of the clinic"""
_inherit = 'hr.employee'
job_position = fields.Char(string="Designation",
help="To add the job position of the doctor")
specialised_in_id = fields.Many2one('dental.specialist',
string='Specialised In',
help="Add the doctor specialised", required="1")
dob = fields.Date(string="Date of Birth",
required=True,
help="DOB of the patient")
doctor_age = fields.Integer(compute='_compute_doctor_age',
store=True,
string="Age",
help="Age of the Doctor")
sex = fields.Selection([('male', 'Male'),
('female', 'Female')],
string="Sex",
help="Sex of the patient")
time_shift_ids = fields.Many2many('dental.time.shift',
string="Time Shift",
help="Time shift of the doctor")
@api.constrains('specialised_in_id')
def _check_shift(self):
for record in self:
if record.specialised_in_id and not record.time_shift_ids:
raise ValidationError("At least one shift must be assigned to the doctor.")
@api.model
def create(self, vals_list):
res = super(DentalDoctor, self).create(vals_list)
self.env['res.partner'].create({
'name': vals_list['name'],
'email': vals_list['work_email'],
'phone': vals_list['work_phone'],
})
return res
def unlink(self):
"""Delete the corresponding user from 'res.users' while
deleting the doctor"""
for record in self:
self.env['res.users'].search([
('id', '=', record.user_id.id)]).unlink()
res = super(DentalDoctor, self).unlink()
return res
@api.depends('dob')
def _compute_doctor_age(self):
"""To calculate the age of the doctor from the DOB"""
for record in self:
record.doctor_age = (fields.date.today().year - record.dob.year -
((fields.date.today().month,
fields.date.today().day) <
(record.dob.month,
record.dob.day))) if record.dob else False

36
dental_clinical_management/models/dental_medicine.py

@ -0,0 +1,36 @@
# -*- coding: utf-8 -*-
################################################################################
#
# Cybrosys Technologies Pvt. Ltd.
#
# Copyright (C) 2024-TODAY Cybrosys Technologies(<https://www.cybrosys.com>).
# Author: Cybrosys Techno Solutions(<https://www.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 DentalMedicine(models.Model):
"""For creating the medicines used in the dental clinic"""
_inherit = 'product.template'
is_medicine = fields.Boolean('Is Medicine',
help="If the product is a Medicine")
generic_name = fields.Char(string="Generic Name",
required=True,
help="Generic name of the medicament")
dosage_strength = fields.Integer(string="Dosage Strength",
required=True,
help="Dosage strength of medicament")

129
dental_clinical_management/models/dental_patients.py

@ -0,0 +1,129 @@
# -*- coding: utf-8 -*-
################################################################################
#
# Cybrosys Technologies Pvt. Ltd.
#
# Copyright (C) 2024-TODAY Cybrosys Technologies(<https://www.cybrosys.com>).
# Author: Cybrosys Techno Solutions(<https://www.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
from odoo.tools import email_normalize
class DentalPatients(models.Model):
"""To create Patients in the clinic, use res.partner model and customize it"""
_inherit = 'res.partner'
company_type = fields.Selection(selection_add=[('person', 'Patient'),
('company', 'Medicine '
'Distibutor')],
help="Patient type")
dob = fields.Date(string="Date of Birth",
help="DOB of the patient")
patient_age = fields.Integer(compute='_compute_patient_age',
store=True,
string="Age",
help="Age of the patient")
sex = fields.Selection([('male', 'Male'), ('female', 'Female')],
string="Sex",
help="Sex of the patient")
insurance_company_id = fields.Many2one('insurance.company',
string="Insurance Company",
help="Mention the insurance company")
start_date = fields.Date(string="Member Since",
help="Patient insurance start date")
expiration_date = fields.Date(string="Expiration Date",
help="Patient insurance expiration date")
insureds_name = fields.Char(string="Insured's Name",
help="Name of the insured's")
identification_number = fields.Char(string="Identification Number",
help="Identification Number of "
"insured's")
is_patient = fields.Boolean(string="Is Patient",
help="To set it's a patient")
medical_questionnaire_ids = fields.One2many('medical.questionnaire',
'patient_id',
readonly=False,
help="connect model medical "
"questionnaire in "
"patients")
report_ids = fields.One2many('xray.report', 'patient_id',
string='X-Ray',
help="To add the xray reports of the patient")
@api.model
def create(self, vals):
"""Overrides the create method to handle additional logic for DentalPatients.
When a new DentalPatient is created, It then proceeds to create a portal
wizard for the patient to grant them access to the portal.
If the `company_type` is not `person`, it assumes the record is for a
Medicine Distributor or another entity. In this case, it creates a user
from a template with predefined groups and permissions, and normalizes
the email address for consistency."""
if 'company_type' in vals and vals.get('company_type') == 'person':
vals['is_patient'] = True
res = super(DentalPatients, self).create(vals)
if 'company_type' in vals and vals.get('company_type') == 'person':
wizard = self.env['portal.wizard'].create({
'partner_ids': [fields.Command.link(res.id)]
})
portal_wizard = self.env['portal.wizard.user'].sudo().create({
'partner_id': res.id,
'email': res.email,
'wizard_id': wizard.id,
})
portal_wizard.action_grant_access()
else:
try:
user = self.env['res.users'].with_context(
no_reset_password=True)._create_user_from_template({
'email': email_normalize(res.email),
'login': email_normalize(res.email),
'partner_id': res.id,
'groups_id': [
self.env.ref("base.group_user").id,
self.env.ref(
'dental_clinical_management.group_dental_doctor').id,
self.env.ref('sales_team.group_sale_salesman').id,
self.env.ref('hr.group_hr_user').id,
self.env.ref('account.group_account_invoice').id,
self.env.ref('stock.group_stock_user').id,
self.env.ref('purchase.group_purchase_user').id
],
'company_id': self.env.company.id,
'company_ids': [(6, 0, self.env.company.ids)],
})
self.env['hr.employee'].search(
[('work_email', '=', res.email)]).user_id = user.id
except:
raise UserError(_("Email already used for another dentist"))
return res
@api.depends('dob')
def _compute_patient_age(self):
"""Computes the age of the patient based on their date of birth (dob)
and updates the `patient_age` field. The age is calculated by
subtracting the year of the patient's dob from the current year.
If the current date is before the patient's birthday in the current
year, one year is subtracted from the age."""
for record in self:
record.patient_age = (fields.date.today().year - record.dob.year -
((fields.date.today().month,
fields.date.today().day) <
(record.dob.month,
record.dob.day))) if record.dob else False

224
dental_clinical_management/models/dental_prescription.py

@ -0,0 +1,224 @@
# -*- coding: utf-8 -*-
################################################################################
#
# Cybrosys Technologies Pvt. Ltd.
#
# Copyright (C) 2024-TODAY Cybrosys Technologies(<https://www.cybrosys.com>).
# Author: Cybrosys Techno Solutions(<https://www.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 DentalPrescription(models.Model):
"""Prescription of patient from the dental clinic"""
_name = 'dental.prescription'
_description = "Dental Prescription"
_inherit = ['mail.thread']
_rec_name = "sequence_no"
sequence_no = fields.Char(string='Sequence No', required=True,
readonly=True, default=lambda self: _('New'),
help="Sequence number of the dental prescription")
appointment_ids = fields.Many2many('dental.appointment',
string="Appointment",
compute="_compute_appointment_ids",
help="All appointments created")
appointment_id = fields.Many2one('dental.appointment',
string="Appointment",
domain="[('id','in',appointment_ids)]",
required=True,
help="All appointments created")
patient_id = fields.Many2one(related="appointment_id.patient_id",
string="Patient",
required=True,
help="name of the patient")
token_no = fields.Integer(related="appointment_id.token_no",
string="Token Number",
help="Token number of the patient")
treatment_id = fields.Many2one('dental.treatment',
string="Treatment",
help="Name of the treatment "
"done for patient")
cost = fields.Float(related="treatment_id.cost",
string="Treatment Cost",
help="Cost of treatment")
currency_id = fields.Many2one('res.currency', 'Currency',
default=lambda self: self.env.user.company_id.currency_id,
required=True,
help="To add the currency type in cost")
prescribed_doctor_id = fields.Many2one(related="appointment_id.doctor_id",
string='Prescribed Doctor',
required=True,
help="Doctor who is prescribed")
prescription_date = fields.Date(related="appointment_id.date",
string='Prescription Date',
required=True,
help="Date of the prescription")
state = fields.Selection([('new', 'New'),
('done', 'Prescribed'),
('invoiced', 'Invoiced')],
default="new",
string="state",
help="state of the appointment")
medicine_ids = fields.One2many('dental.prescription_lines',
'prescription_id',
string="Medicine",
help="medicines")
invoice_data_id = fields.Many2one(comodel_name="account.move",
string="Invoice Data",
help="Invoice Data")
grand_total = fields.Float(compute="_compute_grand_total",
string="Grand Total",
help="Get the grand total amount")
@api.model
def create(self, vals):
"""Function declared for creating sequence Number for patients"""
if vals.get('sequence_no', _('New')) == _('New'):
vals['sequence_no'] = self.env['ir.sequence'].next_by_code(
'dental.prescriptions') or _('New')
res = super(DentalPrescription, self).create(vals)
return res
@api.depends('appointment_id')
def _compute_appointment_ids(self):
"""Computes and assigns the `appointment_ids` field for each record.
This method searches for all `dental.appointment` records that have
a state of `new` and a date equal to today's date. It then updates
the `appointment_ids` field of each `DentalPrescription` record
with the IDs of these found appointments."""
for rec in self:
rec.appointment_ids = self.env['dental.appointment'].search(
[('state', '=', 'new'), ('date', '=', fields.Date.today())]).ids
def action_prescribed(self):
"""Marks the prescription and its associated appointment as `done`.
This method updates the state of both the DentalPrescription instance
and its linked dental.appointment instance to `done`, indicating that
the prescription has been finalized and the appointment has been completed.
"""
self.state = 'done'
self.appointment_id.state = 'done'
def create_invoice(self):
"""Create an invoice based on the patient invoice."""
self.ensure_one()
invoice_vals = {
'move_type': 'out_invoice',
'partner_id': self.patient_id.id,
'invoice_line_ids': [
fields.Command.create({
'name': self.treatment_id.name,
'quantity': 1,
'price_unit': self.cost,
})
]
}
invoice = self.env['account.move'].create(invoice_vals)
for rec in self.medicine_ids:
product_id = self.env['product.product'].search([
('product_tmpl_id', '=', rec.medicament_id.id)])
invoice['invoice_line_ids'] = [(0, 0, {
'product_id': product_id.id,
'name': rec.display_name,
'quantity': rec.quantity,
'price_unit': rec.price,
})]
self.invoice_data_id = invoice.id
invoice.action_post()
self.state = 'invoiced'
return {
'name': _('Customer Invoice'),
'view_mode': 'form',
'view_id': self.env.ref('account.view_move_form').id,
'res_model': 'account.move',
'context': "{'move_type':'out_invoice'}",
'type': 'ir.actions.act_window',
'res_id': self.invoice_data_id.id,
}
def action_view_invoice(self):
"""Invoice view"""
return {
'name': _('Customer Invoice'),
'view_mode': 'form',
'view_id': self.env.ref('account.view_move_form').id,
'res_model': 'account.move',
'context': "{'move_type':'out_invoice'}",
'type': 'ir.actions.act_window',
'res_id': self.invoice_data_id.id,
}
def _compute_grand_total(self):
"""Computes the grand total cost of the dental prescription.
This method initializes the grand total with the cost of the treatment
and then iterates over all the prescribed medicines, adding their total
cost to the grand total. The grand total is stored in the `grand_total`
field of the `DentalPrescription` model."""
self.grand_total = self.cost
for rec in self.medicine_ids:
self.grand_total += rec.total
class DentalPrescriptionLines(models.Model):
"""Prescription lines of the dental clinic prescription"""
_name = 'dental.prescription_lines'
_description = "Dental Prescriptions Lines"
_rec_name = "medicament_id"
medicament_id = fields.Many2one('product.template',
domain="[('is_medicine', '=', True)]",
string="Medicament",
help="Name of the medicine")
generic_name = fields.Char(string="Generic Name",
related="medicament_id.generic_name",
help="Generic name of the medicament")
dosage_strength = fields.Integer(string="Dosage Strength",
related="medicament_id.dosage_strength",
help="Dosage strength of medicament")
medicament_form = fields.Selection([('tablet', 'Tablets'),
('capsule', 'Capsules'),
('liquid', 'Liquid'),
('injection', 'Injections')],
string="Medicament Form",
required=True,
help="Add the form of the medicine")
quantity = fields.Integer(string="Quantity",
required=True,
help="Quantity of medicine")
frequency_id = fields.Many2one('medicine.frequency',
string="Frequency",
required=True,
help="Frequency of medicine")
price = fields.Float(related='medicament_id.list_price',
string="Price",
help="Cost of medicine")
total = fields.Float(string="Total Price",
help="Total price of medicine")
prescription_id = fields.Many2one('dental.prescription',
help="Relate the model with "
"dental_prescription")
@api.onchange('quantity')
def _onchange_quantity(self):
"""Updates the total price of the medicament based on the quantity.
This method is triggered by an onchange event of the `quantity` field.
It calculates the total price by multiplying the `quantity` of the
medicament by its `price` and updates the `total` field with the new value.
"""
for rec in self:
rec.total = rec.price * rec.quantity

31
dental_clinical_management/models/dental_specialist.py

@ -0,0 +1,31 @@
# -*- coding: utf-8 -*-
################################################################################
#
# Cybrosys Technologies Pvt. Ltd.
#
# Copyright (C) 2024-TODAY Cybrosys Technologies(<https://www.cybrosys.com>).
# Author: Cybrosys Techno Solutions(<https://www.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 DentalSpecialist(models.Model):
"""To mention doctors Specialised field"""
_name = 'dental.specialist'
_description = "Dental Specialist"
name = fields.Char(string="Name", help="Name of the dental specialist")
code = fields.Char(string="Code", help="Add the code for the name")

54
dental_clinical_management/models/dental_time_shift.py

@ -0,0 +1,54 @@
# -*- coding: utf-8 -*-
################################################################################
#
# Cybrosys Technologies Pvt. Ltd.
#
# Copyright (C) 2024-TODAY Cybrosys Technologies(<https://www.cybrosys.com>).
# Author: Cybrosys Techno Solutions(<https://www.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 DentalTimeShift(models.Model):
"""Doctors time shift, different time slots"""
_name = 'dental.time.shift'
_description = "Dental Time Shift"
_rec_name = 'name'
name = fields.Char(string='Name', readonly=True,
help="name of the time shifts")
shift_type = fields.Selection(
selection=[('morning', 'Morning'), ('day', 'Day'),
('evening', 'Evening'), ('night', 'Night')],
string="Shift Type", help="Selection field for the shift type")
start_time = fields.Float(string="Start Time", help="start time of time "
"slot", required=True)
end_time = fields.Float(string="End Time", help="End time of time slot", required=True)
@api.model_create_multi
def create(self, vals_list):
"""Overrides the default create method to set the `name` field of the
newly created `dental.time.shift` record(s) to a string that represents
the shift time range."""
res = super(DentalTimeShift, self).create(vals_list)
res.name = f'{res.start_time} to {res.end_time}'
return res
@api.onchange('start_time', 'end_time')
def _onchange_time(self):
name = f'{self.start_time} to {self.end_time}'
self.update({'name': name})

36
dental_clinical_management/models/dental_treatment.py

@ -0,0 +1,36 @@
# -*- coding: utf-8 -*-
################################################################################
#
# Cybrosys Technologies Pvt. Ltd.
#
# Copyright (C) 2024-TODAY Cybrosys Technologies(<https://www.cybrosys.com>).
# Author: Cybrosys Techno Solutions(<https://www.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 DentalTreatment(models.Model):
"""For adding Dental treatment details of the patients"""
_name = 'dental.treatment'
_description = "Dental Treatment"
_inherit = ['mail.thread']
name = fields.Char(string='Treatment Name', help="Date of the treatment")
treatment_categ_id = fields.Many2one('treatment.category',
string="Category",
help="name of the treatment")
cost = fields.Float(string='Cost',
help="Cost of the Treatment")

33
dental_clinical_management/models/insurance_company.py

@ -0,0 +1,33 @@
# -*- coding: utf-8 -*-
################################################################################
#
# Cybrosys Technologies Pvt. Ltd.
#
# Copyright (C) 2024-TODAY Cybrosys Technologies(<https://www.cybrosys.com>).
# Author: Cybrosys Techno Solutions(<https://www.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 InsuranceCompany(models.Model):
"""To add the insurance details"""
_name = 'insurance.company'
_description = "Insurance Company"
name = fields.Char(string="Name", help="Name of the insurance company")
phone = fields.Char(string="Phone", help="Phone number of the insurance "
"company")
email = fields.Char(string="Email", help="Email of the insurance company")

38
dental_clinical_management/models/medical_questionnaire.py

@ -0,0 +1,38 @@
# -*- coding: utf-8 -*-
################################################################################
#
# Cybrosys Technologies Pvt. Ltd.
#
# Copyright (C) 2024-TODAY Cybrosys Technologies(<https://www.cybrosys.com>).
# Author: Cybrosys Techno Solutions(<https://www.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 MedicalQuestionnaire(models.Model):
"""Medical questions to be asked to the patients while their appointment"""
_name = 'medical.questionnaire'
_description = 'Medical Questionnaire'
question_id = fields.Many2one('medical.questions',
string='Questions',
help="All added question")
yes_no = fields.Selection([('yes', 'Yes'), ('no', 'No')],
string='Yes or No', help="choose the answer")
reason = fields.Text(string='Reason', help="Reason for the question answer")
patient_id = fields.Many2one('res.partner',
string='Patient',
help="Patient name")

53
dental_clinical_management/models/medical_questions.py

@ -0,0 +1,53 @@
# -*- coding: utf-8 -*-
################################################################################
#
# Cybrosys Technologies Pvt. Ltd.
#
# Copyright (C) 2024-TODAY Cybrosys Technologies(<https://www.cybrosys.com>).
# Author: Cybrosys Techno Solutions(<https://www.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 MedicalQuestions(models.Model):
"""To add medical questionnaire question"""
_name = 'medical.questions'
_description = 'Medical Questions'
_rec_name = 'question'
question = fields.Char(string='Question')
@api.model
def create(self, vals):
"""Overrides the default create method to add a new medical question
record and automatically create a corresponding entry in the
`medical.questionnaire` model."""
res = super(MedicalQuestions, self).create(vals)
self.env['medical.questionnaire'].create({
'question_id': res.id
})
return res
def unlink(self):
"""Overrides the default unlink method to delete the current medical
question record. Before deletion, it searches for and deletes any
associated records in the `medical.questionnaire` model that
reference this medical question."""
for rec in self:
for line in self.env['medical.questionnaire'].search(
[('question_id', '=', rec.id)]):
line.unlink()
return super(MedicalQuestions, self).unlink()

34
dental_clinical_management/models/medicine_frequency.py

@ -0,0 +1,34 @@
# -*- coding: utf-8 -*-
################################################################################
#
# Cybrosys Technologies Pvt. Ltd.
#
# Copyright (C) 2024-TODAY Cybrosys Technologies(<https://www.cybrosys.com>).
# Author: Cybrosys Techno Solutions(<https://www.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 MedicineFrequency(models.Model):
"""To specifying the medicine frequency, how to consume it."""
_name = 'medicine.frequency'
_description = "Medicine Frequency"
_rec_name = "medicament_frequency"
code = fields.Char(string="Code", help="code of medicine frequency")
medicament_frequency = fields.Char(string="Medicine Frequency",
help="Add the frequency of medicine how "
"to eat")

30
dental_clinical_management/models/treatment_category.py

@ -0,0 +1,30 @@
# -*- coding: utf-8 -*-
################################################################################
#
# Cybrosys Technologies Pvt. Ltd.
#
# Copyright (C) 2024-TODAY Cybrosys Technologies(<https://www.cybrosys.com>).
# Author: Cybrosys Techno Solutions(<https://www.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 TreatmentCategory(models.Model):
"""Adding the treatment category"""
_name = 'treatment.category'
_description = "Treatment Category"
name = fields.Char(string="Name", help="Name of the treatment category")

108
dental_clinical_management/report/dental_appointment_card.xml

@ -0,0 +1,108 @@
<?xml version="1.0" encoding="UTF-8"?>
<odoo>
<!-- Appointment card report template -->
<template id="dental_clinical_management_appointment_card">
<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">
<h1 style="margin: 10px; color:white;">
Appointment Card
</h1>
</div>
<div class="page" style="padding: 10px;">
<h1>
<b>Token:
<t t-esc="token"/>
</b>
</h1>
<p>
<b>Doctor:
<t t-esc="doctor"/>
</b>
<br/>
<b>Specialised:
<t t-esc="specialised"/>
</b>
<br/>
<b>Time:
<t t-esc="appointment_time"/>
</b>
<br/>
<b>Date:
<t t-esc="date"/>
</b>
</p>
<div style="position:absolute; left:320px; top:100px;">
<img t-attf-src="{{ request.httprequest.url_root }}dental_clinical_management/static/src/img/appointment.jpeg"
style="height: 140px; width: 150px;"/>
</div>
</div>
</div>
</section>
</t>
</template>
<template id="dental_clinical_management_appointment_cards">
<t t-call="web.html_container">
<section>
<div style="width: 500px; height: 260px; border: 2px black solid; border-radius: 5px;">
<t t-foreach="docs" t-as="doc">
<div class="container"
style="width: 500px; height: 50px; background-color:red">
<h1 style="margin: 10px; color:white;">
Appointment Card
</h1>
</div>
<div class="page" style="padding: 10px;">
<h1>
<b>Token:
<t t-esc="doc.token_no"/>
</b>
</h1>
<p>
<b>Doctor:
<t t-esc="doc.doctor_id.name"/>
</b>
<br/>
<b>Specialised:
<t t-esc="doc.specialist_id.name"/>
</b>
<br/>
<b>Time:
<t t-esc="doc.shift_id.name"/>
</b>
<br/>
<b>Date:
<t t-esc="doc.date"/>
</b>
</p>
<div style="position:absolute; left:320px; top:100px;">
<img t-attf-src="{{ request.httprequest.url_root }}dental_clinical_management/static/src/img/appointment.jpeg"
style="height: 140px; width: 150px;"/>
</div>
</div>
</t>
</div>
</section>
</t>
</template>
<record id="action_appointment_card" model="ir.actions.report">
<field name="name">Appointment Card</field>
<field name="model">dental.appointment</field>
<field name="report_type">qweb-pdf</field>
<field name="report_name">dental_clinical_management.dental_clinical_management_appointment_card</field>
<field name="report_file">dental_clinical_management.dental_clinical_management_appointment_card</field>
</record>
<!-- Action report appointment card -->
<record id="action_appointment_cards" model="ir.actions.report">
<field name="name">Appointment Card</field>
<field name="model">dental.appointment</field>
<field name="report_type">qweb-pdf</field>
<field name="report_name">dental_clinical_management.dental_clinical_management_appointment_cards</field>
<field name="report_file">dental_clinical_management.dental_clinical_management_appointment_cards</field>
<field name="binding_model_id"
ref="dental_clinical_management.model_dental_appointment"/>
</record>
</odoo>

17
dental_clinical_management/report/dental_prescription_report.xml

@ -0,0 +1,17 @@
<?xml version="1.0" encoding="utf-8"?>
<odoo>
<!-- Report Action of Dental Prescription Pdf -->
<record id="report_pdf_dental_prescription" model="ir.actions.report">
<field name="name">Prescription Pdf</field>
<field name="model">dental.prescription</field>
<field name="report_type">qweb-pdf</field>
<field name="report_name">dental_clinical_management.report_prescription</field>
<field name="report_file">
dental_clinical_management.report_prescription
</field>
<field name="print_report_name">'Prescription Report - %s' % (object.sequence_no)</field>
<field name="binding_model_id"
ref="dental_clinical_management.model_dental_prescription"/>
<field name="binding_type">report</field>
</record>
</odoo>

120
dental_clinical_management/report/dental_prescription_templates.xml

@ -0,0 +1,120 @@
<?xml version="1.0" encoding="utf-8"?>
<odoo>
<!-- Pdf template of Prescription Report-->
<template id="report_prescription">
<t t-call="web.html_container">
<t t-foreach="docs" t-as="o">
<t t-call="web.external_layout">
<div classtemplate="page">
<div class="oe_structure"/>
<div class="text-center">
<h2>DENTAL PRESCRIPTION REPORT</h2>
</div>
<br/>
<table class="table table-borderless">
<tbody>
<tr>
<td>
Patient Name :
<span t-field="o.patient_id"/>
</td>
<td>
Doctor Name :
<span t-field="o.prescribed_doctor_id"/>
</td>
</tr>
<tr>
<td>
Appointment ID :
<span t-field="o.appointment_id"/>
</td>
<td>
Treatment :
<span t-field="o.treatment_id"/>
</td>
</tr>
<tr>
<td>
Token NO :
<span t-field="o.token_no"/>
</td>
<td>
Date :
<span t-field="o.prescription_date"/>
</td>
</tr>
</tbody>
</table>
<table class="table table-bordered mt32">
<thead>
<tr>
<th>Sl.No</th>
<t t-set="counter" t-value="0"/>
<th class="text-center">
<span>Medicament</span>
</th>
<th class="text-center">
<span>Generic Name</span>
</th>
<th class="text-center">
<span>Dosage Strength</span>
</th>
<th class="text-center">
<span>Medicament Form</span>
</th>
<th class="text-center">
<span>Quantity</span>
</th>
<th class="text-center">
<span>Frequency</span>
</th>
</tr>
</thead>
<tbody>
<t t-foreach="o.medicine_ids" t-as="medicine">
<tr class="text-center">
<td style="text-align:center;">
<t t-set="counter"
t-value="counter + 1"/>
<t t-esc="counter"/>
</td>
<td style="text-align:center;">
<span>
<t t-esc="medicine.medicament_id.name"/>
</span>
</td>
<td style="text-align:center;">
<span>
<t t-esc="medicine.generic_name"/>
</span>
</td>
<td style="text-align:center;">
<span>
<t t-esc="medicine.dosage_strength"/>
</span>
</td>
<td style="text-align:center;">
<span>
<t t-esc="medicine.medicament_form"/>
</span>
</td>
<td style="text-align:center;">
<span>
<t t-esc="medicine.quantity"/>
</span>
</td>
<td style="text-align:center;">
<span>
<t t-esc="medicine.frequency_id.medicament_frequency"/>
</span>
</td>
</tr>
</t>
</tbody>
</table>
</div>
</t>
</t>
</t>
</template>
</odoo>

27
dental_clinical_management/security/dental_clinical_management_groups.xml

@ -0,0 +1,27 @@
<?xml version="1.0" encoding="utf-8"?>
<odoo>
<!-- Created the category Dental Clinic to set the Groups -->
<record id="module_category_dental_clinic" model="ir.module.category">
<field name="name">Dental Clinic</field>
<field name="sequence">18</field>
</record>
<!-- Created the Groups as Own Documents Only and this groups will be only access their own datas -->
<record id="group_dental_doctor" model="res.groups">
<field name="name">User: Own Documents Only</field>
<field name="category_id" ref="module_category_dental_clinic"/>
<field name="implied_ids" eval="[(4, ref('base.group_user'))]"/>
<field name="comment">the user will have access to his own data in the
dental clinic application.
</field>
</record>
<!-- Created the Groups as OManager and this groups can we view all the datas -->
<record id="group_dental_manager" model="res.groups">
<field name="name">Manager</field>
<field name="comment">the user will have an access to all the dental
clinic configuration.
</field>
<field name="category_id" ref="module_category_dental_clinic"/>
<field name="implied_ids" eval="[(4, ref('group_dental_doctor'))]"/>
<field name="users" eval="[(4, ref('base.user_root'))]"/>
</record>
</odoo>

33
dental_clinical_management/security/dental_clinical_management_security.xml

@ -0,0 +1,33 @@
<?xml version="1.0" encoding="utf-8"?>
<odoo>
<!-- Set the record rule for visible only the corresponding doctor appointments -->
<record id="own_dental_appointments" model="ir.rule">
<field name="name">Own Appointments</field>
<field name="model_id" ref="model_dental_appointment"/>
<field name="domain_force">[('doctor_id.user_id', '=', user.id)]</field>
<field name="groups"
eval="[Command.link(ref('dental_clinical_management.group_dental_doctor'))]"/>
</record>
<!-- To see all the appointments for the manager -->
<record id="see_all_dental_appointments" model="ir.rule">
<field name="name">All Appointments</field>
<field ref="model_dental_appointment" name="model_id"/>
<field name="domain_force">[(1, '=', 1)]</field>
<field name="groups" eval="[Command.link(ref('dental_clinical_management.group_dental_manager'))]"/>
</record>
<!-- Set the record rule for visible only the corresponding doctor prescriptions -->
<record id="own_dental_prescription" model="ir.rule">
<field name="name">Own Prescriptions</field>
<field name="model_id" ref="model_dental_prescription"/>
<field name="domain_force">[('prescribed_doctor_id.user_id', '=', user.id)]</field>
<field name="groups"
eval="[Command.link(ref('dental_clinical_management.group_dental_doctor'))]"/>
</record>
<!-- To see all the prescriptions for the manager -->
<record id="see_all_dental_prescriptions" model="ir.rule">
<field name="name">All Prescriptions</field>
<field ref="model_dental_prescription" name="model_id"/>
<field name="domain_force">[(1, '=', 1)]</field>
<field name="groups" eval="[Command.link(ref('dental_clinical_management.group_dental_manager'))]"/>
</record>
</odoo>

27
dental_clinical_management/security/ir.model.access.csv

@ -0,0 +1,27 @@
id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink
access_dental_time_shift,access.dental.time.shift,model_dental_time_shift,base.group_user,1,1,1,1
access_medicine_frequency,access.medicine.frequency,model_medicine_frequency,base.group_user,1,1,1,1
access_medical_questions,access.medical.questions,model_medical_questions,base.group_user,1,1,1,1
access_medical_questionnaire,access.medical.questionnaire,model_medical_questionnaire,base.group_user,1,1,1,1
access_xray_report,access.xray.report,model_xray_report,base.group_user,1,1,1,1
access_portal_dental_prescription,access.portal.dental.prescription,model_dental_prescription,base.group_portal,1,0,0,0
access_portal_dental_prescription_lines,access.portal.dental.prescription_lines,model_dental_prescription_lines,base.group_portal,1,0,0,0
access_portal_dental_appointment,access.portal.dental.appointment,model_dental_appointment,base.group_portal,1,0,0,0
access_portal_dental_specialist,access.portal.dental.specialist,model_dental_specialist,base.group_portal,1,0,0,0
access_portal_dental_treatment,access.portal.dental.treatment,model_dental_treatment,base.group_portal,1,0,0,0
access_portal_product_template,access.portal.product.template,model_product_template,base.group_portal,1,0,0,0
access_portal_medicine_frequency,access.portal.medicine.frequency,model_medicine_frequency,base.group_portal,1,0,0,0
access_user_dental_appointment,access.user.dental.appointment,model_dental_appointment,dental_clinical_management.group_dental_doctor,1,1,0,0
access_user_dental_prescription,access.user.dental.prescription,model_dental_prescription,dental_clinical_management.group_dental_doctor,1,1,1,1
access_user_dental_prescription_lines,access.user.dental.prescription_lines,model_dental_prescription_lines,dental_clinical_management.group_dental_doctor,1,1,1,1
access_user_dental_specialist,access.user.dental.specialist,model_dental_specialist,dental_clinical_management.group_dental_doctor,1,0,0,0
access_user_treatment_category,access.user.treatment.category,model_treatment_category,dental_clinical_management.group_dental_doctor,1,0,0,0
access_user_dental_treatment,access.user.dental.treatment,model_dental_treatment,dental_clinical_management.group_dental_doctor,1,0,0,0
access_user_insurance_company,access.user.insurance.company,model_insurance_company,dental_clinical_management.group_dental_doctor,1,0,0,0
access_manager_dental_appointment,access.manager.dental.appointment,model_dental_appointment,dental_clinical_management.group_dental_manager,1,1,1,1
access_manager_dental_prescription,access.manager.dental.prescription,model_dental_prescription,dental_clinical_management.group_dental_manager,1,1,1,1
access_manager_dental_prescription_lines,access.manager.dental.prescription_lines,model_dental_prescription_lines,dental_clinical_management.group_dental_manager,1,1,1,1
access_manager_dental_specialist,access.manager.dental.specialist,model_dental_specialist,dental_clinical_management.group_dental_manager,1,1,1,1
access_manager_treatment_category,access.manager.treatment.category,model_treatment_category,dental_clinical_management.group_dental_manager,1,1,1,1
access_manager_dental_treatment,access.manager.dental.treatment,model_dental_treatment,dental_clinical_management.group_dental_manager,1,1,1,1
access_manager_insurance_company,access.manager.insurance.company,model_insurance_company,dental_clinical_management.group_dental_manager,1,1,1,1
1 id name model_id:id group_id:id perm_read perm_write perm_create perm_unlink
2 access_dental_time_shift access.dental.time.shift model_dental_time_shift base.group_user 1 1 1 1
3 access_medicine_frequency access.medicine.frequency model_medicine_frequency base.group_user 1 1 1 1
4 access_medical_questions access.medical.questions model_medical_questions base.group_user 1 1 1 1
5 access_medical_questionnaire access.medical.questionnaire model_medical_questionnaire base.group_user 1 1 1 1
6 access_xray_report access.xray.report model_xray_report base.group_user 1 1 1 1
7 access_portal_dental_prescription access.portal.dental.prescription model_dental_prescription base.group_portal 1 0 0 0
8 access_portal_dental_prescription_lines access.portal.dental.prescription_lines model_dental_prescription_lines base.group_portal 1 0 0 0
9 access_portal_dental_appointment access.portal.dental.appointment model_dental_appointment base.group_portal 1 0 0 0
10 access_portal_dental_specialist access.portal.dental.specialist model_dental_specialist base.group_portal 1 0 0 0
11 access_portal_dental_treatment access.portal.dental.treatment model_dental_treatment base.group_portal 1 0 0 0
12 access_portal_product_template access.portal.product.template model_product_template base.group_portal 1 0 0 0
13 access_portal_medicine_frequency access.portal.medicine.frequency model_medicine_frequency base.group_portal 1 0 0 0
14 access_user_dental_appointment access.user.dental.appointment model_dental_appointment dental_clinical_management.group_dental_doctor 1 1 0 0
15 access_user_dental_prescription access.user.dental.prescription model_dental_prescription dental_clinical_management.group_dental_doctor 1 1 1 1
16 access_user_dental_prescription_lines access.user.dental.prescription_lines model_dental_prescription_lines dental_clinical_management.group_dental_doctor 1 1 1 1
17 access_user_dental_specialist access.user.dental.specialist model_dental_specialist dental_clinical_management.group_dental_doctor 1 0 0 0
18 access_user_treatment_category access.user.treatment.category model_treatment_category dental_clinical_management.group_dental_doctor 1 0 0 0
19 access_user_dental_treatment access.user.dental.treatment model_dental_treatment dental_clinical_management.group_dental_doctor 1 0 0 0
20 access_user_insurance_company access.user.insurance.company model_insurance_company dental_clinical_management.group_dental_doctor 1 0 0 0
21 access_manager_dental_appointment access.manager.dental.appointment model_dental_appointment dental_clinical_management.group_dental_manager 1 1 1 1
22 access_manager_dental_prescription access.manager.dental.prescription model_dental_prescription dental_clinical_management.group_dental_manager 1 1 1 1
23 access_manager_dental_prescription_lines access.manager.dental.prescription_lines model_dental_prescription_lines dental_clinical_management.group_dental_manager 1 1 1 1
24 access_manager_dental_specialist access.manager.dental.specialist model_dental_specialist dental_clinical_management.group_dental_manager 1 1 1 1
25 access_manager_treatment_category access.manager.treatment.category model_treatment_category dental_clinical_management.group_dental_manager 1 1 1 1
26 access_manager_dental_treatment access.manager.dental.treatment model_dental_treatment dental_clinical_management.group_dental_manager 1 1 1 1
27 access_manager_insurance_company access.manager.insurance.company model_insurance_company dental_clinical_management.group_dental_manager 1 1 1 1

BIN
dental_clinical_management/static/description/assets/icons/check.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.6 KiB

BIN
dental_clinical_management/static/description/assets/icons/chevron.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 310 B

BIN
dental_clinical_management/static/description/assets/icons/cogs.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

BIN
dental_clinical_management/static/description/assets/icons/consultation.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

BIN
dental_clinical_management/static/description/assets/icons/ecom-black.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 576 B

BIN
dental_clinical_management/static/description/assets/icons/education-black.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 733 B

BIN
dental_clinical_management/static/description/assets/icons/hotel-black.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 911 B

BIN
dental_clinical_management/static/description/assets/icons/license.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

BIN
dental_clinical_management/static/description/assets/icons/lifebuoy.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

BIN
dental_clinical_management/static/description/assets/icons/manufacturing-black.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 673 B

BIN
dental_clinical_management/static/description/assets/icons/pos-black.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 878 B

BIN
dental_clinical_management/static/description/assets/icons/puzzle.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 653 B

BIN
dental_clinical_management/static/description/assets/icons/restaurant-black.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 905 B

BIN
dental_clinical_management/static/description/assets/icons/service-black.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 839 B

BIN
dental_clinical_management/static/description/assets/icons/trading-black.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 427 B

BIN
dental_clinical_management/static/description/assets/icons/training.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 627 B

BIN
dental_clinical_management/static/description/assets/icons/update.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

BIN
dental_clinical_management/static/description/assets/icons/user.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 988 B

BIN
dental_clinical_management/static/description/assets/icons/wrench.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

BIN
dental_clinical_management/static/description/assets/misc/categories.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

BIN
dental_clinical_management/static/description/assets/misc/check-box.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

BIN
dental_clinical_management/static/description/assets/misc/compass.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 KiB

BIN
dental_clinical_management/static/description/assets/misc/corporate.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

BIN
dental_clinical_management/static/description/assets/misc/customer-support.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.1 KiB

BIN
dental_clinical_management/static/description/assets/misc/cybrosys-logo.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.4 KiB

BIN
dental_clinical_management/static/description/assets/misc/features.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 589 B

BIN
dental_clinical_management/static/description/assets/misc/logo.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.4 KiB

BIN
dental_clinical_management/static/description/assets/misc/pictures.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 KiB

BIN
dental_clinical_management/static/description/assets/misc/pie-chart.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.3 KiB

BIN
dental_clinical_management/static/description/assets/misc/right-arrow.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 967 B

BIN
dental_clinical_management/static/description/assets/misc/star.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 KiB

BIN
dental_clinical_management/static/description/assets/misc/support.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.8 KiB

BIN
dental_clinical_management/static/description/assets/misc/whatsapp.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.0 KiB

BIN
dental_clinical_management/static/description/assets/modules/1.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 59 KiB

BIN
dental_clinical_management/static/description/assets/modules/2.jpg

Binary file not shown.

After

Width:  |  Height:  |  Size: 57 KiB

BIN
dental_clinical_management/static/description/assets/modules/3.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 58 KiB

BIN
dental_clinical_management/static/description/assets/modules/4.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 59 KiB

BIN
dental_clinical_management/static/description/assets/modules/5.jpg

Binary file not shown.

After

Width:  |  Height:  |  Size: 88 KiB

BIN
dental_clinical_management/static/description/assets/modules/6.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 76 KiB

BIN
dental_clinical_management/static/description/assets/screenshots/1.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 89 KiB

BIN
dental_clinical_management/static/description/assets/screenshots/10.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 83 KiB

BIN
dental_clinical_management/static/description/assets/screenshots/11.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 60 KiB

BIN
dental_clinical_management/static/description/assets/screenshots/12.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 61 KiB

BIN
dental_clinical_management/static/description/assets/screenshots/13.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 118 KiB

BIN
dental_clinical_management/static/description/assets/screenshots/14.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 118 KiB

BIN
dental_clinical_management/static/description/assets/screenshots/15.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 120 KiB

BIN
dental_clinical_management/static/description/assets/screenshots/16.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 101 KiB

BIN
dental_clinical_management/static/description/assets/screenshots/17.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 119 KiB

BIN
dental_clinical_management/static/description/assets/screenshots/18.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 124 KiB

BIN
dental_clinical_management/static/description/assets/screenshots/19.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 106 KiB

BIN
dental_clinical_management/static/description/assets/screenshots/2.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 51 KiB

BIN
dental_clinical_management/static/description/assets/screenshots/20.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 47 KiB

BIN
dental_clinical_management/static/description/assets/screenshots/21.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 65 KiB

BIN
dental_clinical_management/static/description/assets/screenshots/22.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 98 KiB

BIN
dental_clinical_management/static/description/assets/screenshots/23.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 95 KiB

BIN
dental_clinical_management/static/description/assets/screenshots/24.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 53 KiB

BIN
dental_clinical_management/static/description/assets/screenshots/25.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 74 KiB

BIN
dental_clinical_management/static/description/assets/screenshots/26.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 152 KiB

BIN
dental_clinical_management/static/description/assets/screenshots/27.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 55 KiB

BIN
dental_clinical_management/static/description/assets/screenshots/28.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 54 KiB

BIN
dental_clinical_management/static/description/assets/screenshots/29.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 106 KiB

BIN
dental_clinical_management/static/description/assets/screenshots/3.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 54 KiB

BIN
dental_clinical_management/static/description/assets/screenshots/30.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 121 KiB

Some files were not shown because too many files changed in this diff

Loading…
Cancel
Save