<?xml version="1.0" encoding="utf-8" ?>
<odoo>
    <record id="action_pos_collect_sepa" model="ir.actions.server">
        <field name="name">Collect by SEPA direct debit</field>
        <field name="model_id" ref="point_of_sale.model_pos_session" />
        <field name="binding_model_id" ref="point_of_sale.model_pos_session" />
        <field name="binding_view_types">list,form</field>
        <field name="state">code</field>
        <field name="code"><![CDATA[
# Collect the still-open "Customer Account" receivables of the selected POS
# sessions through a SEPA direct debit payment order (debit order).
#
# Unfactured POS orders do not get their own accounting move: the receivable
# generated by a "Customer Account" payment method (split_transactions) lands
# in the SINGLE journal entry of the session (session.move_id). So we read the
# open receivable lines from that move, keep the ones whose partner has a valid
# SEPA mandate, and create the payment lines inside a draft inbound payment
# order. The SEPA file (pain.008) is generated afterwards from that order.
#
# Lines are skipped (and reported) when: the session has no move yet, no open
# receivable line, no partner, the line is already in a payment order, or the
# partner has no valid SEPA mandate.

Mode = env["account.payment.mode"]
Order = env["account.payment.order"]
Mandate = env["account.banking.mandate"]
PaymentLine = env["account.payment.line"]

# --- Resolve the inbound SEPA payment mode (partner mode, with fallback) ---
def is_sepa_inbound(mode):
    return bool(
        mode
        and mode.payment_order_ok
        and mode.payment_method_id.code == "sepa_direct_debit"
        and mode.payment_method_id.payment_type == "inbound"
    )

fallback_mode = Mode.search(
    [
        ("payment_order_ok", "=", True),
        ("payment_method_id.code", "=", "sepa_direct_debit"),
        ("payment_method_id.payment_type", "=", "inbound"),
    ],
    limit=1,
)

# --- Collect open receivable lines from the selected sessions' moves ---
lines_by_mode = {}
skipped = {"no_move": 0, "no_line": 0, "no_partner": 0, "already": 0, "no_mandate": 0, "no_mode": 0}

for session in records:
    move = session.move_id
    if not move:
        skipped["no_move"] += 1
        continue
    rec_lines = move.line_ids.filtered(
        lambda l: l.account_id.account_type == "asset_receivable"
        and not l.reconciled
        and l.amount_residual > 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 PaymentLine.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
        partner_mode = partner.customer_payment_mode_id
        mode = partner_mode if is_sepa_inbound(partner_mode) else 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():
    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"
    "  session without accounting move: %(no_move)s\n"
    "  session without open receivable line: %(no_line)s\n"
    "  line without 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,
    },
}
]]></field>
    </record>
</odoo>
