- README.md: reescrito con tabla completa de los 14 addons (6 OCA + 8 custom), versiones actuales, árbol de dependencias y comandos de desarrollo - docs/README.md: simplificado a índice limpio, eliminadas referencias rotas - website_sale_aplicoop/CHANGELOG.md: añadidas versiones 1.7.0, 1.8.0 y 1.9.0 con los cambios agrupados por temática desde el último registro (1.6.0) - website_sale_aplicoop/README_DEV.md: reescrito para reflejar v1.9.0 — modelos actuales (group.order.slot), controladores /eskaera, catálogo whitelist/blacklist, lazy loading, crons y árbol de dependencias Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
7.5 KiB
Website Sale - Aplicoop
Versión: 18.0.1.9.0 | Licencia: AGPL-3 | Autor: Criptomart SL
Sistema de pedidos colaborativos para grupos de consumo. Reemplaza el legacy Aplicoop con una solución moderna integrada en Odoo 18.
Resumen de funcionalidades
- Gestión completa de órdenes de grupo (draft → confirmed → collected → invoiced → completed)
- Carrito separado por grupo de consumo; tienda estándar de
website_saledeshabilitada - Control de catálogo por listas de inclusión (proveedores, categorías, productos) y exclusión (blacklists)
- Cron diario de auto-confirmación + creación automática de lotes de picking
- Paginación de productos (lazy loading) para cargas rápidas
- Soporte multilingüe: ES, EU, PT, GL, CA, FR, IT
- Restricción de acceso portal por grupo de consumo
Modelos
group.order
Orden de grupo central. Contiene toda la lógica de ciclo de vida.
Campos principales:
| Campo | Tipo | Descripción |
|---|---|---|
name |
Char | Identificador de la orden |
consumer_group_id |
Many2one → res.partner |
Grupo de consumo |
state |
Selection | draft / confirmed / collected / invoiced / completed / cancelled |
cutoff_date |
Datetime | Hasta cuándo se pueden añadir productos |
pickup_date |
Date | Día de recogida para los socios |
delivery_date |
Date | Fecha de entrega (almacenada, calculada por cron) |
product_ids |
Many2many | Productos incluidos directamente |
category_ids |
Many2many | Categorías incluidas (y sus subcategorías) |
supplier_ids |
Many2many | Proveedores incluidos (por main_seller_id) |
excluded_product_ids |
Many2many | Blacklist de productos |
excluded_supplier_ids |
Many2many | Blacklist de proveedores |
excluded_category_ids |
Many2many | Blacklist de categorías (recursiva) |
allow_home_delivery |
Boolean | Permite envío a domicilio además de recogida |
Métodos clave:
_get_products_for_group_order()— catálogo efectivo aplicando whitelist + blacklist_get_products_paginated(page, per_page)— paginación para lazy loading_cron_confirm_group_orders()— auto-confirma órdenes pasado el cutoff y crea lotes de picking_cron_update_dates()— recalcula fechas de entrega/recogida diariamente
group.order.slot (en desarrollo)
Franjas horarias de recogida para una orden de grupo.
| Campo | Tipo | Descripción |
|---|---|---|
group_order_id |
Many2one | Orden de grupo |
weekday |
Selection (0–6) | Día de la semana (0 = lunes) |
start_hour / end_hour |
Float | Horario en formato decimal (9.5 = 09:30) |
sequence |
Integer | Orden de visualización |
Extensiones de modelos core
product.template
main_seller_id— proveedor principal (deproduct_main_seller)sequenceenproduct.category— orden de visualización en la tienda web
sale.order
group_order_id— enlace a la orden de grupoconsumer_group_id— propagado desdegroup_order_idpickup_slot_label— etiqueta legible de la franja de recogida
stock.picking
- Extensión para agrupación por grupo de consumo en lotes de picking
Controladores
Todos los endpoints viven bajo /eskaera/:
| Ruta | Descripción |
|---|---|
GET /eskaera |
Lista de órdenes de grupo activas del usuario |
GET /eskaera/<order_id> |
Tienda de la orden (con lazy loading) |
GET /eskaera/<order_id>/load-page?page=N |
Carga AJAX de página de productos |
POST /eskaera/<order_id>/add |
Añadir producto al carrito |
POST /eskaera/<order_id>/confirm |
Confirmar carrito (sale.order en draft) |
POST /eskaera/clear-cart |
Limpiar carrito actual |
Las rutas /cart y /shop de website_sale están redirigidas a /eskaera.
Seguridad portal: los usuarios solo ven órdenes de su consumer_group_id. La regla rule_group_order_company_read incluye guardia user.share.
Templates QWeb
| Template | Descripción |
|---|---|
eskaera_list |
Lista de órdenes activas |
eskaera_shop |
Página de la tienda (incluye eskaera_shop_products) |
eskaera_shop_products |
Grid de productos (reutilizable por lazy loading + initial render) |
eskaera_cart |
Sidebar del carrito |
eskaera_checkout |
Confirmación del pedido |
load_from_history |
Cargar productos de una orden histórica |
JavaScript (website_sale.js)
Clase GroupOrderShop (extiende publicWidget.Widget):
_attachEventListeners()— inicializa todos los listeners_attachLoadMoreListener()— botón "Cargar más" para lazy loading (AJAX)_onAddToCart()— añadir al carrito con feedback visual_onClearCart()— limpiar carrito_onDeliveryToggle()— toggle envío a domicilio / recogida
Control del catálogo
La lógica en _get_products_for_group_order() aplica en este orden:
- Whitelist: unión de
product_ids+ productos decategory_ids(recursivo) + productos desupplier_ids(pormain_seller_id) - Blacklist: se restan
excluded_product_ids, productos conmain_seller_idenexcluded_supplier_ids, y productos enexcluded_category_ids(recursivo) - La blacklist tiene prioridad absoluta sobre cualquier fuente de inclusión
Lazy loading
Configurable desde Ajustes > Website > Shop:
website_sale_aplicoop.lazy_loading_enabled(default:True)website_sale_aplicoop.products_per_page(default:20)
La página inicial renderiza la primera página server-side. El botón "Cargar más" hace peticiones AJAX al endpoint /load-page que devuelve HTML parcial con el template eskaera_shop_products.
Cron jobs
| Cron | Frecuencia | Acción |
|---|---|---|
_cron_confirm_group_orders |
Diario (medianoche) | Confirma sale.orders pasado el cutoff; crea lotes de picking agrupados por consumer_group + pickup_date |
_cron_update_dates |
Diario | Recalcula delivery_date y pickup_date en órdenes activas |
Dependencias
website_sale_aplicoop
├── website_sale (Odoo core)
├── sale (Odoo core)
├── product_main_seller (OCA)
├── product_sale_price_from_pricelist (custom)
│ └── product_pricelist_total_margin (custom)
│ └── product_price_category (OCA)
└── stock_picking_batch_custom (custom)
Instalación y actualización
docker-compose exec -T odoo odoo -d odoo -u website_sale_aplicoop --stop-after-init
Para migraciones con cambios de esquema (e.g., nuevas columnas):
docker-compose exec -T odoo odoo -d odoo --update website_sale_aplicoop --stop-after-init
Tests
docker-compose exec -T odoo odoo -d odoo --test-enable --stop-after-init -u website_sale_aplicoop
Los tests están en tests/:
test_group_order.py— ciclo de vida básico, fechas, crontest_product_discovery.py— whitelist/blacklist (productos, proveedores, categorías)test_confirm_eskaera.py— integración: confirmación de carrito y generación de sale.order
Traducciones
# Exportar .pot
docker-compose exec -T odoo odoo -d odoo \
-i website_sale_aplicoop \
--i18n-export=/tmp/website_sale_aplicoop.pot \
--stop-after-init
# Actualizar .po existentes
cd website_sale_aplicoop/i18n
for lang in es eu; do
msgmerge -U ${lang}.po ../website_sale_aplicoop.pot
done
Ver docs/TRANSLATIONS.md para convenciones.
Repositorio
- Repo: https://git.criptomart.net/criptomart/addons-cm
- Changelog: CHANGELOG.md