From 1ad60feb5007fc0aaf19f44383ada04aa804f138 Mon Sep 17 00:00:00 2001 From: Enric Tobella Date: Fri, 25 Mar 2022 11:12:22 +0100 Subject: [PATCH] [ADD] lims Co-authored-by: Kevin Luna --- lims/README.rst | 89 ++++++ lims/__init__.py | 1 + lims/__manifest__.py | 25 ++ lims/data/ir_sequence_data.xml | 19 ++ lims/demo/demo.xml | 12 + lims/models/__init__.py | 6 + lims/models/lims_analysis.py | 180 +++++++++++ lims/models/lims_department.py | 14 + lims/models/lims_sample.py | 148 +++++++++ lims/models/lims_sample_type.py | 14 + lims/models/product_template.py | 13 + lims/models/res_users.py | 11 + lims/readme/CONTRIBUTORS.rst | 2 + lims/readme/DESCRIPTION.rst | 3 + lims/readme/ROADMAP.rst | 9 + lims/readme/USAGE.rst | 8 + lims/security/ir.model.access.csv | 11 + lims/security/security.xml | 50 +++ lims/static/description/icon.png | Bin 0 -> 27295 bytes lims/static/description/index.html | 459 ++++++++++++++++++++++++++++ lims/views/lims_analysis.xml | 88 ++++++ lims/views/lims_department.xml | 69 +++++ lims/views/lims_sample.xml | 103 +++++++ lims/views/lims_sample_template.xml | 46 +++ lims/views/lims_sample_type.xml | 74 +++++ lims/views/menu.xml | 20 ++ lims/views/product_template.xml | 68 +++++ setup/lims/odoo/addons/lims | 1 + setup/lims/setup.py | 6 + 29 files changed, 1549 insertions(+) create mode 100644 lims/README.rst create mode 100644 lims/__init__.py create mode 100644 lims/__manifest__.py create mode 100644 lims/data/ir_sequence_data.xml create mode 100644 lims/demo/demo.xml create mode 100644 lims/models/__init__.py create mode 100644 lims/models/lims_analysis.py create mode 100644 lims/models/lims_department.py create mode 100644 lims/models/lims_sample.py create mode 100644 lims/models/lims_sample_type.py create mode 100644 lims/models/product_template.py create mode 100644 lims/models/res_users.py create mode 100644 lims/readme/CONTRIBUTORS.rst create mode 100644 lims/readme/DESCRIPTION.rst create mode 100644 lims/readme/ROADMAP.rst create mode 100644 lims/readme/USAGE.rst create mode 100644 lims/security/ir.model.access.csv create mode 100644 lims/security/security.xml create mode 100644 lims/static/description/icon.png create mode 100644 lims/static/description/index.html create mode 100644 lims/views/lims_analysis.xml create mode 100644 lims/views/lims_department.xml create mode 100644 lims/views/lims_sample.xml create mode 100644 lims/views/lims_sample_template.xml create mode 100644 lims/views/lims_sample_type.xml create mode 100644 lims/views/menu.xml create mode 100644 lims/views/product_template.xml create mode 120000 setup/lims/odoo/addons/lims create mode 100644 setup/lims/setup.py diff --git a/lims/README.rst b/lims/README.rst new file mode 100644 index 0000000..9181909 --- /dev/null +++ b/lims/README.rst @@ -0,0 +1,89 @@ +==== +Lims +==== + +.. + !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + !! This file is generated by oca-gen-addon-readme !! + !! changes will be overwritten. !! + !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + !! source digest: sha256:05b7fd50b44f8d195624bc3de3642e125de904aa3b3dd42d9f5cebb7f4917ead + !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + +.. |badge1| image:: https://img.shields.io/badge/maturity-Beta-yellow.png + :target: https://odoo-community.org/page/development-status + :alt: Beta +.. |badge2| image:: https://img.shields.io/badge/licence-LGPL--3-blue.png + :target: http://www.gnu.org/licenses/lgpl-3.0-standalone.html + :alt: License: LGPL-3 +.. |badge3| image:: https://img.shields.io/badge/github-tegin%2Flims-lightgray.png?logo=github + :target: https://github.com/tegin/lims/tree/14.0/lims + :alt: tegin/lims + +|badge1| |badge2| |badge3| + +This module allows to manage a Laboratory from an odoo instance. + +It implements a simple LIMS for your company. + +**Table of contents** + +.. contents:: + :local: + +Usage +===== + +1. A sampler user will create a sample from `LIMS > Sample > Samples` + 1. Add a sample date, customer and sample type + 2. Add the different analysis you will do + 3. Receive the sample +2. An analyst user will review al the samples to analyze and will set the value. + Once it has been set, he will submit the results +3. A verifier user will verify all the results. + The verifier must be different than the analyst + +Known issues / Roadmap +====================== + +The following characteristics are still Work In Progress: + +* Usage of worklist +* Integration with devices +* Integration with sales / accounting +* Calculations +* Quality controls +* Batching of samples +* Sample storage + +Bug Tracker +=========== + +Bugs are tracked on `GitHub Issues `_. +In case of trouble, please check there if your issue has already been reported. +If you spotted it first, help us to smash it by providing a detailed and welcomed +`feedback `_. + +Do not contact contributors directly about support or help with technical issues. + +Credits +======= + +Authors +~~~~~~~ + +* Dixmit +* Creu Blanca + +Contributors +~~~~~~~~~~~~ + +* Dixmit + * Enric Tobella + +Maintainers +~~~~~~~~~~~ + +This module is part of the `tegin/lims `_ project on GitHub. + +You are welcome to contribute. diff --git a/lims/__init__.py b/lims/__init__.py new file mode 100644 index 0000000..0650744 --- /dev/null +++ b/lims/__init__.py @@ -0,0 +1 @@ +from . import models diff --git a/lims/__manifest__.py b/lims/__manifest__.py new file mode 100644 index 0000000..388cbbd --- /dev/null +++ b/lims/__manifest__.py @@ -0,0 +1,25 @@ +# Copyright 2023 Dixmit +# License LGPL-3.0 or later (http://www.gnu.org/licenses/lgpl). + +{ + "name": "Lims", + "summary": """ + Laboratory Information Management System""", + "version": "14.0.1.0.0", + "license": "LGPL-3", + "author": "Dixmit, Creu Blanca,Odoo Community Association (OCA)", + "website": "https://github.com/tegin/lims", + "depends": ["product"], + "data": [ + "security/security.xml", + "security/ir.model.access.csv", + "data/ir_sequence_data.xml", + "views/menu.xml", + "views/lims_department.xml", + "views/lims_sample_type.xml", + "views/lims_sample.xml", + "views/lims_analysis.xml", + "views/product_template.xml", + ], + "demo": ["demo/demo.xml"], +} diff --git a/lims/data/ir_sequence_data.xml b/lims/data/ir_sequence_data.xml new file mode 100644 index 0000000..6604bb4 --- /dev/null +++ b/lims/data/ir_sequence_data.xml @@ -0,0 +1,19 @@ + + + + + LIMS Sample sequence + lims.sample + SPL + 6 + + + LIMS Analysis sequence + lims.analysis + LA + 6 + + diff --git a/lims/demo/demo.xml b/lims/demo/demo.xml new file mode 100644 index 0000000..74f15f4 --- /dev/null +++ b/lims/demo/demo.xml @@ -0,0 +1,12 @@ + + + + + Blood + + + Hematology + + + diff --git a/lims/models/__init__.py b/lims/models/__init__.py new file mode 100644 index 0000000..c2755a1 --- /dev/null +++ b/lims/models/__init__.py @@ -0,0 +1,6 @@ +from . import lims_sample +from . import lims_sample_type +from . import lims_department +from . import lims_analysis +from . import res_users +from . import product_template diff --git a/lims/models/lims_analysis.py b/lims/models/lims_analysis.py new file mode 100644 index 0000000..581364e --- /dev/null +++ b/lims/models/lims_analysis.py @@ -0,0 +1,180 @@ +# Copyright 2023 Dixmit +# License LGPL-3.0 or later (http://www.gnu.org/licenses/lgpl). + +from odoo import _, api, fields, models +from odoo.exceptions import AccessDenied + + +class LimsAnalysis(models.Model): + _name = "lims.analysis" + _description = "Analysis" + _check_company_auto = True + + identifier = fields.Char(required=True, default="/", readonly=True) + sample_id = fields.Many2one("lims.sample", required=True) + company_id = fields.Many2one( + "res.company", related="sample_id.company_id", store=True + ) + state = fields.Selection( + [ + ("registered", "Registered"), + ("to_analyze", "To Analyze"), + ("to_be_verified", "To be verified"), + ("verified", "Verified"), + ("rejected", "Rejected"), + ], + required=True, + default="registered", + readonly=True, + ) + product_id = fields.Many2one( + "product.product", + required=True, + domain=[("laboratory_ok", "=", True)], + readonly=True, + states={"registered": [("readonly", False)]}, + ) + name = fields.Char( + required=True, + readonly=True, + states={"registered": [("readonly", False)]}, + ) + analyst_id = fields.Many2one("res.users", readonly=True) + capture_date = fields.Datetime(readonly=True) + submitted_date = fields.Datetime() + verified_by = fields.Many2one("res.users", readonly=True) + due_date = fields.Datetime(readonly=True) + verification_date = fields.Datetime(readonly=True) + uom_id = fields.Many2one( + "uom.uom", + readonly=True, + states={"registered": [("readonly", False)]}, + ) + progress = fields.Float(compute="_compute_progress", store=True) + can_verify = fields.Boolean(compute="_compute_can_verify") + value = fields.Char( + readonly=True, + states={"to_analyze": [("readonly", False)]}, + ) + # TODO: Replace this for something better. isn't it? + + _sql_constraints = [ + ( + "identifier_unique", + "unique(identifier, company_id)", + "Sample identifier must be unique", + ) + ] + + @api.onchange("product_id") + def _onchange_product(self): + for record in self: + if not record.product_id: + continue + record.name = record.product_id.name + record.uom_id = record.product_id.laboratory_uom_id + + @api.model_create_multi + def create(self, mvals): + for vals in mvals: + if vals.get("identifier", "/") == "/": + vals["identifier"] = self._get_identifier(vals) + return super().create(mvals) + + def _get_identifier(self, vals): + return ( + self.env["ir.sequence"] + .with_context(force_company=vals.get("company_id", self.env.company.id)) + .next_by_code("lims.analysis") + or "/" + ) + + @api.model + def _add_missing_default_values(self, values): + defaults = super()._add_missing_default_values(values) + product = self.env["product.product"].browse(defaults["product_id"]) + if "uom_id" not in values: + defaults["uom_id"] = product.laboratory_uom_id.id + if values.get("name"): + defaults["name"] = product.name + return defaults + + def _receive_sample(self): + for record in self: + record.write(record._receive_sample_vals()) + + def _receive_sample_vals(self): + return { + "state": "to_analyze", + } + + def analyze_action(self): + if not self.env.user.has_group("lims.group_lims_analyst"): + raise AccessDenied(_("You are not allowed to analyze this")) + for record in self.filtered(lambda r: r.state == "to_analyze"): + record.write(record._analyze_action_vals()) + self.mapped("sample_id").check_to_verify() + + def _analyze_action_vals(self): + return { + "state": "to_be_verified", + "analyst_id": self.env.user.id, + "submitted_date": fields.Datetime.now(), + } + + def verify_action(self): + if not self.env.user.has_group("lims.group_lims_verifier"): + raise AccessDenied(_("You are not allowed to verify an analysis")) + for record in self.filtered(lambda r: r.can_verify): + record.write(record._verify_action_vals()) + self.mapped("sample_id").check_verify() + + def _verify_action_vals(self): + return { + "state": "verified", + "verified_by": self.env.user.id, + "verification_date": fields.Datetime.now(), + } + + @api.depends("state") + def _compute_progress(self): + for record in self: + record.progress = record._get_progress() + + def final_states(self): + return ["verified"] + + def _get_progress(self): + if self.state in self.final_states(): + return 100 + if self.state == "to_be_verified": + return 50 + return 0 + + @api.depends_context("uid") + @api.depends("state", "analyst_id") + def _compute_can_verify(self): + verify_param = int( + self.env["ir.config_parameter"] + .sudo() + .get_param("lims.unforce_double_verification_manager"), + ) and self.env.user.has_group("lims.group_lims_manager") + for record in self: + record.can_verify = record.state == "to_be_verified" and ( + verify_param or record.analyst_id != self.env.user + ) + + def retract_action(self): + if not self.env.user.has_group("lims.group_lims_verifier"): + raise AccessDenied( + _("You are not allowed to retract an analysis to be verified") + ) + for record in self.filtered(lambda r: r.state == "to_be_verified"): + record.write(record._retract_action_vals()) + + def _retract_action_vals(self): + return { + "state": "to_analyze", + "analyst_id": False, + "submitted_date": False, + } diff --git a/lims/models/lims_department.py b/lims/models/lims_department.py new file mode 100644 index 0000000..f11fe91 --- /dev/null +++ b/lims/models/lims_department.py @@ -0,0 +1,14 @@ +# Copyright 2023 Dixmit +# License LGPL-3.0 or later (http://www.gnu.org/licenses/lgpl). + +from odoo import fields, models + + +class LimsDepartment(models.Model): + + _name = "lims.department" + _description = "Department" + + name = fields.Char(required=True) + active = fields.Boolean(default=True) + user_ids = fields.Many2many("res.users") diff --git a/lims/models/lims_sample.py b/lims/models/lims_sample.py new file mode 100644 index 0000000..b397f44 --- /dev/null +++ b/lims/models/lims_sample.py @@ -0,0 +1,148 @@ +# Copyright 2023 Dixmit +# License LGPL-3.0 or later (http://www.gnu.org/licenses/lgpl). + +from odoo import api, fields, models + + +class LimsSample(models.Model): + _name = "lims.sample" + _inherit = ["mail.thread", "mail.activity.mixin"] + _description = "Sample" + _rec_name = "identifier" + _check_company_auto = True + + identifier = fields.Char(required=True, default="/", readonly=True, copy=False) + external_identifier = fields.Char() + state = fields.Selection( + [ + ("registered", "Registered"), + ("scheduled_sampling", "Scheduled Sampling"), + ("due", "Sample due"), + ("received", "Received"), + ("to_be_verified", "To be verified"), + ("verified", "Verified"), + ("published", "Published"), + ("cancelled", "Cancelled"), + ("invalid", "Invalid"), + ], + required=True, + default="due", + readonly=True, + tracking=True, + ) + sample_type_id = fields.Many2one( + "lims.sample.type", + required=True, + states={"due": [("readonly", False)]}, + tracking=True, + ) + sample_date = fields.Datetime( + default=fields.Datetime.now(), + required=True, + readonly=True, + states={"due": [("readonly", False)]}, + tracking=True, + ) + received_date = fields.Datetime(readonly=True) + published_date = fields.Datetime(readonly=True) + customer_id = fields.Many2one("res.partner", tracking=True) + company_id = fields.Many2one( + "res.company", default=lambda self: self.env.company.id, tracking=True + ) + priority = fields.Selection( + [ + ("1", "Highest"), + ("2", "High"), + ("3", "Normal"), + ("4", "Low"), + ("5", "Lowest"), + ], + required=True, + default="3", + ) + analysis_ids = fields.One2many("lims.analysis", inverse_name="sample_id") + interpretation = fields.Html() + progress = fields.Float( + compute="_compute_progress", + store=True, + ) + + _sql_constraints = [ + ( + "identifier_unique", + "unique(identifier, company_id)", + "Sample identifier must be unique", + ) + ] + + @api.model_create_multi + def create(self, mvals): + for vals in mvals: + if vals.get("identifier", "/") == "/": + vals["identifier"] = self._get_identifier(vals) + return super().create(mvals) + + def _get_identifier(self, vals): + return ( + self.env["ir.sequence"] + .with_context(force_company=vals.get("company_id", self.env.company.id)) + .next_by_code("lims.sample") + or "/" + ) + + def receive_sample_action(self): + for record in self: + record.filtered(lambda r: r.state == "due").write( + record._receive_sample_vals() + ) + record.analysis_ids._receive_sample() + + def _receive_sample_vals(self): + return { + "state": "received", + "received_date": fields.Datetime.now(), + } + + def check_to_verify(self): + for record in self: + if record._check_to_verify: + record.write(record._check_to_verify_vals()) + + def _check_to_verify(self): + return not any( + self.analysis_ids.filtered( + lambda r: r.state in ["registered", "to_analyze"] + ) + ) + + def _check_to_verify_vals(self): + return {"state": "to_be_verified"} + + def check_verify(self): + for record in self: + if record._check_verify(): + record.write(record._check_verify_vals()) + + def _check_verify(self): + return not any( + self.analysis_ids.filtered( + lambda r: r.state in ["registered", "to_analyze", "to_be_verified"] + ) + ) + + def _check_verify_vals(self): + return {"state": "verified"} + + @api.depends("analysis_ids", "analysis_ids.progress") + def _compute_progress(self): + for record in self: + record.progress = record._get_progress() + + def get_analysis(self): + return self.analysis_ids.filtered(lambda r: r.state not in ["invalid"]) + + def _get_progress(self): + analysis = self.get_analysis() + if not analysis: + return 0 + return sum(analysis.mapped("progress")) / len(analysis) diff --git a/lims/models/lims_sample_type.py b/lims/models/lims_sample_type.py new file mode 100644 index 0000000..0352f3c --- /dev/null +++ b/lims/models/lims_sample_type.py @@ -0,0 +1,14 @@ +# Copyright 2023 Dixmit +# License LGPL-3.0 or later (http://www.gnu.org/licenses/lgpl). + +from odoo import fields, models + + +class LimsSampleType(models.Model): + _name = "lims.sample.type" + _description = "Sample Type" + + name = fields.Char(required=True) + description = fields.Text() + hazardous = fields.Boolean() + active = fields.Boolean(default=True) diff --git a/lims/models/product_template.py b/lims/models/product_template.py new file mode 100644 index 0000000..41fa7a9 --- /dev/null +++ b/lims/models/product_template.py @@ -0,0 +1,13 @@ +# Copyright 2023 Dixmit +# License LGPL-3.0 or later (http://www.gnu.org/licenses/lgpl). + +from odoo import fields, models + + +class ProductTemplate(models.Model): + + _inherit = "product.template" + + laboratory_ok = fields.Boolean(string="Can be used on Lab") + is_lab_template = fields.Boolean() + laboratory_uom_id = fields.Many2one("uom.uom") diff --git a/lims/models/res_users.py b/lims/models/res_users.py new file mode 100644 index 0000000..3004984 --- /dev/null +++ b/lims/models/res_users.py @@ -0,0 +1,11 @@ +# Copyright 2023 Dixmit +# License LGPL-3.0 or later (http://www.gnu.org/licenses/lgpl). + +from odoo import fields, models + + +class ResUsers(models.Model): + + _inherit = "res.users" + + lims_department_ids = fields.Many2many("lims.department") diff --git a/lims/readme/CONTRIBUTORS.rst b/lims/readme/CONTRIBUTORS.rst new file mode 100644 index 0000000..f8b9fad --- /dev/null +++ b/lims/readme/CONTRIBUTORS.rst @@ -0,0 +1,2 @@ +* Dixmit + * Enric Tobella diff --git a/lims/readme/DESCRIPTION.rst b/lims/readme/DESCRIPTION.rst new file mode 100644 index 0000000..73a3252 --- /dev/null +++ b/lims/readme/DESCRIPTION.rst @@ -0,0 +1,3 @@ +This module allows to manage a Laboratory from an odoo instance. + +It implements a simple LIMS for your company. diff --git a/lims/readme/ROADMAP.rst b/lims/readme/ROADMAP.rst new file mode 100644 index 0000000..764f581 --- /dev/null +++ b/lims/readme/ROADMAP.rst @@ -0,0 +1,9 @@ +The following characteristics are still Work In Progress: + +* Usage of worklist +* Integration with devices +* Integration with sales / accounting +* Calculations +* Quality controls +* Batching of samples +* Sample storage diff --git a/lims/readme/USAGE.rst b/lims/readme/USAGE.rst new file mode 100644 index 0000000..17e023d --- /dev/null +++ b/lims/readme/USAGE.rst @@ -0,0 +1,8 @@ +1. A sampler user will create a sample from `LIMS > Sample > Samples` + 1. Add a sample date, customer and sample type + 2. Add the different analysis you will do + 3. Receive the sample +2. An analyst user will review al the samples to analyze and will set the value. + Once it has been set, he will submit the results +3. A verifier user will verify all the results. + The verifier must be different than the analyst diff --git a/lims/security/ir.model.access.csv b/lims/security/ir.model.access.csv new file mode 100644 index 0000000..210e66a --- /dev/null +++ b/lims/security/ir.model.access.csv @@ -0,0 +1,11 @@ +id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink +access_lims_sample_type,access_lims_analysis,model_lims_sample_type,lims.group_lims_base,1,0,0,0 +manage_lims_sample_type,access_lims_analysis,model_lims_sample_type,lims.group_lims_manager,1,1,1,1 +access_lims_department,access_lims_analysis,model_lims_department,lims.group_lims_base,1,0,0,0 +manage_lims_department,access_lims_analysis,model_lims_department,lims.group_lims_manager,1,1,1,1 +access_lims_sample,access_lims_analysis,model_lims_sample,lims.group_lims_base,1,0,0,0 +manage_lims_sample,access_lims_analysis,model_lims_sample,lims.group_lims_sampler,1,1,1,0 +access_lims_analysis,access_lims_analysis,model_lims_analysis,lims.group_lims_base,1,0,0,0 +manage_lims_analysis_analyst,access_lims_analysis,model_lims_analysis,lims.group_lims_analyst,1,1,1,1 +manage_lims_analysis_verifier,access_lims_analysis,model_lims_analysis,lims.group_lims_verifier,1,1,1,1 +manage_lims_analysis_publisher,access_lims_analysis,model_lims_analysis,lims.group_lims_publisher,1,1,1,1 diff --git a/lims/security/security.xml b/lims/security/security.xml new file mode 100644 index 0000000..470baae --- /dev/null +++ b/lims/security/security.xml @@ -0,0 +1,50 @@ + + + + + LIMS + + + LIMS Base Root Menu + + + + Sampler + + + + + Analyst + + + + + Verifier + + + + + Publisher + + + + + Manager + + + + + + diff --git a/lims/static/description/icon.png b/lims/static/description/icon.png new file mode 100644 index 0000000000000000000000000000000000000000..af9bd353f7bb557c95aa4ea0c7357caa8ad4848a GIT binary patch literal 27295 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 D#Ckw1 literal 0 HcmV?d00001 diff --git a/lims/static/description/index.html b/lims/static/description/index.html new file mode 100644 index 0000000..01529c2 --- /dev/null +++ b/lims/static/description/index.html @@ -0,0 +1,459 @@ + + + + + + +Lims + + + +
+

Lims

+ + +

Beta License: LGPL-3 tegin/lims

+

This module allows to manage a Laboratory from an odoo instance.

+

It implements a simple LIMS for your company.

+

Table of contents

+ +
+

Usage

+
    +
  1. +
    A sampler user will create a sample from LIMS > Sample > Samples
    +
      +
    1. Add a sample date, customer and sample type
    2. +
    3. Add the different analysis you will do
    4. +
    5. Receive the sample
    6. +
    +
    +
    +
  2. +
  3. An analyst user will review al the samples to analyze and will set the value. +Once it has been set, he will submit the results
  4. +
  5. A verifier user will verify all the results. +The verifier must be different than the analyst
  6. +
+
+
+

Known issues / Roadmap

+

The following characteristics are still Work In Progress:

+
    +
  • Usage of worklist
  • +
  • Integration with devices
  • +
  • Integration with sales / accounting
  • +
  • Calculations
  • +
  • Quality controls
  • +
  • Batching of samples
  • +
  • Sample storage
  • +
+
+
+

Bug Tracker

+

Bugs are tracked on GitHub Issues. +In case of trouble, please check there if your issue has already been reported. +If you spotted it first, help us to smash it by providing a detailed and welcomed +feedback.

+

Do not contact contributors directly about support or help with technical issues.

+
+
+

Credits

+
+

Authors

+
    +
  • Dixmit
  • +
  • Creu Blanca
  • +
+
+
+

Contributors

+
    +
  • +
    Dixmit
    +
      +
    • Enric Tobella
    • +
    +
    +
    +
  • +
+
+
+

Maintainers

+

This module is part of the tegin/lims project on GitHub.

+

You are welcome to contribute.

+
+
+
+ + diff --git a/lims/views/lims_analysis.xml b/lims/views/lims_analysis.xml new file mode 100644 index 0000000..c92540f --- /dev/null +++ b/lims/views/lims_analysis.xml @@ -0,0 +1,88 @@ + + + + + lims.analysis.form (in lims) + lims.analysis + +
+
+ +
+ + +
+

+

+ + + + + + +
+ + + + + lims.analysis.search (in lims) + lims.analysis + + + + + + + + lims.analysis.tree (in lims) + lims.analysis + + + + + + + + + + + +