| @ -0,0 +1,54 @@ | |||||
|  | .. 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 | ||||
|  | 
 | ||||
|  | Medical Lab Management | ||||
|  | ====================== | ||||
|  | Helps You To Manage Medical Lab Operations. | ||||
|  | 
 | ||||
|  | Configuration | ||||
|  | ============ | ||||
|  | - www.odoo.com/documentation/18.0/setup/install.html | ||||
|  | - Install our custom addon | ||||
|  | 
 | ||||
|  | Company | ||||
|  | ------- | ||||
|  | * `Cybrosys Techno Solutions <https://cybrosys.com/>`__ | ||||
|  | 
 | ||||
|  | License | ||||
|  | ------- | ||||
|  | GNU AFFERO GENERAL PUBLIC LICENSE, Version 3 (AGPLv3) | ||||
|  | (https://www.gnu.org/licenses/agpl-3.0-standalone.html) | ||||
|  | 
 | ||||
|  | Credits | ||||
|  | ------- | ||||
|  | * Developers: 	Anusha P P, | ||||
|  |                 Niyas Raphy, | ||||
|  |                 (V14) Muhammad P, | ||||
|  |                 (V15) Mily Shajan, | ||||
|  |                 (V16) Sabeel B, | ||||
|  |                 (V17) Sruthi Pavithran, | ||||
|  |                 (V18) Gayathri V, | ||||
|  |   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,22 @@ | |||||
|  | # -*- coding: utf-8 -*- | ||||
|  | ############################################################################# | ||||
|  | # | ||||
|  | #    Cybrosys Technologies Pvt. Ltd. | ||||
|  | # | ||||
|  | #    Copyright (C) 2025-TODAY Cybrosys Technologies(<https://www.cybrosys.com>). | ||||
|  | #    Author: Gayathri V (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 models | ||||
| @ -0,0 +1,60 @@ | |||||
|  | # -*- coding: utf-8 -*- | ||||
|  | ############################################################################# | ||||
|  | # | ||||
|  | #    Cybrosys Technologies Pvt. Ltd. | ||||
|  | # | ||||
|  | #    Copyright (C) 2025-TODAY Cybrosys Technologies(<https://www.cybrosys.com>). | ||||
|  | #    Author: Gayathri V (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': "Medical Lab Management", | ||||
|  |     'version': '18.0.1.0.0', | ||||
|  |     'category': 'Industries', | ||||
|  |     'summary': """Manage Medical Lab Operations.""", | ||||
|  |     'description': """Manage Medical Laboratory Operations,  | ||||
|  |      Manage Appointments.""", | ||||
|  |     'author': "Cybrosys Techno Solutions", | ||||
|  |     'company': "Cybrosys Techno Solutions", | ||||
|  |     'maintainer': 'Cybrosys Techno Solutions', | ||||
|  |     'website': "https://www.cybrosys.com", | ||||
|  |     'depends': ['base', 'mail', 'account', 'contacts'], | ||||
|  |     'data': [ | ||||
|  |         'security/medical_lab_management_security.xml', | ||||
|  |         'security/ir.model.access.csv', | ||||
|  |         'data/lab_appointment_sequence.xml', | ||||
|  |         'data/lab_patient_sequence.xml', | ||||
|  |         'data/lab_request_sequence.xml', | ||||
|  |         'views/res_partner_views.xml', | ||||
|  |         'views/lab_patient_views.xml', | ||||
|  |         'views/test_unit_views.xml', | ||||
|  |         'views/lab_test_views.xml', | ||||
|  |         'views/lab_test_content_type_views.xml', | ||||
|  |         'views/physician_specialty_views.xml', | ||||
|  |         'views/physician_details_views.xml', | ||||
|  |         'views/lab_request_views.xml', | ||||
|  |         'views/lab_appointment_views.xml', | ||||
|  |         'views/account_move_views.xml', | ||||
|  |         'report/lab_request_reports.xml', | ||||
|  |         'report/lab_patient_reports.xml', | ||||
|  |         'report/lab_request_templates.xml', | ||||
|  |         'report/lab_patient_templates.xml', | ||||
|  |     ], | ||||
|  |     'images': ['static/description/banner.png'], | ||||
|  |     'license': 'AGPL-3', | ||||
|  |     'installable': True, | ||||
|  |     'auto_install': False, | ||||
|  |     'application': True, | ||||
|  | } | ||||
| @ -0,0 +1,13 @@ | |||||
|  | <?xml version="1.0" encoding="UTF-8"?> | ||||
|  | <odoo> | ||||
|  |     <!-- Creating sequence for lab appointment--> | ||||
|  |     <data noupdate="1"> | ||||
|  |         <record id="lab_appointment_sequence" model="ir.sequence"> | ||||
|  |             <field name="name">Appointment</field> | ||||
|  |             <field name="code">lab.appointment</field> | ||||
|  |             <field name="prefix">ID</field> | ||||
|  |             <field name="padding">3</field> | ||||
|  |             <field name="company_id" eval="False"/> | ||||
|  |         </record> | ||||
|  |     </data> | ||||
|  | </odoo> | ||||
| @ -0,0 +1,13 @@ | |||||
|  | <?xml version="1.0" encoding="UTF-8"?> | ||||
|  | <odoo> | ||||
|  | <!--    Creating sequence for lab patient--> | ||||
|  |      <data noupdate="1"> | ||||
|  |         <record id="lab_patient_sequence" model="ir.sequence"> | ||||
|  |             <field name="name">Patient</field> | ||||
|  |             <field name="code">lab.patient</field> | ||||
|  |             <field name="prefix">PID</field> | ||||
|  |             <field name="padding">3</field> | ||||
|  |             <field name="company_id" eval="False"/> | ||||
|  |         </record> | ||||
|  |     </data> | ||||
|  | </odoo> | ||||
| @ -0,0 +1,13 @@ | |||||
|  | <?xml version="1.0" encoding="UTF-8"?> | ||||
|  | <odoo> | ||||
|  | <!--    Creating sequence for lab request--> | ||||
|  |     <data noupdate="1"> | ||||
|  |         <record id="lab_request_sequence" model="ir.sequence"> | ||||
|  |             <field name="name">Lab Request</field> | ||||
|  |             <field name="code">lab.request</field> | ||||
|  |             <field name="prefix">LR</field> | ||||
|  |             <field name="padding">3</field> | ||||
|  |             <field name="company_id" eval="False"/> | ||||
|  |         </record> | ||||
|  |     </data> | ||||
|  | </odoo> | ||||
| @ -0,0 +1,6 @@ | |||||
|  | ## Module <medical_lab_management> | ||||
|  | 
 | ||||
|  | #### 19.04.2025 | ||||
|  | #### Version 18.0.1.0.0 | ||||
|  | #### ADD | ||||
|  | - Initial Commit for Medical Lab Management. | ||||
| @ -0,0 +1,32 @@ | |||||
|  | # -*- coding: utf-8 -*- | ||||
|  | ############################################################################# | ||||
|  | # | ||||
|  | #    Cybrosys Technologies Pvt. Ltd. | ||||
|  | # | ||||
|  | #    Copyright (C) 2025-TODAY Cybrosys Technologies(<https://www.cybrosys.com>). | ||||
|  | #    Author: Gayathri V (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_move | ||||
|  | from . import lab_appointment | ||||
|  | from . import lab_appointment_lines | ||||
|  | from . import lab_patient | ||||
|  | from . import lab_request | ||||
|  | from . import lab_test | ||||
|  | from . import lab_test_attribute | ||||
|  | from . import lab_test_content_type | ||||
|  | from . import physician_speciality | ||||
|  | from . import res_partner | ||||
|  | from . import test_unit | ||||
| @ -0,0 +1,49 @@ | |||||
|  | # -*- coding: utf-8 -*- | ||||
|  | ############################################################################# | ||||
|  | # | ||||
|  | #    Cybrosys Technologies Pvt. Ltd. | ||||
|  | # | ||||
|  | #    Copyright (C) 2025-TODAY Cybrosys Technologies(<https://www.cybrosys.com>). | ||||
|  | #    Author: Gayathri V (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 AccountMove(models.Model): | ||||
|  |     """ | ||||
|  |        This class inherits the 'account.move' model to add fields for lab | ||||
|  |        invoices. | ||||
|  |     """ | ||||
|  |     _inherit = 'account.move' | ||||
|  | 
 | ||||
|  |     is_lab_invoice = fields.Boolean(string="Is Lab Invoice", | ||||
|  |                                     help="Is it Lab Invoice or Not") | ||||
|  |     lab_request_id = fields.Many2one('lab.appointment', | ||||
|  |                                      string="Lab Appointment", | ||||
|  |                                      help="Source Document") | ||||
|  | 
 | ||||
|  |     def _invoice_paid_hook(self): | ||||
|  |         """ | ||||
|  |            This function extends the behavior of the 'action_post' | ||||
|  |            method to update the state of the associated Lab Appointment to | ||||
|  |            'invoiced' when the invoice is marked as paid. | ||||
|  |            :param self: The record itself. | ||||
|  |         """ | ||||
|  |         res = super()._invoice_paid_hook() | ||||
|  | 
 | ||||
|  |         for rec in self: | ||||
|  |             rec.lab_request_id.write({'state': 'invoiced'}) | ||||
|  |         return res | ||||
| @ -0,0 +1,212 @@ | |||||
|  | # -*- coding: utf-8 -*- | ||||
|  | ############################################################################# | ||||
|  | # | ||||
|  | #    Cybrosys Technologies Pvt. Ltd. | ||||
|  | # | ||||
|  | #    Copyright (C) 2025-TODAY Cybrosys Technologies(<https://www.cybrosys.com>). | ||||
|  | #    Author: Gayathri V (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.exceptions import UserError | ||||
|  | from odoo import api, fields, models, _ | ||||
|  | 
 | ||||
|  | 
 | ||||
|  | class LabAppointment(models.Model): | ||||
|  |     """ | ||||
|  |        Model for managing lab appointments.This class defines the structure a | ||||
|  |        nd behavior of lab appointments, including the creation of invoices and | ||||
|  |        lab test requests. | ||||
|  |     """ | ||||
|  |     _name = 'lab.appointment' | ||||
|  |     _inherit = ['mail.thread'] | ||||
|  |     _description = "Appointment" | ||||
|  |     _order = 'appointment_date' | ||||
|  | 
 | ||||
|  |     user_id = fields.Many2one('res.users', help="Responsible user", | ||||
|  |                               string='Responsible', readonly=True) | ||||
|  |     patient_id = fields.Many2one('lab.patient', | ||||
|  |                                  string='Patient', required=True, | ||||
|  |                                  help='Patient Name') | ||||
|  |     name = fields.Char(string='Appointment ID', readonly=True, | ||||
|  |                        default=lambda self: _('New'), | ||||
|  |                        help='Name of the lab appointment') | ||||
|  |     date = fields.Datetime(string='Requested Date', | ||||
|  |                            default=lambda s: fields.Datetime.now(), | ||||
|  |                            help="Date in which patient appointment is noted") | ||||
|  |     appointment_date = fields.Datetime(string='Appointment Date', | ||||
|  |                                        default=lambda s: fields.Datetime.now(), | ||||
|  |                                        help="This is the appointment date") | ||||
|  |     physician_id = fields.Many2one('res.partner', | ||||
|  |                                    string='Referred By', | ||||
|  |                                    help="Physician referred by") | ||||
|  |     comment = fields.Text(string='Comments', help="Extra information") | ||||
|  |     appointment_line_ids = fields.One2many('lab.appointment.lines', | ||||
|  |                                            'test_line_appointment_id', | ||||
|  |                                            string="Test Request", | ||||
|  |                                            help="Test requests for appointment") | ||||
|  |     request_count = fields.Integer(compute="_compute_state", | ||||
|  |                                    string='# of Requests', copy=False, | ||||
|  |                                    default=0,help="Number of Requests") | ||||
|  |     inv_count = fields.Integer(compute="_compute_state",help="Number of Invoice", | ||||
|  |                                string='# of Invoices', copy=False, default=0) | ||||
|  |     state = fields.Selection([ | ||||
|  |         ('draft', 'Draft'), | ||||
|  |         ('confirm', 'Confirmed'), | ||||
|  |         ('request_lab', 'Lab Requested'), | ||||
|  |         ('completed', 'Test Result'), | ||||
|  |         ('to_invoice', 'To Invoice'), | ||||
|  |         ('invoiced', 'Done'), | ||||
|  |         ('cancel', 'Cancelled'), | ||||
|  |     ], string='Status', readonly=True, copy=False, index=True, tracking=True, | ||||
|  |         default='draft', | ||||
|  |     ) | ||||
|  |     priority = fields.Selection([ | ||||
|  |         ('0', 'Low'), | ||||
|  |         ('1', 'Normal'), | ||||
|  |         ('2', 'High') | ||||
|  |     ], default='0') | ||||
|  | 
 | ||||
|  | 
 | ||||
|  |     @api.model_create_multi | ||||
|  |     def create(self, vals_list): | ||||
|  |         """ | ||||
|  |            Create a new lab appointment record.This method creates a new lab | ||||
|  |            appointment record and assigns a unique appointment ID to it. | ||||
|  |            :param self: The record itself. | ||||
|  |            :param dict vals_list: A dictionary of values for creating the lab | ||||
|  |            appointment record. | ||||
|  |            :return: The created lab appointment record. | ||||
|  |            :rtype: LabAppointment | ||||
|  | 
 | ||||
|  |         """ | ||||
|  |         for vals in vals_list: | ||||
|  |             vals['name'] = self.env['ir.sequence'].next_by_code( | ||||
|  |                 'lab.appointment') or _('New') | ||||
|  |         return super().create(vals_list) | ||||
|  | 
 | ||||
|  |     def _compute_state(self): | ||||
|  |         """ | ||||
|  |             Compute the number of test requests and invoices related to the | ||||
|  |             appointment.This method calculates and updates the counts of test | ||||
|  |             requests and invoices associated with the appointment. | ||||
|  |             :param self: The record itself. | ||||
|  |         """ | ||||
|  |         for obj in self: | ||||
|  |             obj.request_count = self.env['lab.request'].search_count( | ||||
|  |                 [('app_id', '=', obj.id)]) | ||||
|  |             obj.inv_count = self.env['account.move'].search_count( | ||||
|  |                 [('lab_request_id', '=', obj.id)]) | ||||
|  | 
 | ||||
|  |     def action_create_invoice(self): | ||||
|  |         """ | ||||
|  |            Create an invoice for the lab appointment.This method creates an | ||||
|  |            invoice for the lab appointment and adds invoice lines for the | ||||
|  |            selected lab tests. | ||||
|  |            :param self: The record itself. | ||||
|  |         """ | ||||
|  |         account_move = self.env["account.move"] | ||||
|  |         for lab in self: | ||||
|  |             lab.write({'state': 'to_invoice'}) | ||||
|  |             curr_invoice = { | ||||
|  |                 'partner_id': lab.patient_id.patient_id.id, | ||||
|  |                 'state': 'draft', | ||||
|  |                 'move_type': 'out_invoice', | ||||
|  |                 'invoice_date': str(datetime.datetime.now()), | ||||
|  |                 'invoice_origin': "Lab Test# : " + lab.name, | ||||
|  |                 'lab_request_id': lab.id, | ||||
|  |                 'is_lab_invoice': True, | ||||
|  |             } | ||||
|  |             inv_ids = account_move.create(curr_invoice) | ||||
|  |             inv_id = inv_ids.id | ||||
|  |             if inv_ids: | ||||
|  |                 journal = self.env['account.journal'].search( | ||||
|  |                     [('type', '=', 'sale')], limit=1) | ||||
|  |                 prd_account_id = journal.default_account_id.id | ||||
|  |                 list_value = [] | ||||
|  |                 if lab.appointment_line_ids: | ||||
|  |                     for line in lab.appointment_line_ids: | ||||
|  |                         list_value.append((0, 0, { | ||||
|  |                             'name': line.lab_test_id.lab_test, | ||||
|  |                             'price_unit': line.cost, | ||||
|  |                             'quantity': 1.0, | ||||
|  |                             'account_id': prd_account_id, | ||||
|  |                             'move_id': inv_id, | ||||
|  |                         })) | ||||
|  |                     inv_ids.write({'invoice_line_ids': list_value}) | ||||
|  |             view_id = self.env.ref('account.view_move_form').id | ||||
|  |             return { | ||||
|  |                 'view_mode': 'form', | ||||
|  |                 'res_model': 'account.move', | ||||
|  |                 'view_id': view_id, | ||||
|  |                 'type': 'ir.actions.act_window', | ||||
|  |                 'name': _('Lab Invoices'), | ||||
|  |                 'res_id': inv_id | ||||
|  |             } | ||||
|  | 
 | ||||
|  |     def action_request(self): | ||||
|  |         """ | ||||
|  |             Create lab test requests for the selected lab tests.This method | ||||
|  |             creates lab test requests for the selected lab tests associated | ||||
|  |             with the appointment | ||||
|  |             :param self: The record itself. | ||||
|  |         """ | ||||
|  |         if self.appointment_line_ids: | ||||
|  |             for line in self.appointment_line_ids: | ||||
|  |                 lab_test = self.env['lab.test'].search( | ||||
|  |                     [('lab_test', '=', line.lab_test_id.lab_test)]) | ||||
|  |                 self.env['lab.request'].create( | ||||
|  |                     {'lab_request_id': self.name, | ||||
|  |                      'app_id': self.id, | ||||
|  |                      'lab_requestor_id': self.patient_id.id, | ||||
|  |                      'lab_requesting_date': self.appointment_date, | ||||
|  |                      'test_request_id': line.lab_test_id.id, | ||||
|  |                      'request_line_ids': [(6, 0, | ||||
|  |                                        [x.id for x in lab_test.test_lines_ids])], | ||||
|  |                      }) | ||||
|  |             self.state = 'request_lab' | ||||
|  |         else: | ||||
|  |             raise UserError(_('Please Select Lab Test.')) | ||||
|  | 
 | ||||
|  |     def action_confirm_appointment(self): | ||||
|  |         """ | ||||
|  |            Confirm the lab appointment and send a confirmation email to the | ||||
|  |            patient. | ||||
|  |            :param self: The record itself. | ||||
|  |         """ | ||||
|  |         message_body = ("Dear " + | ||||
|  |                         self.patient_id.name + "," + | ||||
|  |                         "<br>Your Appointment Has been Confirmed " + | ||||
|  |                         "<br>Appointment ID : " + self.name + | ||||
|  |                         "<br>Date : " + str(self.appointment_date) + | ||||
|  |                         '<br><br>Thank you') | ||||
|  |         template_obj = self.env['mail.mail'] | ||||
|  |         template_data = { | ||||
|  |             'subject': 'Appointment Confirmation', | ||||
|  |             'body_html': message_body, | ||||
|  |             'email_from': 'michaelmorbius915@gmail.com', | ||||
|  |             'email_to': self.patient_id.email | ||||
|  |         } | ||||
|  |         template_id = template_obj.create(template_data) | ||||
|  |         template_obj.send(template_id) | ||||
|  |         self.write({'state': 'confirm'}) | ||||
|  | 
 | ||||
|  |     def action_cancel_appointment(self): | ||||
|  |         """ | ||||
|  |            Cancel the lab appointment.This method cancels the lab appointment | ||||
|  |            by setting its state to 'cancel'. | ||||
|  |            :param self: The record itself. | ||||
|  |         """ | ||||
|  |         return self.write({'state': 'cancel'}) | ||||
| @ -0,0 +1,47 @@ | |||||
|  | # -*- coding: utf-8 -*- | ||||
|  | ############################################################################# | ||||
|  | # | ||||
|  | #    Cybrosys Technologies Pvt. Ltd. | ||||
|  | # | ||||
|  | #    Copyright (C) 2025-TODAY Cybrosys Technologies(<https://www.cybrosys.com>). | ||||
|  | #    Author: Gayathri V (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 LabAppointmentLines(models.Model): | ||||
|  |     """ | ||||
|  |         This class represents Lab Appointment Lines, which are individual | ||||
|  |         tests associated with a Lab Appointment. | ||||
|  |     """ | ||||
|  |     _name = 'lab.appointment.lines' | ||||
|  |     _description = 'Lab Appointment ' | ||||
|  | 
 | ||||
|  |     lab_test_id = fields.Many2one('lab.test', string="Test") | ||||
|  |     cost = fields.Float(string="Cost", help="Cost of the lab test") | ||||
|  |     requesting_date = fields.Date(string="Date", | ||||
|  |                                   help="Requesting date of lab test") | ||||
|  |     test_line_appointment_id = fields.Many2one('lab.appointment', | ||||
|  |                                                string="Appointment") | ||||
|  | 
 | ||||
|  |     @api.onchange('lab_test_id') | ||||
|  |     def cost_update(self): | ||||
|  |         """ | ||||
|  |            Update the 'cost' field when a Lab Test is selected. | ||||
|  |            :param self: The record itself. | ||||
|  |         """ | ||||
|  |         if self.lab_test_id: | ||||
|  |             self.cost = self.lab_test_id.test_cost | ||||
| @ -0,0 +1,107 @@ | |||||
|  | # -*- coding: utf-8 -*- | ||||
|  | ############################################################################# | ||||
|  | # | ||||
|  | #    Cybrosys Technologies Pvt. Ltd. | ||||
|  | # | ||||
|  | #    Copyright (C) 2025-TODAY Cybrosys Technologies(<https://www.cybrosys.com>). | ||||
|  | #    Author: Gayathri V (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 dateutil.relativedelta import relativedelta | ||||
|  | from odoo import api, fields, models, _ | ||||
|  | 
 | ||||
|  | 
 | ||||
|  | class LabPatient(models.Model): | ||||
|  |     """ | ||||
|  |         This class represents Patient information in a laboratory system. | ||||
|  |     """ | ||||
|  |     _name = 'lab.patient' | ||||
|  |     _rec_name = 'patient_id' | ||||
|  |     _description = 'Patient' | ||||
|  | 
 | ||||
|  |     patient_id = fields.Many2one('res.partner', string='Partner', | ||||
|  |                               required=True) | ||||
|  |     patient_image = fields.Binary(string='Photo', | ||||
|  |                                   help="Profile image for patient") | ||||
|  |     patient = fields.Char(string='Patient', readonly=True) | ||||
|  |     name = fields.Char(string='Patient ID', default=lambda self: _('New'), readonly=True) | ||||
|  |     title = fields.Selection([ | ||||
|  |         ('ms', 'Miss'), | ||||
|  |         ('mister', 'Mister'), | ||||
|  |         ('mrs', 'Mrs'), | ||||
|  |     ], string='Title', default='mister', required=True) | ||||
|  |     emergency_contact_id = fields.Many2one( | ||||
|  |         'res.partner', string='Emergency Contact', | ||||
|  |         help="Emergency contact number for patient") | ||||
|  |     gender = fields.Selection( | ||||
|  |         [('m', 'Male'), ('f', 'Female'), | ||||
|  |          ('ot', 'Other')], string='Gender',help="Gender of the patient", required=True) | ||||
|  |     dob = fields.Date(string='Date Of Birth', help="Date of birth of patient", | ||||
|  |                       required=True) | ||||
|  |     age = fields.Char(string='Age', help="Age of the patient", | ||||
|  |                       compute='compute_age', store=True) | ||||
|  |     blood_group = fields.Selection( | ||||
|  |         [('A+', 'A+ve'), ('B+', 'B+ve'), ('O+', 'O+ve'), | ||||
|  |          ('AB+', 'AB+ve'), ('A-', 'A-ve'), ('B-', 'B-ve'), ('O-', 'O-ve'), | ||||
|  |          ('AB-', 'AB-ve')], 'Blood Group') | ||||
|  |     visa_info = fields.Char(string='Visa Info', size=64, | ||||
|  |                             help="Fill visa information") | ||||
|  |     id_proof_number = fields.Char(string='ID Proof Number', | ||||
|  |                                   help="Fill id proof information") | ||||
|  |     note = fields.Text(string='Note') | ||||
|  |     date = fields.Datetime(string='Date Requested', | ||||
|  |                            default=lambda s: fields.Datetime.now(), | ||||
|  |                            help="Requested date of lab request") | ||||
|  |     phone = fields.Char(string="Phone", required=True, | ||||
|  |                         help="Phone number of patient") | ||||
|  |     email = fields.Char(string="Email", required=True, help="Email of patient") | ||||
|  | 
 | ||||
|  |     @api.depends('dob') | ||||
|  |     def compute_age(self): | ||||
|  |         """ | ||||
|  |            Compute the patient's age based on their date of birth. | ||||
|  |            :param self: The record itself. | ||||
|  |         """ | ||||
|  |         for data in self: | ||||
|  |             if data.dob: | ||||
|  |                 dob = fields.Datetime.from_string(data.dob) | ||||
|  |                 date = fields.Datetime.from_string(data.date) | ||||
|  |                 delta = relativedelta(date, dob) | ||||
|  |                 data.age = str(delta.years) + ' ' + 'years' | ||||
|  |             else: | ||||
|  |                 data.age = '' | ||||
|  | 
 | ||||
|  |     @api.model_create_multi | ||||
|  |     def create(self, vals_list): | ||||
|  |         """ | ||||
|  |             Create a new patient record and generate a unique patient ID | ||||
|  |             :param self: The record itself. | ||||
|  |             :param dict vals_list: A dictionary of values for creating the patient record. | ||||
|  |             :return: The created patient record. | ||||
|  |             :rtype: LabPatient | ||||
|  |         """ | ||||
|  |         for vals in vals_list: | ||||
|  |             sequence = self.env['ir.sequence'].next_by_code('lab.patient') | ||||
|  |             vals['name'] = sequence or _('New') | ||||
|  |         return super().create(vals_list) | ||||
|  | 
 | ||||
|  |     @api.onchange('patient') | ||||
|  |     def detail_get(self): | ||||
|  |         """ | ||||
|  |            Update patient contact details based on the selected partner | ||||
|  |            :param self: The record itself. | ||||
|  |         """ | ||||
|  |         self.phone = self.patient.phone | ||||
|  |         self.email = self.patient.email | ||||
| @ -0,0 +1,119 @@ | |||||
|  | # -*- coding: utf-8 -*- | ||||
|  | ############################################################################# | ||||
|  | # | ||||
|  | #    Cybrosys Technologies Pvt. Ltd. | ||||
|  | # | ||||
|  | #    Copyright (C) 2025-TODAY Cybrosys Technologies(<https://www.cybrosys.com>). | ||||
|  | #    Author: Gayathri V (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 LabRequest(models.Model): | ||||
|  |     """ | ||||
|  |         Model for managing Lab Requests | ||||
|  |     """ | ||||
|  |     _name = 'lab.request' | ||||
|  |     _inherit = ['mail.thread'] | ||||
|  |     _rec_name = 'lab_request_id' | ||||
|  |     _description = 'Lab Request' | ||||
|  | 
 | ||||
|  |     name = fields.Char(string='Lab Test', size=16, readonly=True, | ||||
|  |                        required=True, help="Lab result ID", | ||||
|  |                        default=lambda *a: '#') | ||||
|  |     lab_request_id = fields.Char(string='Appointment ID', | ||||
|  |                                  help="Lab appointment ID") | ||||
|  |     app_id = fields.Many2one('lab.appointment', | ||||
|  |                              string='Appointment') | ||||
|  |     lab_requestor_id = fields.Many2one('lab.patient', | ||||
|  |                                     string='Patient', required=True, | ||||
|  |                                     help='Patient Name') | ||||
|  |     test_request_id = fields.Many2one('lab.test', string='Test') | ||||
|  |     lab_requesting_date = fields.Datetime(string='Requested Date') | ||||
|  |     comment = fields.Text('Comment') | ||||
|  |     request_line_ids = fields.One2many('lab.test.attribute', | ||||
|  |                                    'test_request_reverse_id', | ||||
|  |                                    string="Test Lines") | ||||
|  |     state = fields.Selection([ | ||||
|  |         ('draft', 'Draft'), | ||||
|  |         ('sample_collection', 'Sample Collected'), | ||||
|  |         ('test_in_progress', 'Test In Progress'), | ||||
|  |         ('completed', 'Completed'), | ||||
|  |         ('cancel', 'Cancelled'), | ||||
|  | 
 | ||||
|  |     ], string='Status', readonly=True, copy=False, index=True, tracking=True, | ||||
|  |         default='draft') | ||||
|  | 
 | ||||
|  |     @api.model_create_multi | ||||
|  |     def create(self, vals_list): | ||||
|  |         """ | ||||
|  |             Create a new lab request | ||||
|  |             :param self: The record itself. | ||||
|  |             :param dict vals_list: A dictionary of values for creating the lab request. | ||||
|  |             :return: The created lab request record. | ||||
|  |             :rtype: LabRequest | ||||
|  |         """ | ||||
|  |         for vals in vals_list: | ||||
|  |             sequence = self.env['ir.sequence'].next_by_code('lab.request') | ||||
|  |             vals['name'] = sequence or '/' | ||||
|  |         return super().create(vals_list) | ||||
|  | 
 | ||||
|  |     def action_set_to_sample_collection(self): | ||||
|  |         """ | ||||
|  |            Set the lab request's state to 'Sample Collected | ||||
|  |            :param self: The record itself. | ||||
|  |         """ | ||||
|  |         return self.write({'state': 'sample_collection'}) | ||||
|  | 
 | ||||
|  |     def action_set_to_test_in_progress(self): | ||||
|  |         """ | ||||
|  |            Set the lab request's state to 'Test In Progress' | ||||
|  |            :param self: The record itself. | ||||
|  |         """ | ||||
|  |         return self.write({'state': 'test_in_progress'}) | ||||
|  | 
 | ||||
|  |     def action_cancel_lab_test(self): | ||||
|  |         """ | ||||
|  |             Cancel the lab test. | ||||
|  |             :param self: The record itself. | ||||
|  |         """ | ||||
|  |         return self.write({'state': 'cancel'}) | ||||
|  | 
 | ||||
|  |     def action_set_to_test_completed(self): | ||||
|  |         """ | ||||
|  |            Set the lab request's state to 'Completed' | ||||
|  |            :param self: The record itself. | ||||
|  |         """ | ||||
|  |         if not self.request_line_ids: | ||||
|  |             raise ValidationError(_("No Result Lines Entered !")) | ||||
|  |         req_obj = self.env['lab.request'].search_count( | ||||
|  |             [('app_id', '=', self.app_id.id), ('id', '!=', self.id)]) | ||||
|  |         req_obj_count = (self.env['lab.request'].search_count | ||||
|  |                          ([('app_id', '=', self.app_id.id), | ||||
|  |                            ('id', '!=', self.id), ('state', '=', 'completed')] | ||||
|  |                           )) | ||||
|  |         if req_obj == req_obj_count: | ||||
|  |             app_obj = self.env['lab.appointment'].browse(self.app_id.id) | ||||
|  |             app_obj.write({'state': 'completed'}) | ||||
|  |         return self.write({'state': 'completed'}) | ||||
|  | 
 | ||||
|  |     def action_print_lab_test(self): | ||||
|  |         """ | ||||
|  |             Print the lab test report | ||||
|  |             :param self: The record itself. | ||||
|  |         """ | ||||
|  |         return self.env.ref('medical_lab_management.action_lab_request_report').report_action(self) | ||||
| @ -0,0 +1,40 @@ | |||||
|  | # -*- coding: utf-8 -*- | ||||
|  | ############################################################################# | ||||
|  | # | ||||
|  | #    Cybrosys Technologies Pvt. Ltd. | ||||
|  | # | ||||
|  | #    Copyright (C) 2025-TODAY Cybrosys Technologies(<https://www.cybrosys.com>). | ||||
|  | #    Author: Gayathri V (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): | ||||
|  |     """ | ||||
|  |        Model for managing lab test details. | ||||
|  |     """ | ||||
|  |     _name = 'lab.test' | ||||
|  |     _description = "Lab Test" | ||||
|  |     _rec_name = 'lab_test' | ||||
|  |     _inherit = ['mail.thread'] | ||||
|  | 
 | ||||
|  |     lab_test = fields.Char(string="Test Name", required=True, | ||||
|  |                            help="Name of lab test ") | ||||
|  |     lab_test_code = fields.Char(string="Test Code", required=True) | ||||
|  |     test_lines_ids = fields.One2many('lab.test.attribute', | ||||
|  |                                  'test_line_reverse_id', | ||||
|  |                                  string="Attribute") | ||||
|  |     test_cost = fields.Float(string="Cost", required=True) | ||||
| @ -0,0 +1,43 @@ | |||||
|  | # -*- coding: utf-8 -*- | ||||
|  | ############################################################################# | ||||
|  | # | ||||
|  | #    Cybrosys Technologies Pvt. Ltd. | ||||
|  | # | ||||
|  | #    Copyright (C) 2025-TODAY Cybrosys Technologies(<https://www.cybrosys.com>). | ||||
|  | #    Author: Gayathri V (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 LabTestAttribute(models.Model): | ||||
|  |     """ | ||||
|  |        Model for managing lab test result | ||||
|  |     """ | ||||
|  |     _name = 'lab.test.attribute' | ||||
|  |     _description = "Lab Test Attributes" | ||||
|  | 
 | ||||
|  |     test_content_id = fields.Many2one('lab.test.content.type', | ||||
|  |                                    string="Content", help="Content type", required=True) | ||||
|  |     result = fields.Char(string="Result", help="Result for lab test") | ||||
|  |     unit_id = fields.Many2one('test.unit', string="Unit", | ||||
|  |                            help="Unit for lab test") | ||||
|  |     interval = fields.Char(string="Reference Intervals", | ||||
|  |                            help="Reference intervals for lab test") | ||||
|  |     test_line_reverse_id = fields.Many2one('lab.test', | ||||
|  |                                         string="Attribute", | ||||
|  |                                         help="Name of the test") | ||||
|  |     test_request_reverse_id = fields.Many2one('lab.request', | ||||
|  |                                            string="Request") | ||||
| @ -0,0 +1,38 @@ | |||||
|  | # -*- coding: utf-8 -*- | ||||
|  | ############################################################################# | ||||
|  | # | ||||
|  | #    Cybrosys Technologies Pvt. Ltd. | ||||
|  | # | ||||
|  | #    Copyright (C) 2025-TODAY Cybrosys Technologies(<https://www.cybrosys.com>). | ||||
|  | #    Author: Gayathri V (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 LabTestContentType(models.Model): | ||||
|  |     """ | ||||
|  |        Model for managing test content types | ||||
|  |     """ | ||||
|  |     _name = 'lab.test.content.type' | ||||
|  |     _rec_name = 'content_type_name' | ||||
|  |     _description = "Content" | ||||
|  | 
 | ||||
|  |     content_type_name = fields.Char(string="Name", required=True, | ||||
|  |                                     help="Content type name") | ||||
|  |     content_type_code = fields.Char(string="Code", help="Content type code") | ||||
|  |     parent_test_id = fields.Many2one('lab.test', | ||||
|  |                                   string="Test Category", | ||||
|  |                                   help="Category of test") | ||||
| @ -0,0 +1,37 @@ | |||||
|  | # -*- coding: utf-8 -*- | ||||
|  | ############################################################################# | ||||
|  | # | ||||
|  | #    Cybrosys Technologies Pvt. Ltd. | ||||
|  | # | ||||
|  | #    Copyright (C) 2025-TODAY Cybrosys Technologies(<https://www.cybrosys.com>). | ||||
|  | #    Author: Gayathri V (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 PhysicianSpeciality(models.Model): | ||||
|  |     """ | ||||
|  |        Model for managing physician details | ||||
|  |     """ | ||||
|  |     _name = 'physician.speciality' | ||||
|  |     _description = 'Medical Specialty' | ||||
|  | 
 | ||||
|  |     code = fields.Char(string='ID') | ||||
|  |     name = fields.Char(string='Specialty', help='Name of the specialty', | ||||
|  |                        required=True) | ||||
|  |     _sql_constraints = [ | ||||
|  |         ('name_uniq', 'UNIQUE(name)', 'Name must be unique!'), | ||||
|  |     ] | ||||
| @ -0,0 +1,41 @@ | |||||
|  | # -*- coding: utf-8 -*- | ||||
|  | ############################################################################# | ||||
|  | # | ||||
|  | #    Cybrosys Technologies Pvt. Ltd. | ||||
|  | # | ||||
|  | #    Copyright (C) 2025-TODAY Cybrosys Technologies(<https://www.cybrosys.com>). | ||||
|  | #    Author: Gayathri V (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 ResPartner(models.Model): | ||||
|  |     """ | ||||
|  |        This class inherits the 'res.partner' model to represent patients and | ||||
|  |        physicians in the system. | ||||
|  |     """ | ||||
|  |     _inherit = 'res.partner' | ||||
|  |     _description = "Patient" | ||||
|  | 
 | ||||
|  |     is_patient = fields.Boolean(string='Is Patient', | ||||
|  |                                 help="Patient Identification") | ||||
|  |     is_physician = fields.Boolean(string='Is Physician', | ||||
|  |                                   help="Physician Identification") | ||||
|  |     speciality_id = fields.Many2one('physician.speciality', | ||||
|  |                                  string='Speciality', | ||||
|  |                                  help="Speciality of  the physician") | ||||
|  |     hospital_id = fields.Many2one('res.partner', string='Hospital', | ||||
|  |                                help="Name of the hospital") | ||||
| @ -0,0 +1,34 @@ | |||||
|  | # -*- coding: utf-8 -*- | ||||
|  | ############################################################################# | ||||
|  | # | ||||
|  | #    Cybrosys Technologies Pvt. Ltd. | ||||
|  | # | ||||
|  | #    Copyright (C) 2025-TODAY Cybrosys Technologies(<https://www.cybrosys.com>). | ||||
|  | #    Author: Gayathri V (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 TestUnit(models.Model): | ||||
|  |     """ | ||||
|  |         Model for managing test units | ||||
|  |     """ | ||||
|  |     _name = 'test.unit' | ||||
|  |     _rec_name = 'code' | ||||
|  |     _description = "Test Unit" | ||||
|  | 
 | ||||
|  |     unit = fields.Char(string="Unit", required=True, help="Unit name") | ||||
|  |     code = fields.Char(string="Code", required=True, help="Unit code") | ||||
| @ -0,0 +1,15 @@ | |||||
|  | <?xml version="1.0" encoding="utf-8"?> | ||||
|  | <odoo> | ||||
|  | <!--    Report action for patient card--> | ||||
|  |     <data> | ||||
|  |         <record id="action_lab_patient_report" model="ir.actions.report"> | ||||
|  |             <field name="name">Patient Card</field> | ||||
|  |             <field name="model">lab.patient</field> | ||||
|  |             <field name="report_type">qweb-pdf</field> | ||||
|  |             <field name="report_name">medical_lab_management.lab_patient_report</field> | ||||
|  |             <field name="report_file">medical_lab_management.lab_patient_report</field> | ||||
|  |             <field name="binding_model_id" ref="model_lab_patient"/> | ||||
|  |             <field name="binding_type">report</field> | ||||
|  |         </record> | ||||
|  |     </data> | ||||
|  | </odoo> | ||||
| @ -0,0 +1,72 @@ | |||||
|  | <?xml version="1.0" encoding="utf-8"?> | ||||
|  | <odoo> | ||||
|  | <!--    Report template of patient card--> | ||||
|  |     <data> | ||||
|  |         <template id="lab_patient_report"> | ||||
|  |             <t t-call="web.html_container"> | ||||
|  |                     <t t-foreach="docs" t-as="o" t-key="o_index"> | ||||
|  |                         <div class="page"> | ||||
|  |                             <div class="oe_structure"/> | ||||
|  |                             <div class="row"> | ||||
|  |                             <center> | ||||
|  |                             <br/> | ||||
|  |                                 <div class="col-xs-8" style="margin:auto"> | ||||
|  |                                     <table class="table table-condensed" style="border: 3px solid black !important; width: 40%; position: relative;"> | ||||
|  |                                         <tr> | ||||
|  |                                             <td width="40%"> | ||||
|  |                                                 <p style="text-align:center;padding-top:10px;"> | ||||
|  |                                                     <img t-if="not o.patient_image" t-att-src="'/web/static/src/img/placeholder.png'" height="120" border="1" width="120"/> | ||||
|  |                                                     <img t-if="o.patient_image" t-att-src="'data:image/png;base64,%s' %o.patient_image.decode('utf-8')" height="120" border="1" width="120"/> | ||||
|  |                                                 </p> | ||||
|  |                                                 <p style="text-align:center;"> | ||||
|  |                                                     <strong><span t-field="o.patient_id"/></strong> | ||||
|  |                                                 </p> | ||||
|  |                                             </td> | ||||
|  |                                             <td width="40%"> | ||||
|  |                                                 <table border="0" style="text-align:center; position: absolute; top: 20px; left: 180px;"> | ||||
|  |                                                     <tr> | ||||
|  |                                                         <td> | ||||
|  |                                                             <p style="text-align:left;"><strong>Patient ID:</strong></p> | ||||
|  |                                                         </td> | ||||
|  |                                                         <td> | ||||
|  |                                                             <p style="text-align:left;"  t-field="o.name"/> | ||||
|  |                                                         </td> | ||||
|  |                                                     </tr> | ||||
|  |                                                     <tr> | ||||
|  |                                                         <td> | ||||
|  |                                                              <p style="text-align:left;"><strong>Sex:</strong></p> | ||||
|  |                                                         </td> | ||||
|  |                                                         <td> | ||||
|  |                                                             <t t-if="o.gender=='m'"> | ||||
|  |                                                                 <p style="text-align:left;">Male</p> | ||||
|  |                                                             </t> | ||||
|  |                                                             <t t-if="o.gender=='ot'"> | ||||
|  |                                                                 <p style="text-align:left;">Other</p> | ||||
|  |                                                             </t> | ||||
|  |                                                              <t t-if="o.gender=='f'"> | ||||
|  |                                                                 <p style="text-align:left;">Female</p> | ||||
|  |                                                             </t> | ||||
|  |                                                         </td> | ||||
|  |                                                     </tr> | ||||
|  |                                                     <tr> | ||||
|  |                                                         <td> | ||||
|  |                                                             <p style="text-align:left;"><strong>Age:</strong></p> | ||||
|  |                                                         </td> | ||||
|  |                                                         <td> | ||||
|  |                                                             <p style="text-align:left;" t-field="o.age"/> | ||||
|  |                                                         </td> | ||||
|  |                                                     </tr> | ||||
|  |                                                 </table> | ||||
|  |                                             </td> | ||||
|  |                                         </tr> | ||||
|  |                                     </table> | ||||
|  |                                 </div> | ||||
|  |                             </center> | ||||
|  |                             </div> | ||||
|  |                         </div> | ||||
|  |                         <p t-if="o_index + 1 != len(docs)" style="page-break-after:always"/> | ||||
|  |                     </t> | ||||
|  |             </t> | ||||
|  |         </template> | ||||
|  |     </data> | ||||
|  | </odoo> | ||||
| @ -0,0 +1,13 @@ | |||||
|  | <?xml version="1.0" encoding="utf-8"?> | ||||
|  | <odoo> | ||||
|  | <!--    Report action of lab test result--> | ||||
|  |     <data> | ||||
|  |         <record id="action_lab_request_report" model="ir.actions.report"> | ||||
|  |             <field name="name">Lab Test Result</field> | ||||
|  |             <field name="model">lab.request</field> | ||||
|  |             <field name="report_type">qweb-pdf</field> | ||||
|  |             <field name="report_name">medical_lab_management.lab_request_report</field> | ||||
|  |             <field name="report_file">medical_lab_management.lab_request_report</field> | ||||
|  |         </record> | ||||
|  |     </data> | ||||
|  | </odoo> | ||||
| @ -0,0 +1,50 @@ | |||||
|  | <?xml version="1.0" encoding="utf-8"?> | ||||
|  | <odoo> | ||||
|  | <!--    Report template of lab test templates--> | ||||
|  |     <data> | ||||
|  |         <template id="lab_request_report"> | ||||
|  |               <t t-call="web.html_container"> | ||||
|  |                 <t t-call="web.external_layout"> | ||||
|  |                 <t t-foreach="docs" t-as="o"> | ||||
|  |                     <div class="page"> | ||||
|  |                         <br /> | ||||
|  |                         <h3 style="text-decoration:underline;text-align:center;"><b>Lab Test Report</b></h3> | ||||
|  |                         <br/> | ||||
|  |                         <br/> | ||||
|  |                         <table width="99%" class="table-borderless" style="margin-left:50px;margin-top:5px;border: None solid black;"> | ||||
|  |                             <tr> | ||||
|  |                                 <td style="width:50px;height:25px" ><span>Patient: </span><span t-att-style="style" t-esc="o.lab_requestor_id.name"/></td> | ||||
|  |                                 <td style="width:50px;height:25px" ><span>Test  : </span><span t-att-style="style" t-esc="o.test_request_id.lab_test"/></td> | ||||
|  |                                 <td style="width:50px;height:25px" ><span>Date: </span><span t-att-style="style" t-esc="o.lab_requesting_date"/></td> | ||||
|  |                             </tr> | ||||
|  |                         </table> | ||||
|  |                         <br/> | ||||
|  |                         <br/> | ||||
|  |                          <table width="99%" style="border:1px solid black;padding-left:1.16cm;"> | ||||
|  |                              <thead> | ||||
|  |                                 <th style="border:1px solid black;text-align:center;" width="13%" class="td4"><strong>Content</strong></th> | ||||
|  |                                 <th style="border:1px solid black;text-align:center;" width="13%" class="td4"><strong>Unit</strong></th> | ||||
|  |                                 <th style="border:1px solid black;text-align:center;" width="13%" class="td4"><strong>Normal Range</strong></th> | ||||
|  |                                 <th style="border:1px solid black;text-align:center;" width="13%" class="td4"><strong>Result</strong></th> | ||||
|  |                             </thead> | ||||
|  |                             <tbody> | ||||
|  |                                 <t t-foreach="o.request_line_ids" t-as="l"> | ||||
|  |                                     <tr style="border:1px solid black"> | ||||
|  |                                         <td style="border:1px solid black;text-align:center;"><span t-esc="l.test_content_id.content_type_name" style="font-size:16px;"/></td> | ||||
|  |                                         <td style="border:1px solid black;text-align:center;"><span t-esc="l.unit_id.code" style="font-size:16px;"/></td> | ||||
|  |                                         <td style="border:1px solid black;text-align:center;"><span t-esc="l.interval" style="font-size:16px;"/></td> | ||||
|  |                                         <td style="border:1px solid black;text-align:center;"><span t-esc="l.result" style="font-size:16px;"/></td> | ||||
|  |                                     </tr> | ||||
|  |                                 </t> | ||||
|  |                             </tbody> | ||||
|  |                          </table> | ||||
|  |                          <br/> | ||||
|  |                          <br/> | ||||
|  |                     </div> | ||||
|  |                     <p style="page-break-after:always"/> | ||||
|  |                 </t> | ||||
|  |            </t> | ||||
|  |               </t> | ||||
|  |         </template> | ||||
|  |     </data> | ||||
|  | </odoo> | ||||
| 
 | 
| @ -0,0 +1,17 @@ | |||||
|  | <?xml version="1.0" encoding="utf-8"?> | ||||
|  | <odoo> | ||||
|  |      <record model="ir.module.category" id="module_category_lab_management"> | ||||
|  |         <field name="name">Lab Management</field> | ||||
|  |      </record> | ||||
|  |      <record id="group_lab_management_user" model="res.groups"> | ||||
|  |          <field name="name">Lab User</field> | ||||
|  |          <field name="category_id" ref="module_category_lab_management"/> | ||||
|  |          <field name="implied_ids" eval="[(4, ref('base.group_user'))]"/> | ||||
|  |      </record> | ||||
|  |     <record id="group_lab_management_technician" model="res.groups"> | ||||
|  |          <field name="name">Lab Manager</field> | ||||
|  |          <field name="category_id" ref="module_category_lab_management"/> | ||||
|  |          <field name="implied_ids" eval="[(4, ref('group_lab_management_user'))]"/> | ||||
|  |          <field name="users" eval="[(4, ref('base.user_root')), (4, ref('base.user_admin'))]"/> | ||||
|  |      </record> | ||||
|  | </odoo> | ||||
| After Width: | Height: | Size: 2.2 KiB | 
| After Width: | Height: | Size: 28 KiB | 
| After Width: | Height: | Size: 628 KiB | 
| After Width: | Height: | Size: 1.1 KiB | 
| After Width: | Height: | Size: 210 KiB | 
| After Width: | Height: | Size: 209 KiB | 
| After Width: | Height: | Size: 109 KiB | 
| After Width: | Height: | Size: 495 B | 
| After Width: | Height: | Size: 1.0 KiB | 
| After Width: | Height: | Size: 624 B | 
| After Width: | Height: | Size: 136 KiB | 
| After Width: | Height: | Size: 214 KiB | 
| After Width: | Height: | Size: 36 KiB | 
| After Width: | Height: | Size: 36 KiB | 
| After Width: | Height: | Size: 3.6 KiB | 
| After Width: | Height: | Size: 310 B | 
| After Width: | Height: | Size: 929 B | 
| After Width: | Height: | Size: 1.3 KiB | 
| After Width: | Height: | Size: 3.3 KiB | 
| After Width: | Height: | Size: 1.4 KiB | 
| After Width: | Height: | Size: 17 KiB | 
| After Width: | Height: | Size: 542 B | 
| After Width: | Height: | Size: 576 B | 
| After Width: | Height: | Size: 733 B | 
| After Width: | Height: | Size: 4.3 KiB | 
| After Width: | Height: | Size: 1.2 KiB | 
| After Width: | Height: | Size: 4.0 KiB | 
| After Width: | Height: | Size: 1.7 KiB | 
| After Width: | Height: | Size: 266 KiB | 
| After Width: | Height: | Size: 2.2 KiB | 
| 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: 1.2 KiB | 
| After Width: | Height: | Size: 600 B | 
| After Width: | Height: | Size: 673 B | 
| After Width: | Height: | Size: 2.0 KiB | 
| After Width: | Height: | Size: 462 B | 
| After Width: | Height: | Size: 2.1 KiB | 
| After Width: | Height: | Size: 926 B | 
| After Width: | Height: | Size: 9.0 KiB | 
| After Width: | Height: | Size: 23 KiB | 
| After Width: | Height: | Size: 7.0 KiB | 
| After Width: | Height: | Size: 11 KiB | 
| After Width: | Height: | Size: 878 B | 
| After Width: | Height: | Size: 1.2 KiB | 
| After Width: | Height: | Size: 653 B | 
| After Width: | Height: | Size: 800 B | 
| After Width: | Height: | Size: 905 B | 
| After Width: | Height: | Size: 189 KiB | 
| After Width: | Height: | Size: 4.3 KiB | 
| After Width: | Height: | Size: 839 B | 
| After Width: | Height: | Size: 1.7 KiB | 
| After Width: | Height: | Size: 5.9 KiB | 
| After Width: | Height: | Size: 1.6 KiB | 
| After Width: | Height: | Size: 34 KiB | 
| After Width: | Height: | Size: 26 KiB | 
| After Width: | Height: | Size: 3.8 KiB | 
| After Width: | Height: | Size: 23 KiB | 
| After Width: | Height: | Size: 1.9 KiB | 
| After Width: | Height: | Size: 2.3 KiB | 
| After Width: | Height: | Size: 427 B | 
| After Width: | Height: | Size: 627 B | 
| After Width: | Height: | Size: 1.1 KiB | 
| After Width: | Height: | Size: 1.2 KiB | 
| After Width: | Height: | Size: 988 B | 
| After Width: | Height: | Size: 3.7 KiB | 
| After Width: | Height: | Size: 5.0 KiB | 
| After Width: | Height: | Size: 875 B | 
| After Width: | Height: | Size: 1.2 KiB | 
| After Width: | Height: | Size: 80 KiB | 
| After Width: | Height: | Size: 3.2 KiB | 
| After Width: | Height: | Size: 565 B | 
| After Width: | Height: | Size: 26 KiB |