El método _get_price() del addon OCA ya maneja correctamente los impuestos según la configuración de Odoo. El cálculo adicional con compute_all() estaba duplicando los impuestos cuando price_include estaba activado. Cambios: - Eliminado método _compute_price_with_taxes() - Revertido eskaera_shop() para usar directamente _get_price() - Revertido add_to_eskaera_cart() para usar directamente _get_price() El precio mostrado ahora respeta la configuración de impuestos de Odoo sin duplicación.
175 lines
5.2 KiB
Markdown
175 lines
5.2 KiB
Markdown
# Resumen de Corrección: Precios sin IVA en Tienda Online
|
|
|
|
## Problema Identificado
|
|
La tienda online de Aplicoop mostraba precios **sin impuestos incluidos** cuando debería mostrar precios con IVA.
|
|
|
|
## Causa Raíz
|
|
El método `_get_price()` del addon OCA `product_get_price_helper` retorna el precio base **sin impuestos** por defecto. El campo `tax_included` solo indica si el producto tiene impuestos con `price_include=True`, pero no calcula automáticamente el precio con impuestos añadidos.
|
|
|
|
## Solución Implementada
|
|
|
|
### 1. Nuevo Método: `_compute_price_with_taxes()`
|
|
**Archivo**: `website_sale_aplicoop/controllers/website_sale.py`
|
|
|
|
```python
|
|
def _compute_price_with_taxes(self, product_variant, base_price, pricelist=None, fposition=None):
|
|
"""
|
|
Calcula el precio con impuestos incluidos.
|
|
|
|
Args:
|
|
product_variant: product.product recordset
|
|
base_price: float - precio base sin impuestos
|
|
pricelist: product.pricelist recordset (opcional)
|
|
fposition: account.fiscal.position recordset (opcional)
|
|
|
|
Returns:
|
|
float - precio con impuestos incluidos
|
|
"""
|
|
# 1. Obtener impuestos del producto
|
|
taxes = product_variant.taxes_id.filtered(
|
|
lambda tax: tax.company_id == request.env.company
|
|
)
|
|
|
|
# 2. Aplicar posición fiscal si existe
|
|
if fposition:
|
|
taxes = fposition.map_tax(taxes)
|
|
|
|
# 3. Si no hay impuestos, retornar precio base
|
|
if not taxes:
|
|
return base_price
|
|
|
|
# 4. Calcular impuestos usando compute_all()
|
|
tax_result = taxes.compute_all(
|
|
base_price,
|
|
currency=pricelist.currency_id if pricelist else request.env.company.currency_id,
|
|
quantity=1.0,
|
|
product=product_variant,
|
|
)
|
|
|
|
# 5. Retornar precio CON impuestos incluidos
|
|
return tax_result['total_included']
|
|
```
|
|
|
|
### 2. Actualización en `eskaera_shop()`
|
|
El método que muestra la lista de productos ahora calcula precios con IVA:
|
|
|
|
**ANTES:**
|
|
```python
|
|
price = price_info.get('value', 0.0) # Sin impuestos
|
|
product_price_info[product.id] = {
|
|
'price': price, # ❌ Sin IVA
|
|
'tax_included': price_info.get('tax_included', True),
|
|
}
|
|
```
|
|
|
|
**DESPUÉS:**
|
|
```python
|
|
base_price = price_info.get('value', 0.0) # Precio base sin impuestos
|
|
|
|
# Calcular precio CON impuestos
|
|
price_with_taxes = self._compute_price_with_taxes(
|
|
product_variant,
|
|
base_price,
|
|
pricelist,
|
|
request.website.fiscal_position_id
|
|
)
|
|
|
|
product_price_info[product.id] = {
|
|
'price': price_with_taxes, # ✓ CON IVA incluido
|
|
'tax_included': True, # Ahora siempre True
|
|
}
|
|
```
|
|
|
|
### 3. Actualización en `add_to_eskaera_cart()`
|
|
El método que añade productos al carrito también calcula con IVA:
|
|
|
|
**ANTES:**
|
|
```python
|
|
price_with_tax = price_info.get('value', product.list_price) # ❌ Sin IVA
|
|
```
|
|
|
|
**DESPUÉS:**
|
|
```python
|
|
base_price = price_info.get('value', product.list_price)
|
|
|
|
# Calcular precio CON impuestos
|
|
price_with_tax = self._compute_price_with_taxes(
|
|
product_variant,
|
|
base_price,
|
|
pricelist,
|
|
request.website.fiscal_position_id
|
|
) # ✓ CON IVA incluido
|
|
```
|
|
|
|
## Ejemplo Práctico
|
|
|
|
### Producto con IVA 21%
|
|
- **Precio base**: 100.00 €
|
|
- **IVA (21%)**: 21.00 €
|
|
- **Precio mostrado**: **121.00 €** ✓
|
|
|
|
### Producto con IVA 10%
|
|
- **Precio base**: 100.00 €
|
|
- **IVA (10%)**: 10.00 €
|
|
- **Precio mostrado**: **110.00 €** ✓
|
|
|
|
### Producto sin IVA
|
|
- **Precio base**: 100.00 €
|
|
- **IVA**: 0.00 €
|
|
- **Precio mostrado**: **100.00 €** ✓
|
|
|
|
## Tests Creados
|
|
|
|
### Archivo: `test_price_with_taxes_included.py`
|
|
Contiene tests unitarios que verifican:
|
|
|
|
1. ✓ Cálculo correcto de IVA 21%
|
|
2. ✓ Cálculo correcto de IVA 10%
|
|
3. ✓ Productos sin IVA
|
|
4. ✓ Múltiples impuestos
|
|
5. ✓ Posiciones fiscales
|
|
6. ✓ Precios con alta precisión
|
|
7. ✓ Comportamiento de OCA `_get_price()`
|
|
|
|
## Archivos Modificados
|
|
|
|
1. **`website_sale_aplicoop/controllers/website_sale.py`**
|
|
- Añadido método `_compute_price_with_taxes()`
|
|
- Actualizado `eskaera_shop()` para usar precios con IVA
|
|
- Actualizado `add_to_eskaera_cart()` para usar precios con IVA
|
|
|
|
2. **`website_sale_aplicoop/tests/test_price_with_taxes_included.py`** (nuevo)
|
|
- 13 tests para verificar cálculos de impuestos
|
|
|
|
## Validación
|
|
|
|
Para verificar la corrección en producción:
|
|
|
|
```bash
|
|
# 1. Reiniciar Odoo
|
|
docker-compose restart odoo
|
|
|
|
# 2. Actualizar el módulo
|
|
docker-compose exec odoo odoo -c /etc/odoo/odoo.conf -d odoo -u website_sale_aplicoop --stop-after-init
|
|
|
|
# 3. Verificar en navegador
|
|
# Ir a: http://localhost:8069/eskaera
|
|
# Los precios ahora deberían mostrar IVA incluido
|
|
```
|
|
|
|
## Beneficios
|
|
|
|
✅ **Transparencia**: Los usuarios ven el precio final que pagarán
|
|
✅ **Cumplimiento legal**: Obligatorio mostrar precios con IVA en B2C
|
|
✅ **Consistencia**: Todos los precios mostrados incluyen impuestos
|
|
✅ **Mantenibilidad**: Código limpio y documentado
|
|
✅ **Testeable**: Tests unitarios comprueban el funcionamiento
|
|
|
|
## Notas Técnicas
|
|
|
|
- El método utiliza `taxes.compute_all()` de Odoo, que es el estándar para calcular impuestos
|
|
- Respeta las posiciones fiscales configuradas
|
|
- Compatible con múltiples impuestos por producto
|
|
- Maneja correctamente productos sin impuestos
|
|
- El precio base (sin IVA) se usa internamente para cálculos de descuentos
|
|
- El precio final (con IVA) se muestra al usuario
|