{"id":326579,"date":"2021-07-17T09:00:09","date_gmt":"2021-07-17T09:00:09","guid":{"rendered":"http:\/\/savepearlharbor.com\/?p=326579"},"modified":"-0001-11-30T00:00:00","modified_gmt":"-0001-11-29T21:00:00","slug":"","status":"publish","type":"post","link":"https:\/\/savepearlharbor.com\/?p=326579","title":{"rendered":"Empire ERP. \u0417\u0430\u043d\u0438\u043c\u0430\u0442\u0435\u043b\u044c\u043d\u0430\u044f \u0431\u0443\u0445\u0433\u0430\u043b\u0442\u0435\u0440\u0438\u044f: PostgreSQL"},"content":{"rendered":"\n<div class=\"post__text post__text-html post__text_v1\" id=\"post-content-body\">\n<p>\u041f\u0440\u043e\u0434\u043e\u043b\u0436\u0435\u043d\u0438\u0435 \u0446\u0438\u043a\u043b\u0430 <a href=\"https:\/\/habr.com\/ru\/post\/471304\/\">&quot;\u0417\u0430\u043d\u0438\u043c\u0430\u0442\u0435\u043b\u044c\u043d\u0430\u044f \u0431\u0443\u0445\u0433\u0430\u043b\u0442\u0435\u0440\u0438\u044f&quot;<\/a>.<br \/>  \u041f\u043e\u043f\u0440\u043e\u0431\u0443\u0435\u043c \u0441\u043f\u0440\u043e\u0435\u043a\u0442\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u0431\u0430\u0437\u0443 \u0434\u0430\u043d\u043d\u044b\u0445 \u043c\u043e\u0434\u0443\u043b\u044f &quot;\u0411\u0443\u0445\u0433\u0430\u043b\u0442\u0435\u0440\u0438\u044f&quot; \u043d\u0430 PostgreSQL.<\/p>\n<p><a name=\"habracut\"><\/a>  <\/p>\n<h2 id=\"nastroyka-proekta\">\u041d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0430 \u043f\u0440\u043e\u0435\u043a\u0442\u0430<\/h2>\n<p>  <\/p>\n<p>\u041a\u043b\u043e\u043d\u0438\u0440\u0443\u0435\u043c \u043f\u0440\u043e\u0435\u043a\u0442 \u0441 \u0433\u0438\u0442\u0445\u0430\u0431\u0430:<\/p>\n<p>  <\/p>\n<pre><code class=\"bash\">git clone https:\/\/github.com\/nomhoi\/empire-erp.git<\/code><\/pre>\n<p>  <\/p>\n<p>\u0417\u0430\u0445\u043e\u0434\u0438\u043c \u0432 \u043f\u0430\u043f\u043a\u0443 <strong>reaserch\/day2\/<\/strong>.<\/p>\n<p>  <\/p>\n<h2 id=\"step-1-glavnaya-kniga\">Step 1. \u0413\u043b\u0430\u0432\u043d\u0430\u044f \u043a\u043d\u0438\u0433\u0430<\/h2>\n<p>  <\/p>\n<p>\u0417\u0430\u043f\u0443\u0441\u0442\u0438\u043c \u0431\u0430\u0437\u0443 \u0434\u0430\u043d\u043d\u044b\u0445 \u0438 \u0432\u044b\u043f\u043e\u043b\u043d\u0438\u043c \u0442\u0435\u0441\u0442\u044b:<\/p>\n<p>  <\/p>\n<pre><code class=\"bash\">docker-compose run test<\/code><\/pre>\n<p>  <\/p>\n<p>\u0412 \u043f\u0440\u043e\u0435\u043a\u0442\u0435 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u0442\u0441\u044f \u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a\u0430 <strong>pytest-postgresql<\/strong>. \u0421 \u043f\u043e\u043c\u043e\u0449\u044c\u044e \u044d\u0442\u043e\u0439 \u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a\u0438 \u0441\u043e\u0437\u0434\u0430\u044e\u0442\u0441\u044f \u0444\u0438\u043a\u0441\u0430\u0446\u0438\u0438 \u0432 \u0432\u0438\u0434\u0435 \u0431\u0430\u0437 \u0434\u0430\u043d\u043d\u044b\u0445, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u044e\u0442\u0441\u044f \u0432 \u043a\u0430\u0447\u0435\u0441\u0442\u0432\u0435 \u0448\u0430\u0431\u043b\u043e\u043d\u043e\u0432 \u043f\u0440\u0438 \u0441\u043e\u0437\u0434\u0430\u043d\u0438\u0438 \u0431\u0430\u0437 \u0434\u0430\u043d\u043d\u044b\u0445 \u0434\u043b\u044f \u043a\u0430\u0436\u0434\u043e\u0433\u043e \u0442\u0435\u0441\u0442\u0430.<\/p>\n<p>  <\/p>\n<p>\u0412 \u0434\u0430\u043d\u043d\u043e\u043c \u0441\u043b\u0443\u0447\u0430\u0435 \u0441\u043e\u0437\u0434\u0430\u0435\u0442\u0441\u044f \u0444\u0438\u043a\u0441\u0430\u0446\u0438\u044f \u043d\u0430 \u0431\u0430\u0437\u0435 <strong>code\/step1.sql<\/strong>:<\/p>\n<p>  <\/p>\n<pre><code class=\"sql\">DROP TABLE IF EXISTS general_ledger;  CREATE TABLE general_ledger(     id        serial,     debit_id  smallint NOT NULL,     credit_id smallint NOT NULL,     amount    money NOT NULL );  INSERT INTO general_ledger(debit_id, credit_id, amount) VALUES  (1, 12, 100.00),         (1, 6, 120.00),         (12, 1, 20.00); <\/code><\/pre>\n<p>  <\/p>\n<p>\u0417\u0434\u0435\u0441\u044c \u043c\u044b \u0441\u043e\u0437\u0434\u0430\u0435\u043c \u0442\u0430\u0431\u043b\u0438\u0446\u0443 \u0433\u043b\u0430\u0432\u043d\u043e\u0439 \u043a\u043d\u0438\u0433\u0438 <strong>general_ledger<\/strong> \u0438 \u0434\u043e\u0431\u0430\u0432\u043b\u044f\u0435\u043c \u0432 \u043d\u0435\u0435 \u0442\u0440\u0438 \u043f\u0440\u043e\u0432\u043e\u0434\u043a\u0438.<\/p>\n<p>  <\/p>\n<p>test_step1.py:<\/p>\n<p>  <\/p>\n<pre><code class=\"python\">import pytest_postgresql.factories.client import pytest_postgresql.factories.noprocess from pytest_postgresql.compat import connection  postgresql_my_proc = pytest_postgresql.factories.noprocess.postgresql_noproc(     dbname=&quot;empire-erp-2&quot;, load=[&quot;.\/step1.sql&quot;] ) postgres = pytest_postgresql.factories.client.postgresql(     &quot;postgresql_my_proc&quot;, dbname=&quot;empire-erp-2&quot; )  def test_1(postgres: connection) -&gt; None:     with postgres.cursor() as cur:         cur.execute(&quot;SELECT * FROM general_ledger ORDER BY id;&quot;)         res = cur.fetchall()         assert len(res) == 3<\/code><\/pre>\n<p>  <\/p>\n<p>\u041c\u043e\u0436\u043d\u043e \u0432\u044b\u043f\u043e\u043b\u043d\u0438\u0442\u044c sql \u0437\u0430\u043f\u0440\u043e\u0441\u044b \u0432\u0440\u0443\u0447\u043d\u0443\u044e. \u041f\u043e\u0434\u043a\u043b\u044e\u0447\u0438\u043c\u0441\u044f \u043a \u0431\u0430\u0437\u0435 \u0434\u0430\u043d\u043d\u044b\u0445 <strong>empire-erp<\/strong>:<\/p>\n<p>  <\/p>\n<pre><code class=\"bash\">docker exec -it db psql -U postgres -d empire-erp<\/code><\/pre>\n<p>  <\/p>\n<p>\u0412\u044b\u043f\u043e\u043b\u043d\u044f\u0435\u043c \u043a\u043e\u043c\u0430\u043d\u0434\u0443 \u0432 \u043a\u043e\u043c\u0430\u043d\u0434\u043d\u043e\u0439 \u0441\u0442\u0440\u043e\u043a\u0435 <strong>psql<\/strong> \u0434\u043b\u044f \u0438\u043d\u0438\u0446\u0438\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u0438 \u0431\u0430\u0437\u044b \u0434\u0430\u043d\u043d\u044b\u0445 \u0434\u043b\u044f \u043f\u0435\u0440\u0432\u043e\u0433\u043e \u0448\u0430\u0433\u0430:<\/p>\n<p>  <\/p>\n<pre><code class=\"plaintext\">empire-erp=# \\i step1.sql<\/code><\/pre>\n<p>  <\/p>\n<p>\u0412\u044b\u043f\u043e\u043b\u043d\u044f\u0435\u043c \u0437\u0430\u043f\u0440\u043e\u0441 \u0434\u043b\u044f \u043f\u043e\u043b\u0443\u0447\u0435\u043d\u0438\u044f \u0441\u043f\u0438\u0441\u043a\u0430 \u043f\u0440\u043e\u0432\u043e\u0434\u043e\u043a \u0438\u0437 \u0433\u043b\u0430\u0432\u043d\u043e\u0439 \u043a\u043d\u0438\u0433\u0438:<\/p>\n<p>  <\/p>\n<pre><code class=\"sql\">SELECT * FROM general_ledger ORDER BY id;  id | debit_id | credit_id | amount   ----+----------+-----------+---------   1 |        1 |        12 | $100.00   2 |        1 |         6 | $120.00   3 |       12 |         1 |  $20.00 (3 rows) <\/code><\/pre>\n<p>  <\/p>\n<p>\u0414\u043b\u044f \u043f\u043e\u043b\u0443\u0447\u0435\u043d\u0438\u044f \u0441\u043f\u0438\u0441\u043a\u0430 \u043f\u0440\u043e\u0432\u043e\u0434\u043e\u043a \u043f\u043e \u0441\u0447\u0435\u0442\u0443 1 \u043c\u043e\u0436\u043d\u043e \u0432\u044b\u043f\u043e\u043b\u043d\u0438\u0442\u044c \u0442\u0430\u043a\u043e\u0439 \u0437\u0430\u043f\u0440\u043e\u0441:<\/p>\n<p>  <\/p>\n<pre><code class=\"sql\">SELECT id                AS general_ledger_id,        credit_id         AS corr_id,        amount            AS debit_amount,        ( 0.00 ) :: money AS credit_amount FROM   general_ledger WHERE  debit_id = 1 UNION SELECT id                AS general_ledger_id,        debit_id          AS corr_id,        ( 0.00 ) :: money AS debit_amount,        amount            AS credit_amount FROM   general_ledger WHERE  credit_id = 1 ORDER  BY general_ledger_id;  general_ledger_id | corr_id | debit_amount | credit_amount  -------------------+---------+--------------+---------------                  1 |      12 |      $100.00 |         $0.00                  2 |       6 |      $120.00 |         $0.00                  3 |      12 |        $0.00 |        $20.00 (3 rows) <\/code><\/pre>\n<p>  <\/p>\n<p>\u0418\u043b\u0438 \u0441\u043e\u0437\u0434\u0430\u0442\u044c \u0444\u0443\u043d\u043a\u0446\u0438\u044e <strong>account_entries<\/strong> :<\/p>\n<p>  <\/p>\n<pre><code class=\"sql\">DROP FUNCTION IF EXISTS account_entries;  CREATE FUNCTION account_entries(account_id integer) RETURNS TABLE (     general_ledger_id   integer,     corr_id             smallint,     debit_amount        money,     credit_amount       money ) AS $$     SELECT id                AS general_ledger_id,            credit_id         AS corr_id,            amount            AS debit_amount,            ( 0.00 ) :: money AS credit_amount     FROM   general_ledger     WHERE  debit_id = account_id     UNION     SELECT id                AS general_ledger_id,            debit_id          AS corr_id,            ( 0.00 ) :: money AS debit_amount,            amount            AS credit_amount     FROM   general_ledger     WHERE  credit_id = account_id     ORDER  BY general_ledger_id; $$ LANGUAGE sql;<\/code><\/pre>\n<p>  <\/p>\n<p>\u0412\u044b\u043f\u043e\u043b\u043d\u0438\u043c \u043a\u043e\u043c\u0430\u043d\u0434\u0443:<\/p>\n<p>  <\/p>\n<pre><code class=\"plaintext\">empire-erp=# \\i step1_3.sql<\/code><\/pre>\n<p>  <\/p>\n<p>\u0412\u044b\u043f\u043e\u043b\u043d\u0438\u043c \u0437\u0430\u043f\u0440\u043e\u0441:<\/p>\n<p>  <\/p>\n<pre><code class=\"sql\">SELECT * FROM account_entries(1);  general_ledger_id | corr_id | debit_amount | credit_amount  -------------------+---------+--------------+---------------                  1 |      12 |      $100.00 |         $0.00                  2 |       6 |      $120.00 |         $0.00                  3 |      12 |        $0.00 |        $20.00 (3 rows) <\/code><\/pre>\n<p>  <\/p>\n<h2 id=\"step-2-oborotnaya-vedomost-i-balans\">Step 2. \u041e\u0431\u043e\u0440\u043e\u0442\u043d\u0430\u044f \u0432\u0435\u0434\u043e\u043c\u043e\u0441\u0442\u044c \u0438 \u0431\u0430\u043b\u0430\u043d\u0441<\/h2>\n<p>  <\/p>\n<p>\u041a\u0430\u043a \u0438 \u0432 \u043f\u0440\u0435\u0434\u044b\u0434\u0443\u0449\u0435\u0439 \u0441\u0442\u0430\u0442\u044c\u0435 \u2014 \u0432\u0441\u0435 \u0442\u0440\u0430\u043d\u0437\u0430\u043a\u0446\u0438\u0438 \u0432\u044b\u043f\u043e\u043b\u043d\u044f\u044e\u0442\u0441\u044f \u0432 \u043e\u0434\u043d\u043e\u043c \u043e\u0442\u0447\u0435\u0442\u043d\u043e\u043c \u043f\u0435\u0440\u0438\u043e\u0434\u0435, \u0432 \u043d\u0430\u0447\u0430\u043b\u0435 \u043f\u0435\u0440\u0438\u043e\u0434\u0430 \u043e\u0441\u0442\u0430\u0442\u043a\u0438 \u043e\u0442\u0441\u0443\u0442\u0441\u0442\u0432\u0443\u044e\u0442.<\/p>\n<p>  <\/p>\n<p>\u0412\u044b\u043f\u043e\u043b\u043d\u0438\u043c \u043a\u043e\u043c\u0430\u043d\u0434\u0443:<\/p>\n<p>  <\/p>\n<pre><code class=\"plaintext\">empire-erp=# \\i step2.sql<\/code><\/pre>\n<p>  <\/p>\n<p>\u0414\u043b\u044f \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u0435\u043d\u0438\u044f \u043e\u0431\u043e\u0440\u043e\u0442\u043e\u0432 \u043f\u043e \u0441\u0447\u0435\u0442\u0430\u043c \u0432\u044b\u043f\u043e\u043b\u043d\u0438\u043c \u0442\u0430\u043a\u043e\u0439 \u0437\u0430\u043f\u0440\u043e\u0441:<\/p>\n<p>  <\/p>\n<pre><code class=\"sql\">DROP TABLE IF EXISTS turnout;  SELECT account_id,        sum(debit_turnout)  AS debit_turnout,        sum(credit_turnout) AS credit_turnout INTO   turnout FROM   (SELECT debit_id          AS account_id,                sum(amount)       AS debit_turnout,                ( 0.00 ) :: money AS credit_turnout         FROM   general_ledger         GROUP  BY debit_id         UNION         SELECT credit_id         AS account_id,                ( 0.00 ) :: money AS debit_turnout,                sum(amount)       AS credit_turnout         FROM   general_ledger         GROUP  BY credit_id) AS turnout GROUP  BY account_id ORDER  BY account_id;  SELECT * FROM turnout; DROP TABLE SELECT 3  account_id | debit_turnout | credit_turnout  ------------+---------------+----------------           1 |       $220.00 |         $20.00           6 |         $0.00 |        $120.00          12 |        $20.00 |        $100.00 (3 rows) <\/code><\/pre>\n<p>  <\/p>\n<p>\u041e\u0431\u043e\u0440\u043e\u0442\u043d\u0430\u044f \u0432\u0435\u0434\u043e\u043c\u043e\u0441\u0442\u044c<\/p>\n<p>  <\/p>\n<pre><code class=\"sql\">SELECT start_balance.id            AS account_id,        start_balance.debit_amount  AS debit_start,        start_balance.credit_amount AS credit_start,        turnout.debit_turnout,        turnout.credit_turnout,        CASE          WHEN turnout.debit_turnout + start_balance.debit_amount -               turnout.credit_turnout - start_balance.credit_amount &gt;= ( 0.0 ) :: money          THEN turnout.debit_turnout + start_balance.debit_amount -               turnout.credit_turnout - start_balance.credit_amount          ELSE ( 0.0 ) :: money        END                         AS debit_final,        CASE          WHEN turnout.credit_turnout + start_balance.credit_amount -               turnout.debit_turnout - start_balance.debit_amount &gt;= ( 0.0 ) :: money          THEN turnout.credit_turnout + start_balance.credit_amount -               turnout.debit_turnout - start_balance.debit_amount          ELSE ( 0.0 ) :: money        END                         AS credit_final FROM   start_balance        LEFT JOIN turnout               ON start_balance.id = turnout.account_id;  account_id | debit_start | credit_start | debit_turnout | credit_turnout | debit_final | credit_final  ------------+-------------+--------------+---------------+----------------+-------------+--------------           1 |       $0.00 |        $0.00 |       $220.00 |         $20.00 |     $200.00 |        $0.00           2 |       $0.00 |        $0.00 |               |                |       $0.00 |        $0.00           3 |       $0.00 |        $0.00 |               |                |       $0.00 |        $0.00           4 |       $0.00 |        $0.00 |               |                |       $0.00 |        $0.00           5 |       $0.00 |        $0.00 |               |                |       $0.00 |        $0.00           6 |       $0.00 |        $0.00 |         $0.00 |        $120.00 |       $0.00 |      $120.00           7 |       $0.00 |        $0.00 |               |                |       $0.00 |        $0.00           8 |       $0.00 |        $0.00 |               |                |       $0.00 |        $0.00           9 |       $0.00 |        $0.00 |               |                |       $0.00 |        $0.00          10 |       $0.00 |        $0.00 |               |                |       $0.00 |        $0.00          11 |       $0.00 |        $0.00 |               |                |       $0.00 |        $0.00          12 |       $0.00 |        $0.00 |        $20.00 |        $100.00 |       $0.00 |       $80.00 (12 rows) <\/code><\/pre>\n<p>  <\/p>\n<p>\u0411\u0430\u043b\u0430\u043d\u0441 \u043c\u044b \u043f\u043e\u043b\u0443\u0447\u0430\u0435\u043c \u0438\u0437 \u0434\u0432\u0443\u0445 \u043f\u043e\u0441\u043b\u0435\u0434\u043d\u0438\u0445 \u0441\u0442\u043e\u043b\u0431\u0446\u043e\u0432 \u043e\u0431\u043e\u0440\u043e\u0442\u043d\u043e\u0439 \u0432\u0435\u0434\u043e\u043c\u043e\u0441\u0442\u0438. \u0414\u043b\u044f \u043f\u0440\u043e\u0432\u0435\u0440\u043a\u0438 \u043f\u0440\u043e\u0441\u0443\u043c\u043c\u0438\u0440\u0443\u0435\u043c \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u044f \u0441\u0442\u043e\u043b\u0431\u0446\u043e\u0432 \u0438 \u0441\u0432\u0435\u0440\u0438\u043c \u043f\u043e\u043b\u0443\u0447\u0435\u043d\u043d\u044b\u0435 \u0441\u0443\u043c\u043c\u044b \u0434\u0440\u0443\u0433 \u0441 \u0434\u0440\u0443\u0433\u043e\u043c, \u043e\u043d\u0438 \u0434\u043e\u043b\u0436\u043d\u044b \u0441\u043e\u0432\u043f\u0430\u0434\u0430\u0442\u044c. \u042d\u0442\u043e \u0443\u0436\u0435 \u043d\u0435\u0441\u043b\u043e\u0436\u043d\u043e \u0438 \u044f \u043d\u0435 \u0431\u0443\u0434\u0443 \u0437\u0434\u0435\u0441\u044c \u043f\u0440\u0438\u0432\u043e\u0434\u0438\u0442\u044c \u043a\u043e\u0434.<\/p>\n<p>  <\/p>\n<p>\u041f\u0440\u043e\u0431\u043b\u0435\u043c\u044b \u0441\u043e \u0441\u0442\u043e\u0440\u043d\u043e, \u043a\u043e\u0442\u043e\u0440\u0430\u044f \u0431\u044b\u043b\u0430 \u0432 \u043f\u0440\u043e\u0448\u043b\u043e\u0439 \u0441\u0442\u0430\u0442\u044c\u0435 \u0441\u0435\u0439\u0447\u0430\u0441 \u043d\u0435 \u0434\u043e\u043b\u0436\u043d\u043e \u0431\u044b\u0442\u044c, \u043d\u0435 \u043f\u0440\u043e\u0432\u0435\u0440\u044f\u043b.<\/p>\n<p>  <\/p>\n<h2 id=\"step-3-proverka-dobavleniya-provodok\">Step 3. \u041f\u0440\u043e\u0432\u0435\u0440\u043a\u0430 \u0434\u043e\u0431\u0430\u0432\u043b\u0435\u043d\u0438\u044f \u043f\u0440\u043e\u0432\u043e\u0434\u043e\u043a<\/h2>\n<p>  <\/p>\n<p>\u041d\u0430 \u0430\u043a\u0442\u0438\u0432\u043d\u044b\u0445 \u0441\u0447\u0435\u0442\u0430\u0445 \u043e\u0441\u0442\u0430\u0442\u043a\u0438 \u043c\u043e\u0433\u0443\u0442 \u0431\u044b\u0442\u044c \u0442\u043e\u043b\u044c\u043a\u043e \u043f\u043e \u0434\u0435\u0431\u0435\u0442\u0443, \u0430 \u043d\u0430 \u043f\u0430\u0441\u0441\u0438\u0432\u043d\u044b\u0445 \u2014 \u043f\u043e \u043a\u0440\u0435\u0434\u0438\u0442\u0443. \u0411\u0443\u0434\u0435\u043c \u043f\u0440\u043e\u0432\u0435\u0440\u044f\u0442\u044c \u0442\u0430\u043a\u0438\u0435 \u0443\u0441\u043b\u043e\u0432\u0438\u044f.<\/p>\n<p>  <\/p>\n<h3 id=\"31-proverka-uzhe-zapolnennoy-glavnoy-knigi\">3.1 \u041f\u0440\u043e\u0432\u0435\u0440\u043a\u0430 \u0443\u0436\u0435 \u0437\u0430\u043f\u043e\u043b\u043d\u0435\u043d\u043d\u043e\u0439 \u0433\u043b\u0430\u0432\u043d\u043e\u0439 \u043a\u043d\u0438\u0433\u0438<\/h3>\n<p>  <\/p>\n<p>\u0414\u043e\u043f\u0443\u0441\u0442\u0438\u043c, \u043c\u044b \u0437\u0430\u043d\u0435\u0441\u043b\u0438 \u0432\u0441\u0435 \u043f\u0440\u043e\u0432\u043e\u0434\u043a\u0438 \u0432 \u0433\u043b\u0430\u0432\u043d\u0443\u044e \u043a\u043d\u0438\u0433\u0443 \u0438 \u043d\u0443\u0436\u043d\u043e \u043f\u0440\u043e\u0432\u0435\u0440\u0438\u0442\u044c \u0438\u0445 \u043d\u0430 \u0432\u044b\u0448\u0435\u0443\u043f\u043e\u043c\u044f\u043d\u0443\u0442\u043e\u0435 \u0443\u0441\u043b\u043e\u0432\u0438\u0435. \u0414\u043b\u044f \u044d\u0442\u043e\u0433\u043e \u043d\u0443\u0436\u043d\u043e \u0445\u0440\u0430\u043d\u0438\u0442\u044c \u043e\u0441\u0442\u0430\u0442\u043a\u0438 \u043f\u043e \u0434\u0435\u0431\u0435\u0442\u0443 \u0438 \u043a\u0440\u0435\u0434\u0438\u0442\u0443 \u043d\u0430 \u0441\u0447\u0435\u0442\u0430\u0445.<\/p>\n<p>  <\/p>\n<p>\u0415\u0441\u043b\u0438 \u043f\u0438\u0448\u0435\u043c \u043d\u0430 PL\/pgSQL, \u0442\u043e \u0434\u043b\u044f \u0445\u0440\u0430\u043d\u0435\u043d\u0438\u044f \u043e\u0441\u0442\u0430\u0442\u043a\u043e\u0432 \u043f\u043e \u0441\u0447\u0435\u0442\u0430\u043c \u043c\u044b \u043c\u043e\u0436\u0435\u043c \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c \u0442\u0430\u0431\u043b\u0438\u0446\u0443 \u0441 \u0442\u0430\u043a\u043e\u0439 \u0441\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u043e\u0439:<\/p>\n<p>  <\/p>\n<pre><code class=\"sql\">CREATE TABLE balance (     account_id      smallint NOT NULL,     debit_amount    money DEFAULT 0.0,     credit_amount   money DEFAULT 0.0 );<\/code><\/pre>\n<p>  <\/p>\n<p>\u0415\u0441\u043b\u0438 \u043f\u0438\u0448\u0435\u043c \u043d\u0430 PL\/Python, \u0442\u043e \u043c\u043e\u0436\u0435\u043c \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c \u0441\u043b\u043e\u0432\u0430\u0440\u044c. \u0415\u0441\u043b\u0438 \u043f\u0438\u0448\u0435\u043c \u043d\u0430 C++ \u2014 unordered_map.<\/p>\n<p>  <\/p>\n<p>\u0410\u043b\u0433\u043e\u0440\u0438\u0442\u043c\u044b \u043f\u0440\u043e\u0432\u0435\u0440\u043a\u0438 \u043e\u0441\u0442\u0430\u0442\u043a\u043e\u0432 \u043d\u0430 \u0430\u043a\u0442\u0438\u0432\u043d\u044b\u0445 \u0438 \u043f\u0430\u0441\u0441\u0438\u0432\u043d\u044b\u0445 \u0441\u0447\u0435\u0442\u0430\u0445 \u0438 \u043e\u0431\u043d\u043e\u0432\u043b\u0435\u043d\u0438\u044f \u043e\u0441\u0442\u0430\u0442\u043a\u043e\u0432 \u043d\u0430 \u0432\u0441\u0435\u0445 \u0441\u0447\u0435\u0442\u0430\u0445 \u0432 \u0442\u0430\u0431\u043b\u0438\u0446\u0435 \u043e\u0441\u0442\u0430\u0442\u043a\u043e\u0432 \u0434\u043b\u044f \u0440\u0430\u0437\u043d\u044b\u0445 \u0442\u0438\u043f\u043e\u0432 \u0441\u0447\u0435\u0442\u043e\u0432 \u0440\u0430\u0437\u043b\u0438\u0447\u0430\u044e\u0442\u0441\u044f. \u041d\u0443\u0436\u043d\u043e \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u044f\u0442\u044c \u0442\u0438\u043f\u044b \u0441\u0447\u0435\u0442\u043e\u0432 \u043a\u0430\u0436\u0434\u043e\u0439 \u043f\u0440\u043e\u0432\u043e\u0434\u043a\u0438. \u0414\u043b\u044f \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u0435\u043d\u0438\u044f \u0442\u0438\u043f\u0430 \u043f\u0440\u043e\u0432\u043e\u0434\u043a\u0438 \u0432 \u0442\u0430\u0431\u043b\u0438\u0446\u0443 \u043f\u043b\u0430\u043d\u0430 \u0441\u0447\u0435\u0442\u043e\u0432 <strong>coa<\/strong> (chart of accounts) \u0434\u043e\u0431\u0430\u0432\u0438\u043c \u043f\u043e\u043b\u0435 \u0434\u043b\u044f \u0442\u0438\u043f\u0430 \u0441\u0447\u0435\u0442\u0430: <strong>account_type<\/strong>:<\/p>\n<p>  <\/p>\n<pre><code class=\"sql\">CREATE TYPE t_account_type AS ENUM ('active', 'passive', 'active-passive');  CREATE TABLE coa (     account_id      smallint NOT NULL,     account_type    t_account_type NOT NULL,     name            text NOT NULL );<\/code><\/pre>\n<p>  <\/p>\n<p>\u0418 \u043a\u0430\u043a\u0438\u043c-\u0442\u043e \u043e\u0431\u0440\u0430\u0437\u043e\u043c \u0431\u0443\u0434\u0435\u043c \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u044f\u0442\u044c \u0441 \u043f\u043e\u043c\u043e\u0449\u044c\u044e \u0441\u043f\u0435\u0446\u0438\u0430\u043b\u044c\u043d\u043e\u0439 \u0444\u0443\u043d\u043a\u0446\u0438\u0438. \u041d\u0430 \u0421++ \u043c\u043e\u0436\u043d\u043e \u043e\u043f\u044f\u0442\u044c \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c unordered_map.<\/p>\n<p>  <\/p>\n<p>\u0410\u043b\u0433\u043e\u0440\u0438\u0442\u043c\u044b \u043f\u0440\u043e\u0432\u0435\u0440\u043a\u0438 \u0438 \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u0435\u043d\u0438\u044f \u043e\u0441\u0442\u0430\u0442\u043a\u043e\u0432 \u043f\u0440\u0438\u0432\u043e\u0434\u0438\u043b\u0438\u0441\u044c \u0432 \u043f\u0440\u043e\u0448\u043b\u043e\u0439 \u0441\u0442\u0430\u0442\u044c\u0435, \u043d\u0435 \u0431\u0443\u0434\u0443 \u0437\u0434\u0435\u0441\u044c \u0438\u0445 \u043f\u043e\u0432\u0442\u043e\u0440\u044f\u0442\u044c. \u0415\u0441\u043b\u0438 \u043e\u0431\u043d\u0430\u0440\u0443\u0436\u0438\u0442\u0441\u044f \u043e\u0448\u0438\u0431\u043a\u0430, \u0442\u043e \u043c\u043e\u0436\u043d\u043e \u043f\u043e\u0434\u043d\u044f\u0442\u044c \u0438\u0441\u043a\u043b\u044e\u0447\u0435\u043d\u0438\u0435 \u0438 \u0432\u044b\u0432\u0435\u0441\u0442\u0438 \u0438\u043d\u0444\u043e\u0440\u043c\u0430\u0446\u0438\u044e \u043e\u0431 \u043e\u0448\u0438\u0431\u043a\u0435.<\/p>\n<p>  <\/p>\n<h3 id=\"32-proverka-na-kazhdom-vvode-provodki\">3.2 \u041f\u0440\u043e\u0432\u0435\u0440\u043a\u0430 \u043d\u0430 \u043a\u0430\u0436\u0434\u043e\u043c \u0432\u0432\u043e\u0434\u0435 \u043f\u0440\u043e\u0432\u043e\u0434\u043a\u0438<\/h3>\n<p>  <\/p>\n<p>\u041c\u043e\u0436\u043d\u043e \u043f\u0440\u043e\u0432\u0435\u0440\u044f\u0442\u044c \u043f\u0440\u043e\u0432\u043e\u0434\u043a\u0438 \u0432 \u043c\u043e\u043c\u0435\u043d\u0442 \u0437\u0430\u043d\u0435\u0441\u0435\u043d\u0438\u044f \u0438\u0445 \u0432 \u0433\u043b\u0430\u0432\u043d\u0443\u044e \u043a\u043d\u0438\u0433\u0443. \u042d\u0442\u043e \u043c\u043e\u0436\u043d\u043e \u0432\u044b\u043f\u043e\u043b\u043d\u0438\u0442\u044c \u0441 \u043f\u043e\u043c\u043e\u0449\u044c\u044e \u0442\u0440\u0438\u0433\u0433\u0435\u0440\u043d\u043e\u0439 \u0444\u0443\u043d\u043a\u0446\u0438\u0438. \u0422\u0440\u0438\u0433\u0433\u0435\u0440\u043d\u0430\u044f \u0444\u0443\u043d\u043a\u0446\u0438\u044f \u0431\u0443\u0434\u0435\u0442 \u0432\u044b\u043f\u043e\u043b\u043d\u044f\u0442\u044c\u0441\u044f \u043f\u043e\u0441\u043b\u0435 \u0432\u0432\u043e\u0434\u0430 \u043f\u0440\u043e\u0432\u043e\u0434\u043a\u0438 \u0432 \u0433\u043b\u0430\u0432\u043d\u0443\u044e \u043a\u043d\u0438\u0433\u0443. \u0412 \u0441\u043b\u0443\u0447\u0430\u0435 \u0432\u043e\u0437\u043d\u0438\u043a\u043d\u043e\u0432\u0435\u043d\u0438\u044f \u043e\u0448\u0438\u0431\u043a\u0438 \u043f\u043e\u0434\u043d\u0438\u043c\u0435\u0442\u0441\u044f \u0438\u0441\u043a\u043b\u044e\u0447\u0435\u043d\u0438\u0435 \u0438 \u0442\u0440\u0430\u043d\u0437\u0430\u043a\u0446\u0438\u044f \u043e\u0442\u043a\u0430\u0442\u0438\u0442\u0441\u044f.<\/p>\n<p>  <\/p>\n<p>\u041d\u0430 Python \u0438 C++ \u043d\u0443\u0436\u043d\u043e \u0438\u043c\u0435\u0442\u044c \u0432 \u0432\u0438\u0434\u0443, \u0447\u0442\u043e \u0432 PostgreSQL \u0441\u043e\u0435\u0434\u0438\u043d\u0435\u043d\u0438\u044f \u044f\u0432\u043b\u044f\u044e\u0442\u0441\u044f \u043e\u0442\u0434\u0435\u043b\u044c\u043d\u044b\u043c\u0438 \u043f\u0440\u043e\u0446\u0435\u0441\u0441\u0430\u043c\u0438, \u043f\u043e\u044d\u0442\u043e\u043c\u0443 \u0441\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u0443 \u0441 \u043e\u0441\u0442\u0430\u0442\u043a\u0430\u043c\u0438 \u043d\u0443\u0436\u043d\u043e \u0445\u0440\u0430\u043d\u0438\u0442\u044c \u0432 \u0440\u0430\u0437\u0434\u0435\u043b\u044f\u0435\u043c\u043e\u0439 \u043c\u0435\u0436\u0434\u0443 \u043f\u0440\u043e\u0446\u0435\u0441\u0441\u0430\u043c\u0438 \u043f\u0430\u043c\u044f\u0442\u0438 \u0438 \u043a\u043e\u043e\u0440\u0434\u0438\u043d\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u0435\u0435 \u043e\u0431\u043d\u043e\u0432\u043b\u0435\u043d\u0438\u0435.<\/p>\n<p>  <\/p>\n<h3 id=\"33-drugie-oshibki\">3.3 \u0414\u0440\u0443\u0433\u0438\u0435 \u043e\u0448\u0438\u0431\u043a\u0438<\/h3>\n<p>  <\/p>\n<p>\u0412 \u044d\u0442\u043e\u0439 \u0441\u0442\u0430\u0442\u044c\u0435 <a href=\"https:\/\/en.wikipedia.org\/wiki\/Trial_balance\" rel=\"nofollow noopener noreferrer\">https:\/\/en.wikipedia.org\/wiki\/Trial_balance<\/a> \u0443\u043a\u0430\u0437\u044b\u0432\u0430\u044e\u0442\u0441\u044f \u043d\u0435\u0441\u043a\u043e\u043b\u044c\u043a\u043e \u043e\u0448\u0438\u0431\u043e\u043a \u0432 \u0440\u0430\u0437\u0434\u0435\u043b\u0435 Limitations. \u041f\u0435\u0440\u0432\u0430\u044f \u043e\u0448\u0438\u0431\u043a\u0430 \u0432 \u043d\u0430\u0448\u0435\u043c \u0441\u043b\u0443\u0447\u0430\u0435 \u043d\u0435 \u043f\u0440\u043e\u044f\u0432\u0438\u0442\u0441\u044f, \u043f\u043e\u0441\u043a\u043e\u043b\u044c\u043a\u0443 \u0434\u0430\u043d\u043d\u044b\u0435 \u0431\u0435\u0440\u0443\u0442\u0441\u044f \u0442\u043e\u043b\u044c\u043a\u043e \u0438\u0437 \u0433\u043b\u0430\u0432\u043d\u043e\u0439 \u043a\u043d\u0438\u0433\u0438:<\/p>\n<p>  <\/p>\n<blockquote><p>An error of original entry is when both sides of a transaction include the wrong amount.[2] For example, if a purchase invoice for \u00a321 is entered as \u00a312, this will result in an incorrect debit entry (to purchases), and an incorrect credit entry (to the relevant creditor account), both for \u00a39 less, so the total of both columns will be \u00a39 less, and will thus balance.<\/p><\/blockquote>\n<p>\u041e\u0441\u0442\u0430\u043b\u044c\u043d\u044b\u0435 \u043e\u0448\u0438\u0431\u043a\u0438 \u0438\u0437 \u044d\u0442\u043e\u0439 \u0441\u0442\u0430\u0442\u044c\u0438 \u0435\u0449\u0435 \u043d\u0435 \u0440\u0430\u0437\u043e\u0431\u0440\u0430\u043b. \u041a\u0442\u043e \u0440\u0430\u0437\u0431\u0435\u0440\u0435\u0442 \u0438 \u0440\u0430\u0437\u044a\u044f\u0441\u043d\u0438\u0442 \u0432\u0441\u0435\u043c, \u0442\u043e\u043c\u0443 \u0437\u0430\u0440\u0435\u0437\u0435\u0440\u0432\u0438\u0440\u0443\u044e \u043f\u043b\u0430\u043d\u0435\u0442\u0443.<\/p>\n<p>  <\/p>\n<h2 id=\"step-4-rezyume\">Step 4. \u0420\u0435\u0437\u044e\u043c\u0435<\/h2>\n<p>  <\/p>\n<p>\u041a\u0430\u043a \u0432\u0438\u0434\u0438\u043c, \u043c\u044b \u043c\u043e\u0436\u0435\u043c \u0432\u0441\u044e \u043b\u043e\u0433\u0438\u043a\u0443 \u043c\u043e\u0434\u0443\u043b\u044f &quot;\u0411\u0443\u0445\u0433\u0430\u043b\u0442\u0435\u0440\u0438\u044f&quot; \u0440\u0435\u0430\u043b\u0438\u0437\u043e\u0432\u0430\u0442\u044c \u043d\u0430 \u0441\u0442\u043e\u0440\u043e\u043d\u0435 \u0441\u0435\u0440\u0432\u0435\u0440\u0430 \u0431\u0430\u0437\u044b \u0434\u0430\u043d\u043d\u044b\u0445 \u0438 \u0441\u043e\u0437\u0434\u0430\u0442\u044c SQL API.<br \/>  \u041d\u0430 \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0435\u043c \u0434\u043d\u0435 \u0440\u0430\u0441\u0441\u043c\u043e\u0442\u0440\u0438\u043c \u0430\u043d\u0430\u043b\u0438\u0442\u0438\u0447\u0435\u0441\u043a\u0438\u0435 \u0441\u0447\u0435\u0442\u0430 \u0438 \u043d\u0435\u043c\u043e\u0436\u043a\u043e \u043f\u043e\u043a\u043e\u0434\u0438\u0440\u0443\u0435\u043c \u043d\u0430 UML.<\/p>\n<p>  <\/p>\n<h2 id=\"step-5-zanimatelnoe\">Step 5. \u0417\u0430\u043d\u0438\u043c\u0430\u0442\u0435\u043b\u044c\u043d\u043e\u0435<\/h2>\n<p>  <\/p>\n<p>\u0412 \u044d\u0442\u043e\u0439 \u043a\u043d\u0438\u0433\u0435 <a href=\"http:\/\/aima.cs.berkeley.edu\/newchap00.pdf\" rel=\"nofollow noopener noreferrer\">Artificial Intelligence. A Modern Approach<\/a> \u0435\u0441\u0442\u044c \u0433\u043b\u0430\u0432\u0430 <strong>Automated Planning<\/strong>. \u041f\u043e\u0441\u043a\u043e\u043b\u044c\u043a\u0443 ERP \u043f\u0440\u043e \u043f\u043b\u0430\u043d\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u0435, \u0442\u043e \u0438\u043c\u0435\u0435\u0442 \u0441\u043c\u044b\u0441\u043b \u0434\u043e\u0431\u0440\u0430\u0442\u044c\u0441\u044f \u0434\u043e \u044d\u0442\u043e\u0439 \u0433\u043b\u0430\u0432\u044b.<\/p>\n<p>  <\/p>\n<p>\u0417\u0434\u0435\u0441\u044c <a href=\"https:\/\/xn----8sbis2aqlf5f.xn--p1ai\/2\" rel=\"nofollow noopener noreferrer\">https:\/\/\u0438\u0442-\u0433\u0440\u0430\u043d\u0442\u044b.\u0440\u0444\/2<\/a> \u0432 \u043a\u043e\u043d\u043a\u0443\u0440\u0441\u043d\u043e\u0439 \u0434\u043e\u043a\u0443\u043c\u0435\u043d\u0442\u0430\u0446\u0438\u0438 \u0432 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0438 #3 \u0432\u0438\u0434\u0438\u043c, \u0447\u0442\u043e ERP \u0441\u0438\u0441\u0442\u0435\u043c\u044b \u0438\u043c\u0435\u044e\u0442 \u043f\u0440\u0438\u043e\u0440\u0438\u0442\u0435\u0442 1-\u0433\u043e \u043f\u043e\u0440\u044f\u0434\u043a\u0430, \u043d\u0430\u0434\u043e \u043f\u043e\u0441\u043c\u043e\u0442\u0440\u0435\u0442\u044c \u0442\u0440\u0435\u0431\u043e\u0432\u0430\u043d\u0438\u044f.<\/p>\n<\/div>\n<p> \u0441\u0441\u044b\u043b\u043a\u0430 \u043d\u0430 \u043e\u0440\u0438\u0433\u0438\u043d\u0430\u043b \u0441\u0442\u0430\u0442\u044c\u0438 <a href=\"https:\/\/habr.com\/ru\/post\/568192\/\"> https:\/\/habr.com\/ru\/post\/568192\/<\/a><\/p>\n","protected":false},"excerpt":{"rendered":"\n<div class=\"post__text post__text-html post__text_v1\" id=\"post-content-body\">\n<p>\u041f\u0440\u043e\u0434\u043e\u043b\u0436\u0435\u043d\u0438\u0435 \u0446\u0438\u043a\u043b\u0430 <a href=\"https:\/\/habr.com\/ru\/post\/471304\/\">&quot;\u0417\u0430\u043d\u0438\u043c\u0430\u0442\u0435\u043b\u044c\u043d\u0430\u044f \u0431\u0443\u0445\u0433\u0430\u043b\u0442\u0435\u0440\u0438\u044f&quot;<\/a>.<br \/>  \u041f\u043e\u043f\u0440\u043e\u0431\u0443\u0435\u043c \u0441\u043f\u0440\u043e\u0435\u043a\u0442\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u0431\u0430\u0437\u0443 \u0434\u0430\u043d\u043d\u044b\u0445 \u043c\u043e\u0434\u0443\u043b\u044f &quot;\u0411\u0443\u0445\u0433\u0430\u043b\u0442\u0435\u0440\u0438\u044f&quot; \u043d\u0430 PostgreSQL.<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[],"tags":[],"class_list":["post-326579","post","type-post","status-publish","format-standard","hentry"],"_links":{"self":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/posts\/326579","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=326579"}],"version-history":[{"count":0,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/posts\/326579\/revisions"}],"wp:attachment":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=326579"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=326579"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=326579"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}