es__check_b2b_mandate_applicability
Identify the applicable Spanish B2B electronic invoicing mandate (VERI*FACTU, SII, TicketBAI, NaTicket) using annual turnover, province code, SII enrollment, and entity type, applying Real Decreto 254/2025.
Instructions
Determina el régimen de facturación electrónica aplicable (VERI*FACTU, SII, TicketBAI, NaTicket) a partir del volumen de operaciones, código de provincia y enrolamiento en SII. Aplica la lógica de exclusión mutua del Real Decreto 254/2025.
Input Schema
| Name | Required | Description | Default |
|---|---|---|---|
| annual_turnover_eur | Yes | Volumen anual de operaciones IVA en EUR. | |
| tax_address_province_code | Yes | Código de provincia INE de dos dígitos. | |
| enrolled_in_sii | No | Inscripción en el SII (por defecto: false). | |
| entity_type | No | Tipo de obligado: 'IS' (Sociedades) o 'IRPF'. |
Implementation Reference
- The handler function that executes the tool logic for es__check_b2b_mandate_applicability. Extracts arguments (annual_turnover_eur, tax_address_province_code, enrolled_in_sii, entity_type), calls _detect_regime() to determine the applicable regime (VERIFACTU, TICKETBAI, NATICKET, VERIFACTU+SII), and returns the applicable systems and notes.
async def handle_es_check_b2b_mandate_applicability( arguments: dict[str, Any], ) -> list[types.TextContent]: try: turnover = arguments.get("annual_turnover_eur") province_code = str(arguments.get("tax_address_province_code", "")).strip() enrolled = bool(arguments.get("enrolled_in_sii", False)) entity_type_str = arguments.get("entity_type", "IS") if turnover is None: return err("annual_turnover_eur is required", "MISSING_PARAM") if not province_code: return err("tax_address_province_code is required", "MISSING_PARAM") try: entity_type = EntityType(entity_type_str) except ValueError: return err(f"Invalid entity_type: {entity_type_str!r}. Must be 'IS' or 'IRPF'.") regime = _detect_regime(province_code, enrolled, annual_turnover_eur=float(turnover)) notes: list[str] = [] applicable_systems: list[str] = [] if regime == SpanishRegime.TICKETBAI: applicable_systems = ["TicketBAI (provincial)"] notes.append( "El País Vasco opera bajo TicketBAI en lugar de VERI*FACTU. " "Seleccione la provincia correcta (araba / gipuzkoa / bizkaia) — " "cada una tiene su propio XSD y endpoint de envío." ) elif regime == SpanishRegime.NATICKET: applicable_systems = ["NaTicket (Hacienda Foral de Navarra)"] notes.append("VERI*FACTU no aplica en Navarra.") elif regime == SpanishRegime.VERIFACTU_SII: applicable_systems = ["SII"] notes.append( "Inscrito en SII: exento de VERI*FACTU (Real Decreto 254/2025). " "Obligación de comunicación de facturas en 4 días hábiles." ) if float(turnover) > _SII_TURNOVER_THRESHOLD_EUR: notes.append( f"Facturación ({float(turnover):,.2f} EUR) supera el umbral SII (€6M)." ) else: # VERIFACTU applicable_systems = ["VERI*FACTU"] deadline = "enero 2027" if entity_type == EntityType.IS else "julio 2027" notes.append( f"VERI*FACTU obligatorio desde {deadline} (RD-ley 15/2025). " "Obligatorio también Facturae/FACe para facturas B2G." ) if float(turnover) > _SII_TURNOVER_THRESHOLD_EUR: notes.append( f"Facturación ({float(turnover):,.2f} EUR) supera el umbral SII (€6M). " "Puede estar obligado a inscribirse en el SII, lo cual excluye VERI*FACTU." ) # Facturae/FACe always applies for B2G applicable_systems.append("Facturae / FACe (obligatorio para facturas B2G desde 2015)") # Crea y Crece (pending) applicable_systems.append("B2B Crea y Crece (Ley 18/2022, reglamento pendiente)") return ok({ "annual_turnover_eur": float(turnover), "province_code": province_code, "entity_type": entity_type.value, "enrolled_in_sii": enrolled, "primary_regime": regime.value, "applicable_systems": applicable_systems, "notes": notes, "sii_exclusion_applies": regime == SpanishRegime.VERIFACTU_SII, "disclaimer": ( "Según RD-ley 15/2025 y RD 254/2025. " "Sujeto a cambios por legislación posterior. " "No constituye asesoramiento jurídico ni fiscal." ), }) except Exception as exc: logger.exception("es__check_b2b_mandate_applicability failed") return err(str(exc)) - The Tool definition with inputSchema for es__check_b2b_mandate_applicability. Defines input parameters: annual_turnover_eur (number), tax_address_province_code (string), enrolled_in_sii (boolean, default false), entity_type (enum: IS/IRPF).
TOOL_ES_CHECK_B2B_MANDATE_APPLICABILITY = types.Tool( name="es__check_b2b_mandate_applicability", description=( "Determina el régimen de facturación electrónica aplicable (VERI*FACTU, SII, TicketBAI, " "NaTicket) a partir del volumen de operaciones, código de provincia y enrolamiento en SII. " "Aplica la lógica de exclusión mutua del Real Decreto 254/2025." ), inputSchema={ "type": "object", "properties": { "annual_turnover_eur": { "type": "number", "description": "Volumen anual de operaciones IVA en EUR.", }, "tax_address_province_code": { "type": "string", "description": "Código de provincia INE de dos dígitos.", }, "enrolled_in_sii": { "type": "boolean", "description": "Inscripción en el SII (por defecto: false).", "default": False, }, "entity_type": { "type": "string", "enum": ["IS", "IRPF"], "description": "Tipo de obligado: 'IS' (Sociedades) o 'IRPF'.", }, }, "required": ["annual_turnover_eur", "tax_address_province_code"], }, ) - mcp_facturacion_electronica_es/server.py:108-137 (registration)Registration table (_TOOL_HANDLERS) mapping tool name 'es__check_b2b_mandate_applicability' to the handler function handle_es_check_b2b_mandate_applicability.
_TOOL_HANDLERS: dict[str, Any] = { # VERI*FACTU "es__generate_verifactu_record": handle_es_generate_verifactu_record, "es__validate_verifactu_record": handle_es_validate_verifactu_record, "es__submit_verifactu_to_aeat": handle_es_submit_verifactu_to_aeat, "es__generate_qr_verifactu": handle_es_generate_qr_verifactu, "es__cancel_verifactu_record": handle_es_cancel_verifactu_record, # Facturae / FACe "es__generate_facturae_xml": handle_es_generate_facturae_xml, "es__sign_facturae_xades": handle_es_sign_facturae_xades, "es__submit_to_face": handle_es_submit_to_face, "es__get_face_invoice_status": handle_es_get_face_invoice_status, "es__validate_facturae_schema": handle_es_validate_facturae_schema, # SII "es__build_sii_invoice_record": handle_es_build_sii_invoice_record, "es__submit_sii_batch": handle_es_submit_sii_batch, "es__query_sii_status": handle_es_query_sii_status, "es__generate_sii_correction": handle_es_generate_sii_correction, # TicketBAI "es__generate_ticketbai_xml": handle_es_generate_ticketbai_xml, "es__submit_ticketbai": handle_es_submit_ticketbai, "es__validate_ticketbai_schema": handle_es_validate_ticketbai_schema, # Crea y Crece / B2B "es__generate_b2b_einvoice_es": handle_es_generate_b2b_einvoice_es, "es__check_b2b_mandate_applicability": handle_es_check_b2b_mandate_applicability, # Utilities "es__detect_regional_regime": handle_es_detect_regional_regime, "es__get_compliance_status": handle_es_get_compliance_status, "es__parse_aeat_response": handle_es_parse_aeat_response, } - mcp_facturacion_electronica_es/server.py:77-106 (registration)Registration of the tool in the _ALL_TOOLS list at line 101, which is returned by the MCP list_tools handler.
_ALL_TOOLS: list[types.Tool] = [ # VERI*FACTU TOOL_ES_GENERATE_VERIFACTU_RECORD, TOOL_ES_VALIDATE_VERIFACTU_RECORD, TOOL_ES_SUBMIT_VERIFACTU_TO_AEAT, TOOL_ES_GENERATE_QR_VERIFACTU, TOOL_ES_CANCEL_VERIFACTU_RECORD, # Facturae / FACe TOOL_ES_GENERATE_FACTURAE_XML, TOOL_ES_SIGN_FACTURAE_XADES, TOOL_ES_SUBMIT_TO_FACE, TOOL_ES_GET_FACE_INVOICE_STATUS, TOOL_ES_VALIDATE_FACTURAE_SCHEMA, # SII TOOL_ES_BUILD_SII_INVOICE_RECORD, TOOL_ES_SUBMIT_SII_BATCH, TOOL_ES_QUERY_SII_STATUS, TOOL_ES_GENERATE_SII_CORRECTION, # TicketBAI TOOL_ES_GENERATE_TICKETBAI_XML, TOOL_ES_SUBMIT_TICKETBAI, TOOL_ES_VALIDATE_TICKETBAI_SCHEMA, # Crea y Crece / B2B TOOL_ES_GENERATE_B2B_EINVOICE_ES, TOOL_ES_CHECK_B2B_MANDATE_APPLICABILITY, # Utilities TOOL_ES_DETECT_REGIONAL_REGIME, TOOL_ES_GET_COMPLIANCE_STATUS, TOOL_ES_PARSE_AEAT_RESPONSE, ] - The _detect_regime() helper function used by the handler to determine the Spanish e-invoicing regime from province code and SII enrolment. Returns SpanishRegime enum: TICKETBAI, NATICKET, VERIFACTU_SII, or VERIFACTU.
def _detect_regime( province_code: str, enrolled_in_sii: bool, annual_turnover_eur: float | None = None, ) -> SpanishRegime: """Pure-logic regime detection from province code and SII enrolment.""" code = str(province_code).strip().zfill(2) if code in _TICKETBAI_INE_CODES: return SpanishRegime.TICKETBAI if code == _NATICKET_INE_CODE: return SpanishRegime.NATICKET if enrolled_in_sii: return SpanishRegime.VERIFACTU_SII if annual_turnover_eur is not None and annual_turnover_eur > _SII_TURNOVER_THRESHOLD_EUR: # Large turnover may trigger voluntary SII; regime is still VERIFACTU # until formally enrolled (enrollment is what triggers the exclusion) pass return SpanishRegime.VERIFACTU