feat(#60): Agregar visualización de re-muestras en órdenes de laboratorio

- Agregar campo computed all_sample_ids que incluye re-muestras
- Método recursivo para obtener todas las re-muestras
- Mejorar vista de orden con pestaña unificada de muestras
- Mostrar indicador de re-muestra y muestra original
- Incluir estado y motivo de rechazo en la vista

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

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
Luis Ernesto Portillo Zaldivar 2025-07-16 08:38:14 -06:00
parent 1e079a896b
commit b225fa0815
3 changed files with 55 additions and 14 deletions

View File

@ -33,6 +33,31 @@ class SaleOrder(models.Model):
help="Muestras de laboratorio generadas automáticamente cuando se confirmó esta orden"
)
all_sample_ids = fields.Many2many(
'stock.lot',
string='Todas las Muestras (inc. Re-muestras)',
compute='_compute_all_samples',
help="Todas las muestras relacionadas con esta orden, incluyendo re-muestras"
)
@api.depends('generated_sample_ids', 'generated_sample_ids.child_sample_ids')
def _compute_all_samples(self):
"""Compute all samples including resamples"""
for order in self:
all_samples = order.generated_sample_ids
# Add all resamples recursively
resamples = self.env['stock.lot']
for sample in order.generated_sample_ids:
resamples |= self._get_all_resamples(sample)
order.all_sample_ids = all_samples | resamples
def _get_all_resamples(self, sample):
"""Recursively get all resamples of a sample"""
resamples = sample.child_sample_ids
for resample in sample.child_sample_ids:
resamples |= self._get_all_resamples(resample)
return resamples
def action_confirm(self):
"""Override to generate laboratory samples and tests automatically"""
res = super(SaleOrder, self).action_confirm()

View File

@ -29,26 +29,42 @@
</xpath>
<!-- Add Generated Samples tab -->
<xpath expr="//notebook" position="inside">
<page string="Muestras Generadas" name="generated_samples" invisible="not is_lab_request">
<group>
<field name="generated_sample_ids" nolabel="1" readonly="1">
<list string="Muestras Generadas" create="false" edit="false" delete="false">
<page string="Muestras" name="all_samples" invisible="not is_lab_request">
<group string="Todas las Muestras (incluyendo Re-muestras)">
<field name="all_sample_ids" nolabel="1" readonly="1">
<list string="Todas las Muestras" create="false" edit="false" delete="false">
<field name="name" string="Código de Muestra"/>
<field name="barcode" string="Código de Barras"/>
<field name="barcode" string="Código de Barras" optional="show"/>
<field name="sample_type_product_id" string="Tipo de Muestra"/>
<field name="volume_ml" string="Volumen (ml)"/>
<field name="analysis_names" string="Análisis"/>
<field name="state" string="Estado"/>
<field name="volume_ml" string="Volumen (ml)" optional="show"/>
<field name="analysis_names" string="Análisis" optional="show"/>
<field name="is_resample" string="Es Re-muestra" widget="boolean_toggle"/>
<field name="parent_sample_id" string="Muestra Original" optional="show"/>
<field name="state" string="Estado" widget="badge"
decoration-success="state == 'analyzed'"
decoration-info="state == 'in_process'"
decoration-danger="state == 'rejected'"
decoration-warning="state == 'pending_collection'"/>
<field name="rejection_reason_id" string="Motivo Rechazo" optional="show"/>
<button name="action_collect" string="Recolectar" type="object"
class="btn-primary" invisible="state != 'pending_collection'"/>
class="btn-sm btn-primary" invisible="state != 'pending_collection'"/>
</list>
</field>
</group>
<group invisible="not generated_sample_ids">
<div class="alert alert-info" role="alert">
<p>Las muestras han sido generadas automáticamente basándose en los análisis solicitados.
Cada muestra agrupa los análisis que requieren el mismo tipo de contenedor.</p>
</div>
<group string="Resumen" col="4">
<field name="generated_sample_ids" invisible="1"/>
<group>
<label for="generated_sample_ids" string="Muestras Originales:"/>
<div>
<span class="badge badge-primary"><field name="generated_sample_ids" readonly="1" widget="many2many_tags"/></span>
</div>
</group>
<group>
<div class="alert alert-info" role="alert">
<p><i class="fa fa-info-circle"/> Las muestras han sido generadas automáticamente basándose en los análisis solicitados.</p>
<p>Las re-muestras se generan cuando una muestra es rechazada.</p>
</div>
</group>
</group>
</page>
</xpath>