chippyash / simple-accounts-3
由数据库支持的双式记账会计V3
Requires
- php: >=7.2
- ext-ds: *
- ext-pdo: *
- chippyash/assembly-builder: >=2,<3
- chippyash/monad: >=2,<3
- myclabs/php-enum: >=1.3.2,<2
- nicmart/tree: >=0.2.5,<1
- zendframework/zend-db: >=2.9.2,<3
Requires (Dev)
- ext-dom: *
- chippyash/currency: >=5.0.2
- doctrine/migrations: ~1.5.0|~1.6
- mikey179/vfsstream: >=1.6.5,<2
- php-ds/php-ds: ~1.3.0
- phpunit/phpunit: ~8.5
- symplify/easy-coding-standard: ^6.1
Suggests
- chippyash/currency: To turn account values into real currency values
- doctrine/migrations: To assist in database implementation for PHP
README
质量保证
- 请注意,此库V2版本起不再提供PHP<7.2的开发者支持。
是什么
提供了一个简单数据库支持的总账会计库,允许快速将双式记账实施到应用程序中。
此库替代了 chippyash/simple-accounts
此库不提供销售账簿、采购账簿或其他运营账簿。您的应用程序可能以某种形式拥有这些账簿。这提供了“中心”会计功能。
为什么
虽然完整的会计系统可用,需要大量集成工作,但某些应用程序只需要能够保持某种形式的内部账户。这个库是我多年前为一位客户编写的,用于记录在网站上获得的游戏积分的直接后裔。使用双式记账会计范式,网站所有者可以跟踪谁积累了积分,以及以何种方式,同时还可以看到这对他们的业务意味着什么,因为游戏积分通过折扣和奖品转换为客户的实际价值。
要求
此应用程序支持两种SQL版本,MariaDb和MySql。
MariaDb
MariaDb使用一个高性能插件,大大简化了处理层次数据。
您需要安装OQGraph插件并运行MariaDB >=10。请查看.travis.yml
构建脚本,了解我们如何在Travis构建服务器上执行此操作。我们了解到的一个“陷阱”是设置创建触发器的用户。根据您的MariaDb配置,您可能需要给创建数据库的脚本用户赋予'SUPER'权限。这似乎没有道理,但请注意。对于Travis服务器上的MariaDb 10,需要设置。请参阅scripts/test-user.sql
如果您无法使用OQGraph插件,请按照MySql的说明操作。它也适用于MariaDb。
MySql
考虑到并非所有人都能利用MariaDb的优势,我提供了一种替代的数据库实现,用于普通的MySql,它使用嵌套集。请参阅Mike Hillyer的博客以了解其实施的基础。
请注意,这不如MariaDb解决方案高效。请查看每个数据库的存储过程定义,了解原因。如果可能,请使用MariaDb。如果您能使MySql代码更高效,请提交一个pull request!
Postgres用户应该能够将MySql代码修改为实施数据库。我很少使用它,因此在此库中没有提供直接支持。如果您想贡献Postgres SQL语句,请随时提供pull request。这将是受欢迎的。
目前不支持Windows变体。如果您需要它,请随时提交pull request。此库是在Linux下开发的。
如何
启动并运行
创建一个数据库,比如叫“test”。
创建一个数据库用户,“test”,密码为“test”。(您可以通过运行scripts\test-user.sql
来完成此操作。)
给该用户授予对test数据库的所有权限。(参见上面的SUPER权限说明)
现在运行创建脚本
对于MariaDb
./createmariaddb.sh test test test
对于MySql
./createmysqldb.sh test test test
用于创建数据库组件。注意 - 使用 PHP Doctrine 迁移的用户应阅读 PHP 代码基本部分,以利用提供的迁移。
您可以通过执行 ./sqltest.sh test test test localhost
来运行 SQL 测试。
- 将
test/php/phpunit.xml
文件复制到test/php/local-phpunit.xml
,并编辑它以确保您有正确的数据库连接参数
您可以通过执行 ./build.sh
来运行 PHP 测试。如果您已安装 TestDox-Converter,它还会在 ./docs 目录中生成测试合约。如果没有安装,则可能会失败。检查脚本内容以运行原始 PHPUnit 命令。
您可以通过运行 examples/currency-example.php
程序来了解如何在不同类型之间进行转换。
cd examples chmod u+x currency-example.php ./currency-example.php
该库和数据库只处理整数,因此如果您需要浮点数支持,请使用 Chippyash\Currency 或提供自己的处理程序。
编码基础 - 术语
为了使内容简洁并避免混淆,尤其是如果您是会计师并习惯于不同的术语,以下是本说明中使用的术语的定义。
- SA:简单会计,本库
- COA:科目表。这是一个完整的科目表。它有账簿。COA 在本质上具有层次性,有一个
root
账簿,通常称为 'COA'。它通常有两个主要子账簿,资产负债表(BS)和损益表(P&L)。在这些之下,将存在各种其他账簿。您可以在网络上找到许多有关 COA 构建的参考资料。 - 账簿或账户:可以互换使用。科目表中的一条记录,它包含在账簿上已进行的所有日记账交易的余额。在 SA 中,指导原则是如果您更新子账簿,则它将更新其父账簿,直至根账簿,从而保持整个 COA 平衡。
- 名义或名义代码:在总账(GL)中,账簿通常通过其
名义代码
或名义
来引用。这是会计师或簿记员的简码,用于账簿。该系统中的每个账簿都有一个名义代码。从数据库的角度看,它提供了账簿唯一键的一部分,以及科目表 ID。按照惯例,它是一个数字字符串,通常从 4 位数字开始。名义用于将相关的账簿分组在一起。默认情况下,此库支持多达 10 位名义代码。示例程序仅使用 4 位数字,这已经足够满足日常使用。请参阅科目表 XML 文件以获取示例。 - 日记账或日记账录入或交易:账簿余额变化的记录。它包括两部分,即录入原因的详细信息以及影响每个账簿的更改的详细信息。日记账必须是平衡的。也就是说,其借方和贷方金额必须相等。如果它们不相等,系统将失败。这是复式记账的防御性原则。
编码基础(SQL)
如前所述,本库的基础在于在 MariaDb 上运行(已安装 OQGraph 插件)或 MySql 上运行的 SQL 代码。
SQL API 通过存储过程提供。如果您想提供变体,请尊重 API。
对于 MariaDb,请参阅
- 在 src/sql/mariadb/build-procs 中的存储过程定义
- 在 src/sql/mariadb/build-triggers 脚本中维护账目余额的触发器。
否则SQL相当直接。研究OQGraph文档以了解其用法。背后有魔法,但使用简单——这就是我喜欢的代码 ;-)
对于MySql,请参阅
- src/sql/mysql/build-procs中的过程定义
- 在src/sql/mysql/build-triggers脚本中维护账户余额的触发器。
一个稍微令人困惑的过程是sa_fu_add_txn
。特别是参数,
- arNominals TEXT,
- arAmounts TEXT,
- arTxnType TEXT
这些需要一个匹配的逗号分隔值集,这是将数组放入SQL的唯一方法。
- arNominals:要生效的名称列表
- arAmounts:要使用的金额列表
- arTxnType:每个名称的借方或贷方列表
PHP代码通过在调用存储过程之前将值压缩成字符串来处理这个问题
请参阅Accountant::writeTransaction()方法。参阅test/sql/add_transaction_test.sql中大约L17的部分以了解如何原生调用SQL过程。
如果你比我更擅长SQL(这并不难!),那么我会很欣赏任何关于操作效率的建议。
编码基础(PHP)
以下内容将为您介绍您可以使用库做什么,但您应该始终参考测试以获得更深入的见解。
与前一个库版本的更改
组织
与库的先前版本不同,我们不支持组织的概念。组织超出了本库的范围,因为您的实现将根据您的需求而有所不同。相反,您应该计划创建一种形式的一对多连接,将您的组织和它们使用的任何会计科目表(COA)连接起来。sa_coa表可以存储无限数量的COA,所以这应该不会成为太大的问题。
Doctrine迁移
如果您正在使用Doctrine迁移和Mariadb,您可以利用在src\php\SAccounts\Doctrine
中提供的迁移文件。
对于本库的开发,您可以通过进入本库的根目录并运行以下命令将所需的数据库结构迁移到测试数据库中
vendor/bin/doctrine-migrations migrations:migrate --configuration doctrine-migrations.xml --db-configuration doctrine-db.php
要迁移回,请使用
vendor/bin/doctrine-migrations migrations:migrate prev --configuration doctrine-migrations.xml --db-configuration doctrine-db.php
对于生产使用,您可以复制迁移文件到您自己的迁移目录(文件位于src/php/SAccounts/Doctrine),或者更方便地通过在现有结构中创建自己的迁移类并从提供的迁移中扩展它们。这将保持它们的顺序。
请注意,新功能可能会导致额外的迁移,因此如果您将此库更新到新功能版本,请检查是否有新版本。
控制账户
与组织一样,我们不支持此库中的控制账户概念。它们是您与应用程序以及本库之间的实现细节,通常是配置问题。因此,在需要此类功能的地方添加配置链接。另一个问题是术语的使用。太多的会计师反对在先前的版本中使用它,所以最好将其省略。
会计人员
会计人员负责您可以在Simple Accounts中执行的大多数操作,并且需要在任何事情发生之前创建。会计人员需要一个Zend Db Adapter作为构造参数。
use SAccounts\Accountant; use Zend\Db\Adapter\Adapter; $accountant = new Accountant( new Adapter( [ 'driver' => 'Pdo_mysql', 'database' => 'test', 'username' => 'test', 'password' => 'test' ] ) );
创建新的会计科目表
您可以通过提供ChartDefinition来创建新的会计科目表(COA)。ChartDefinition通过XML定义文件提供。可以在src\xml\personal.xml
中找到一个定义示例,以及用于验证任何定义的XSD,该XSD位于src\xsd\chart-definition.xsd
中。
use SAccounts\ChartDefinition; $definition = new ChartDefinition('src/xml/personal.xml'); $chartId = $accountant->createChart('Personal', $definition);
这将创建 sa_coa
表中的条目,并返回新图表的ID。你可能希望将其存储在自己的表中,以便以后检索。
会计师现在与该COA相关联。要使用另一个COA,你需要创建另一个会计师。要创建会计师并指定使用现有的COA,只需在构造会计师时将图表ID作为第二个参数即可。
请注意,你无需显式保存COA。当你用会计师执行操作时,它会以事务方式完成。
会计师操作
大多数对COA的操作都是通过会计师完成的。
对COA的操作通常要求你提供账户的名称代码,即账户标识符。虽然数据库中使用的是主整数ID,但外部我们使用名称代码进行操作。
将账户账簿添加到COA中
use SAccounts\Nominal; use SAccounts\Account; $nominal = new Nominal('7700'); $prntNominal = new Nominal(('7000')); $accountant->addAccount( $nominal, //nominal code AccountType::EXPENSE(), //account type new StringType('foo'), //account name $prntNominal //parent account nominal code (or null) );
父名称代码必须已存在,只有一个例外。在一个全新的COA中,你可以添加根账户并省略父名称代码参数。对于根账户,AccountType必须是AccountType::REAL()。尝试添加第二个根账户将引发异常。
AccountType非常重要,并且必须适合你要添加的账户。它控制账户余额的获取方式。它还允许你在账户上显示适当的借方和贷方值的标签。请查看src/xml/personal.xml
文件,了解AccountTypes的使用示例。
在典型情况下,根账户是真实账户,并且有两个子账户,资产负债表(类型为DR)和损益表(类型为CR)。所有其他账户都是这两个账户的子账户。然而,你可以根据自己的意愿配置图表。
所有DR(借方)类型的账户从dr金额 - cr金额获取余额。所有CR(贷方)类型的账户从cr金额 - dr金额获取余额。真实账户从abs(cr金额 - dr金额)获取余额,这与abs(dr金额 - cr金额)相同,通常等于零。
从COA中删除账户账簿
只有当其余额为零时,你才能删除账户账簿。尝试删除非零账簿将引发异常。注意:删除账簿将删除其所有子账簿。
这里的零是指借方和贷方账户值都等于零。因此,你不能删除已对其或任何子账户进行过交易的账户账簿。这是一项简单的安全措施,以确保数据不会丢失。
$accountant->delAccount(new Nominal('7000'));
获取COA
创建COA或用图表ID实例化会计师后,你可以简单地使用以下方法获取COA
use SAccounts\Chart; /* @var Chart $chart */ $chart = $accountant->fetchChart();
COA操作
基本COA操作
//get an Account from the Chart /* @var Account $acount */ $account = $chart->getAccount(new Nominal('2000')); //get the parent account of an Account $account = $chart->getAccount($chart->getParentId(new Nominal('2000'))) //or $subAccount = $chart->getAccount(new Nominal('2000')); $prntAccount = $chart->getAccount($chart->getParentId($account->getNominal())); //testing if an account exists in the COA //returns true or false $exists = $chart->hasAccount(new Nominal('3000')); //get the name of the COA /* @var StringType $name */ $name = $chart->getName(); //get a ledger's values $account = $chart->getAccount(new Nominal('2000')); /* @var IntType $dr */ $dr = $account->dr(); /* @var IntType $cr */ $cr = $account->cr(); //NB getting the balance of the root COA account should return zero. If not //then your accounts are out of balance and need investigating. Perhaps something //outside of SA made an update, or a database glitch occurred. /* @var IntType $balance */ $balance = $account->getBalance(); /* @var Nominal $nom */ $nom = $account->getNominal(); /* @var StringType $name */ $name = $account->getName(); /* @var AccountType $type */ $type = $account->getType();
COA作为树
在幕后,图表被保留为nicmart/Tree,我推荐你如果需要执行树操作的话使用它。获取对它的访问权限对各种任务都很有用,例如显示试算平衡表。为此,我们使用树访问者。你可以在examples/currency-example.php
脚本中看到完整的示例。感兴趣的是
$accountant->fetchChart()->getTree()->accept(new ChartPrinter(Crcy::create($crcyCd)));
提供了两个用户访问者
SAccounts\Visitor\ChartPrinter
,它将COA打印到控制台SAccounts\Visitor\ChartArray
,它返回一个值和账户余额的数组
Chart内部使用其他访问者,但它们都应该帮助你创建自己的访问者,如果你需要的话。
日记账条目
创建条目
您可以通过向系统中添加交易来在账户中创建日记账分录。交易由两部分组成,日记账描述和交易分录列表,每个受交易影响的账户一个分录。这些交易有借方或贷方金额。所有借方金额之和必须等于所有贷方金额之和,以便交易达到平衡,从而使系统能够接受交易。
基本交易类型是SplitTransaction
/** * Constructor * * @param string $note Defaults to '' if not set * @param string $src user defined source of transaction * @param int $ref user defined reference for transaction * @param \DateTime $date Defaults to today if not set */ public function __construct( string $note = null, string $src = null, int $ref = null, \DateTime $date = null )
在构建之后,您可以通过将Entry对象传递给addEntry()方法来添加交易分录。
use SAccounts\Transaction\SplitTransaction; use SAccounts\Transaction\Entry; $amount = new IntType(100); $txn = (new SplitTransaction()) ->addEntry(new Entry(new Nominal('0000'), $amount, AccountType::DR())) ->addEntry(new Entry(new Nominal('1000'), $amount, AccountType::CR()))
在这里,我们为同一金额的两个账户添加了两个分录,但交易类型一个是借方,另一个是贷方。您可以使用checkBalance()
方法检查交易是否平衡,如果交易平衡则返回true,否则返回false。
虽然SplitTransaction对于添加包含多个分录的交易很有用(例如,销售由销售账户、增值税账户和银行账户分录组成),但对于简单的两个账户分录(如银行账户之间的转账)您可以使用SimpleTransaction,它是SplitTransaction的子类。
/** * Constructor * * @param Nominal $drAc Account to debit * @param Nominal $crAc Account to credit * @param int $amount Transaction amount * @param string $note Defaults to '' if not set * @param int $ref Defaults to 0 if not set * @param \DateTime $date Defaults to today if not set */ public function __construct( Nominal $drAc, Nominal $crAc, int $amount, ?string $note = null, ?string $src = null, ?int $ref = null, ?\DateTime $date = null )
因此
use SAccounts\Transaction\SimpleTransaction; $txn = new SimpleTransaction(new Nominal('0000'), new Nominal('1000'), 1226);
通过任何方式创建交易后,您可以通过以下方式将其添加到账户中
$txnId = $accountant->writeTransaction($txn);
编写交易将自动更新COA账簿余额。
检索分录
您可以通过以下方式从账户中检索单个交易
/* @var SplitTransaction $txn */ $txn = $accountant->fetchTransaction(102);
要检索账户账簿的所有分录
/** @var Ds\Set $transactions */ $transactions = $accountant->fetchAccountJournals(new Nominal('2000'));
该集合包含具有分录的SplitTransactions,这些分录仅反映交易针对该日记账分录的双重分录的一侧。您可以在examples/journal-entries-example.php
中看到一个如何工作的示例。
注意事项
该库是根据纯SQL在数据库中构建的。虽然我提供了PHP API层,但您可以使用任何语言访问底层SQL。如果您是Python、Java或其他开发者,请随时在src
目录下添加自己的语言API。
这里提到的参考主要适用于我主要使用PHP进行开发。如果您选择的开发语言不适用,请忽略它们。
最后,如有疑问,请阅读源代码。它有很好的文档。
更多文档
测试合约位于docs目录中。
该库使用了标准PHP DS扩展。
它还大量使用了来自Monad和Assembly库的功能编程。
如果您不熟悉它们,请花点时间学习它们。
由于该库仅处理整数值(以确保数值精度),您可能需要查看在示例脚本中使用的Currency库。
查看ZF4软件包以获取更多软件包。
更改库
- 将其分叉
- 编写测试
- 修改它
- 发起拉取请求
找到了您无法解决的错误吗?
- 将其分叉
- 编写测试
- 发起拉取请求
注意。在您的拉取请求之前,请确保您已将分支更新到HEAD。
或者 - 提出问题票据。
在哪里?
该库托管在Github上。它可在Packagist.org上找到。
安装(PHP)
安装 Composer
生产环境
"chippyash/simple-accounts-3": "~2.0"
composer install --no-dev
开发环境
克隆此仓库,然后在本地仓库根目录下运行Composer以拉取依赖项
git clone git@github.com:chippyash/simple-accounts-3.git simple-accounts cd simple-accounts composer update
-
将
test/php/phpunit.xml
文件复制到test/php/local-phpunit.xml
,并编辑它以确保您有正确的数据库连接参数 -
运行测试:
composer test:run
-
代码检查:
composer lint:run
-
修复代码检查问题:
composer lint:fix
许可证
此软件库在BSD 3 Clause 许可证下发布
此软件库版权所有(c)2017-2020,Ashley Kitson,英国
历史
V1.0.0 首次生产版本发布
V1.0.1 首次发布文档
V1.1.0 添加PHP Doctrine Migrations
V1.1.1 修改迁移的命名空间
V1.1.2 支持 PHP 7.0 & 7.1
V1.1.3 支持 PHP 7.2
V1.2.0 添加获取一个账户所有交易的能力
V1.2.1 更新文档许可证
V1.3.0 支持MySQL
V1.3.1 修改mariadb迁移的文件路径
V1.3.2 明确对实际账户余额的处理
V1.4.0 许可证从GPL V3更改为BSD 3 Clause
V1.4.1 修复问题1
V2.0.0 兼容性中断。放弃对PHP<7.2的支持。删除对chippyash/strongtype的依赖。
V2.0.1 删除对chippyash/identity的依赖