Akaunting - 专为小型企业和自由职业者设计的在线会计软件

Akaunting - 开源会计软件

项目描述

Akaunting是一款专为小型企业和自由职业者设计的在线会计软件,采用现代技术栈(Laravel、VueJS、Tailwind、RESTful API等)构建。得益于其模块化结构,Akaunting为用户和开发者提供了丰富的应用商店。

功能特性

  • 财务管理:发票、账单、收入和支出跟踪
  • 银行对账:自动匹配银行交易
  • 多货币支持:支持多种货币交易
  • 报表系统:财务报告和业务分析
  • 模块化设计:可通过应用商店扩展功能
  • 多语言支持:支持多种语言界面
  • 定时任务:自动发送发票提醒和账单提醒
  • PWA支持:渐进式Web应用,支持离线使用
  • RESTful API:方便与其他系统集成

安装指南

系统要求

  • PHP 8.1或更高版本
  • 数据库(如MariaDB、MySQL、PostgreSQL、SQLite)
  • Web服务器(如Apache、Nginx、IIS)

安装步骤

  1. 安装Composer和Npm
  2. 克隆仓库:
    git clone https://github.com/akaunting/akaunting.git
    
  3. 安装依赖:
    composer install
    npm install
    npm run dev
    
  4. 安装Akaunting:
    php artisan install --db-name="akaunting" --db-username="root" --db-password="pass" --admin-email="admin@company.com" --admin-password="123456"
    
  5. (可选)创建示例数据:
    php artisan sample-data:seed
    

使用说明

基本使用

// 示例:发送发票提醒
$invoices = Document::with('contact')
            ->invoice()
            ->accrued()
            ->notPaid()
            ->due($date)
            ->cursor();

foreach ($invoices as $invoice) {
    event(new DocumentReminded($invoice, Notification::class));
}

定时任务

Akaunting内置了多种定时任务,可通过Laravel调度系统运行:

// 在Kernel.php中定义的定时任务
$schedule->command('reminder:invoice')->dailyAt($schedule_time);
$schedule->command('reminder:bill')->dailyAt($schedule_time);
$schedule->command('recurring:check')->dailyAt($schedule_time)->runInBackground();

核心代码

分类构建器

<?php
namespace App\Builders;

use Illuminate\Database\Eloquent\Builder;
use Illuminate\Pagination\Paginator;

class Category extends Builder
{
    /**
     * 执行查询并返回包含子分类的集合
     */
    public function get($columns = ['*'])
    {
        $collection = parent::get($columns);

        return $collection->withChildren('sub_categories', function ($list, $parent, $relation, $level, $addChildren) {
            $parent->load($relation);
            $parent->level = $level;

            $list->push($parent);

            if ($parent->$relation->count() == 0) {
                return;
            }

            foreach ($parent->$relation as $item) {
                $addChildren($list, $item, $relation, $level + 1, $addChildren);
            }
        });
    }
}

账单提醒命令

<?php
namespace App\Console\Commands;

use App\Events\Document\DocumentReminded;
use App\Models\Common\Company;
use App\Models\Document\Document;
use App\Utilities\Date;

class BillReminder extends Command
{
    protected $signature = 'reminder:bill';
    protected $description = 'Send reminders for bills';

    public function handle()
    {
        $today = Date::today();
        $start_date = $today->copy()->subWeek()->toDateString() . ' 00:00:00';
        $end_date = $today->copy()->addMonth()->toDateString() . ' 23:59:59';

        $companies = Company::whereHas('bills', function ($query) use ($start_date, $end_date) {
            $query->whereBetween('due_at', [$start_date, $end_date])
                  ->accrued()
                  ->notPaid();
        })->enabled()->cursor();

        foreach ($companies as $company) {
            $company->makeCurrent();
            
            if (!setting('schedule.send_bill_reminder')) {
                continue;
            }

            $days = explode(',', setting('schedule.bill_days'));
            foreach ($days as $day) {
                $this->remind((int) trim($day));
            }
        }
    }
}

更新系统

<?php
namespace App\Console\Commands;

use App\Events\Install\UpdateFinished;
use App\Jobs\Install\CopyFiles;
use App\Jobs\Install\DownloadFile;
use App\Jobs\Install\UnzipFile;

class Update extends Command
{
    protected $signature = 'update {alias} {company} {new=latest}';
    protected $description = 'Allows to update Akaunting and modules directly through CLI';

    public function handle()
    {
        $this->alias = $this->argument('alias');
        $this->company = $this->argument('company');
        $this->new = $this->getNewVersion();
        $this->old = $this->getOldVersion();

        company($this->company)->makeCurrent();

        if (!$path = $this->download()) {
            return self::CMD_ERROR;
        }

        if (!$this->unzip($path)) {
            return self::CMD_ERROR;
        }

        if (!$this->copyFiles($path)) {
            return self::CMD_ERROR;
        }

        if (!$this->finish()) {
            return self::CMD_ERROR;
        }

        return self::CMD_SUCCESS;
    }
}

更多精彩内容 请关注我的个人公众号 公众号(办公AI智能小助手)
公众号二维码

posted @ 2025-06-29 10:01  qife  阅读(32)  评论(0)    收藏  举报