\"feat(#6): Implementar solicitudes de laboratorio y corregir datos de demostracion\"
This commit is contained in:
parent
638d9b130a
commit
f56b60ad15
83
GEMINI.md
83
GEMINI.md
|
@ -240,4 +240,87 @@ Esto envía la cadena `"{'default_categ_id': ref(...)}"` al cliente, que no pued
|
|||
}"/>
|
||||
```
|
||||
Al usar `eval`, Odoo ejecuta la expresión en el servidor, reemplaza `ref(...)` por el ID numérico correspondiente, y envía un diccionario JSON válido al cliente.
|
||||
|
||||
### Herencia de Vistas y XPath
|
||||
|
||||
Al heredar vistas para modificarlas, es crucial que las expresiones `XPath` sean precisas. Un error común es hacer referencia a campos o estructuras que han cambiado en la nueva versión de Odoo.
|
||||
|
||||
**Ejemplo de Error:**
|
||||
Al intentar modificar las líneas de una orden de venta (`sale.order`), una expresión XPath que funcionaba en versiones anteriores puede fallar en Odoo 18.
|
||||
|
||||
**Expresión Incorrecta (para Odoo < 18):**
|
||||
```xml
|
||||
<xpath expr="//field[@name='order_line']/tree/field[@name='product_template_id']" position="attributes">
|
||||
<attribute name="domain">[('is_analysis', '=', True)]</attribute>
|
||||
</xpath>
|
||||
```
|
||||
Esta expresión falla por dos razones:
|
||||
1. La vista de líneas ahora usa `<list>` en lugar de `<tree>`.
|
||||
2. El campo del producto en las líneas de venta es `product_id`, no `product_template_id`.
|
||||
|
||||
**Expresión Correcta (para Odoo 18):**
|
||||
Para hacer la expresión más robusta y compatible, se puede usar `//` para buscar en cualquier nivel descendiente.
|
||||
```xml
|
||||
<xpath expr="//field[@name='order_line']//field[@name='product_id']" position="attributes">
|
||||
<attribute name="domain">[('is_analysis', '=', True)]</attribute>
|
||||
</xpath>
|
||||
```
|
||||
Esta expresión busca el campo `product_id` dentro del campo `order_line`, sin importar si está dentro de una etiqueta `<list>` o `<tree>`, haciendo la herencia más resistente a cambios menores de estructura.
|
||||
|
||||
---
|
||||
|
||||
## Consultar la Base de Datos con un Script
|
||||
|
||||
Interactuar con la base de datos directamente usando `psql` a través de `docker-compose exec` puede ser complicado debido a la forma en que el shell maneja las comillas. Una alternativa más robusta y confiable es utilizar un script de Python que aproveche el ORM de Odoo.
|
||||
|
||||
### Procedimiento
|
||||
|
||||
1. **Crear un Script de Python:**
|
||||
Crea un script que se conecte a la base de datos y ejecute la consulta deseada.
|
||||
|
||||
**Ejemplo (`verify_products.py`):**
|
||||
```python
|
||||
import odoo
|
||||
import json
|
||||
|
||||
def verify_lab_order_products(cr):
|
||||
cr.execute("""
|
||||
SELECT
|
||||
so.name AS order_name,
|
||||
sol.id AS line_id,
|
||||
pt.name->>'en_US' AS product_name,
|
||||
pt.is_analysis
|
||||
FROM
|
||||
sale_order so
|
||||
JOIN
|
||||
sale_order_line sol ON so.id = sol.order_id
|
||||
JOIN
|
||||
product_product pp ON sol.product_id = pp.id
|
||||
JOIN
|
||||
product_template pt ON pp.product_tmpl_id = pt.id
|
||||
WHERE
|
||||
so.is_lab_request = TRUE;
|
||||
""")
|
||||
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))
|
||||
```
|
||||
|
||||
2. **Copiar el Script al Contenedor:**
|
||||
Usa el comando `docker cp` para copiar el script al contenedor de Odoo.
|
||||
```bash
|
||||
docker cp verify_products.py lims_odoo:/tmp/verify_products.py
|
||||
```
|
||||
|
||||
3. **Ejecutar el Script:**
|
||||
Ejecuta el script dentro del contenedor usando `docker-compose exec`.
|
||||
```bash
|
||||
docker-compose exec odoo python3 /tmp/verify_products.py
|
||||
```
|
||||
|
||||
Este método evita los problemas de entrecomillado y permite ejecutar consultas complejas de manera confiable.
|
||||
|
|
53
create_lab_requests.py
Normal file
53
create_lab_requests.py
Normal file
|
@ -0,0 +1,53 @@
|
|||
import odoo
|
||||
import json
|
||||
|
||||
def create_lab_requests(cr):
|
||||
env = odoo.api.Environment(cr, odoo.SUPERUSER_ID, {})
|
||||
|
||||
# Delete unwanted demo sale orders
|
||||
unwanted_orders = env['sale.order'].search([('name', 'in', ['S00001', 'S00002', 'S00003', 'S00004', 'S00005', 'S00006', 'S00007', 'S00008', 'S00009', 'S00010', 'S00011', 'S00012', 'S00013', 'S00014', 'S00015', 'S00016', 'S00017', 'S00018', 'S00019', 'S00020', 'S00021', 'S00022'])])
|
||||
for order in unwanted_orders:
|
||||
try:
|
||||
order.action_cancel()
|
||||
except Exception:
|
||||
pass
|
||||
try:
|
||||
unwanted_orders.unlink()
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
# Get patient and doctor
|
||||
patient1 = env.ref('lims_management.demo_patient_1')
|
||||
doctor1 = env.ref('lims_management.demo_doctor_1')
|
||||
patient2 = env.ref('lims_management.demo_patient_2')
|
||||
|
||||
# Get analysis products
|
||||
hemograma = env.ref('lims_management.analysis_hemograma')
|
||||
perfil_lipidico = env.ref('lims_management.analysis_perfil_lipidico')
|
||||
|
||||
# Create Lab Request 1
|
||||
env['sale.order'].create({
|
||||
'partner_id': patient1.id,
|
||||
'doctor_id': doctor1.id,
|
||||
'is_lab_request': True,
|
||||
'order_line': [
|
||||
(0, 0, {'product_id': hemograma.product_variant_id.id, 'product_uom_qty': 1}),
|
||||
(0, 0, {'product_id': perfil_lipidico.product_variant_id.id, 'product_uom_qty': 1})
|
||||
]
|
||||
})
|
||||
|
||||
# Create Lab Request 2
|
||||
env['sale.order'].create({
|
||||
'partner_id': patient2.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()
|
|
@ -24,6 +24,7 @@ services:
|
|||
- ./lims_management:/mnt/extra-addons/lims_management
|
||||
- ./odoo.conf:/etc/odoo/odoo.conf
|
||||
- ./init_odoo.py:/app/init_odoo.py
|
||||
- ./create_lab_requests.py:/app/create_lab_requests.py
|
||||
command: ["/usr/bin/python3", "/app/init_odoo.py"]
|
||||
environment:
|
||||
HOST: db
|
||||
|
|
BIN
documents/logs/Quotation - S00021.pdf
Normal file
BIN
documents/logs/Quotation - S00021.pdf
Normal file
Binary file not shown.
BIN
documents/logs/Quotation - S00022.pdf
Normal file
BIN
documents/logs/Quotation - S00022.pdf
Normal file
Binary file not shown.
169
documents/logs/producto.json
Normal file
169
documents/logs/producto.json
Normal file
|
@ -0,0 +1,169 @@
|
|||
{
|
||||
"account_tag_ids": [],
|
||||
"active": true,
|
||||
"activity_date_deadline": false,
|
||||
"activity_exception_decoration": false,
|
||||
"activity_exception_icon": false,
|
||||
"activity_ids": [],
|
||||
"activity_state": false,
|
||||
"activity_summary": false,
|
||||
"activity_type_icon": false,
|
||||
"activity_type_id": false,
|
||||
"activity_user_id": false,
|
||||
"analysis_type": false,
|
||||
"attribute_line_ids": [],
|
||||
"barcode": false,
|
||||
"can_image_1024_be_zoomed": false,
|
||||
"categ_id": [
|
||||
10,
|
||||
"All / Home Construction"
|
||||
],
|
||||
"color": 0,
|
||||
"combo_ids": [],
|
||||
"company_id": false,
|
||||
"cost_currency_id": [
|
||||
1,
|
||||
"USD"
|
||||
],
|
||||
"cost_method": "standard",
|
||||
"create_date": "2025-07-14 07:23:12",
|
||||
"create_uid": [
|
||||
1,
|
||||
"OdooBot"
|
||||
],
|
||||
"currency_id": [
|
||||
1,
|
||||
"USD"
|
||||
],
|
||||
"default_code": false,
|
||||
"description": false,
|
||||
"description_picking": false,
|
||||
"description_pickingin": false,
|
||||
"description_pickingout": false,
|
||||
"description_purchase": false,
|
||||
"description_sale": false,
|
||||
"display_name": "Furniture Assembly",
|
||||
"expense_policy": "no",
|
||||
"fiscal_country_codes": "US",
|
||||
"has_available_route_ids": false,
|
||||
"has_configurable_attributes": false,
|
||||
"has_message": true,
|
||||
"id": 29,
|
||||
"image_1024": false,
|
||||
"image_128": false,
|
||||
"image_1920": false,
|
||||
"image_256": false,
|
||||
"image_512": false,
|
||||
"incoming_qty": 0,
|
||||
"invoice_policy": "order",
|
||||
"is_analysis": false,
|
||||
"is_favorite": false,
|
||||
"is_product_variant": false,
|
||||
"is_storable": false,
|
||||
"list_price": 2000,
|
||||
"location_id": false,
|
||||
"lot_valuated": false,
|
||||
"message_attachment_count": 0,
|
||||
"message_follower_ids": [],
|
||||
"message_has_error": false,
|
||||
"message_has_error_counter": 0,
|
||||
"message_has_sms_error": false,
|
||||
"message_ids": [
|
||||
188,
|
||||
114
|
||||
],
|
||||
"message_is_follower": false,
|
||||
"message_needaction": false,
|
||||
"message_needaction_counter": 0,
|
||||
"message_partner_ids": [],
|
||||
"my_activity_date_deadline": false,
|
||||
"name": "Furniture Assembly",
|
||||
"nbr_moves_in": 0,
|
||||
"nbr_moves_out": 0,
|
||||
"nbr_reordering_rules": 0,
|
||||
"optional_product_ids": [],
|
||||
"outgoing_qty": 0,
|
||||
"packaging_ids": [],
|
||||
"pricelist_item_count": 0,
|
||||
"product_document_count": 0,
|
||||
"product_document_ids": [],
|
||||
"product_properties": [],
|
||||
"product_tag_ids": [],
|
||||
"product_tooltip": "Invoice ordered quantities as soon as this service is sold.",
|
||||
"product_variant_count": 1,
|
||||
"product_variant_id": [
|
||||
38,
|
||||
"Furniture Assembly"
|
||||
],
|
||||
"product_variant_ids": [
|
||||
38
|
||||
],
|
||||
"property_account_expense_id": false,
|
||||
"property_account_income_id": false,
|
||||
"property_stock_inventory": [
|
||||
14,
|
||||
"Virtual Locations/Inventory adjustment"
|
||||
],
|
||||
"property_stock_production": [
|
||||
15,
|
||||
"Virtual Locations/Production"
|
||||
],
|
||||
"purchase_ok": true,
|
||||
"qty_available": 0,
|
||||
"reordering_max_qty": 0,
|
||||
"reordering_min_qty": 0,
|
||||
"responsible_id": [
|
||||
1,
|
||||
"OdooBot"
|
||||
],
|
||||
"route_from_categ_ids": [],
|
||||
"route_ids": [],
|
||||
"sale_delay": 0,
|
||||
"sale_line_warn": "no-message",
|
||||
"sale_line_warn_msg": false,
|
||||
"sale_ok": true,
|
||||
"sales_count": 0,
|
||||
"seller_ids": [],
|
||||
"sequence": 1,
|
||||
"service_tracking": "no",
|
||||
"service_type": "manual",
|
||||
"show_forecasted_qty_status_button": false,
|
||||
"show_on_hand_qty_status_button": false,
|
||||
"standard_price": 2500,
|
||||
"supplier_taxes_id": [],
|
||||
"tax_string": " ",
|
||||
"taxes_id": [],
|
||||
"technical_specifications": false,
|
||||
"tracking": "none",
|
||||
"type": "service",
|
||||
"uom_category_id": [
|
||||
3,
|
||||
"Working Time"
|
||||
],
|
||||
"uom_id": [
|
||||
4,
|
||||
"Hours"
|
||||
],
|
||||
"uom_name": "Hours",
|
||||
"uom_po_id": [
|
||||
4,
|
||||
"Hours"
|
||||
],
|
||||
"valid_product_template_attribute_line_ids": [],
|
||||
"valuation": "manual_periodic",
|
||||
"value_range_ids": [],
|
||||
"variant_seller_ids": [],
|
||||
"virtual_available": 0,
|
||||
"visible_expense_policy": false,
|
||||
"volume": 0,
|
||||
"volume_uom_name": "m³",
|
||||
"warehouse_id": false,
|
||||
"website_message_ids": [],
|
||||
"weight": 0,
|
||||
"weight_uom_name": "kg",
|
||||
"write_date": "2025-07-14 07:23:55",
|
||||
"write_uid": [
|
||||
1,
|
||||
"OdooBot"
|
||||
]
|
||||
}
|
158
documents/logs/s00021.json
Normal file
158
documents/logs/s00021.json
Normal file
|
@ -0,0 +1,158 @@
|
|||
{
|
||||
"access_token": false,
|
||||
"access_url": "/my/orders/21",
|
||||
"access_warning": "",
|
||||
"activity_date_deadline": false,
|
||||
"activity_exception_decoration": false,
|
||||
"activity_exception_icon": false,
|
||||
"activity_ids": [],
|
||||
"activity_state": false,
|
||||
"activity_summary": false,
|
||||
"activity_type_icon": false,
|
||||
"activity_type_id": false,
|
||||
"activity_user_id": false,
|
||||
"amount_invoiced": 0,
|
||||
"amount_paid": 0,
|
||||
"amount_tax": 0,
|
||||
"amount_to_invoice": 2589,
|
||||
"amount_total": 2589,
|
||||
"amount_undiscounted": 2589,
|
||||
"amount_untaxed": 2589,
|
||||
"authorized_transaction_ids": [],
|
||||
"available_product_document_ids": [
|
||||
2
|
||||
],
|
||||
"campaign_id": false,
|
||||
"client_order_ref": false,
|
||||
"commitment_date": false,
|
||||
"company_id": [
|
||||
1,
|
||||
"My Company (San Francisco)"
|
||||
],
|
||||
"company_price_include": "tax_excluded",
|
||||
"country_code": "US",
|
||||
"create_date": "2025-07-14 07:24:01",
|
||||
"create_uid": [
|
||||
1,
|
||||
"OdooBot"
|
||||
],
|
||||
"currency_id": [
|
||||
1,
|
||||
"USD"
|
||||
],
|
||||
"currency_rate": 1,
|
||||
"customizable_pdf_form_fields": false,
|
||||
"date_order": "2025-07-14 07:24:02",
|
||||
"delivery_count": 0,
|
||||
"delivery_status": false,
|
||||
"display_name": "S00021",
|
||||
"doctor_id": [
|
||||
46,
|
||||
"Dr. Luis Herrera"
|
||||
],
|
||||
"duplicated_order_ids": [],
|
||||
"effective_date": false,
|
||||
"expected_date": "2025-07-14 07:26:23",
|
||||
"fiscal_position_id": false,
|
||||
"has_active_pricelist": false,
|
||||
"has_archived_products": false,
|
||||
"has_message": true,
|
||||
"id": 21,
|
||||
"incoterm": false,
|
||||
"incoterm_location": false,
|
||||
"invoice_count": 0,
|
||||
"invoice_ids": [],
|
||||
"invoice_status": "no",
|
||||
"is_expired": false,
|
||||
"is_lab_request": true,
|
||||
"is_pdf_quote_builder_available": true,
|
||||
"journal_id": false,
|
||||
"json_popover": "{\"popoverTemplate\": \"sale_stock.DelayAlertWidget\", \"late_elements\": []}",
|
||||
"locked": false,
|
||||
"medium_id": false,
|
||||
"message_attachment_count": 0,
|
||||
"message_follower_ids": [],
|
||||
"message_has_error": false,
|
||||
"message_has_error_counter": 0,
|
||||
"message_has_sms_error": false,
|
||||
"message_ids": [
|
||||
310
|
||||
],
|
||||
"message_is_follower": false,
|
||||
"message_needaction": false,
|
||||
"message_needaction_counter": 0,
|
||||
"message_partner_ids": [],
|
||||
"my_activity_date_deadline": false,
|
||||
"name": "S00021",
|
||||
"note": false,
|
||||
"order_line": [
|
||||
45,
|
||||
46
|
||||
],
|
||||
"origin": false,
|
||||
"partner_credit_warning": "",
|
||||
"partner_id": [
|
||||
44,
|
||||
"Ana Torres"
|
||||
],
|
||||
"partner_invoice_id": [
|
||||
44,
|
||||
"Ana Torres"
|
||||
],
|
||||
"partner_shipping_id": [
|
||||
44,
|
||||
"Ana Torres"
|
||||
],
|
||||
"payment_term_id": false,
|
||||
"pending_email_template_id": false,
|
||||
"picking_ids": [],
|
||||
"picking_policy": "direct",
|
||||
"prepayment_percent": 1,
|
||||
"pricelist_id": false,
|
||||
"procurement_group_id": false,
|
||||
"quotation_document_ids": [],
|
||||
"reference": false,
|
||||
"require_payment": true,
|
||||
"require_signature": true,
|
||||
"sale_order_option_ids": [],
|
||||
"sale_order_template_id": false,
|
||||
"show_json_popover": false,
|
||||
"show_update_fpos": false,
|
||||
"show_update_pricelist": false,
|
||||
"signature": false,
|
||||
"signed_by": false,
|
||||
"signed_on": false,
|
||||
"source_id": false,
|
||||
"state": "draft",
|
||||
"tag_ids": [],
|
||||
"tax_calculation_rounding_method": "round_per_line",
|
||||
"tax_country_id": [
|
||||
233,
|
||||
"United States"
|
||||
],
|
||||
"tax_totals": {
|
||||
"currency_id": 1
|
||||
},
|
||||
"team_id": [
|
||||
1,
|
||||
"Sales"
|
||||
],
|
||||
"terms_type": "plain",
|
||||
"transaction_ids": [],
|
||||
"type_name": "Quotation",
|
||||
"user_id": [
|
||||
1,
|
||||
"OdooBot"
|
||||
],
|
||||
"validity_date": "2025-08-13",
|
||||
"warehouse_id": [
|
||||
1,
|
||||
"YourCompany"
|
||||
],
|
||||
"website_message_ids": [],
|
||||
"write_date": "2025-07-14 07:24:04",
|
||||
"write_uid": [
|
||||
1,
|
||||
"OdooBot"
|
||||
]
|
||||
}
|
650
documents/metadata.json
Normal file
650
documents/metadata.json
Normal file
|
@ -0,0 +1,650 @@
|
|||
{
|
||||
"sale_order": [
|
||||
[
|
||||
"id",
|
||||
"integer"
|
||||
],
|
||||
[
|
||||
"message_main_attachment_id",
|
||||
"integer"
|
||||
],
|
||||
[
|
||||
"access_token",
|
||||
"character varying"
|
||||
],
|
||||
[
|
||||
"name",
|
||||
"character varying"
|
||||
],
|
||||
[
|
||||
"origin",
|
||||
"character varying"
|
||||
],
|
||||
[
|
||||
"client_order_ref",
|
||||
"character varying"
|
||||
],
|
||||
[
|
||||
"reference",
|
||||
"character varying"
|
||||
],
|
||||
[
|
||||
"state",
|
||||
"character varying"
|
||||
],
|
||||
[
|
||||
"date_order",
|
||||
"timestamp without time zone"
|
||||
],
|
||||
[
|
||||
"validity_date",
|
||||
"date"
|
||||
],
|
||||
[
|
||||
"commitment_date",
|
||||
"timestamp without time zone"
|
||||
],
|
||||
[
|
||||
"expected_date",
|
||||
"timestamp without time zone"
|
||||
],
|
||||
[
|
||||
"user_id",
|
||||
"integer"
|
||||
],
|
||||
[
|
||||
"partner_id",
|
||||
"integer"
|
||||
],
|
||||
[
|
||||
"partner_invoice_id",
|
||||
"integer"
|
||||
],
|
||||
[
|
||||
"partner_shipping_id",
|
||||
"integer"
|
||||
],
|
||||
[
|
||||
"pricelist_id",
|
||||
"integer"
|
||||
],
|
||||
[
|
||||
"currency_id",
|
||||
"integer"
|
||||
],
|
||||
[
|
||||
"analytic_account_id",
|
||||
"integer"
|
||||
],
|
||||
[
|
||||
"order_line",
|
||||
"integer"
|
||||
],
|
||||
[
|
||||
"invoice_count",
|
||||
"integer"
|
||||
],
|
||||
[
|
||||
"invoice_status",
|
||||
"character varying"
|
||||
],
|
||||
[
|
||||
"note",
|
||||
"text"
|
||||
],
|
||||
[
|
||||
"amount_untaxed",
|
||||
"numeric"
|
||||
],
|
||||
[
|
||||
"amount_tax",
|
||||
"numeric"
|
||||
],
|
||||
[
|
||||
"amount_total",
|
||||
"numeric"
|
||||
],
|
||||
[
|
||||
"currency_rate",
|
||||
"numeric"
|
||||
],
|
||||
[
|
||||
"payment_term_id",
|
||||
"integer"
|
||||
],
|
||||
[
|
||||
"fiscal_position_id",
|
||||
"integer"
|
||||
],
|
||||
[
|
||||
"company_id",
|
||||
"integer"
|
||||
],
|
||||
[
|
||||
"team_id",
|
||||
"integer"
|
||||
],
|
||||
[
|
||||
"signature",
|
||||
"text"
|
||||
],
|
||||
[
|
||||
"signed_by",
|
||||
"character varying"
|
||||
],
|
||||
[
|
||||
"signed_on",
|
||||
"timestamp without time zone"
|
||||
],
|
||||
[
|
||||
"create_uid",
|
||||
"integer"
|
||||
],
|
||||
[
|
||||
"create_date",
|
||||
"timestamp without time zone"
|
||||
],
|
||||
[
|
||||
"write_uid",
|
||||
"integer"
|
||||
],
|
||||
[
|
||||
"write_date",
|
||||
"timestamp without time zone"
|
||||
],
|
||||
[
|
||||
"sale_order_template_id",
|
||||
"integer"
|
||||
],
|
||||
[
|
||||
"incoterm",
|
||||
"integer"
|
||||
],
|
||||
[
|
||||
"picking_policy",
|
||||
"character varying"
|
||||
],
|
||||
[
|
||||
"warehouse_id",
|
||||
"integer"
|
||||
],
|
||||
[
|
||||
"procurement_group_id",
|
||||
"integer"
|
||||
],
|
||||
[
|
||||
"campaign_id",
|
||||
"integer"
|
||||
],
|
||||
[
|
||||
"medium_id",
|
||||
"integer"
|
||||
],
|
||||
[
|
||||
"source_id",
|
||||
"integer"
|
||||
],
|
||||
[
|
||||
"delivery_count",
|
||||
"integer"
|
||||
],
|
||||
[
|
||||
"is_lab_request",
|
||||
"boolean"
|
||||
],
|
||||
[
|
||||
"doctor_id",
|
||||
"integer"
|
||||
]
|
||||
],
|
||||
"sale_order_line": [
|
||||
[
|
||||
"id",
|
||||
"integer"
|
||||
],
|
||||
[
|
||||
"order_id",
|
||||
"integer"
|
||||
],
|
||||
[
|
||||
"name",
|
||||
"text"
|
||||
],
|
||||
[
|
||||
"sequence",
|
||||
"integer"
|
||||
],
|
||||
[
|
||||
"invoice_status",
|
||||
"character varying"
|
||||
],
|
||||
[
|
||||
"price_unit",
|
||||
"numeric"
|
||||
],
|
||||
[
|
||||
"price_subtotal",
|
||||
"numeric"
|
||||
],
|
||||
[
|
||||
"price_tax",
|
||||
"double precision"
|
||||
],
|
||||
[
|
||||
"price_total",
|
||||
"numeric"
|
||||
],
|
||||
[
|
||||
"price_reduce",
|
||||
"numeric"
|
||||
],
|
||||
[
|
||||
"tax_id",
|
||||
"integer"
|
||||
],
|
||||
[
|
||||
"price_reduce_taxinc",
|
||||
"numeric"
|
||||
],
|
||||
[
|
||||
"price_reduce_taxexcl",
|
||||
"numeric"
|
||||
],
|
||||
[
|
||||
"discount",
|
||||
"numeric"
|
||||
],
|
||||
[
|
||||
"product_id",
|
||||
"integer"
|
||||
],
|
||||
[
|
||||
"product_template_id",
|
||||
"integer"
|
||||
],
|
||||
[
|
||||
"product_uom_category_id",
|
||||
"integer"
|
||||
],
|
||||
[
|
||||
"product_uom",
|
||||
"integer"
|
||||
],
|
||||
[
|
||||
"product_uom_qty",
|
||||
"numeric"
|
||||
],
|
||||
[
|
||||
"product_uom_readonly",
|
||||
"boolean"
|
||||
],
|
||||
[
|
||||
"qty_delivered_method",
|
||||
"character varying"
|
||||
],
|
||||
[
|
||||
"qty_delivered",
|
||||
"numeric"
|
||||
],
|
||||
[
|
||||
"qty_delivered_manual",
|
||||
"numeric"
|
||||
],
|
||||
[
|
||||
"qty_to_invoice",
|
||||
"numeric"
|
||||
],
|
||||
[
|
||||
"qty_invoiced",
|
||||
"numeric"
|
||||
],
|
||||
[
|
||||
"untaxed_amount_invoiced",
|
||||
"numeric"
|
||||
],
|
||||
[
|
||||
"untaxed_amount_to_invoice",
|
||||
"numeric"
|
||||
],
|
||||
[
|
||||
"salesman_id",
|
||||
"integer"
|
||||
],
|
||||
[
|
||||
"currency_id",
|
||||
"integer"
|
||||
],
|
||||
[
|
||||
"company_id",
|
||||
"integer"
|
||||
],
|
||||
[
|
||||
"order_partner_id",
|
||||
"integer"
|
||||
],
|
||||
[
|
||||
"is_expense",
|
||||
"boolean"
|
||||
],
|
||||
[
|
||||
"is_downpayment",
|
||||
"boolean"
|
||||
],
|
||||
[
|
||||
"state",
|
||||
"character varying"
|
||||
],
|
||||
[
|
||||
"customer_lead",
|
||||
"double precision"
|
||||
],
|
||||
[
|
||||
"display_type",
|
||||
"character varying"
|
||||
],
|
||||
[
|
||||
"create_uid",
|
||||
"integer"
|
||||
],
|
||||
[
|
||||
"create_date",
|
||||
"timestamp without time zone"
|
||||
],
|
||||
[
|
||||
"write_uid",
|
||||
"integer"
|
||||
],
|
||||
[
|
||||
"write_date",
|
||||
"timestamp without time zone"
|
||||
],
|
||||
[
|
||||
"analytic_distribution",
|
||||
"jsonb"
|
||||
],
|
||||
[
|
||||
"analytic_line_ids",
|
||||
"integer"
|
||||
],
|
||||
[
|
||||
"is_service",
|
||||
"boolean"
|
||||
],
|
||||
[
|
||||
"sale_order_option_ids",
|
||||
"integer"
|
||||
],
|
||||
[
|
||||
"linked_line_id",
|
||||
"integer"
|
||||
],
|
||||
[
|
||||
"product_packaging_id",
|
||||
"integer"
|
||||
],
|
||||
[
|
||||
"product_packaging_qty",
|
||||
"numeric"
|
||||
],
|
||||
[
|
||||
"product_packaging_description",
|
||||
"text"
|
||||
]
|
||||
],
|
||||
"product_template": [
|
||||
[
|
||||
"id",
|
||||
"integer"
|
||||
],
|
||||
[
|
||||
"message_main_attachment_id",
|
||||
"integer"
|
||||
],
|
||||
[
|
||||
"sequence",
|
||||
"integer"
|
||||
],
|
||||
[
|
||||
"name",
|
||||
"jsonb"
|
||||
],
|
||||
[
|
||||
"description",
|
||||
"jsonb"
|
||||
],
|
||||
[
|
||||
"description_purchase",
|
||||
"text"
|
||||
],
|
||||
[
|
||||
"description_sale",
|
||||
"jsonb"
|
||||
],
|
||||
[
|
||||
"type",
|
||||
"character varying"
|
||||
],
|
||||
[
|
||||
"categ_id",
|
||||
"integer"
|
||||
],
|
||||
[
|
||||
"currency_id",
|
||||
"integer"
|
||||
],
|
||||
[
|
||||
"cost_currency_id",
|
||||
"integer"
|
||||
],
|
||||
[
|
||||
"list_price",
|
||||
"numeric"
|
||||
],
|
||||
[
|
||||
"volume",
|
||||
"double precision"
|
||||
],
|
||||
[
|
||||
"weight",
|
||||
"double precision"
|
||||
],
|
||||
[
|
||||
"sale_ok",
|
||||
"boolean"
|
||||
],
|
||||
[
|
||||
"purchase_ok",
|
||||
"boolean"
|
||||
],
|
||||
[
|
||||
"uom_id",
|
||||
"integer"
|
||||
],
|
||||
[
|
||||
"uom_po_id",
|
||||
"integer"
|
||||
],
|
||||
[
|
||||
"company_id",
|
||||
"integer"
|
||||
],
|
||||
[
|
||||
"active",
|
||||
"boolean"
|
||||
],
|
||||
[
|
||||
"color",
|
||||
"integer"
|
||||
],
|
||||
[
|
||||
"default_code",
|
||||
"character varying"
|
||||
],
|
||||
[
|
||||
"can_image_1024_be_zoomed",
|
||||
"boolean"
|
||||
],
|
||||
[
|
||||
"create_uid",
|
||||
"integer"
|
||||
],
|
||||
[
|
||||
"create_date",
|
||||
"timestamp without time zone"
|
||||
],
|
||||
[
|
||||
"write_uid",
|
||||
"integer"
|
||||
],
|
||||
[
|
||||
"write_date",
|
||||
"timestamp without time zone"
|
||||
],
|
||||
[
|
||||
"service_type",
|
||||
"character varying"
|
||||
],
|
||||
[
|
||||
"sale_line_warn",
|
||||
"character varying"
|
||||
],
|
||||
[
|
||||
"sale_line_warn_msg",
|
||||
"text"
|
||||
],
|
||||
[
|
||||
"expense_policy",
|
||||
"character varying"
|
||||
],
|
||||
[
|
||||
"visible_expense_policy",
|
||||
"boolean"
|
||||
],
|
||||
[
|
||||
"invoice_policy",
|
||||
"character varying"
|
||||
],
|
||||
[
|
||||
"sale_delay",
|
||||
"double precision"
|
||||
],
|
||||
[
|
||||
"tracking",
|
||||
"character varying"
|
||||
],
|
||||
[
|
||||
"description_picking",
|
||||
"text"
|
||||
],
|
||||
[
|
||||
"description_pickingout",
|
||||
"text"
|
||||
],
|
||||
[
|
||||
"description_pickingin",
|
||||
"text"
|
||||
],
|
||||
[
|
||||
"responsible_id",
|
||||
"integer"
|
||||
],
|
||||
[
|
||||
"property_stock_production",
|
||||
"integer"
|
||||
],
|
||||
[
|
||||
"property_stock_inventory",
|
||||
"integer"
|
||||
],
|
||||
[
|
||||
"service_tracking",
|
||||
"character varying"
|
||||
],
|
||||
[
|
||||
"is_analysis",
|
||||
"boolean"
|
||||
],
|
||||
[
|
||||
"analysis_type",
|
||||
"character varying"
|
||||
],
|
||||
[
|
||||
"technical_specifications",
|
||||
"text"
|
||||
]
|
||||
],
|
||||
"product_product": [
|
||||
[
|
||||
"id",
|
||||
"integer"
|
||||
],
|
||||
[
|
||||
"message_main_attachment_id",
|
||||
"integer"
|
||||
],
|
||||
[
|
||||
"product_tmpl_id",
|
||||
"integer"
|
||||
],
|
||||
[
|
||||
"default_code",
|
||||
"character varying"
|
||||
],
|
||||
[
|
||||
"barcode",
|
||||
"character varying"
|
||||
],
|
||||
[
|
||||
"combination_indices",
|
||||
"character varying"
|
||||
],
|
||||
[
|
||||
"volume",
|
||||
"double precision"
|
||||
],
|
||||
[
|
||||
"weight",
|
||||
"double precision"
|
||||
],
|
||||
[
|
||||
"active",
|
||||
"boolean"
|
||||
],
|
||||
[
|
||||
"can_be_expensed",
|
||||
"boolean"
|
||||
],
|
||||
[
|
||||
"create_uid",
|
||||
"integer"
|
||||
],
|
||||
[
|
||||
"create_date",
|
||||
"timestamp without time zone"
|
||||
],
|
||||
[
|
||||
"write_uid",
|
||||
"integer"
|
||||
],
|
||||
[
|
||||
"write_date",
|
||||
"timestamp without time zone"
|
||||
],
|
||||
[
|
||||
"lst_price",
|
||||
"numeric"
|
||||
],
|
||||
[
|
||||
"standard_price",
|
||||
"numeric"
|
||||
],
|
||||
[
|
||||
"property_stock_production",
|
||||
"integer"
|
||||
],
|
||||
[
|
||||
"property_stock_inventory",
|
||||
"integer"
|
||||
]
|
||||
]
|
||||
}
|
21
get_metadata.py
Normal file
21
get_metadata.py
Normal file
|
@ -0,0 +1,21 @@
|
|||
import odoo
|
||||
import json
|
||||
|
||||
def get_table_metadata(cr, table_name):
|
||||
cr.execute("""
|
||||
SELECT column_name, data_type
|
||||
FROM information_schema.columns
|
||||
WHERE table_name = %s
|
||||
""", (table_name,))
|
||||
return cr.fetchall()
|
||||
|
||||
if __name__ == '__main__':
|
||||
db_name = 'lims_demo'
|
||||
registry = odoo.registry(db_name)
|
||||
with registry.cursor() as cr:
|
||||
metadata = {}
|
||||
tables = ['sale_order', 'sale_order_line', 'product_template', 'product_product']
|
||||
for table in tables:
|
||||
metadata[table] = get_table_metadata(cr, table)
|
||||
|
||||
print(json.dumps(metadata, indent=4))
|
41
init_odoo.py
41
init_odoo.py
|
@ -58,7 +58,46 @@ try:
|
|||
sys.exit(result.returncode)
|
||||
|
||||
print("Inicialización de Odoo completada exitosamente.")
|
||||
sys.exit(0)
|
||||
|
||||
# --- Lógica para crear datos de demostración personalizados ---
|
||||
print("Creando solicitudes de laboratorio de demostración...")
|
||||
sys.stdout.flush()
|
||||
|
||||
with open("/app/create_lab_requests.py", "r") as f:
|
||||
script_content = f.read()
|
||||
|
||||
# Reutilizamos el entorno de Odoo para ejecutar un script
|
||||
create_requests_command = f"""
|
||||
odoo shell -c {ODOO_CONF} -d {DB_NAME} <<'EOF'
|
||||
{script_content}
|
||||
EOF
|
||||
"""
|
||||
|
||||
try:
|
||||
result = subprocess.run(
|
||||
create_requests_command,
|
||||
shell=True,
|
||||
capture_output=True,
|
||||
text=True,
|
||||
check=False
|
||||
)
|
||||
|
||||
print("--- Create Lab Requests stdout ---")
|
||||
print(result.stdout)
|
||||
print("--- Create Lab Requests stderr ---")
|
||||
print(result.stderr)
|
||||
sys.stdout.flush()
|
||||
|
||||
if result.returncode != 0:
|
||||
print(f"Fallo al crear las solicitudes de laboratorio con código de salida {result.returncode}")
|
||||
sys.exit(result.returncode)
|
||||
|
||||
print("Solicitudes de laboratorio de demostración creadas exitosamente.")
|
||||
sys.exit(0)
|
||||
|
||||
except Exception as e:
|
||||
print(f"Ocurrió un error inesperado al crear las solicitudes de laboratorio: {e}")
|
||||
sys.exit(1)
|
||||
|
||||
except FileNotFoundError:
|
||||
print("Error: El comando 'odoo' no se encontró. Asegúrate de que la imagen del contenedor es correcta y odoo está en el PATH.")
|
||||
|
|
|
@ -16,7 +16,7 @@
|
|||
'website': "https://gitea.grupoconsiti.com/luis_portillo/clinical_laboratory",
|
||||
'category': 'Industries',
|
||||
'version': '18.0.1.0.0',
|
||||
'depends': ['base', 'product'],
|
||||
'depends': ['base', 'product', 'sale'],
|
||||
'data': [
|
||||
'security/lims_security.xml',
|
||||
'security/ir.model.access.csv',
|
||||
|
@ -24,11 +24,12 @@
|
|||
'data/product_category.xml',
|
||||
'views/partner_views.xml',
|
||||
'views/analysis_views.xml',
|
||||
'views/sale_order_views.xml',
|
||||
'views/menus.xml',
|
||||
],
|
||||
'demo': [
|
||||
'demo/lims_demo.xml',
|
||||
'demo/analysis_demo.xml',
|
||||
'demo/z_lims_demo.xml',
|
||||
'demo/z_analysis_demo.xml',
|
||||
],
|
||||
'installable': True,
|
||||
'application': True,
|
||||
|
|
8
lims_management/data/sale_demo_cleanup.xml
Normal file
8
lims_management/data/sale_demo_cleanup.xml
Normal file
|
@ -0,0 +1,8 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<odoo>
|
||||
<data noupdate="1">
|
||||
<function model="sale.order" name="search" eval="[('name', 'in', ['S00001', 'S00002', 'S00003', 'S00004', 'S00005', 'S00006', 'S00007', 'S00008', 'S00009', 'S00010', 'S00011', 'S00012', 'S00013', 'S00014', 'S00015', 'S00016', 'S00017', 'S00018', 'S00019', 'S00020', 'S00021', 'S00022'])]"/>
|
||||
<function model="sale.order" name="action_cancel"/>
|
||||
<function model="sale.order" name="unlink"/>
|
||||
</data>
|
||||
</odoo>
|
|
@ -1,4 +1,5 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
from . import partner
|
||||
from . import product
|
||||
from . import analysis_range
|
||||
from . import analysis_range
|
||||
from . import sale_order
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
BIN
lims_management/models/__pycache__/sale_order.cpython-312.pyc
Normal file
BIN
lims_management/models/__pycache__/sale_order.cpython-312.pyc
Normal file
Binary file not shown.
19
lims_management/models/sale_order.py
Normal file
19
lims_management/models/sale_order.py
Normal file
|
@ -0,0 +1,19 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
from odoo import models, fields
|
||||
|
||||
class SaleOrder(models.Model):
|
||||
_inherit = 'sale.order'
|
||||
|
||||
is_lab_request = fields.Boolean(
|
||||
string="Is a Laboratory Request",
|
||||
default=False,
|
||||
copy=False,
|
||||
help="Technical field to identify if the sale order is a laboratory request."
|
||||
)
|
||||
|
||||
doctor_id = fields.Many2one(
|
||||
'res.partner',
|
||||
string="Referring Doctor",
|
||||
domain="[('is_doctor', '=', True)]",
|
||||
help="The doctor who referred the patient for this laboratory request."
|
||||
)
|
|
@ -1,2 +1,3 @@
|
|||
id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink
|
||||
access_lims_analysis_range_user,lims.analysis.range.user,model_lims_analysis_range,base.group_user,1,1,1,1
|
||||
access_sale_order_receptionist,sale.order.receptionist,sale.model_sale_order,group_lims_receptionist,1,1,1,0
|
||||
|
|
|
|
@ -53,6 +53,28 @@
|
|||
action="action_lims_doctor"
|
||||
sequence="30"/>
|
||||
|
||||
<!-- Acción de Ventana para Solicitudes de Laboratorio -->
|
||||
<record id="action_lims_lab_request" model="ir.actions.act_window">
|
||||
<field name="name">Solicitudes de Laboratorio</field>
|
||||
<field name="res_model">sale.order</field>
|
||||
<field name="view_mode">list,form</field>
|
||||
<field name="domain">[('is_lab_request', '=', True)]</field>
|
||||
<field name="context">{'default_is_lab_request': True}</field>
|
||||
<field name="help" type="html">
|
||||
<p class="o_view_nocontent_smiling_face">
|
||||
Crea una nueva solicitud de laboratorio
|
||||
</p>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<!-- Menú para Solicitudes de Laboratorio -->
|
||||
<menuitem
|
||||
id="lims_menu_lab_requests"
|
||||
name="Solicitudes de Laboratorio"
|
||||
parent="lims_menu_root"
|
||||
action="action_lims_lab_request"
|
||||
sequence="15"/>
|
||||
|
||||
<!-- Submenú de Configuración -->
|
||||
<menuitem
|
||||
id="lims_menu_config"
|
||||
|
|
36
lims_management/views/sale_order_views.xml
Normal file
36
lims_management/views/sale_order_views.xml
Normal file
|
@ -0,0 +1,36 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<odoo>
|
||||
<data>
|
||||
|
||||
<!-- Inherit Form View to Modify Sale Order for Lab Requests -->
|
||||
<record id="view_order_form_inherit_lims" model="ir.ui.view">
|
||||
<field name="name">sale.order.form.inherit.lims</field>
|
||||
<field name="model">sale.order</field>
|
||||
<field name="inherit_id" ref="sale.view_order_form"/>
|
||||
<field name="arch" type="xml">
|
||||
<xpath expr="//field[@name='partner_id']" position="after">
|
||||
<field name="doctor_id" invisible="not is_lab_request"/>
|
||||
</xpath>
|
||||
<xpath expr="//field[@name='partner_id']" position="attributes">
|
||||
<attribute name="string">Paciente</attribute>
|
||||
</xpath>
|
||||
<xpath expr="//field[@name='order_line']//field[@name='product_id']" position="attributes">
|
||||
<attribute name="domain">[('is_analysis', '=', True)]</attribute>
|
||||
</xpath>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<!-- Inherit List View to Add Referring Doctor -->
|
||||
<record id="view_order_tree_inherit_lims" model="ir.ui.view">
|
||||
<field name="name">sale.order.tree.inherit.lims</field>
|
||||
<field name="model">sale.order</field>
|
||||
<field name="inherit_id" ref="sale.view_order_tree"/>
|
||||
<field name="arch" type="xml">
|
||||
<xpath expr="//field[@name='partner_id']" position="after">
|
||||
<field name="doctor_id"/>
|
||||
</xpath>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
</data>
|
||||
</odoo>
|
30
verify_products.py
Normal file
30
verify_products.py
Normal file
|
@ -0,0 +1,30 @@
|
|||
import odoo
|
||||
import json
|
||||
|
||||
def verify_lab_order_products(cr):
|
||||
cr.execute("""
|
||||
SELECT
|
||||
so.name AS order_name,
|
||||
sol.id AS line_id,
|
||||
pt.name->>'en_US' AS product_name,
|
||||
pt.is_analysis
|
||||
FROM
|
||||
sale_order so
|
||||
JOIN
|
||||
sale_order_line sol ON so.id = sol.order_id
|
||||
JOIN
|
||||
product_product pp ON sol.product_id = pp.id
|
||||
JOIN
|
||||
product_template pt ON pp.product_tmpl_id = pt.id
|
||||
WHERE
|
||||
so.is_lab_request = TRUE;
|
||||
""")
|
||||
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))
|
Loading…
Reference in New Issue
Block a user