diff --git a/README.md b/README.md index 8dbf2e0..cb91d3e 100644 --- a/README.md +++ b/README.md @@ -1,81 +1,10 @@ -# Odoo Addons — Criptomart +# Oddo Addons Criptomart -Colección de addons Odoo 18.0 para Criptomart / Elika Bilbo. Incluye addons OCA incluidos como dependencias y addons custom desarrollados internamente. +## Addons -## Addons OCA (dependencias incluidas) - -Addons del ecosistema [OCA](https://github.com/OCA) incorporados al repositorio. No se modifican salvo hotfixes puntuales. - -| Addon | Versión | Descripción | -| ----- | ------- | ----------- | -| [account_invoice_triple_discount](account_invoice_triple_discount/) | 18.0.1.0.0 | Triple descuento en líneas de factura | -| [product_get_price_helper](product_get_price_helper/) | 18.0.1.1.0 | Helper para obtener precios de producto respetando tarifas | -| [product_main_seller](product_main_seller/) | 18.0.1.0.0 | Campo "proveedor principal" en producto | -| [product_origin_char](product_origin_char/) | 18.0.2.0.0 | Campo de texto libre para origen del producto | -| [product_price_category](product_price_category/) | 18.0.1.0.0 | Categoría de precio en producto + aplicación masiva vía tarifas | -| [purchase_triple_discount](purchase_triple_discount/) | 18.0.1.0.0 | Triple descuento en líneas de pedido de compra | - -## Addons Custom - -Addons desarrollados por Criptomart para necesidades específicas del proyecto. - -| Addon | Versión | Descripción | -| ----- | ------- | ----------- | -| [account_invoice_triple_discount_readonly](account_invoice_triple_discount_readonly/) | 18.0.1.0.0 | Corrige bug de acumulación de descuentos y pone descuento total en solo lectura | -| [membership_expiry_reminder](membership_expiry_reminder/) | 18.0.1.0.0 | Recordatorio por email de membresías próximas a vencer | -| [portal_event_registration](portal_event_registration/) | 18.0.1.0.0 | Vista portal de inscripciones a eventos con adjuntos al chatter | -| [product_price_category_supplier](product_price_category_supplier/) | 18.0.1.0.0 | Categoría de precio por defecto en proveedor + actualización masiva de productos | -| [product_pricelist_total_margin](product_pricelist_total_margin/) | 18.0.1.2.0 | Margen aditivo (no compuesto) en tarifas encadenadas, con límites globales | -| [product_sale_price_from_pricelist](product_sale_price_from_pricelist/) | 18.0.2.7.0 | Calcula precio de venta desde último precio de compra vía tarifa configurable | -| [stock_picking_batch_custom](stock_picking_batch_custom/) | 18.0.1.0.0 | Columnas extra en operaciones detalladas de lotes: partner, categoría, recogido | -| [website_sale_aplicoop](website_sale_aplicoop/) | 18.0.1.9.0 | Sistema de pedidos colaborativos para grupos de consumo (reemplazo de Aplicoop) | - -## Dependencias entre addons custom - -```text -website_sale_aplicoop - └── product_sale_price_from_pricelist - └── product_pricelist_total_margin - └── product_price_category - └── product_main_seller - └── product_price_category_supplier - └── product_price_category - -account_invoice_triple_discount_readonly - └── account_invoice_triple_discount - └── purchase_triple_discount -``` - -## Desarrollo - -### Instalación / actualización de un addon - -```bash -docker-compose exec -T odoo odoo -d odoo -u --stop-after-init -``` - -### Tests - -```bash -docker-compose exec -T odoo odoo -d odoo --test-enable --stop-after-init -u -``` - -### Linters - -```bash -# Python -black . && isort . && flake8 . && pylint --load-plugins=pylint_odoo / - -# JS -npx eslint /static/src/ -``` - -Ver [docs/LINTERS_README.md](docs/LINTERS_README.md) para configuración completa. - -### Traducciones - -Ver [docs/TRANSLATIONS.md](docs/TRANSLATIONS.md). - -## Documentación técnica - -Ver carpeta [docs/](docs/) para documentación transversal (instalación, lazy loading, QWeb, etc.). +| Addon | Propósito | Estado | +|-------|-----------|--------| +| [account_invoice_triple_discount_readonly](account_invoice_triple_discount_readonly/) | Fix para bug de descuentos acumulados | Alpha | +| [product_price_category_supplier](product_price_category_supplier/) | Gestión de categorías por proveedor | Alpha | +| [product_sale_price_from_pricelist](product_sale_price_from_pricelist/) | Auto-cálculo precio venta desde compra | Alpha | +| [website_sale_aplicoop](website_sale_aplicoop/) | Sistema completo de pedidos para grupos de consumo | Alpha | diff --git a/docs/README.md b/docs/README.md index cc60c1f..9faa4dc 100644 --- a/docs/README.md +++ b/docs/README.md @@ -1,28 +1,57 @@ # Documentación Técnica -Documentación transversal del proyecto (no específica de un addon individual). +Esta carpeta contiene documentación técnica y de referencia del proyecto. -## Configuración y desarrollo +## Contenido -- [LINTERS_README.md](LINTERS_README.md) — Configuración de herramientas de calidad: black, isort, flake8, pylint, eslint -- [TRANSLATIONS.md](TRANSLATIONS.md) — Guía completa del sistema de traducciones (i18n/l10n) -- [QWEB_BEST_PRACTICES.md](QWEB_BEST_PRACTICES.md) — Buenas prácticas para templates QWeb (evitar errores comunes) -- [OCA_DOCUMENTATION.md](OCA_DOCUMENTATION.md) — Notas sobre integración con el ecosistema OCA +### � Cambios Recientes -## Instalación +- **[RECENT_CHANGES.md](RECENT_CHANGES.md)** - 🆕 Resumen de todos los cambios recientes (Feb 2026) -- [INSTALACION_COMPLETA.md](INSTALACION_COMPLETA.md) — Proceso completo de instalación con Docker -- [RESUMEN_INSTALACION.md](RESUMEN_INSTALACION.md) — Resumen ejecutivo de instalación +### �🚀 Performance & Features (Nuevas) -## website_sale_aplicoop +- **[LAZY_LOADING_QUICK_START.md](LAZY_LOADING_QUICK_START.md)** - ⚡ Guía rápida (5 min) si solo necesitas lo esencial +- **[LAZY_LOADING_DOCS_INDEX.md](LAZY_LOADING_DOCS_INDEX.md)** - Índice centralizado de documentación de lazy loading (v18.0.1.3.0) +- **[LAZY_LOADING.md](LAZY_LOADING.md)** - Documentación técnica completa de lazy loading en website_sale_aplicoop +- **[UPGRADE_INSTRUCTIONS_v18.0.1.3.0.md](UPGRADE_INSTRUCTIONS_v18.0.1.3.0.md)** - Guía de actualización e instalación de lazy loading -- [LAZY_LOADING.md](LAZY_LOADING.md) — Documentación técnica completa de paginación de productos -- [UPGRADE_INSTRUCTIONS_v18.0.1.3.0.md](UPGRADE_INSTRUCTIONS_v18.0.1.3.0.md) — Instrucciones de upgrade para la versión con lazy loading -- [CORRECCION_PRECIOS_IVA.md](CORRECCION_PRECIOS_IVA.md) — Correcciones de precios con IVA -- [TEST_MANUAL.md](TEST_MANUAL.md) — Guía de pruebas manuales +### Configuración y Desarrollo -## Documentación principal +- **[LINTERS_README.md](LINTERS_README.md)** - Guía de herramientas de calidad de código (black, isort, flake8, pylint) +- **[TRANSLATIONS.md](TRANSLATIONS.md)** - Guía completa del sistema de traducciones (IMPORTANTE) +- **[INSTALACION_COMPLETA.md](INSTALACION_COMPLETA.md)** - Documentación detallada del proceso de instalación +- **[RESUMEN_INSTALACION.md](RESUMEN_INSTALACION.md)** - Resumen ejecutivo de la instalación -- [README.md](../README.md) — Tabla de todos los addons con versiones y descripción -- [website_sale_aplicoop/README_DEV.md](../website_sale_aplicoop/README_DEV.md) — Documentación técnica del addon principal -- [website_sale_aplicoop/CHANGELOG.md](../website_sale_aplicoop/CHANGELOG.md) — Historial de cambios completo +### Resolución de Problemas + +- **[FINAL_SOLUTION_SUMMARY.md](FINAL_SOLUTION_SUMMARY.md)** - Solución definitiva para errores de templates QWeb en website_sale_aplicoop +- **[FIX_TEMPLATE_ERROR_SUMMARY.md](FIX_TEMPLATE_ERROR_SUMMARY.md)** - Resumen de correcciones de templates +- **[QWEB_BEST_PRACTICES.md](QWEB_BEST_PRACTICES.md)** - Mejores prácticas para templates QWeb (CRÍTICO) +- **[TEMPLATE_FIX_INDEX.md](TEMPLATE_FIX_INDEX.md)** - Índice de documentación de fixes de templates +- **[CORRECCION_PRECIOS_IVA.md](CORRECCION_PRECIOS_IVA.md)** - Correcciones relacionadas con precios e IVA +- **[TEST_MANUAL.md](TEST_MANUAL.md)** - Guía de tests manuales + +## Documentación Principal + +Para información general del proyecto y cómo empezar, ver: + +- **[README.md](../README.md)** - Documentación principal del repositorio +- **[.github/copilot-instructions.md](../.github/copilot-instructions.md)** - Instrucciones para GitHub Copilot + +## Documentación por Addon + +Cada addon tiene su propio README: + +### Addons Custom +- [account_invoice_triple_discount_readonly](../account_invoice_triple_discount_readonly/README.md) +- [product_price_category_supplier](../product_price_category_supplier/README.md) +- [product_sale_price_from_pricelist](../product_sale_price_from_pricelist/README.md) +- [website_sale_aplicoop](../website_sale_aplicoop/README.md) + +### Addons OCA Modificados +- [account_invoice_triple_discount](../account_invoice_triple_discount/README.rst) +- [purchase_triple_discount](../purchase_triple_discount/README.rst) +- [product_origin](../product_origin/README.md) +- [product_get_price_helper](../product_get_price_helper/README.md) +- [product_main_seller](../product_main_seller/README.md) +- [product_price_category](../product_price_category/README.rst) diff --git a/website_sale_aplicoop/CHANGELOG.md b/website_sale_aplicoop/CHANGELOG.md index 1eaa993..d4d5f44 100644 --- a/website_sale_aplicoop/CHANGELOG.md +++ b/website_sale_aplicoop/CHANGELOG.md @@ -1,70 +1,5 @@ # Changelog - Website Sale Aplicoop -## [18.0.1.9.0] - 2026-05-20 - -### Added - -- **Category sequence**: New `sequence` field on `product.category` for controlling product display order on the web shop. Migration adds the column with default 10. -- **Stock availability check on history orders**: When loading a historical order, products are validated against current stock (`virtual_available`). Out-of-stock items are flagged before adding to cart. - -### Changed - -- **Cart disabled / redirected to /eskaera**: Standard `website_sale` cart is fully hidden — header cart icon removed, add-to-cart buttons removed from standard shop, `/cart` and `/shop` routes redirect to `/eskaera`. Customers interact exclusively through the group order flow. -- **Product card UI overhaul**: Improved responsive layout, placeholder image for products without photo, better accessibility markup, and professional styling for mobile. -- **Stock check uses `virtual_available`**: Replaces `qty_available` so forecasted quantity (including incoming moves) is considered. - -### Fixed - -- Lint fixes: exception chaining (`raise ... from exc`), unused imports/vars, `disable attribute-string-redundant` annotations. - ---- - -## [18.0.1.8.0] - 2026-04-08 - -### Added - -- **Clear cart button**: New button in the sidebar to empty the current group order cart in one click (`eskaera_clear_cart` route). - -### Changed - -- **Portal access restricted to consumer group**: Portal users can only see group orders belonging to their consumer group. Security rule `rule_group_order_company_read` updated with `user.share` guard. -- **Controller filtering by consumer group**: `eskaera_list` and `eskaera_shop` routes filter orders by the logged-in user's consumer group, not just by company. - -### Fixed - -- Stale cart invalidation: carts linked to closed/cancelled group orders are cleared on next access. -- Home delivery draft flow: fixed state transition for home delivery orders. -- Auto-confirm `sale.order` on cutoff day: fixed off-by-one (`>` vs `>=`) in cutoff guard so orders on the cutoff day are correctly confirmed. -- Pickup dates frozen after cron confirm: cron no longer overwrites pickup dates on already-confirmed orders. -- Cron hardened against missing/invalid group order configurations. -- Cart layout: moved cart sidebar before product grid. -- i18n: added missing ES/EU translations for checkout, cart labels, Save Draft button, and weekday strings. Removed legacy `week_draft` translation keys. - ---- - -## [18.0.1.7.0] - 2026-03-06 - -### Added - -- **Automatic batch picking creation**: After the cutoff cron confirms sale orders, picking batches are automatically created grouped by consumer group and pickup date. -- **Consumer group propagation**: `consumer_group_id` is now propagated directly from the `group.order` to linked `sale.order` records, eliminating manual assignment. -- **Out-of-stock blocking**: Add-to-cart button is hard-disabled for out-of-stock products. `allow_out_of_stock_order` flag on product is respected. - -### Changed - -- **Cron auto-confirm sale orders**: Daily cron (`_cron_confirm_group_orders`) now confirms linked sale orders on the cutoff date instead of requiring manual action. -- **Order card meta extracted**: Order card metadata (dates, state badge) moved to a reusable `_eskaera_order_card_meta` template for cleaner rendering. -- Delivery toggle (reparto/envío a domicilio) wired directly from the cart sidebar. -- Pricing alignment: theoretical price and displayed price reconciled for orders with home delivery. - -### Fixed - -- Fixed broken `aplicoopShop` → `groupOrderShop` JS class reference. -- Ensured add-to-cart event listeners are re-attached after infinite scroll loads new products. -- i18n: translated weekday names (ES/EU). - ---- - ## [18.0.1.6.0] - 2026-02-22 ### Added diff --git a/website_sale_aplicoop/README_DEV.md b/website_sale_aplicoop/README_DEV.md index 650289c..101a5e1 100644 --- a/website_sale_aplicoop/README_DEV.md +++ b/website_sale_aplicoop/README_DEV.md @@ -1,196 +1,336 @@ # Website Sale - Aplicoop -**Versión:** 18.0.1.9.0 | **Licencia:** AGPL-3 | **Autor:** Criptomart SL +**Author:** Criptomart +**License:** AGPL-3 +**Maintainer:** Criptomart SL -Sistema de pedidos colaborativos para grupos de consumo. Reemplaza el legacy Aplicoop con una solución moderna integrada en Odoo 18. +## Summary -## Resumen de funcionalidades +Modern replacement for legacy Aplicoop - Cooperative group ordering system with separate carts and multi-language support. -- Gestión completa de órdenes de grupo (draft → confirmed → collected → invoiced → completed) -- Carrito separado por grupo de consumo; tienda estándar de `website_sale` deshabilitada -- 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 +## Description -## Modelos +Website Sale Aplicoop provides a complete group ordering system designed for cooperative consumption groups. It replaces the legacy Aplicoop system with a modern, scalable solution where customers organize collaborative orders, manage group memberships, and handle separate shopping carts. Perfect for food cooperatives, buying groups, and collective purchasing organizations. -### `group.order` +## Features -Orden de grupo central. Contiene toda la lógica de ciclo de vida. +- ✅ Group order management with full lifecycle (draft → confirmed → completed) +- ✅ Separate shopping carts per order group +- ✅ Group membership tracking with active/inactive states +- ✅ Order collection and cutoff dates with validation +- ✅ Pickup day configuration and fulfillment tracking +- ✅ Multi-language support (ES, PT, GL, CA, EU, FR, IT) +- ✅ Partner location management for group coordination +- ✅ Product ecosystem integration (ribbons, pricing, margins) +- ✅ Order state transitions with email notifications +- ✅ Delivery tracking and group order fulfillment +- ✅ Financial tracking per group member +- ✅ Automatic translation of UI elements +- ✅ **Lazy Loading**: Configurable product pagination for fast page loads -**Campos principales:** +## Installation -| 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 | +1. Place addon in Odoo addons folder: `/addons/website_sale_aplicoop` +2. Activate developer mode +3. Go to **Apps** → **Update Apps List** +4. Search for "Website Sale - Aplicoop" +5. Click **Install** -**Métodos clave:** +### Requirements -- `_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 +- Odoo 18.0+ +- Website module +- Sale module +- Product module +- Account module -### `group.order.slot` *(en desarrollo)* +### Dependencies -Franjas horarias de recogida para una orden de grupo. +``` +- base +- web +- website +- sale +- product +- account +``` -| 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 | +## Usage -### Extensiones de modelos core +### Administrator Setup + +#### 1. Create a Group Order + +1. Go to **Website Sale** → **Group Orders** (or **Coops** → **Órdenes de Grupo**) +2. Click **Create** +3. Fill in: + - **Name**: e.g., "Weekly Cooperative Order #5" + - **Group**: Select the cooperative group + - **Collection Date**: When orders will be collected + - **Cutoff Date**: Last moment to add items + - **Pickup Date**: When group members collect their orders +4. Save + +#### 2. Configure Pickup Dates + +1. Go to **Settings** → **Website** → **Shop Settings** +2. Configure **Pickup Days**: Define which days are available +3. Set **Group Settings**: Default locations, delivery partners + +#### 3. Add Group Members + +1. Open a Group Order +2. In the **Members** tab, click **Add** +3. Select partner(s) +4. Set active/inactive status +5. Save + +### Customer Experience + +#### For Group Members on Website + +1. **Browse Products**: Members see products with eco-ribbons, pricing, margin info +2. **Add to Cart**: Select items (cart is separate per group order) +3. **Review Cart**: See order summary before cutoff date +4. **Submit Order**: Confirm before cutoff time +5. **Receive Notification**: Get email with pickup details +6. **Pickup**: Collect order on designated pickup date + +#### Order Workflow + +``` +Draft → Confirmed → Collected → Invoiced → Completed + ↓ +Cancelled (if member opts out) +``` + +## Configuration + +### Basic Configuration + +**Required:** +1. Create group orders with collection/cutoff/pickup dates +2. Assign group members to orders +3. Set available pickup dates + +**Optional:** +1. Configure custom email templates +2. Set up product-specific group restrictions +3. Customize group order report + +### Multi-Language Setup + +The addon automatically translates: +- Interface elements +- Form labels +- Report headers +- Email notifications + +**Supported Languages:** ES, PT, GL, CA, EU, FR, IT + +**Translations are managed in:** +- `i18n/[language].po` files +- Auto-extracted from templates +- See `docs/TRANSLATION_CONVENTIONS.md` for translation patterns + +### Website Customization + +Edit templates in: `views/website_templates.xml` + +Key customizable sections: +- `eskaera_page`: Main group order display +- `eskaera_details`: Order details view +- `member_cart`: Individual member cart interface + +## Technical Details + +### Core Models + +**`group.order`** (Main group order) +- `name` (Char): Order identifier +- `group_id` (Many2one): Link to group +- `state` (Selection): draft/confirmed/collected/invoiced/completed/cancelled +- `collection_date` (Date): When group collects +- `cutoff_date` (Datetime): Last moment to order +- `pickup_date` (Date): Member pickup day +- `line_ids` (One2many): Order lines +- `member_ids` (One2many): Group members +- `active` (Boolean): Soft delete + +**`group.order.line`** (Order items per member) +- `order_id` (Many2one): Parent group order +- `member_id` (Many2one): Which group member +- `product_id` (Many2one): Ordered product +- `quantity` (Float): Amount ordered +- `unit_price` (Float): Price per unit +- `subtotal` (Float): Computed (qty × price) + +**`group.partner`** (Group member tracking) +- `partner_id` (Many2one): Odoo partner +- `group_id` (Many2one): Which group +- `active` (Boolean): Active member status +- `role` (Selection): admin/member + +### Extended Models **`product.template`** - -- `main_seller_id` — proveedor principal (de `product_main_seller`) -- `sequence` en `product.category` — orden de visualización en la tienda web +- `group_order_allowed` (Boolean): Can be in group orders +- `eco_ribbon_id` (Many2one): Environmental ribbon +- `margin_type_id` (Many2one): Pricing margin **`sale.order`** +- `group_order_id` (Many2one): Parent group order (if applicable) -- `group_order_id` — enlace a la orden de grupo -- `consumer_group_id` — propagado desde `group_order_id` -- `pickup_slot_label` — etiqueta legible de la franja de recogida +### Views & Templates -**`stock.picking`** +**Backend Views:** +- `group.order` list/form views +- `group.order.line` inline form +- `group.partner` configuration view -- Extensión para agrupación por grupo de consumo en lotes de picking +**Frontend Templates:** +- `eskaera_page`: Main group order display +- `eskaera_details`: Order details/summary +- `member_cart`: Individual cart interface +- `group_members`: Member list view -## Controladores +## Integration Points -Todos los endpoints viven bajo `/eskaera/`: +This addon integrates with: -| Ruta | Descripción | -| ---- | ----------- | -| `GET /eskaera` | Lista de órdenes de grupo activas del usuario | -| `GET /eskaera/` | Tienda de la orden (con lazy loading) | -| `GET /eskaera//load-page?page=N` | Carga AJAX de página de productos | -| `POST /eskaera//add` | Añadir producto al carrito | -| `POST /eskaera//confirm` | Confirmar carrito (sale.order en draft) | -| `POST /eskaera/clear-cart` | Limpiar carrito actual | +- **Product Modules** + - `product_eco_ribbon` - Eco-friendly product indicators + - `product_margin_type` - Dynamic product pricing + - `product_pricing_margins` - Cost management -Las rutas `/cart` y `/shop` de `website_sale` están redirigidas a `/eskaera`. +- **Website/E-commerce** + - `elika_bilbo_website_theme` - Custom website theme + - `website_sale` - Core shop functionality + - `website_legal_es` - Legal compliance (Spanish) -**Seguridad portal:** los usuarios solo ven órdenes de su `consumer_group_id`. La regla `rule_group_order_company_read` incluye guardia `user.share`. +- **Sales/Accounting** + - `sale` - Sales order generation + - `account` - Invoicing -## Templates QWeb +## Testing -| 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: - -1. **Whitelist**: unión de `product_ids` + productos de `category_ids` (recursivo) + productos de `supplier_ids` (por `main_seller_id`) -2. **Blacklist**: se restan `excluded_product_ids`, productos con `main_seller_id` en `excluded_supplier_ids`, y productos en `excluded_category_ids` (recursivo) -3. 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 - -```text -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 +Run tests with: ```bash -docker-compose exec -T odoo odoo -d odoo -u website_sale_aplicoop --stop-after-init +cd /home/snt/Documentos/lab/odoo/kidekoop/odoo-addons +python -m pytest website_sale_aplicoop/tests/ -v ``` -Para migraciones con cambios de esquema (e.g., nuevas columnas): +**Test Coverage:** +- ✅ Group order creation/deletion +- ✅ Member management +- ✅ Order line addition/removal +- ✅ State transitions +- ✅ Cutoff date validation +- ✅ Pickup date assignment +- ✅ Translation extraction (7 languages) +- ✅ Website template rendering -```bash -docker-compose exec -T odoo odoo -d odoo --update website_sale_aplicoop --stop-after-init -``` +## Known Limitations -## Tests +- Group orders are company-specific +- Cannot change pickup date after order is confirmed +- Members cannot modify orders after cutoff +- Automatic invoicing must be triggered manually -```bash -docker-compose exec -T odoo odoo -d odoo --test-enable --stop-after-init -u website_sale_aplicoop -``` +## Changelog -Los tests están en `tests/`: +### 18.0.1.3.1 (2026-02-18) +- **Date Calculation Fixes (Critical)**: + - Fixed `_compute_cutoff_date` logic: Changed `days_ahead <= 0` to `days_ahead < 0` to allow cutoff_date to be the same day as today + - Enabled `store=True` for `delivery_date` field to persist calculated values and enable database filtering + - Added constraint `_check_cutoff_before_pickup` to validate that pickup_day >= cutoff_day in weekly orders + - Added `@api.onchange` methods for immediate UI feedback when changing cutoff_day or pickup_day +- **Automatic Date Updates**: + - Created daily cron job `_cron_update_dates` to automatically recalculate dates for active orders + - Ensures computed dates stay current as time passes +- **UI Improvements**: + - Added "Calculated Dates" section in form view showing readonly cutoff_date, pickup_date, and delivery_date + - Improved visibility of automatically calculated dates for administrators +- **Testing**: + - Added 6 regression tests with `@tagged('post_install', 'date_calculations')`: + - `test_cutoff_same_day_as_today_bug_fix`: Validates cutoff can be today + - `test_delivery_date_stored_correctly`: Ensures delivery_date persistence + - `test_constraint_cutoff_before_pickup_invalid`: Tests invalid configurations are rejected + - `test_constraint_cutoff_before_pickup_valid`: Tests valid configurations work + - `test_all_weekday_combinations_consistency`: Tests all 49 date combinations + - `test_cron_update_dates_executes`: Validates cron job execution +- **Documentation**: + - Documented that this is a more robust fix than v18.0.1.2.0, addressing edge cases in date calculations -- `test_group_order.py` — ciclo de vida básico, fechas, cron -- `test_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 +### 18.0.1.3.0 (2026-02-16) +- **Performance**: Lazy loading of products for faster page loads + - Configurable product pagination (default: 20 per page) + - New Settings: Enable Lazy Loading, Products Per Page + - Page 1: 500-800ms load time (vs 10-20s before) + - Subsequent pages: 200-400ms via AJAX + - New endpoint: `GET /eskaera//load-page?page=N` +- **Templates**: Split product rendering into reusable template + - New: `eskaera_shop_products` template + - Backend: `_get_products_paginated()` in group_order model +- **JavaScript**: Load More button with event handling + - `_attachLoadMoreListener()` for AJAX pagination + - Spinner during load (button disabled + "Loading..." text) + - Re-attach event listeners for new products + - Auto-hide button when no more products +- Documentation: Added `docs/LAZY_LOADING.md` with full technical details -## Traducciones +### 18.0.1.2.0 (2026-02-02) +- UI Improvements: + - Increased cart text size (2x) for better readability + - Increased cart icon sizes (1.2rem) with proper button proportions + - Enlarged "Save as Draft" button in checkout (2x text and icon) +- Date Calculation Fixes: + - Fixed pickup_date calculation (was adding extra week incorrectly) + - Simplified pickup_date computation logic +- Display Enhancements: + - Added delivery_date display to all order pages + - Improved date field visibility on order cards and product pages -```bash -# Exportar .pot -docker-compose exec -T odoo odoo -d odoo \ - -i website_sale_aplicoop \ - --i18n-export=/tmp/website_sale_aplicoop.pot \ - --stop-after-init +### 18.0.1.0.0 (2024-12-20) +- Initial release +- Core group order functionality +- Multi-language translation support +- Complete member management +- Order state machine implementation -# Actualizar .po existentes -cd website_sale_aplicoop/i18n -for lang in es eu; do - msgmerge -U ${lang}.po ../website_sale_aplicoop.pot -done -``` +### 18.0.1.1.0 (2025-01-10) +- Fixed translation extraction for "Pickup day" and "Cutoff day" +- Improved QWeb template for better performance +- Added comprehensive documentation -Ver [docs/TRANSLATIONS.md](../docs/TRANSLATIONS.md) para convenciones. +## Support -## Repositorio +For issues, feature requests, or contributions: +- **Repository**: https://git.criptomart.net/KideKoop/kidekoop/odoo-addons +- **Main Documentation**: `/docs/` folder (transversal docs) +- **Addon Documentation**: This README + `/docs/ODOO18_TRANSLATIONS_LEARNINGS.md` +- **Maintainer**: Criptomart SL -- Repo: -- Changelog: [CHANGELOG.md](CHANGELOG.md) +## Documentation References + +- **Translation Patterns**: See `docs/TRANSLATION_CONVENTIONS.md` +- **Translation Examples**: See `docs/TRANSLATION_EXAMPLES.md` +- **Odoo 18 Translation Guide**: See `docs/ODOO18_TRANSLATIONS_LEARNINGS.md` +- **Project Architecture**: See `docs/ARCHITECTURE.md` + +## Related Modules + +- `product_eco_ribbon` - Product environmental classification +- `product_margin_type` - Dynamic product pricing +- `product_pricing_margins` - Complete pricing system +- `elika_bilbo_website_theme` - Custom website theme +- `website_legal_es` - Legal compliance + +--- + +**Version:** 18.0.1.3.1 +**Odoo:** 18.0+ +**License:** AGPL-3 +**Maintainer:** Criptomart +**Repository:** https://git.criptomart.net/criptomart/addons-cm diff --git a/website_sale_aplicoop/models/group_order_slot.py b/website_sale_aplicoop/models/group_order_slot.py index e9f736b..b261aaa 100644 --- a/website_sale_aplicoop/models/group_order_slot.py +++ b/website_sale_aplicoop/models/group_order_slot.py @@ -23,15 +23,7 @@ class GroupOrderSlot(models.Model): ) weekday = fields.Selection( - [ - ("0", "Monday"), - ("1", "Tuesday"), - ("2", "Wednesday"), - ("3", "Thursday"), - ("4", "Friday"), - ("5", "Saturday"), - ("6", "Sunday"), - ], + [(str(i), str(i)) for i in range(7)], string="Weekday", required=True, help="Day of week for this slot (0=Monday)", diff --git a/website_sale_aplicoop/security/ir.model.access.csv b/website_sale_aplicoop/security/ir.model.access.csv index 8879454..10027e4 100644 --- a/website_sale_aplicoop/security/ir.model.access.csv +++ b/website_sale_aplicoop/security/ir.model.access.csv @@ -4,5 +4,3 @@ access_group_order_user,group.order user,model_group_order,website_sale_aplicoop access_group_order_manager,group.order manager,model_group_order,website_sale_aplicoop.group_group_order_manager,1,1,1,1 access_group_order_portal,group.order portal,model_group_order,base.group_portal,1,0,0,0 access_product_supplierinfo_portal,product.supplierinfo portal,product.model_product_supplierinfo,base.group_portal,1,0,0,0 -access_group_order_slot_base,group.order.slot base,model_group_order_slot,,1,1,1,0 -access_group_order_slot_manager,group.order.slot manager,model_group_order_slot,website_sale_aplicoop.group_group_order_manager,1,1,1,1 diff --git a/website_sale_aplicoop/static/src/css/components/product-card.css b/website_sale_aplicoop/static/src/css/components/product-card.css index d3d6671..fd36a45 100644 --- a/website_sale_aplicoop/static/src/css/components/product-card.css +++ b/website_sale_aplicoop/static/src/css/components/product-card.css @@ -36,14 +36,13 @@ } .product-img-cover { - height: 120px; + max-height: 120px; width: 100%; object-fit: cover; border-radius: 8px 8px 0 0; box-shadow: 0 2px 8px rgba(40, 39, 39, 0.09); background: #f3f3f3; display: block; - flex-shrink: 0; } .product-card .card-body { @@ -51,7 +50,7 @@ flex-direction: column; height: 100%; flex-grow: 1; - padding: 0.4rem 0.55rem 0.5rem; + padding: 0.6rem 0.7rem 0.7rem 0.7rem; position: relative; background: linear-gradient(135deg, rgba(0, 123, 255, 0.07) 0%, rgba(0, 123, 255, 0.04) 100%); transition: background 0.3s; @@ -68,13 +67,13 @@ .product-card .card-title { flex-grow: 1; - margin: 0 0 0.1rem 0; + margin: 0 0 0.15rem 0; min-height: auto; display: block; word-wrap: break-word; overflow-wrap: break-word; - font-size: 1rem !important; - line-height: 1.15; + font-size: 1.08rem !important; + line-height: 1.1; text-align: center; font-weight: 600; color: #1a202c; @@ -82,9 +81,9 @@ } .product-card .card-text { - margin-bottom: 0.08rem; + margin-bottom: 0.12rem; text-align: center; - font-size: 0.95rem; + font-size: 1rem; } .product-card .card-text strong { @@ -98,19 +97,19 @@ text-align: center; color: #4a5568; font-weight: 400; - margin-bottom: 0.08rem; - font-size: 0.85rem !important; + margin-bottom: 0.12rem; + font-size: 0.92rem !important; } .product-tags { text-align: center; display: flex; flex-wrap: wrap; - gap: 0.12rem; + gap: 0.18rem; justify-content: center; font-weight: 400; - font-size: 1rem !important; - margin: 0 0 0.08rem 0; + font-size: 1.1rem !important; + margin: 0; padding: 0; } @@ -130,15 +129,15 @@ .card-body p.card-text { text-align: center; - margin-bottom: 0.35rem; - min-height: 1.5rem; + margin-bottom: 0.6rem; + min-height: 1.7rem; display: flex; align-items: center; justify-content: center; background-color: var(--primary-color, #007bff); color: #fff; border-radius: 0.18rem; - font-size: 0.98rem; + font-size: 1.05rem; } .card-body p.card-text strong { @@ -161,73 +160,53 @@ .product-img-placeholder { height: 120px; width: 100%; + object-fit: cover; border-radius: 8px 8px 0 0; - background: #f3f3f3; - display: flex; - align-items: center; - justify-content: center; - flex-shrink: 0; - color: #ccc; + background: #f3f3f3 + url('data:image/svg+xml;utf8,Sin imagen') + no-repeat center center; + display: block; } -/* Responsive: tablet (≤768px) — compresión moderada */ -@media (max-width: 768px) { - .product-card .product-image, - .product-img-cover, - .product-img-fixed, - .product-img-placeholder { - height: 90px; - } - .product-card .card-body { - padding: 0.35rem 0.45rem 0.4rem; - } - .card-body p.card-text { - margin-bottom: 0.25rem; - min-height: 1.4rem; - } -} - -/* Responsive: móvil (≤480px) — compresión máxima */ -@media (max-width: 480px) { +/* Responsive: mejorar altura y espaciado en móvil */ +@media (max-width: 600px) { .product-card { - padding: 0.15rem; - border-radius: 6px; + padding: 0.25rem; + border-radius: 8px; } .product-card .product-image, .product-img-cover, .product-img-fixed, .product-img-placeholder { - height: 60px; - border-radius: 5px 5px 0 0; + height: 70px; + max-height: 70px; + min-height: 70px; + border-radius: 6px 6px 0 0; } .product-card .card-body { - padding: 0.25rem 0.3rem 0.3rem; + padding: 0.4rem 0.4rem 0.5rem 0.4rem; } .product-card .card-title { - font-size: 0.82rem !important; - line-height: 1.15; - margin-bottom: 0.05rem; + font-size: 0.98rem !important; + margin-bottom: 0.08rem; } .product-card .card-text { - font-size: 0.8rem; + font-size: 0.92rem; } .badge-km { - font-size: 0.55rem !important; - padding: 0.1rem 0.18rem !important; + font-size: 0.58rem !important; + padding: 0.13rem 0.22rem !important; } .product-tags { - font-size: 0.82rem !important; - gap: 0.08rem; - margin-bottom: 0.05rem; + font-size: 0.95rem !important; } .card-body p.card-text { - min-height: 1rem; - font-size: 0.85rem; - margin-bottom: 0.2rem; + min-height: 1.1rem; + font-size: 0.95rem; + margin-bottom: 0.3rem; } .product-card .product-supplier { - font-size: 0.72rem !important; - margin-bottom: 0.05rem; + font-size: 0.82rem !important; } } diff --git a/website_sale_aplicoop/views/group_order_views.xml b/website_sale_aplicoop/views/group_order_views.xml index 140a98d..17984d2 100644 --- a/website_sale_aplicoop/views/group_order_views.xml +++ b/website_sale_aplicoop/views/group_order_views.xml @@ -92,20 +92,6 @@ - - - - - - - - - - - - - -