From 62e0e8a92ca853a37cfe6b49fa1734ff66599250 Mon Sep 17 00:00:00 2001 From: GitHub Copilot Date: Fri, 26 Jun 2026 19:41:54 +0200 Subject: [PATCH] crea mandatos SEPA desde pedidos del TPV --- .claude/settings.json | 3 +- .github/copilot-instructions.md | 61 ++++++-- CLAUDE.md | 29 +++- pos_account_payment_order_sepa/README.md | 33 +++++ pos_account_payment_order_sepa/__init__.py | 1 + .../__manifest__.py | 17 +++ .../data/server_action.xml | 133 ++++++++++++++++++ 7 files changed, 262 insertions(+), 15 deletions(-) create mode 100644 pos_account_payment_order_sepa/README.md create mode 100644 pos_account_payment_order_sepa/__init__.py create mode 100644 pos_account_payment_order_sepa/__manifest__.py create mode 100644 pos_account_payment_order_sepa/data/server_action.xml diff --git a/.claude/settings.json b/.claude/settings.json index 1809bcf..01ad04b 100644 --- a/.claude/settings.json +++ b/.claude/settings.json @@ -2,7 +2,8 @@ "permissions": { "allow": [ "Edit(/.claude/skills/odoo-javascript/**)", - "Bash(git -C /home/snt/Documentos/lab/odoo/addons-cm commit -m ' *)" + "Bash(git -C /home/snt/Documentos/lab/odoo/addons-cm commit -m ' *)", + "Bash(grep -E '\"\\(name|summary|version|author|depends\\)\"' -A0 __TRACKED_VAR__/__manifest__.py)" ] } } diff --git a/.github/copilot-instructions.md b/.github/copilot-instructions.md index 1486fb7..1a7b93b 100644 --- a/.github/copilot-instructions.md +++ b/.github/copilot-instructions.md @@ -3,11 +3,12 @@ No modificar el directorio de fuentes de OCB (`ocb/`) ni los siguientes addons OCA originales: - `product_main_seller` -- `product_origin` - `account_invoice_triple_discount` - `product_get_price_helper` - `product_price_category` - `purchase_triple_discount` +- `base_bank_from_iban` +- `l10n_es_partner` Estos módulos y el core de Odoo (OCB) solo están para referencia y herencia de nuestros addons custom. Cualquier cambio debe hacerse en los addons propios, nunca en los OCA originales ni en el core OCB. @@ -166,16 +167,29 @@ addons-cm/ ├── # === ADDONS OCA NO MODIFICADOS === ├── account_invoice_triple_discount/ # Triple descuento en facturas (OCA) ├── purchase_triple_discount/ # Triple descuento en compras (OCA) -├── product_origin/ # Origen del producto (OCA) ├── product_get_price_helper/ # Helper de precios (OCA) ├── product_main_seller/ # Proveedor principal (OCA) ├── product_price_category/ # Categorías de precio (OCA) +├── base_bank_from_iban/ # Banco desde IBAN (OCA) +├── l10n_es_partner/ # Adaptación partners/bancos ES (OCA) │ ├── # === ADDONS CUSTOM === -├── account_invoice_triple_discount_readonly/ # Fix para triple descuento -├── product_price_category_supplier/ # Extensión categorías precio -├── product_sale_price_from_pricelist/ # Auto-cálculo precio venta -└── website_sale_aplicoop/ # Sistema eskaera (compras grupo) +├── # --- Precios y productos --- +├── product_sale_price_from_pricelist/ # Auto-cálculo precio venta (+ descuentos supplierinfo) +├── product_pricelist_total_margin/ # Margen total aditivo (markup / comercial) con límites +├── product_price_category_supplier/ # Extensión categorías precio por proveedor +├── product_origin_char/ # Campo origen texto libre por producto +├── account_invoice_triple_discount_readonly/ # Fix bug acumulación triple descuento +├── # --- Ventas y web --- +├── website_sale_aplicoop/ # Sistema eskaera (compras grupo) +├── portal_event_registration/ # Portal: ver registros de eventos + adjuntos +├── # --- Membresías --- +├── membership_monthly_invoicing/ # Factura mensual de membresía por socio (cron) +├── membership_expiry_reminder/ # Email recordatorio de renovación próxima +├── # --- Logística y contabilidad --- +├── stock_picking_batch_custom/ # Batch picking: columnas extra + vista operario (Basket Assembly) +├── account_banking_mandate_batch/ # Crear/validar mandatos SEPA en bloque desde contactos +└── l10n_es_edi_tbai_reagyp_recibidas/ # Fix TicketBAI REAGYP facturas recibidas (19 → 02) ```` @@ -187,17 +201,37 @@ addons-cm/ - [account_invoice_triple_discount](../account_invoice_triple_discount/README.rst) - [purchase_triple_discount](../purchase_triple_discount/README.rst) -- [product_origin](../product_origin/README.rst) - [product_get_price_helper](../product_get_price_helper/README.rst) - [product_main_seller](../product_main_seller/README.rst) - [product_price_category](../product_price_category/README.rst) +- [base_bank_from_iban](../base_bank_from_iban/README.rst) +- [l10n_es_partner](../l10n_es_partner/README.rst) ### Addons Custom Propios -- [account_invoice_triple_discount_readonly](../account_invoice_triple_discount_readonly/README.rst) - Fix bug descuentos +**Precios y productos** + +- [product_sale_price_from_pricelist](../product_sale_price_from_pricelist/README.rst) - Auto-precio basado en compra (+ descuentos de supplierinfo) +- [product_pricelist_total_margin](../product_pricelist_total_margin/README.rst) - Margen total aditivo (markup / comercial) con límites globales - [product_price_category_supplier](../product_price_category_supplier/README.rst) - Gestión categorías por proveedor -- [product_sale_price_from_pricelist](../product_sale_price_from_pricelist/README.rst) - Auto-precio basado en compra +- [product_origin_char](../product_origin_char/README.rst) - Campo origen de texto libre por producto +- [account_invoice_triple_discount_readonly](../account_invoice_triple_discount_readonly/README.rst) - Fix bug acumulación descuentos + +**Ventas y web** + - [website_sale_aplicoop](../website_sale_aplicoop/README.rst) - Sistema eskaera completo +- [portal_event_registration](../portal_event_registration/README.rst) - Portal: registros de eventos + adjuntos al chatter + +**Membresías** + +- [membership_monthly_invoicing](../membership_monthly_invoicing/README.rst) - Factura mensual de membresía por socio activo (cron) +- [membership_expiry_reminder](../membership_expiry_reminder/README.rst) - Email automático de recordatorio de renovación + +**Logística y contabilidad** + +- [stock_picking_batch_custom](../stock_picking_batch_custom/README.rst) - Columnas extra y vista operario para batch picking +- [account_banking_mandate_batch](../account_banking_mandate_batch/README.rst) - Creación masiva de mandatos SEPA desde contactos +- [l10n_es_edi_tbai_reagyp_recibidas](../l10n_es_edi_tbai_reagyp_recibidas/README.rst) - Fix TicketBAI REAGYP en facturas recibidas (clave régimen 19 → 02) **Nota**: Todos los addons custom siguen la estructura OCA con readme/ fragmentos. Ver [docs/OCA_DOCUMENTATION.md](../docs/OCA_DOCUMENTATION.md) para detalles. @@ -709,12 +743,19 @@ last_purchase_price_compute_type != "manual_update" # Para auto-cálculo --- -**Last Updated**: 2026-02-18 +**Last Updated**: 2026-06-04 **Odoo Version**: 18.0 **Python Version**: 3.10+ ## Recent Changes Summary +- **2026-06-04**: Nuevos addons custom documentados: `membership_monthly_invoicing`, + `membership_expiry_reminder`, `account_banking_mandate_batch`, `portal_event_registration`, + `product_pricelist_total_margin`, `product_origin_char`, `l10n_es_edi_tbai_reagyp_recibidas`. + `product_origin` (OCA) sustituido por `product_origin_char` (custom). +- **2026-06-04**: `product_sale_price_from_pricelist` aplica descuentos de proveedor desde `supplierinfo`. +- **2026-06**: `stock_picking_batch_custom` — vista operario a pantalla completa (Basket Assembly), + ordenación de operaciones por categoría/producto/partner. - **2026-02-18**: Refactor `product_main_seller` - Remover alias innecesario `default_supplier_id` - **2026-02-16**: v18.0.1.3.1 fixes críticos de cálculo de fechas en Eskaera - **2026-02-12**: v18.0.1.3.0 Lazy loading y fixes de template rendering QWeb diff --git a/CLAUDE.md b/CLAUDE.md index 540305c..780f812 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -6,8 +6,8 @@ Combines OCB (`ocb/`), inherited OCA addons, and our own custom addons. ## ⚠️ Critical rules (non-negotiable) - **DO NOT modify** the OCB core (`ocb/`) nor these original OCA addons (reference/inheritance only): - `product_main_seller`, `product_origin`, `account_invoice_triple_discount`, - `product_get_price_helper`, `product_price_category`, `purchase_triple_discount`. + `product_main_seller`, `account_invoice_triple_discount`, `product_get_price_helper`, + `product_price_category`, `purchase_triple_discount`, `base_bank_from_iban`, `l10n_es_partner`. All changes go in our own custom addons. - **Do NOT use `_()` in field definitions** (triggers import-time warnings). Only in methods/executable code. - **Business logic ALWAYS on `product.product`** (variants), never on `product.template` (use `related` there). @@ -45,12 +45,33 @@ pre-commit run --all-files ## Custom addons +Pricing & products: + - `product_sale_price_from_pricelist` — auto-computes sale price from last purchase price + pricelist. Requires taxes on the product and `last_purchase_price_compute_type != "manual_update"`. + Also applies supplier discounts from `supplierinfo`. +- `product_pricelist_total_margin` — total margin computed additively (Markup or Commercial Margin), with global limits. +- `product_price_category_supplier` — price categories per supplier. +- `product_origin_char` — free-text origin field per product (template-based). +- `account_invoice_triple_discount_readonly` — fix for triple-discount accumulation bug (always use it). + +Sales & website: + - `website_sale_aplicoop` — Eskaera: collaborative purchasing for consumer co-ops (group orders, per-member carts, cutoff/pickup dates, lazy loading, multi-language). -- `account_invoice_triple_discount_readonly` — fix for triple-discount accumulation bug (always use it). -- `product_price_category_supplier` — price categories per supplier. +- `portal_event_registration` — portal users view their event registrations + upload attachments to chatter. + +Membership: + +- `membership_monthly_invoicing` — auto-creates a monthly membership invoice per active member (cron-driven). +- `membership_expiry_reminder` — automated renewal-reminder emails near expiry, with online renew link. + +Logistics & accounting: + +- `stock_picking_batch_custom` — batch picking extras: extra detailed-op columns, ordering by + category/product/partner, and a full-screen operator (Basket Assembly) view. +- `account_banking_mandate_batch` — contextual action to bulk-create/validate SEPA mandates for selected partners. +- `l10n_es_edi_tbai_reagyp_recibidas` — TicketBAI fix: REAGYP vendor-bill regime key 19 → 02. ## Documentation diff --git a/pos_account_payment_order_sepa/README.md b/pos_account_payment_order_sepa/README.md new file mode 100644 index 0000000..a3b2615 --- /dev/null +++ b/pos_account_payment_order_sepa/README.md @@ -0,0 +1,33 @@ +# POS Account Payment Order SEPA + +Adds a contextual action **"Collect by SEPA direct debit"** on the POS orders +list/form (Point of Sale → Orders). + +## Purpose + +When a POS order is paid with a *"Customer Account"* payment method +(`split_transactions = True`), Odoo does not register a real collection: it +leaves the amount as an **open receivable** for the customer inside the +session's journal entry. This module lets you collect those receivables in +bulk through a **SEPA direct debit payment order** (debit order), without +re-invoicing the already-issued (simplified) tickets. + +## Usage + +1. Make sure the affected customers have a **valid SEPA mandate** (see + `account_banking_mandate_batch`). +2. Go to **Point of Sale → Orders**, filter the orders paid on account, select + them and run **Action → Collect by SEPA direct debit**. +3. The action creates the **payment lines** inside a draft inbound SEPA + payment order, grouped by payment mode. Orders without an open receivable, + without a partner, already queued, or whose partner has no valid mandate are + **skipped and reported**. +4. Open **Invoicing → Customers → Payment Orders**, confirm it and **generate + the SEPA file (pain.008)**. + +## Payment mode resolution + +The inbound SEPA payment mode is taken from the partner's +`customer_payment_mode_id` when it is a valid `sepa_direct_debit` inbound mode; +otherwise the first inbound `sepa_direct_debit` payment mode is used as +fallback. diff --git a/pos_account_payment_order_sepa/__init__.py b/pos_account_payment_order_sepa/__init__.py new file mode 100644 index 0000000..d9d1f13 --- /dev/null +++ b/pos_account_payment_order_sepa/__init__.py @@ -0,0 +1 @@ +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). diff --git a/pos_account_payment_order_sepa/__manifest__.py b/pos_account_payment_order_sepa/__manifest__.py new file mode 100644 index 0000000..2779b8d --- /dev/null +++ b/pos_account_payment_order_sepa/__manifest__.py @@ -0,0 +1,17 @@ +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). + +{ + "name": "POS Account Payment Order SEPA", + "summary": "Contextual action on POS orders to collect 'Customer Account' " + "receivables through a SEPA direct debit payment order.", + "version": "18.0.1.0.0", + "license": "AGPL-3", + "author": "Custom", + "depends": [ + "account_banking_sepa_direct_debit", + "point_of_sale", + ], + "data": [ + "data/server_action.xml", + ], +} diff --git a/pos_account_payment_order_sepa/data/server_action.xml b/pos_account_payment_order_sepa/data/server_action.xml new file mode 100644 index 0000000..e3ab750 --- /dev/null +++ b/pos_account_payment_order_sepa/data/server_action.xml @@ -0,0 +1,133 @@ + + + + Collect by SEPA direct debit + + + list,form + code + 0 + ) + if not rec_lines: + skipped["no_line"] += 1 + continue + for line in rec_lines: + partner = line.partner_id + if not partner: + skipped["no_partner"] += 1 + continue + if env["account.payment.line"].search_count( + [("move_line_id", "=", line.id), ("order_id.state", "!=", "cancel")] + ): + skipped["already"] += 1 + continue + if not Mandate.search_count( + [("partner_id", "=", partner.commercial_partner_id.id), ("state", "=", "valid")] + ): + skipped["no_mandate"] += 1 + continue + mode = sepa_mode_for(partner) or fallback_mode + if not mode: + skipped["no_mode"] += 1 + continue + lines_by_mode.setdefault(mode.id, env["account.move.line"]) + lines_by_mode[mode.id] |= line + +# --- Create one draft payment order per payment mode and add the lines --- +created_lines = 0 +order_names = [] +for mode_id, move_lines in lines_by_mode.items(): + mode = Mode.browse(mode_id) + payment_order = Order.search( + [("payment_mode_id", "=", mode_id), ("state", "=", "draft")], limit=1 + ) + if not payment_order: + payment_order = Order.create({"payment_mode_id": mode_id}) + move_lines.create_payment_line_from_move_line(payment_order) + created_lines += len(move_lines) + order_names.append(payment_order.name or "Draft") + +# --- Report --- +message = ( + "Payment lines created: %(created)s\n" + "Payment order(s): %(orders)s\n\n" + "Skipped:\n" + " no accounting move: %(no_move)s\n" + " no open receivable line: %(no_line)s\n" + " no partner: %(no_partner)s\n" + " already in a payment order: %(already)s\n" + " no valid SEPA mandate: %(no_mandate)s\n" + " no SEPA payment mode: %(no_mode)s" +) % { + "created": created_lines, + "orders": ", ".join(order_names) or "-", + "no_move": skipped["no_move"], + "no_line": skipped["no_line"], + "no_partner": skipped["no_partner"], + "already": skipped["already"], + "no_mandate": skipped["no_mandate"], + "no_mode": skipped["no_mode"], +} + +action = { + "type": "ir.actions.client", + "tag": "display_notification", + "params": { + "title": "SEPA collection", + "message": message, + "type": "success" if created_lines else "warning", + "sticky": True, + }, +} +]]> + +