emeq/moneybird 问题修复 & 功能扩展

解决BUG、新增功能、兼容多环境部署,快速响应你的开发需求

邮箱:yvsm@zunyunkeji.com | QQ:316430983 | 微信:yvsm316

emeq/moneybird

Composer 安装命令:

composer require emeq/moneybird

包简介

Laravel package for Moneybird integration with OAuth token management

README 文档

README

Latest Version on Packagist

Laravel package for Moneybird integration with OAuth token management and extended API features.

Installation

You can install the package via composer:

composer require emeq/moneybird

The package will automatically publish the config file and migration to your application during installation. If you need to republish them manually:

# Publish config file
php artisan vendor:publish --tag="moneybird-config"

# Publish migrations
php artisan vendor:publish --tag="moneybird-migrations"

After installation, run the migrations:

php artisan migrate

Configuration

Add the following environment variables to your .env file:

MONEYBIRD_CLIENT_ID=your_client_id
MONEYBIRD_CLIENT_SECRET=your_client_secret
MONEYBIRD_REDIRECT_URI=https://your-app.com/moneybird/callback
MONEYBIRD_WEBHOOK_SECRET=your_webhook_secret
MONEYBIRD_API_TIMEOUT=30

OAuth Setup

  1. Create a Moneybird application at https://moneybird.com/oauth/applications
  2. Set your redirect URI to match MONEYBIRD_REDIRECT_URI (e.g., https://your-app.com/moneybird/auth/callback)
  3. Copy the Client ID and Client Secret to your .env file

Usage

Connecting to Moneybird

Via Routes (Recommended for Web Applications)

The package provides web routes for easy OAuth connection:

  1. Start the connection: Visit /moneybird/connect while authenticated

    • This route requires authentication (auth middleware)
    • It will redirect you to Moneybird's authorization page
  2. Handle the callback: After authorization, Moneybird redirects to /moneybird/auth/callback

    • The callback route automatically exchanges the authorization code for tokens
    • On success, you'll be redirected to your dashboard with a success message
    • On error, you'll be redirected with an error message

Example in your Blade template:

<a href="{{ route('moneybird.connect') }}" class="btn btn-primary">
    Connect to Moneybird
</a>

Example redirect in your controller:

return redirect()->route('moneybird.connect');

Via Artisan Command

Use the artisan command for CLI-based connections:

php artisan moneybird:connect --user-id=1

Programmatically

use Emeq\Moneybird\Services\OAuthService;

$oauthService = app(OAuthService::class);
$authorizationUrl = $oauthService->getAuthorizationUrl();

// Redirect user to $authorizationUrl
// After authorization, exchange the code:
$connection = $oauthService->exchangeCodeForTokens($authorizationCode, $userId);

Testing the Connection

Via Routes

After connecting, you can test the connection by accessing any route that uses the Moneybird service. The package will automatically handle token refresh if needed.

Example test route in your application:

Route::middleware('auth')->get('/moneybird/test', function () {
    $userId = auth()->id();
    $service = \Emeq\Moneybird\Facades\Moneybird::connection($userId);

    try {
        $administrations = $service->administrations()->list();
        return response()->json([
            'success' => true,
            'message' => 'Connection successful!',
            'administrations' => $administrations,
        ]);
    } catch (\Exception $e) {
        return response()->json([
            'success' => false,
            'message' => 'Connection failed: ' . $e->getMessage(),
        ], 500);
    }
});

Via Artisan Command

php artisan moneybird:test-connection --user-id=1

Using the Moneybird Service

use Emeq\Moneybird\Facades\Moneybird;

// Get connection for a user
$service = Moneybird::connection($userId);

// Or for a specific connection
$service = Moneybird::connection(connectionId: $connectionId);

// List administrations
$administrations = $service->administrations()->list();

// Work with contacts
$contacts = $service->contacts()->list();
$contact = $service->contacts()->create([
    'company_name' => 'Example Company',
    'email' => 'contact@example.com',
]);

// Work with sales invoices
$invoices = $service->salesInvoices()->list();
$invoice = $service->salesInvoices()->create([
    'contact_id' => $contact->id,
    'invoice_date' => now()->format('Y-m-d'),
    'details' => [
        [
            'description' => 'Product 1',
            'price' => 100.00,
            'amount' => 1,
        ],
    ],
]);

// Find invoice by invoice ID (invoice number)
$invoice = $service->salesInvoices()->findByInvoiceId('2023-001');

// Send invoice
$service->salesInvoices()->send($invoice->id);

Frontend Components

The package includes reusable Vue components for displaying integrations in your frontend:

IntegrationCard Component (resources/views/IntegrationCard.vue)

A Vue component for displaying integration information in a card format or connection prompt. It supports:

  • Integration logos (with automatic placeholder for missing logos)
  • Clickable integration names with external links
  • Connection status display
  • Action buttons (Connect/Manage for available integrations, "Coming soon" for unavailable ones)
  • Connection prompt mode (when showPrompt prop is true and integration is not connected)

Usage Example - Card Mode:

<template>
    <IntegrationCard
        :integration="{
            id: 'moneybird',
            name: 'Moneybird',
            description: 'Boekhouding en facturering',
            logo: 'https://moneybird.cdn.prismic.io/moneybird/ZkXWvyol0Zci9Mhv_vertical_birdblue.svg',
            url: 'https://www.moneybird.com/',
            available: true,
            connected: false,
            connectUrl: '/moneybird/connect',
        }"
        @click="handleIntegrationClick"
    />
</template>

<script>
import IntegrationCard from "vendor/emeq/moneybird/resources/views/IntegrationCard.vue";

export default {
    components: {
        IntegrationCard,
    },
    methods: {
        handleIntegrationClick(integrationId) {
            // Handle integration click
        },
    },
};
</script>

Usage Example - Connection Prompt Mode:

<template>
    <IntegrationCard
        :integration="{
            id: 'moneybird',
            name: 'Moneybird',
            description: 'Boekhouding en facturering',
            logo: 'https://moneybird.cdn.prismic.io/moneybird/ZkXWvyol0Zci9Mhv_vertical_birdblue.svg',
            url: 'https://www.moneybird.com/',
            available: true,
            connected: false,
            connectUrl: '/moneybird/connect',
        }"
        :show-prompt="true"
    />
</template>

<script>
import IntegrationCard from "vendor/emeq/moneybird/resources/views/IntegrationCard.vue";

export default {
    components: {
        IntegrationCard,
    },
};
</script>

Integration Object Structure:

interface Integration {
    id: string; // Unique identifier (e.g., 'moneybird', 'mollie')
    name: string; // Display name
    description: string; // Short description
    logo: string; // Logo URL (SVG or image)
    url: string; // External website URL
    available: boolean; // Whether integration is available
    connected: boolean; // Whether user has connected
    connectUrl: string; // URL to start connection flow
}

API Routes

The package provides RESTful API routes for accessing Moneybird data. All routes are prefixed with /api/moneybird and require Laravel Sanctum authentication.

Authentication

All API routes require authentication via Laravel Sanctum. Include the Bearer token in the Authorization header:

Authorization: Bearer {your-sanctum-token}

Connection Parameters

You can specify which Moneybird connection to use by including one of these query parameters:

  • connection_id - Use a specific connection by ID
  • user_id - Use the first active connection for a user
  • tenant_id - Use the first active connection for a tenant
  • If none provided, uses the first active connection

Example:

GET /api/moneybird/administrations?connection_id=1
GET /api/moneybird/contacts?user_id=5&tenant_id=tenant1

Response Format

All endpoints return JSON with the following structure:

Success:

{
  "success": true,
  "data": { ... }
}

Error:

{
    "success": false,
    "message": "Error message"
}

Available Endpoints

Administrations
  • GET /api/moneybird/administrations - List all administrations
  • GET /api/moneybird/administrations/{id} - Get a specific administration

Example:

curl -X GET "https://your-app.com/api/moneybird/administrations" \
  -H "Authorization: Bearer {token}" \
  -H "Accept: application/json"
Contacts
  • GET /api/moneybird/contacts - List all contacts (supports filters: firstname, lastname, company_name, email)
  • GET /api/moneybird/contacts/search?q={query} - Search contacts
  • GET /api/moneybird/contacts/{id} - Get a specific contact
  • POST /api/moneybird/contacts - Create a new contact
  • PUT /api/moneybird/contacts/{id} - Update a contact
  • DELETE /api/moneybird/contacts/{id} - Delete a contact

Examples:

# List contacts with filters
curl -X GET "https://your-app.com/api/moneybird/contacts?firstname=John&lastname=Doe" \
  -H "Authorization: Bearer {token}"

# Search contacts
curl -X GET "https://your-app.com/api/moneybird/contacts/search?q=john" \
  -H "Authorization: Bearer {token}"

# Create a contact
curl -X POST "https://your-app.com/api/moneybird/contacts" \
  -H "Authorization: Bearer {token}" \
  -H "Content-Type: application/json" \
  -d '{
    "firstname": "John",
    "lastname": "Doe",
    "email": "john@example.com"
  }'

# Update a contact
curl -X PUT "https://your-app.com/api/moneybird/contacts/123456" \
  -H "Authorization: Bearer {token}" \
  -H "Content-Type: application/json" \
  -d '{
    "firstname": "Jane",
    "lastname": "Doe"
  }'
Sales Invoices
  • GET /api/moneybird/sales-invoices - List all sales invoices (supports filters: contact_id, state, invoice_id)
  • GET /api/moneybird/sales-invoices/by-invoice-id/{invoiceId} - Find invoice by invoice number
  • GET /api/moneybird/sales-invoices/{id} - Get a specific sales invoice
  • POST /api/moneybird/sales-invoices - Create a new sales invoice
  • PUT /api/moneybird/sales-invoices/{id} - Update a sales invoice
  • DELETE /api/moneybird/sales-invoices/{id} - Delete a sales invoice
  • POST /api/moneybird/sales-invoices/{id}/send - Send a sales invoice
  • GET /api/moneybird/sales-invoices/{id}/download/pdf - Download invoice as PDF
  • GET /api/moneybird/sales-invoices/{id}/download/ubl - Download invoice as UBL

Examples:

# List invoices with filters
curl -X GET "https://your-app.com/api/moneybird/sales-invoices?contact_id=123456&state=open" \
  -H "Authorization: Bearer {token}"

# Find by invoice ID
curl -X GET "https://your-app.com/api/moneybird/sales-invoices/by-invoice-id/INV-2024-001" \
  -H "Authorization: Bearer {token}"

# Create an invoice
curl -X POST "https://your-app.com/api/moneybird/sales-invoices" \
  -H "Authorization: Bearer {token}" \
  -H "Content-Type: application/json" \
  -d '{
    "contact_id": "123456",
    "invoice_id": "INV-2024-001",
    "details": [
      {
        "description": "Product 1",
        "price": 100.00,
        "amount": 1
      }
    ]
  }'

# Send an invoice
curl -X POST "https://your-app.com/api/moneybird/sales-invoices/123456/send" \
  -H "Authorization: Bearer {token}" \
  -H "Content-Type: application/json" \
  -d '{
    "delivery_method": "Email",
    "email_address": "customer@example.com"
  }'

# Download PDF
curl -X GET "https://your-app.com/api/moneybird/sales-invoices/123456/download/pdf" \
  -H "Authorization: Bearer {token}" \
  --output invoice.pdf

Webhooks

The package automatically registers a webhook route at /moneybird/webhook (configurable in config/moneybird.php).

Listen to webhook events:

use Emeq\Moneybird\Events\SalesInvoiceCreated;
use Emeq\Moneybird\Events\ContactUpdated;

Event::listen(SalesInvoiceCreated::class, function ($event) {
    // Handle sales invoice created
    $invoiceData = $event->payload;
});

Event::listen(ContactUpdated::class, function ($event) {
    // Handle contact updated
    $contactData = $event->payload;
});

Commands

  • php artisan moneybird:connect - Connect to Moneybird via OAuth
  • php artisan moneybird:test-connection - Test an existing connection
  • php artisan moneybird:refresh-tokens - Refresh expired tokens

Features

  • OAuth 2.0 authentication with automatic token refresh
  • Database-backed token storage
  • Support for multiple administrations
  • Extended API features:
    • Contacts (CRUD operations)
    • Sales Invoices (create, update, send, download, findByInvoiceId)
    • Administrations (list, get)

Testing

composer test

Changelog

Please see CHANGELOG for more information on what has changed recently.

License

The MIT License (MIT). Please see License File for more information. EMEQ

emeq/moneybird 适用场景与选型建议

emeq/moneybird 是一款 基于 PHP 开发的 Composer 扩展包,目前已累计 24 次下载、GitHub Stars 达 0, 最近一次更新时间为 2025 年 11 月 23 日, 在 PHP 生态内属于活跃度较高的组件。

它主要适用于以下技术方向: 「api」 「oauth」 「laravel」 「moneybird」 「emeq」 等业务场景。在实际项目中,围绕这些方向常见需要落地的问题包括:接口对接、性能调优、并发安全、与既有框架(Laravel / ThinkPHP / Yii / Webman 等)的兼容适配,以及生产环境的日志埋点与稳定性保障。

我们在过去多个企业项目中使用过 emeq/moneybird 或与其功能相近的方案,如果你在选型或落地过程中遇到问题,例如 版本兼容、二次改造、私有化封装、与内部系统对接、生产 BUG 排查,欢迎联系我们协助评估。

围绕 emeq/moneybird 我们能提供哪些服务?
定制开发 / 二次开发

基于 emeq/moneybird 在你已有业务上做功能扩展、字段裁剪、UI 适配、与内部账号 / 权限 / 日志系统的深度对接。

BUG 修复 & 性能优化

线上偶发问题、内存泄漏、慢查询、并发异常等排查修复;针对高流量场景做缓存、队列、索引层面的调优。

项目外包 & 长期维护

承接完整的项目从需求 → 设计 → 开发 → 上线 → 长期运维;也可按月提供技术保姆服务。

yvsm@zunyunkeji.com QQ:316430983 微信:yvsm316 西安尊云信息科技 · 专注 PHP / Go / 分布式系统研发

统计信息

  • 总下载量: 24
  • 月度下载量: 0
  • 日度下载量: 0
  • 收藏数: 1
  • 点击次数: 20
  • 依赖项目数: 0
  • 推荐数: 0

GitHub 信息

  • Stars: 0
  • Watchers: 0
  • Forks: 0
  • 开发语言: PHP

其他信息

  • 授权协议: MIT
  • 更新时间: 2025-11-23