> LOADING LARAVEL-MOLONI v1.0...

Laravel Moloni

Integracao completa com a API de faturacao Moloni para Laravel. Gestao de clientes, produtos, faturas e todos os documentos fiscais com type safety total.

Overview

O Laravel Moloni e um pacote que integra a sua aplicacao Laravel com a API do Moloni, a plataforma de faturacao mais utilizada em Portugal. Oferece uma interface fluente e tipada para gerir empresas, clientes, produtos, faturas e todos os outros recursos Moloni, com type safety total atraves de DTOs e enums.

PHP 8.4+ Laravel 12-13 MIT License DTOs Tipados Pest PHP PHPStan

Tipos de documentos suportados

  • Faturas
  • Recibos
  • Notas de Credito
  • Notas de Debito
  • Faturas Simplificadas
  • Fatura-Recibos
  • Guias de Remessa
  • Guias de Transporte
  • Cartas de Porte
  • Orcamentos
  • Documentos Genericos

Instalacao

Instale o pacote via Composer, publique a configuracao e execute as migrations.

Instalacao
bash
composer require digitaldev-lx/laravel-moloni
Publicar configuracao e migrar
bash
php artisan vendor:publish --tag=moloni-config
php artisan migrate

Configuracao

Adicione as credenciais da API Moloni ao ficheiro .env. As credenciais sao obtidas no Moloni Developer Portal.

.env
bash
MOLONI_CLIENT_ID=your-client-id
MOLONI_CLIENT_SECRET=your-client-secret
MOLONI_USERNAME=your-username
MOLONI_PASSWORD=your-password
MOLONI_COMPANY_ID=your-company-id

Variaveis de ambiente

Variavel Descricao
MOLONI_CLIENT_ID Client ID da aplicacao registada no Moloni
MOLONI_CLIENT_SECRET Client Secret da aplicacao
MOLONI_USERNAME Email da conta Moloni
MOLONI_PASSWORD Password da conta Moloni
MOLONI_COMPANY_ID ID da empresa no Moloni

Clientes

Gerir clientes atraves da facade Moloni. Pode listar, pesquisar por NIF e criar novos clientes usando DTOs tipados ou arrays simples.

Listar e pesquisar clientes
php
use DigitaldevLx\LaravelMoloni\Facades\Moloni;

$companyId = config('moloni.company_id');

// Listar todos os clientes
$customers = Moloni::customers()->getAll($companyId);

// Pesquisar por NIF
$customer = Moloni::customers()->getByVat($companyId, '123456789');
Criar cliente com DTO
php
use DigitaldevLx\LaravelMoloni\DataTransferObjects\Customer as CustomerDto;

$dto = new CustomerDto(
    vat: '123456789',
    number: 'C001',
    name: 'John Doe',
    email: 'john@example.com',
    address: '123 Main Street',
    city: 'Lisbon',
    zipCode: '1000-001',
    countryId: 1,
);

$customer = Moloni::customers()->insert($companyId, $dto);
Criar cliente com array
php
$customer = Moloni::customers()->insert($companyId, [
    'vat' => '123456789',
    'number' => 'C001',
    'name' => 'John Doe',
    'email' => 'john@example.com',
]);

Produtos

Gestao completa do catalogo de produtos com suporte a categorias, tipos e unidades de medida.

Listar e pesquisar produtos
php
$companyId = config('moloni.company_id');

// Listar todos
$products = Moloni::products()->getAll($companyId);

// Pesquisar por referencia
$product = Moloni::products()->getByReference($companyId, 'PROD-001');
Criar produto com DTO
php
use DigitaldevLx\LaravelMoloni\DataTransferObjects\Product as ProductDto;
use DigitaldevLx\LaravelMoloni\Enums\ProductType;

$dto = new ProductDto(
    name: 'Widget',
    reference: 'PROD-001',
    type: ProductType::Product,
    categoryId: 1,
    unitId: 1,
    price: 29.99,
);

$product = Moloni::products()->insert($companyId, $dto);

Documentos e Faturas

Emita faturas e outros documentos fiscais com DTOs tipados para produtos, pagamentos e datas. O pacote suporta todos os tipos de documentos do Moloni.

Emitir fatura
php
use DigitaldevLx\LaravelMoloni\DataTransferObjects\Document as DocumentDto;
use DigitaldevLx\LaravelMoloni\DataTransferObjects\DocumentProduct;
use DigitaldevLx\LaravelMoloni\DataTransferObjects\Payment;

$dto = new DocumentDto(
    documentSetId: 1,
    customerId: 1,
    date: '2026-03-31',
    expirationDate: '2026-04-30',
    products: [
        new DocumentProduct(
            productId: 1,
            qty: 2,
            price: 29.99,
        ),
    ],
    payments: [
        new Payment(
            paymentMethodId: 1,
            value: 59.98,
            date: '2026-03-31',
        ),
    ],
);

$invoice = Moloni::invoices()->insert($companyId, $dto);
Obter PDF da fatura
php
$pdfLink = Moloni::invoices()->getPdfLink($companyId, $invoiceId);

Todos os tipos de documentos

Cada tipo de documento segue a mesma interface. Substitua invoices() pelo metodo correspondente:

Tipos de documentos disponiveis
php
Moloni::invoices()             // Faturas
Moloni::receipts()             // Recibos
Moloni::creditNotes()          // Notas de Credito
Moloni::debitNotes()           // Notas de Debito
Moloni::simplifiedInvoices()   // Faturas Simplificadas
Moloni::invoiceReceipts()      // Fatura-Recibos
Moloni::deliveryNotes()        // Guias de Remessa
Moloni::billsOfLading()        // Cartas de Porte
Moloni::waybills()             // Guias de Transporte
Moloni::estimates()            // Orcamentos
Moloni::documents()            // Documentos Genericos

Trait HasMoloniDocuments

Associe documentos Moloni a qualquer model Eloquent:

Associar documentos a um model
php
use DigitaldevLx\LaravelMoloni\Concerns\HasMoloniDocuments;

class Order extends Model
{
    use HasMoloniDocuments;
}

// Aceder aos documentos
$order->moloniDocuments;

Recursos e Configuracoes

Aceda a todos os recursos auxiliares do Moloni -- impostos, metodos de pagamento, series de documentos, armazens e mais.

Recursos da empresa
php
$companyId = config('moloni.company_id');

$taxes = Moloni::taxes()->getAll($companyId);
$paymentMethods = Moloni::paymentMethods()->getAll($companyId);
$documentSets = Moloni::documentSets()->getAll($companyId);
$warehouses = Moloni::warehouses()->getAll($companyId);
$units = Moloni::measurementUnits()->getAll($companyId);
$maturityDates = Moloni::maturityDates()->getAll($companyId);
$deliveryMethods = Moloni::deliveryMethods()->getAll($companyId);
$bankAccounts = Moloni::bankAccounts()->getAll($companyId);
Recursos globais
php
$countries = Moloni::countries()->getAll();
$currencies = Moloni::currencies()->getAll();
$languages = Moloni::languages()->getAll();
$exemptions = Moloni::taxExemptions()->getAll();
$fiscalZones = Moloni::fiscalZones()->getAll($countryId);

Data Transfer Objects

O pacote fornece DTOs tipados no namespace DigitaldevLx\LaravelMoloni\DataTransferObjects para garantir type safety:

Customer Product Document DocumentProduct Supplier Tax Payment Address

Eventos

O pacote emite eventos para todas as mutacoes, permitindo reagir a criacoes, atualizacoes e alteracoes de estado de documentos.

Evento Trigger
DocumentCreated Documento criado com sucesso
DocumentCancelled Documento anulado
DocumentClosed Documento fechado/finalizado
CustomerCreated Novo cliente criado
CustomerUpdated Cliente atualizado
ProductCreated Novo produto criado
ProductUpdated Produto atualizado
TokenRefreshed Token OAuth renovado automaticamente

Registar listeners

EventServiceProvider
php
use DigitaldevLx\LaravelMoloni\Events\DocumentCreated;

class EventServiceProvider extends ServiceProvider
{
    protected $listen = [
        DocumentCreated::class => [
            SendInvoiceNotification::class,
        ],
    ];
}

Tratamento de Erros

O pacote fornece excepcoes tipadas para cada cenario de erro, todas a estender MoloniException.

Excepcao Cenario
AuthenticationException Erros OAuth2 (credenciais invalidas, token expirado)
ValidationException Falhas de validacao de dados
RateLimitException Rate limit da API atingido (HTTP 429)
MoloniException Todos os outros erros da API
Tratamento completo de erros
php
use DigitaldevLx\LaravelMoloni\Exceptions\MoloniException;
use DigitaldevLx\LaravelMoloni\Exceptions\AuthenticationException;
use DigitaldevLx\LaravelMoloni\Exceptions\ValidationException;
use DigitaldevLx\LaravelMoloni\Exceptions\RateLimitException;

try {
    $invoice = Moloni::invoices()->insert($companyId, $data);
} catch (AuthenticationException $e) {
    // $e->authError        - AuthError enum
    // $e->errorDescription - Descricao do erro
    Log::error('Moloni auth failed', ['error' => $e->authError]);
} catch (ValidationException $e) {
    // $e->errors             - Array de erros
    // $e->getFieldErrors()   - Erros por campo
    // $e->hasFieldError('vat') - Verificar campo especifico
    return back()->withErrors($e->getFieldErrors());
} catch (RateLimitException $e) {
    // Retry apos espera
    dispatch(fn () => retry(...))->delay(now()->addMinutes(1));
} catch (MoloniException $e) {
    // Erro generico da API
    Log::error('Moloni error', ['message' => $e->getMessage()]);
}

Erros de validacao

A ValidationException fornece metodos para inspecionar erros campo a campo:

Inspecionar erros de validacao
php
try {
    $customer = Moloni::customers()->insert($companyId, $data);
} catch (ValidationException $e) {
    // Array completo de erros
    $errors = $e->errors;

    // Erros organizados por campo
    $fieldErrors = $e->getFieldErrors();
    // ['vat' => ['NIF invalido'], 'email' => ['Email invalido']]

    // Verificar se um campo especifico falhou
    if ($e->hasFieldError('vat')) {
        // Tratar erro de NIF
    }
}

Boas Praticas

Usar DTOs em vez de arrays

Prefira sempre DTOs tipados a arrays associativos. Os DTOs garantem type safety em compile-time, autocompletar no IDE e validacao implicita da estrutura dos dados.

Tratar todas as excepcoes

A API do Moloni pode retornar erros de autenticacao, validacao ou rate limit. Trate cada tipo de excepcao de forma adequada em vez de capturar apenas MoloniException.

Emitir documentos em background

Use jobs e queues para emitir faturas e outros documentos. Isto evita timeouts em requests HTTP e permite retries automaticos em caso de falha.

Emitir fatura em background
php
// App\Jobs\CreateInvoiceJob.php
class CreateInvoiceJob implements ShouldQueue
{
    public function __construct(
        private Order $order,
        private DocumentDto $document,
    ) {}

    public function handle(): void
    {
        $companyId = config('moloni.company_id');
        Moloni::invoices()->insert($companyId, $this->document);
    }
}

// Despachar o job
CreateInvoiceJob::dispatch($order, $documentDto);

Reagir a eventos

Use os eventos do pacote para manter a sua aplicacao sincronizada. Por exemplo, envie um email ao cliente quando uma fatura e criada, ou atualize o stock quando um produto e modificado.

Guardar o company_id na config

Use config('moloni.company_id') em vez de hardcoded IDs. Isto facilita a mudanca entre ambientes e empresas de teste.

Usar HasMoloniDocuments nos models

Adicione a trait HasMoloniDocuments aos models que geram documentos fiscais (encomendas, subscricoes, etc.) para manter uma relacao directa entre os registos da aplicacao e os documentos no Moloni.

Testes

O pacote utiliza Pest PHP para testes, PHPStan para analise estatica e Pint para formatacao de codigo.

Executar testes e ferramentas de qualidade
bash
# Testes
vendor/bin/pest

# Analise estatica
vendor/bin/phpstan analyse

# Formatacao de codigo
vendor/bin/pint

$ composer require digitaldev-lx/laravel-moloni

Pronto para automatizar a faturacao?

Consulte o repositorio no GitHub para a documentacao completa, issues e contribuicoes.

> COOKIE_CONSENT_REQUIRED

Utilizamos cookies essenciais para o funcionamento do site e cookies analíticos (Google Analytics) para compreender como utiliza o nosso site. Os cookies analíticos só são ativados com o seu consentimento. Política de Privacidade