clinical_laboratory/CLAUDE.md
Luis Ernesto Portillo Zaldivar 472f88a477 feat: Update gitea_cli_helper.py to use file input and add CLAUDE.md
- Modified gitea_cli_helper.py to read issue/PR body from files instead of inline text
- Added CLAUDE.md with comprehensive development guidelines for Claude Code
- CLAUDE.md includes Odoo 18 specific conventions, Docker commands, and project structure

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-07-14 20:22:31 -06:00

6.7 KiB

CLAUDE.md

This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.

Project Overview

This is a Laboratory Information Management System (LIMS) module for Odoo 18 ERP, specifically designed for clinical laboratories. The module manages patients, samples, analyses, and test results.

Key Technologies

  • Odoo 18: ERP framework (Python-based)
  • PostgreSQL 15: Database
  • Docker & Docker Compose: Containerization
  • Gitea: Version control and issue tracking

Development Commands

Starting the Environment

# Start all services
docker-compose up -d

# MANDATORY: View initialization logs to check for errors
docker-compose logs odoo_init

# Stop and clean everything (removes volumes)
docker-compose down -v

Instance Persistence Policy

After successful installation/update, the instance must remain active for user validation. Do NOT stop the instance until user explicitly confirms testing is complete.

Database Operations

Direct PostgreSQL Access

# Connect to PostgreSQL
docker exec -it lims_db psql -U odoo -d odoo

For complex queries, use Python scripts with Odoo ORM:

  1. Create script (e.g., verify_products.py):
import odoo
import json

def verify_lab_order_products(cr):
    cr.execute("""SELECT ... FROM sale_order ...""")
    return cr.fetchall()

if __name__ == '__main__':
    db_name = 'lims_demo'
    registry = odoo.registry(db_name)
    with registry.cursor() as cr:
        results = verify_lab_order_products(cr)
        print(json.dumps(results, indent=4))
  1. Copy to container:
docker cp verify_products.py lims_odoo:/tmp/verify_products.py
  1. Execute:
docker-compose exec odoo python3 /tmp/verify_products.py

Gitea Integration

# Create issue
python gitea_cli_helper.py create-issue --title "Title" --body "Description\nSupports multiple lines"

# Create PR with inline description
python gitea_cli_helper.py create-pr --head "feature-branch" --base "dev" --title "Title" --body "Description"

# Create PR with description from file
python gitea_cli_helper.py create-pr dev --title "feat(#31): Sample lifecycle" --description-file pr_description.txt

# Comment on issue
python gitea_cli_helper.py comment-issue --issue-number 123 --body "Comment text"

# Close issue
python gitea_cli_helper.py close-issue --issue-number 123

Mandatory Reading

At the start of each work session, read these documents to understand requirements and technical design:

  • documents/requirements/RequerimientoInicial.md
  • documents/requirements/ToBeDesing.md

Code Architecture

Module Structure

  • lims_management/models/: Core business logic
    • partner.py: Patient and healthcare provider management
    • product.py: Analysis types and categories
    • sale_order.py: Analysis orders and sample management
    • stock_lot.py: Sample tracking and lifecycle
    • analysis_range.py: Normal ranges for test results

Odoo 18 Specific Conventions

View Definitions

  • CRITICAL: Use <list> instead of <tree> - using <tree> causes ValueError: Wrong value for ir.ui.view.type: 'tree'
  • View mode in actions must be list,form not tree,form

Visibility Attributes

  • Use invisible attribute directly instead of attrs:
    <!-- Wrong (Odoo < 17) -->
    <field name="field" attrs="{'invisible': [('condition', '=', False)]}"/>
    
    <!-- Correct (Odoo 18) -->
    <field name="field" invisible="not condition"/>
    <field name="field" invisible="condition == False"/>
    

Context with ref()

  • Use eval attribute when using ref() in action contexts:
    <!-- Wrong - ref() undefined in client -->
    <field name="context">{'default_categ_id': ref('module.xml_id')}</field>
    
    <!-- Correct - evaluated on server -->
    <field name="context" eval="{'default_categ_id': ref('module.xml_id')}"/>
    

XPath in View Inheritance

  • Use flexible XPath expressions for robustness:
    <!-- More robust - works with list or tree -->
    <xpath expr="//field[@name='order_line']//field[@name='product_id']" position="attributes">
        <attribute name="domain">[('is_analysis', '=', True)]</attribute>
    </xpath>
    

Data Management

  • Initial Data: lims_management/data/ - Sequences, categories, basic configuration
  • Demo Data:
    • XML files in lims_management/demo/
    • Python scripts in root directory for complex demo data creation
    • Use noupdate="1" for demo data to prevent reloading

Security Model

  • Access rights defined in security/ir.model.access.csv
  • Field-level security in security/security.xml
  • Group-based permissions: Laboratory Technician, Manager, etc.

Environment Variables

Required in .env file:

  • GITEA_API_KEY: Personal Access Token for Gitea
  • GITEA_API_KEY_URL: Gitea API base URL (e.g., https://gitea.grupoconsiti.com/api/v1/)
  • GITEA_USERNAME: Gitea username (repository owner)
  • GITEA_REPO_NAME: Repository name (e.g., clinical_laboratory)

Important Patterns

Sample Lifecycle States

STATE_PENDING_COLLECTION = 'pending_collection'
STATE_COLLECTED = 'collected'
STATE_IN_ANALYSIS = 'in_analysis'
STATE_COMPLETED = 'completed'
STATE_CANCELLED = 'cancelled'

Barcode Generation

  • 13-digit format: YYMMDDNNNNNNC
  • Uses barcode Python library for Code-128 generation
  • Stored as PDF with human-readable text

Demo Data Creation

XML Files (Simple Data)

  • Use for basic records without complex dependencies
  • Place in lims_management/demo/
  • Use noupdate="1" to prevent reloading

Python Scripts (Complex Data)

For data with dependencies or business logic:

  1. Create script:
import odoo

def create_lab_requests(cr):
    env = odoo.api.Environment(cr, odoo.SUPERUSER_ID, {})
    
    # Use ref() to get existing records
    patient1 = env.ref('lims_management.demo_patient_1')
    hemograma = env.ref('lims_management.analysis_hemograma')
    
    # Create records with business logic
    env['sale.order'].create({
        'partner_id': patient1.id,
        'is_lab_request': True,
        'order_line': [(0, 0, {
            'product_id': hemograma.product_variant_id.id,
            'product_uom_qty': 1
        })]
    })

if __name__ == '__main__':
    db_name = 'lims_demo'
    registry = odoo.registry(db_name)
    with registry.cursor() as cr:
        create_lab_requests(cr)
        cr.commit()
  1. Integrate in initialization or run separately

Git Workflow

Pre-commit Hook

Automatically installed via scripts/install_hooks.sh:

  • Prevents commits to 'main' or 'dev' branches
  • Enforces feature branch workflow

Branch Naming

  • Feature branches: feature/XX-description (where XX is issue number)
  • Always create PRs to 'dev' branch, not 'main'