# coding: utf-8

"""
    FactPulse REST API

     REST API for electronic invoicing in France: Factur-X (CII), UBL 2.1, AFNOR PDP/PA, electronic signatures.  ## 🎯 Main Features  ### 📄 Invoice Generation - **Formats**: CII XML, UBL 2.1 XML, or Factur-X PDF/A-3 - **Profiles** (CII/PDF): MINIMUM, BASIC, EN16931, EXTENDED - **UBL**: Always EN16931 compliant - **Standards**: EN 16931 (EU directive 2014/55), ISO 19005-3 (PDF/A-3), CII (UN/CEFACT), UBL 2.1 (OASIS) - **Simplified Format**: Generation from SIRET + auto-enrichment (Chorus Pro API + Business Search)  ### ✅ Factur-X - Validation - **XML Validation**: Schematron (45 to 210+ rules depending on profile) - **PDF Validation**: PDF/A-3, Factur-X XMP metadata - **VeraPDF**: Strict PDF/A validation (146+ ISO 19005-3 rules)  ### ✍️ Electronic Signature - **Standards**: PAdES-B-B, PAdES-B-T (RFC 3161 timestamping), PAdES-B-LT (long-term archival) - **eIDAS Levels**: SES (self-signed), AdES (commercial CA), QES (QTSP) - **Validation**: Cryptographic integrity and certificate verification  ### 📋 Flux 6 - Invoice Lifecycle (CDAR) - **CDAR Messages**: Acknowledgements, invoice statuses - **PPF Statuses**: REFUSED (210), PAID (212)  ### 📊 Flux 10 - E-Reporting - **Tax Declarations**: International B2B, B2C - **Flow Types**: 10.1 (B2B transactions), 10.2 (B2B payments), 10.3 (B2C transactions), 10.4 (B2C payments)  ### 📡 AFNOR PDP/PA (XP Z12-013) - **Flow Service**: Submit and search flows to PDPs - **Directory Service**: Company search (SIREN/SIRET) - **Multi-client**: Support for multiple PDP configs per user  ### 🏛️ Chorus Pro - **Public Sector Invoicing**: Complete API for Chorus Pro  ### ⏳ Async Tasks - **Celery**: Asynchronous generation, validation and signing - **Polling**: Status tracking via `/tasks/{task_id}/status` - **Webhooks**: Automatic notifications when tasks complete  ## 🔒 Authentication  All requests require a **JWT token** in the Authorization header: ``` Authorization: Bearer YOUR_JWT_TOKEN ```  ### How to obtain a JWT token?  #### 🔑 Method 1: `/api/token/` API (Recommended)  **URL:** `https://factpulse.fr/api/token/`  This method is **recommended** for integration in your applications and CI/CD workflows.  **Prerequisites:** Having set a password on your account  **For users registered via email/password:** - You already have a password, use it directly  **For users registered via OAuth (Google/GitHub):** - You must first set a password at: https://factpulse.fr/accounts/password/set/ - Once the password is created, you can use the API  **Request example:** ```bash curl -X POST https://factpulse.fr/api/token/ \\   -H \"Content-Type: application/json\" \\   -d '{     \"username\": \"your_email@example.com\",     \"password\": \"your_password\"   }' ```  **Optional `client_uid` parameter:**  To select credentials for a specific client (PA/PDP, Chorus Pro, signing certificates), add `client_uid`:  ```bash curl -X POST https://factpulse.fr/api/token/ \\   -H \"Content-Type: application/json\" \\   -d '{     \"username\": \"your_email@example.com\",     \"password\": \"your_password\",     \"client_uid\": \"550e8400-e29b-41d4-a716-446655440000\"   }' ```  The `client_uid` will be included in the JWT and allow the API to automatically use: - AFNOR/PDP credentials configured for this client - Chorus Pro credentials configured for this client - Electronic signature certificates configured for this client  **Response:** ```json {   \"access\": \"eyJ0eXAiOiJKV1QiLCJhbGc...\",  // Access token (validity: 30 min)   \"refresh\": \"eyJ0eXAiOiJKV1QiLCJhbGc...\"  // Refresh token (validity: 7 days) } ```  **Advantages:** - ✅ Full automation (CI/CD, scripts) - ✅ Programmatic token management - ✅ Refresh token support for automatic access renewal - ✅ Easy integration in any language/tool  #### 🖥️ Method 2: Dashboard Generation (Alternative)  **URL:** https://factpulse.fr/api/dashboard/  This method is suitable for quick tests or occasional use via the graphical interface.  **How it works:** - Log in to the dashboard - Use the \"Generate Test Token\" or \"Generate Production Token\" buttons - Works for **all** users (OAuth and email/password), without requiring a password  **Token types:** - **Test Token**: 24h validity, 1000 calls/day quota (free) - **Production Token**: 7 days validity, quota based on your plan  **Advantages:** - ✅ Quick for API testing - ✅ No password required - ✅ Simple visual interface  **Disadvantages:** - ❌ Requires manual action - ❌ No refresh token - ❌ Less suited for automation  ### 📚 Full Documentation  For more information on authentication and API usage: https://factpulse.fr/documentation-api/     

    The version of the OpenAPI document: 1.0.0
    Contact: contact@factpulse.fr
    Generated by OpenAPI Generator (https://openapi-generator.tech)

    Do not edit the class manually.
"""  # noqa: E501


from __future__ import annotations
import pprint
import re  # noqa: F401
import json

from datetime import date
from pydantic import BaseModel, ConfigDict, Field, StrictStr
from typing import Any, ClassVar, Dict, List, Optional
from factpulse.models.encaisseamount import Encaisseamount
from factpulse.models.recipient_input import RecipientInput
from typing import Optional, Set
from typing_extensions import Self

class CreateCDARRequest(BaseModel):
    """
    Requête de création d'un message CDAR.
    """ # noqa: E501
    document_id: StrictStr = Field(description="Identifiant unique du message CDAR", alias="documentId")
    business_process: Optional[StrictStr] = Field(default='REGULATED', description="Code processus métier (REGULATED, B2C, B2BINT, etc.)", alias="businessProcess")
    type_code: Optional[StrictStr] = Field(default='23', description="Type de message (23=Traitement, 305=Transmission)", alias="typeCode")
    sender_siren: StrictStr = Field(description="SIREN de l'émetteur (9 chiffres)", alias="senderSiren")
    sender_role: Optional[StrictStr] = Field(default='WK', description="Rôle de l'émetteur (WK, SE, BY, etc.)", alias="senderRole")
    sender_name: Optional[StrictStr] = Field(default=None, alias="senderName")
    sender_email: Optional[StrictStr] = Field(default=None, alias="senderEmail")
    recipients: Optional[List[RecipientInput]] = Field(default=None, description="Liste des destinataires")
    invoice_id: StrictStr = Field(description="Identifiant de la facture (BT-1)", alias="invoiceId")
    invoice_issue_date: date = Field(description="Date d'émission de la facture (YYYY-MM-DD)", alias="invoiceIssueDate")
    invoice_type_code: Optional[StrictStr] = Field(default='380', description="Type de document (380=Facture, 381=Avoir)", alias="invoiceTypeCode")
    invoice_seller_siren: Optional[StrictStr] = Field(default=None, alias="invoiceSellerSiren")
    invoice_buyer_siren: Optional[StrictStr] = Field(default=None, alias="invoiceBuyerSiren")
    status: StrictStr = Field(description="Code statut de la facture (200-601)")
    reason_code: Optional[StrictStr] = Field(default=None, alias="reasonCode")
    reason_text: Optional[StrictStr] = Field(default=None, alias="reasonText")
    action_code: Optional[StrictStr] = Field(default=None, alias="actionCode")
    encaisse_amount: Optional[Encaisseamount] = Field(default=None, alias="encaisseAmount")
    __properties: ClassVar[List[str]] = ["documentId", "businessProcess", "typeCode", "senderSiren", "senderRole", "senderName", "senderEmail", "recipients", "invoiceId", "invoiceIssueDate", "invoiceTypeCode", "invoiceSellerSiren", "invoiceBuyerSiren", "status", "reasonCode", "reasonText", "actionCode", "encaisseAmount"]

    model_config = ConfigDict(
        validate_by_name=True,
        validate_by_alias=True,
        validate_assignment=True,
        protected_namespaces=(),
    )


    def to_str(self) -> str:
        """Returns the string representation of the model using alias"""
        return pprint.pformat(self.model_dump(by_alias=True))

    def to_json(self) -> str:
        """Returns the JSON representation of the model using alias"""
        # TODO: pydantic v2: use .model_dump_json(by_alias=True, exclude_unset=True) instead
        return json.dumps(self.to_dict())

    @classmethod
    def from_json(cls, json_str: str) -> Optional[Self]:
        """Create an instance of CreateCDARRequest from a JSON string"""
        return cls.from_dict(json.loads(json_str))

    def to_dict(self) -> Dict[str, Any]:
        """Return the dictionary representation of the model using alias.

        This has the following differences from calling pydantic's
        `self.model_dump(by_alias=True)`:

        * `None` is only added to the output dict for nullable fields that
          were set at model initialization. Other fields with value `None`
          are ignored.
        """
        excluded_fields: Set[str] = set([
        ])

        _dict = self.model_dump(
            by_alias=True,
            exclude=excluded_fields,
            exclude_none=True,
        )
        # override the default output from pydantic by calling `to_dict()` of each item in recipients (list)
        _items = []
        if self.recipients:
            for _item_recipients in self.recipients:
                if _item_recipients:
                    _items.append(_item_recipients.to_dict())
            _dict['recipients'] = _items
        # override the default output from pydantic by calling `to_dict()` of encaisse_amount
        if self.encaisse_amount:
            _dict['encaisseAmount'] = self.encaisse_amount.to_dict()
        # set to None if sender_name (nullable) is None
        # and model_fields_set contains the field
        if self.sender_name is None and "sender_name" in self.model_fields_set:
            _dict['senderName'] = None

        # set to None if sender_email (nullable) is None
        # and model_fields_set contains the field
        if self.sender_email is None and "sender_email" in self.model_fields_set:
            _dict['senderEmail'] = None

        # set to None if invoice_seller_siren (nullable) is None
        # and model_fields_set contains the field
        if self.invoice_seller_siren is None and "invoice_seller_siren" in self.model_fields_set:
            _dict['invoiceSellerSiren'] = None

        # set to None if invoice_buyer_siren (nullable) is None
        # and model_fields_set contains the field
        if self.invoice_buyer_siren is None and "invoice_buyer_siren" in self.model_fields_set:
            _dict['invoiceBuyerSiren'] = None

        # set to None if reason_code (nullable) is None
        # and model_fields_set contains the field
        if self.reason_code is None and "reason_code" in self.model_fields_set:
            _dict['reasonCode'] = None

        # set to None if reason_text (nullable) is None
        # and model_fields_set contains the field
        if self.reason_text is None and "reason_text" in self.model_fields_set:
            _dict['reasonText'] = None

        # set to None if action_code (nullable) is None
        # and model_fields_set contains the field
        if self.action_code is None and "action_code" in self.model_fields_set:
            _dict['actionCode'] = None

        # set to None if encaisse_amount (nullable) is None
        # and model_fields_set contains the field
        if self.encaisse_amount is None and "encaisse_amount" in self.model_fields_set:
            _dict['encaisseAmount'] = None

        return _dict

    @classmethod
    def from_dict(cls, obj: Optional[Dict[str, Any]]) -> Optional[Self]:
        """Create an instance of CreateCDARRequest from a dict"""
        if obj is None:
            return None

        if not isinstance(obj, dict):
            return cls.model_validate(obj)

        _obj = cls.model_validate({
            "documentId": obj.get("documentId"),
            "businessProcess": obj.get("businessProcess") if obj.get("businessProcess") is not None else 'REGULATED',
            "typeCode": obj.get("typeCode") if obj.get("typeCode") is not None else '23',
            "senderSiren": obj.get("senderSiren"),
            "senderRole": obj.get("senderRole") if obj.get("senderRole") is not None else 'WK',
            "senderName": obj.get("senderName"),
            "senderEmail": obj.get("senderEmail"),
            "recipients": [RecipientInput.from_dict(_item) for _item in obj["recipients"]] if obj.get("recipients") is not None else None,
            "invoiceId": obj.get("invoiceId"),
            "invoiceIssueDate": obj.get("invoiceIssueDate"),
            "invoiceTypeCode": obj.get("invoiceTypeCode") if obj.get("invoiceTypeCode") is not None else '380',
            "invoiceSellerSiren": obj.get("invoiceSellerSiren"),
            "invoiceBuyerSiren": obj.get("invoiceBuyerSiren"),
            "status": obj.get("status"),
            "reasonCode": obj.get("reasonCode"),
            "reasonText": obj.get("reasonText"),
            "actionCode": obj.get("actionCode"),
            "encaisseAmount": Encaisseamount.from_dict(obj["encaisseAmount"]) if obj.get("encaisseAmount") is not None else None
        })
        return _obj


