Git Product home page Git Product logo

ledger's Introduction

General Ledger and Journal Accounting Package for Laravel with JSON API

Tests: php 8.0 php 8.1

Ledger lets you track anything related to money in your application with a single package while making your CFO happy at the same time. No matter if your app is handling memberships for a small club or supporting a multinational enterprise, Ledger can handle it.

Ledger is a full-featured implementation of the core of any good accounting system, a double-entry journal and general ledger. It is not a complete accounting solution, but rather the minimum for keeping track of financial transactions. Ledger features a JSON API that provides access to all functions.

That's the only minimal part. Ledger features:

  • Full double-entry accounting system with audit trail capability.
  • Multi-currency support.
  • Support for multiple business units.
  • Sub-journal support.
  • Multilingual.
  • Integrates via direct controller access or through JSON API.
  • Atomic transactions with concurrent update blocking.
  • Reference system supports soft linking to other ERP components.
  • Designed for Laravel from the ground up.

Documentation

Full documentation is available here.

Updates and Chat

We've moved from Twitter to Mastodon. Come join us!

Quick start

Installation and Configuration

Install Ledger with composer:

composer require abivia/ledger

Publish configuration:

php artisan vendor:publish --provider="Abivia\Ledger\LedgerServiceProvider"

Create database tables

php artisan migrate

Configuration

The configuration file is installed as config\ledger.php. You can enable/disable the JSON API, set middleware, and a path prefix to the API.

Updating

To ensure schema changes are in place publish the configuration again and migrate:

php artisan vendor:publish --provider="Abivia\Ledger\LedgerServiceProvider"
php artisan migrate

Donations welcome

Abivia is a small business. Even small donations go a long way.

If you're getting something out of Ledger, you can sponsor us in any amount you wish using Liberapay Liberapay. Liberapay is itself run on donations and charges no fees beyond bank charges.

ledger's People

Contributors

abivia avatar alexgoogole avatar instancezero avatar ivanmazep avatar lewrq avatar shaband avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar

ledger's Issues

Feature is not yet implemented.

array:2 [▼ // platform/plugins/accounting/src/Http/Controllers/AccountController.php:74
"errors" => array:2 [▼
0 => "Feature is not yet implemented."
1 => "Account closing not yet implemented."
]
"time" =>
Illuminate\Support

Carbon @1704729191 {#3862 ▼
#endOfTime: false
#startOfTime: false
#constructedObjectId: "0000000000000f160000000000000000"
#localMonthsOverflow: null
#localYearsOverflow: null
#localStrictModeEnabled: null
#localHumanDiffOptions: null
#localToStringFormat: null
#localSerializer: null
#localMacros: null
#localGenericMacros: null
#localFormatFunction: null
#localTranslator: null
#dumpProperties: array:3 [▶]
#dumpLocale: null
#dumpDateProperties: null
date: 2024-01-08 15:53:11.203817 UTC (+00:00)
}
]

what does that mean ??

Cannot assign null to property ReportData::$journalEntryId of type int

Hello!
I encountered an error while creating a report with the name "trialBalance"

Unable to assign null to property Abivia\Ledger\Models\ReportData::$journalEntryId of type int

This happened because the table named "journal_entries" was empty and JournalEntry::query()->max('journalEntryId') returned null and tried to put it in $reportData->journalEntryId which is of type int.
As a quick fix, I used ?? 0 here https://github.com/abivia/ledger/blob/main/src/Reports/TrialBalanceReport.php#L55.

Stacktrace
[2022-11-18 17:13:25] local.ERROR: Cannot assign null to property Abivia\Ledger\Models\ReportData::$journalEntryId of type int {"exception":"[object] (TypeError(code: 0): Cannot assign null to property Abivia\\Ledger\\Models\\ReportData::$journalEntryId of type int at /var/www/html/vendor/abivia/ledger/src/Reports/TrialBalanceReport.php:57)
[stacktrace]
#0 /var/www/html/vendor/abivia/ledger/src/Http/Controllers/ReportController.php(83): Abivia\\Ledger\\Reports\\TrialBalanceReport->collect()
#1 /var/www/html/vendor/abivia/ledger/src/Http/Controllers/Api/ReportApiController.php(33): Abivia\\Ledger\\Http\\Controllers\\ReportController->generate()
#2 /var/www/html/vendor/laravel/framework/src/Illuminate/Routing/ControllerDispatcher.php(46): Abivia\\Ledger\\Http\\Controllers\\Api\\ReportApiController->run()
#3 /var/www/html/vendor/laravel/framework/src/Illuminate/Routing/Route.php(260): Illuminate\\Routing\\ControllerDispatcher->dispatch()
#4 /var/www/html/vendor/laravel/framework/src/Illuminate/Routing/Route.php(205): Illuminate\\Routing\\Route->runController()
#5 /var/www/html/vendor/laravel/framework/src/Illuminate/Routing/Router.php(727): Illuminate\\Routing\\Route->run()
#6 /var/www/html/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(141): Illuminate\\Routing\\Router->Illuminate\\Routing\\{closure}()
#7 /var/www/html/vendor/laravel/framework/src/Illuminate/Routing/Middleware/SubstituteBindings.php(50): Illuminate\\Pipeline\\Pipeline->Illuminate\\Pipeline\\{closure}()
#8 /var/www/html/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(180): Illuminate\\Routing\\Middleware\\SubstituteBindings->handle()
#9 /var/www/html/vendor/laravel/framework/src/Illuminate/Routing/Middleware/ThrottleRequests.php(126): Illuminate\\Pipeline\\Pipeline->Illuminate\\Pipeline\\{closure}()
#10 /var/www/html/vendor/laravel/framework/src/Illuminate/Routing/Middleware/ThrottleRequests.php(102): Illuminate\\Routing\\Middleware\\ThrottleRequests->handleRequest()
#11 /var/www/html/vendor/laravel/framework/src/Illuminate/Routing/Middleware/ThrottleRequests.php(54): Illuminate\\Routing\\Middleware\\ThrottleRequests->handleRequestUsingNamedLimiter()
#12 /var/www/html/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(180): Illuminate\\Routing\\Middleware\\ThrottleRequests->handle()
#13 /var/www/html/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(116): Illuminate\\Pipeline\\Pipeline->Illuminate\\Pipeline\\{closure}()
#14 /var/www/html/vendor/laravel/framework/src/Illuminate/Routing/Router.php(728): Illuminate\\Pipeline\\Pipeline->then()
#15 /var/www/html/vendor/laravel/framework/src/Illuminate/Routing/Router.php(705): Illuminate\\Routing\\Router->runRouteWithinStack()
#16 /var/www/html/vendor/laravel/framework/src/Illuminate/Routing/Router.php(669): Illuminate\\Routing\\Router->runRoute()
#17 /var/www/html/vendor/laravel/framework/src/Illuminate/Routing/Router.php(658): Illuminate\\Routing\\Router->dispatchToRoute()
#18 /var/www/html/vendor/laravel/framework/src/Illuminate/Foundation/Http/Kernel.php(190): Illuminate\\Routing\\Router->dispatch()
#19 /var/www/html/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(141): Illuminate\\Foundation\\Http\\Kernel->Illuminate\\Foundation\\Http\\{closure}()
#20 /var/www/html/vendor/laravel/framework/src/Illuminate/Foundation/Http/Middleware/TransformsRequest.php(21): Illuminate\\Pipeline\\Pipeline->Illuminate\\Pipeline\\{closure}()
#21 /var/www/html/vendor/laravel/framework/src/Illuminate/Foundation/Http/Middleware/ConvertEmptyStringsToNull.php(31): Illuminate\\Foundation\\Http\\Middleware\\TransformsRequest->handle()
#22 /var/www/html/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(180): Illuminate\\Foundation\\Http\\Middleware\\ConvertEmptyStringsToNull->handle()
#23 /var/www/html/vendor/laravel/framework/src/Illuminate/Foundation/Http/Middleware/TransformsRequest.php(21): Illuminate\\Pipeline\\Pipeline->Illuminate\\Pipeline\\{closure}()
#24 /var/www/html/vendor/laravel/framework/src/Illuminate/Foundation/Http/Middleware/TrimStrings.php(40): Illuminate\\Foundation\\Http\\Middleware\\TransformsRequest->handle()
#25 /var/www/html/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(180): Illuminate\\Foundation\\Http\\Middleware\\TrimStrings->handle()
#26 /var/www/html/vendor/laravel/framework/src/Illuminate/Foundation/Http/Middleware/ValidatePostSize.php(27): Illuminate\\Pipeline\\Pipeline->Illuminate\\Pipeline\\{closure}()
#27 /var/www/html/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(180): Illuminate\\Foundation\\Http\\Middleware\\ValidatePostSize->handle()
#28 /var/www/html/vendor/laravel/framework/src/Illuminate/Foundation/Http/Middleware/PreventRequestsDuringMaintenance.php(86): Illuminate\\Pipeline\\Pipeline->Illuminate\\Pipeline\\{closure}()
#29 /var/www/html/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(180): Illuminate\\Foundation\\Http\\Middleware\\PreventRequestsDuringMaintenance->handle()
#30 /var/www/html/vendor/laravel/framework/src/Illuminate/Http/Middleware/HandleCors.php(62): Illuminate\\Pipeline\\Pipeline->Illuminate\\Pipeline\\{closure}()
#31 /var/www/html/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(180): Illuminate\\Http\\Middleware\\HandleCors->handle()
#32 /var/www/html/vendor/laravel/framework/src/Illuminate/Http/Middleware/TrustProxies.php(39): Illuminate\\Pipeline\\Pipeline->Illuminate\\Pipeline\\{closure}()
#33 /var/www/html/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(180): Illuminate\\Http\\Middleware\\TrustProxies->handle()
#34 /var/www/html/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(116): Illuminate\\Pipeline\\Pipeline->Illuminate\\Pipeline\\{closure}()
#35 /var/www/html/vendor/laravel/framework/src/Illuminate/Foundation/Http/Kernel.php(165): Illuminate\\Pipeline\\Pipeline->then()
#36 /var/www/html/vendor/laravel/framework/src/Illuminate/Foundation/Http/Kernel.php(134): Illuminate\\Foundation\\Http\\Kernel->sendRequestThroughRouter()
#37 /var/www/html/public/index.php(52): Illuminate\\Foundation\\Http\\Kernel->handle()
#38 /var/www/html/vendor/laravel/framework/src/Illuminate/Foundation/resources/server.php(16): require_once('...')
#39 {main}

suggestion for docs correction

If the business purchases a box of paper for $100 with cash (a debit account), then the account representing cash decreases by $100 and the account representing office expenses (a credit account) increases by $100.

Saw this in your docs, and thought your starting accounting example can be refined:

  • when you just buy paper you debit inventory, not expenses
  • expenses is also a debit-sided account, not a credit account
  • you credit cash and debit inventory in the example in text

How to post to a sub-journal

So I created a sub-journal by the example here then added a transaction with a

...
"type": "SALES",
...

In the JSON body. I didn't see any difference in how it journalized this in the database vs the other transactions not posted to the subjournal.

How is it meant to work?

Create Balance not working

After giving code and uuid still return this error
errors
:
[["Request requires an account code or uuid."], "Bad request.",…]
0: ["Request requires an account code or uuid."]
1:"Bad request."
2:"Request requires an account code or uuid."
time:"2023-02-24T03:35:34.008077Z"

Multitenancy Support

Hello,

Thank you for your wonderful work. I am trying to integrate it into a multitenant set-up through Filament V3 where a Ledger would belong to a company.

I have extended the LedgerName model to add the relationship to the company as follows:

<?php

namespace App\Models\Ledger;

use Abivia\Ledger\Models\LedgerName;
use Illuminate\Database\Eloquent\Relations\BelongsTo;
use Wallo\FilamentCompanies\FilamentCompanies;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\SoftDeletes;

class Ledger extends LedgerName  {

    use SoftDeletes;
    protected $table = 'ledger_names';
    public function company(): BelongsTo
    {
        return $this->belongsTo(FilamentCompanies::companyModel(), 'company_id');
    }

    public function createdBy(): BelongsTo
    {
        return $this->belongsTo(FilamentCompanies::userModel(), 'created_by');
    }

    public function updatedBy(): BelongsTo
    {
        return $this->belongsTo(FilamentCompanies::userModel(), 'updated_by');
    }
}

I am looking for a best practise recommendation being new to Laravel while also trying to avoid redoing most of the work which the API already has done when persisting the relationships such as currency, accounts etc.

Best,
N

PHP vs JSON API Completeness

Given the PHP API is more complete than the JSON API, please confirm: does it mean ALL functionality in the PHP is NOT yet available in the JSON?

Or is it the case that JSON has all functionality already and only the documentation is WIP?

API Responses

Testing some of the APIs, I note the responses are not as described in the docs. Specifically calling domain/add and currency/add gets a reply with only "time" in the response whilst the docs show a fuller response.

Do I have a wrong config somewhere?

No "R"ead All for CRUD?

I note you can only get a single item (resource) using the /get API routes. Is this deliberate?

TypeError on query calls

From #21 opened by @marvoh

After installation and adding several accounts, the /account/query together with all the endpoints that are suffixed by '/query' such as /currency/query and journal/query return the following exception instead of an empty result when I don't have anything under it TypeError: Abivia\Ledger\Messages\AccountQuery::fromArray(): Argument #1 ($data) must be of type array, null given, called in /var/www/vendor/abivia/ledger/src/Messages/Message.php on line 121 in file var/www/vendor/abivia/ledger/src/Messages/AccountQuery.php on line 29. Did I miss a configuration?

Originally posted by @instancezero in #21

Error in the example??

As I understand it with Abivia Ledger, a credit is always a positive ve amount whilst a debit is always a negative.

Consistent with this, In your example here, Inventory was debited (-150) when stock was bought.

Therefore, if I’m not muddling things up, when moving the sold value to COGS, it should be a credit (I.e. +10 not -10) to reduce Inventory. Given it’s a debit balance account, the Inventory account should show -140 not -160 after the transaction. COGS should normally carry a debit balance (an expense account) therefore it should be debited (-10 not +10) to increase expense.

Please confirm.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.