# InvoicingService

`src/Services/InvoicingService.php`

The central orchestrator of the package. It is the main entry point for any operation related to electronic documents — creating, validating, dispatching, and retrieving them. Controllers and external code should interact with this service rather than calling lower-level services directly.

It is registered as the `facturacion` singleton in the service container.

---

## Document Type Constants

The service exposes public constants for all supported document type codes:

| Constant | Value | Document |
|---|---|---|
| `TYPE_FE` | `FE` | Electronic Invoice |
| `TYPE_FEE` | `FEE` | Electronic Export Invoice |
| `TYPE_FEC` | `FEC` | Electronic Purchase Invoice |
| `TYPE_TE` | `TE` | Electronic Ticket |
| `TYPE_ND` | `ND` | Electronic Debit Note |
| `TYPE_NC` | `NC` | Electronic Credit Note |
| `TYPE_REP` | `REP` | Electronic Payment Receipt |
| `TYPE_CA` | `CA` | Acceptance Confirmation (Confirmación de Aceptación) |
| `TYPE_CAP` | `CAP` | Partial Acceptance Confirmation (Confirmación de Aceptación Parcial) |
| `TYPE_CR` | `CR` | Rejection Confirmation (Confirmación de Rechazo) |

---

## Create & Send Methods

### `createAndSend(string $type, array $data): array`

The core method that handles the full lifecycle of submitting an electronic document:

1. Validates the input data using the validator registered for the given `$type`.
2. Persists the document to the database via `DbService`.
3. Dispatches `SendReceiptToProviderJob` to send the document to the configured provider asynchronously.

Use this when you need to handle document submission generically (e.g. when the document type is determined at runtime).

**Returns** a standardised array:
- On success: `['success' => true, 'data' => [...], 'message' => '...']`
- On validation failure: `['success' => false, 'message' => 'Validation Error', 'status_code' => 422, 'errors' => [...]]`
- On unexpected error: `['success' => false, 'message' => '...', 'status_code' => 500]`

---

### Type-specific wrappers

These methods are thin wrappers around `createAndSend` for each document type. Use them when the document type is known at the call site for cleaner, more explicit code.

| Method | Document type |
|---|---|
| `createAndSendFE(array $data): array` | Electronic Invoice (FE) |
| `createAndSendFEE(array $data): array` | Electronic Export Invoice (FEE) |
| `createAndSendFEC(array $data): array` | Electronic Purchase Invoice (FEC) |
| `createAndSendTE(array $data): array` | Electronic Ticket (TE) |
| `createAndSendND(array $data): array` | Electronic Debit Note (ND) |
| `createAndSendNC(array $data): array` | Electronic Credit Note (NC) |
| `createAndSendREP(array $data): array` | Electronic Payment Receipt (REP) |

---

### `createAndSendReception(array $data): array`

Validates, persists, and queues a reception message for sending to the provider. Reception messages are the mechanism by which a receiver communicates back to the sender (and Hacienda) whether they accept, partially accept, or reject a document they received.

The document type (CA, CAP, CR) and reception status are derived automatically from the payload:
- `Clave.TipoComprobante` → `05` = CA, `06` = CAP, `07` = CR
- `Detalle.CodigoMensaje` → `1` = accepted, `2` = partially_accepted, `3` = rejected

**Required fields:**

| Field | Rules | Description |
|---|---|---|
| `Clave.TipoComprobante` | required, `05\|06\|07` | Reception message type |
| `Clave.SituacionComprobante` | required, `1\|2\|3` | Situation code (normal / contingency / no internet) |
| `Clave.Sucursal` | nullable, 3 digits | Branch code |
| `Clave.Terminal` | nullable, 5 digits | Terminal code |
| `FechaEmision` | required, `Y-m-d\TH:i:sP` | Emission datetime with timezone |
| `Emisor.Nombre` | required, 5–100 chars | Issuer name |
| `Emisor.Identificacion.Tipo` | required, `01\|02\|03\|04` | Issuer ID type |
| `Emisor.Identificacion.Numero` | required, max 20 chars | Issuer ID number |
| `Receptor.Nombre` | required if Receptor present, 3–100 chars | Recipient name |
| `Receptor.Identificacion.Tipo` | required if Receptor present, `01\|02\|03\|04` | Recipient ID type |
| `Receptor.Identificacion.Numero` | required if Receptor present, max 20 chars | Recipient ID number |
| `Detalle.Clave` | required, exactly 50 chars | Clave of the document being accepted/rejected |
| `Detalle.FechaEmisionDoc` | required, `Y-m-d\TH:i:sP` | Emission date of the referenced document |
| `Detalle.CodigoMensaje` | required, `1\|2\|3` | Accept / partial / reject |
| `Detalle.Mensaje` | required if CodigoMensaje is `2` or `3`, 5–160 chars | Reason for partial acceptance or rejection |
| `Detalle.CodigoActividad` | nullable, 6 chars | Economic activity code |
| `Detalle.CondicionImpuesto` | nullable, `01–05` | Tax condition code |
| `Detalle.MontoTotalImpuestoAcreditar` | nullable, decimal | Tax amount to credit |
| `Detalle.MontoTotalDeGastoAplicable` | nullable, decimal | Applicable expense amount |
| `Detalle.MontoTotalImpuesto` | nullable, decimal | Total tax amount |
| `Detalle.TotalFactura` | nullable, decimal | Total invoice amount |

**Returns** the same standardised array as `createAndSend`:
- On success: `['success' => true, 'data' => ['receipt_id' => ..., 'consecutive_number' => ..., 'status' => 'queued'], 'message' => '...']`
- On validation failure: `['success' => false, 'message' => 'Validation Error', 'status_code' => 422, 'errors' => [...]]`
- On unexpected error: `['success' => false, 'message' => '...', 'status_code' => 500]`

---

## Query Methods

### `getAllDocuments(): LengthAwarePaginator`

Retrieves all electronic documents in the system, regardless of type. Useful for dashboards or admin views that show the full document history.

---

### `getAllByType(string $type): LengthAwarePaginator`

Retrieves all documents of a specific type. Throws `\InvalidArgumentException` if the type code is not supported.

---

### Type-specific wrappers

Convenience methods that call `getAllByType` with the corresponding type code. Use them to fetch a filtered list without specifying the type string manually.

| Method | Fetches |
|---|---|
| `getAllInvoices()` | All FE documents |
| `getAllExportInvoices()` | All FEE documents |
| `getAllCreditNotes()` | All NC documents |
| `getAllDebitNotes()` | All ND documents |
| `getAllPaymentReceipts()` | All REP documents |
| `getAllTickets()` | All TE documents |

---

### `getDocumentsByStatus(string $status): ?LengthAwarePaginator`

Retrieves all documents filtered by their internal processing status (e.g. `pending`, `queued`, `sent`, `error`). Useful for monitoring or retry workflows.

---

### `getDocumentsByHaciendaStatus(string $haciendaStatus): ?LengthAwarePaginator`

Retrieves all documents filtered by the status returned by Hacienda (e.g. `accepted`, `rejected`). Useful for reconciliation and compliance reports.

---

### `getDocumentById(int|string $id): ?Receipt`

Finds a single document by its primary key (database ID) or UI key. Returns `null` if not found.

---

### `getDocumentByUiKey(string $uiKey): ?Receipt`

Finds a single document by its UI key (the UUID exposed to external systems). Returns `null` if not found. Use this to look up a document when you only have the identifier returned by the submission endpoint.

---

### `getDocumentStatus(string $uiKey): ?Receipt`

Returns the document record with its Hacienda processing status using its UI key. Use this when you only need to check whether Hacienda accepted or rejected a document, without loading the full payload.

---

## Provider Methods

### `getProvider()`

Resolves and returns the active provider instance based on the `invoicing.electronic_invoicing_provider` config value. Use this when you need to call provider-specific methods directly (e.g. querying document status from the provider's API outside the normal job flow).

---

## Validation Methods

### `validateByType(string $type, array $data): array`

Validates raw input data against the rules defined for the given document type. Used internally by `createAndSend`, but also available publicly so controllers or other services can pre-validate data before persisting.

- Calls `rules($data)` on the corresponding validator class to build the Laravel validation rules array.
- Calls `after($validator, $data)` to run post-rule checks (detail lines, taxes, invoice summary).
- Throws `ValidationException` if validation fails.
- Returns the validated data array on success.
