Закрытие периода (постановка)

Материал из GedeminWiki
(Различия между версиями)
Перейти к: навигация, поиск
(Сальдо)
(Статистика по новому механизму)
 
(не показаны 17 промежуточных версий 2 участников)
Строка 1: Строка 1:
Для ускорения работы бухгалтерских отчетов (Журнал-ордер, Анализ счета, Карта счета, Оборотная ведомость, Главная книга) и функций работающих с проводками необходимо реализовать механизм закрытия периода. Бухгалтерское закрытие периода подразумевает выбор проводок за заданный период, их группировка по счетам и соответствующим аналитикам, запись полученного сальдо в новую таблицу. В дальнейшем при построении бухгалтерских отчетов начальное и конечное сальдо должно будет вычисляться на основании данных из этой таблицы.
+
Для ускорения работы бухгалтерских отчетов (Журнал-ордер, Анализ счета, Карта счета, Оборотная ведомость, Главная книга) и функций работающих с проводками необходимо реализовать механизм переодического расчета сальдо. Механизм подразумевает выбор проводок за заданный период, их группировка по счетам и соответствующим аналитикам, запись полученного сальдо в новую таблицу. В дальнейшем при построении бухгалтерских отчетов начальное и конечное сальдо должно будет вычисляться на основании данных из этой таблицы.
  
== Сальдо ==
+
== Расчет сальдо ==
Таблица в которую будет производится запись сгруппированных данных по проводкам будет называться AC_ENTRY_SALDO.
+
 
Структура таблицы будет идентична структуре таблицы AC_ENTRY, за исключением некоторых полей:
+
=== Механизм расчета ===
   CREATE TABLE AC_ENTRY_SALDO (
+
 
 +
Таблица в которую будет производится запись сгруппированных данных по проводкам будет называться [[AC_ENTRY_BALANCE]]. Ее структура будет идентична таблице [[AC_ENTRY]], за исключением некоторых полей:
 +
 
 +
   CREATE TABLE AC_ENTRY_BALANCE (
 +
    --------------------------------
 +
    -- Эти поля аналогичны AC_ENTRY
 +
    --------------------------------
 
     ID                      DINTKEY,
 
     ID                      DINTKEY,
 
     COMPANYKEY              DINTKEY,
 
     COMPANYKEY              DINTKEY,
 
     ACCOUNTKEY              DINTKEY,
 
     ACCOUNTKEY              DINTKEY,
 +
    CURRKEY                  DINTKEY,
 
     DEBITNCU                DCURRENCY,
 
     DEBITNCU                DCURRENCY,
 
     DEBITCURR                DCURRENCY,
 
     DEBITCURR                DCURRENCY,
Строка 14: Строка 21:
 
     CREDITCURR              DCURRENCY,
 
     CREDITCURR              DCURRENCY,
 
     CREDITEQ                DCURRENCY,
 
     CREDITEQ                DCURRENCY,
     CURRKEY                  DINTKEY,
+
  <b>  USR$GS_CUSTOMER          USR$GS_DCUSTOMER,</b>
+
     ---------------------------------
  <b>  USR$FA_GROUPKEY          USR$FA_CIPHERKEY,</b>
+
    -- Наличие полей аналитических
  <b>  USR$GS_DEPARTMENT        USR$GS_DDEPARTMENT,</b>
+
    -- признаков зависит от
  <b>  USR$FA_INVCARDKEY        USR$FA_INVCARD,</b>
+
    -- конфигурации учета на текущей
  <b>  USR$GS_GOOD              USR$GS_DGOOD,</b>
+
    -- базе данных           
  <b>  USR$GS_DOCUMENT          USR$GS_DDOCUMENT,</b>
+
    ---------------------------------
  <b>  USR$GS_SERVICE          USR$GS_DSERVICE,</b>
+
    USR$GS_CUSTOMER          USR$GS_DCUSTOMER,
  <b>  USR$GS_EMPLOYEE          USR$GS_DEMPLOYEE,</b>
+
    USR$GS_DEPARTMENT        USR$GS_DDEPARTMENT,
  <b>  USR$VATTYPE_KEY          USR$VATTYPEKEY,</b>
+
    USR$FA_INVCARDKEY        USR$FA_INVCARD,
  <b>  USR$GS_CONTRACT          USR$INV_DCONTRACT,</b>
+
    USR$GS_GOOD              USR$GS_DGOOD,
  <b>  USR$GS_EXPENSES          USR$GS_DEXPENSES,</b>
+
    USR$GS_DOCUMENT          USR$GS_DDOCUMENT,
  <b>  USR$GS_ECONOMICACTIVITY  USR$DECONOMICACTIVITY,</b>
+
    USR$GS_SERVICE          USR$GS_DSERVICE,
  <b>  USR$GS_SALETAXRATE      DCURRENCY,</b>
+
    USR$GS_EMPLOYEE          USR$GS_DEMPLOYEE,
 +
    USR$VATTYPE_KEY          USR$VATTYPEKEY,
 +
    USR$FA_GROUPKEY          USR$FA_CIPHERKEY,
 +
    USR$GS_CONTRACT          USR$INV_DCONTRACT,
 +
    USR$GS_EXPENSES          USR$GS_DEXPENSES,
 +
    USR$GS_ECONOMICACTIVITY  USR$DECONOMICACTIVITY,
 +
    USR$GS_SALETAXRATE      DCURRENCY,
 +
    ---------------------------------
 +
    -- Следующие поля AC_ENTRY
 +
    -- не попадут в таблицу итоговых
 +
    -- значений
 +
    ---------------------------------
 
   <s>  ENTRYDATE                DDATE,</s>
 
   <s>  ENTRYDATE                DDATE,</s>
 
   <s>  RECORDKEY                DMASTERKEY,</s>
 
   <s>  RECORDKEY                DMASTERKEY,</s>
Строка 39: Строка 57:
 
   );
 
   );
  
<b>Fieldname</b> - поля аналитик
+
При изменении структуры таблицы [[AC_ENTRY]], например в случае добавления новой аналитики, структура таблицы [[AC_ENTRY_BALANCE]] также будет обновляться.
 
+
<s>Fieldname</s> – удаленные поля (по сравнению с AC_ENTRY)
+
 
+
При изменении структуры таблицы AC_ENTRY (в случае добавления новой аналитики), структура таблицы AC_ENTRY_SALDO также должна быть обновлена.
+
  
Сальдо в стандартных отчетах будет считаться исходя из AC_ENTRY_SALDO + AC_ENTRY. Например, закрытие периода было сделано на дату CloseDate = 01.01.2008. Мы хотим построить журнал-ордер на дату Date = 01.05.2008. Сальдо на дату Date будет вычислятся как сальдо на дату CloseDate из таблицы AC_ENTRY_SALDO плюс сальдо за период 01.01.2008 – 01.05.2008 рассчитанное по таблице AC_ENTRY старым методом. То же самое если нам понадобится сальдо на дату Date = 01.07.2007. Берем сальдо из AC_ENTRY_SALDO на дату CloseDate и отнимаем сальдо за период 01.07.2007 – 01.01.2008 рассчитанное по таблице AC_ENTRY.
+
Сальдо в стандартных отчетах будет считаться исходя из AC_ENTRY_BALANCE + AC_ENTRY. Например, расчет сальдо был сделан на дату CloseDate = 01.01.2008. Мы хотим построить журнал-ордер на дату Date = 01.05.2008. Сальдо на дату Date будет вычислятся как сальдо на дату CloseDate из таблицы AC_ENTRY_BALANCE плюс сальдо за период 01.01.2008 – 01.05.2008 рассчитанное по таблице AC_ENTRY старым методом. То же самое, если нам понадобится сальдо на дату Date = 01.07.2007. Берем сальдо из AC_ENTRY_BALANCE на дату CloseDate и отнимаем сальдо за период 01.07.2007 – 01.01.2008 рассчитанное по таблице AC_ENTRY.
  
После выполнения процедуры закрытия периода на таблицу AC_ENTRY должен быть повешен универсальный триггер AFTER INSERT OR UPDATE OR DELETE, который будет обновлять данные в таблице AC_ENTRY_SALDO в соответствии с изменениями в проводках. Здесь может возникнуть проблема блокировки, когда с базой работает несколько пользователей и одновременно создается несколько проводок, которые попадают в одну запись таблицы AC_ENTRY_SALDO. Поэтому было решено отказаться от обновления записей таблицы AC_ENTRY_SALDO в пользу добавления дельта-записей содержащих величину изменения сальдо по конкретному счету.
+
После первого выполнения процедуры расчета сальдо на таблицу AC_ENTRY должен быть повешен универсальный триггер AFTER INSERT OR UPDATE OR DELETE, который будет обновлять данные в таблице AC_ENTRY_BALANCE в соответствии с изменениями в проводках за период предшедствующий расчету. Здесь может возникнуть проблема блокировки, когда с базой работает несколько пользователей и одновременно создается несколько проводок, которые попадают в одну запись таблицы AC_ENTRY_BALANCE. Поэтому было решено отказаться от обновления записей таблицы AC_ENTRY_BALANCE в пользу добавления дельта-записей содержащих величину изменения сальдо по конкретному счету в разрезе соответствующих аналитик.
  
 
Например, в AC_ENTRY добавилась проводка:
 
Например, в AC_ENTRY добавилась проводка:
Строка 60: Строка 74:
 
  |}
 
  |}
  
В таблице AC_ENTRY_SALDO по 51 счету содержится следующая запись:
+
В таблице AC_ENTRY_BALANCE по 51 счету содержится следующая запись:
 
{| class="standard"
 
{| class="standard"
 
  !Счет
 
  !Счет
Строка 71: Строка 85:
 
  |}
 
  |}
  
Триггер на таблице AC_ENTRY вставит в таблицу AC_ENTRY_SALDO дельта-запись, данные примут вид:
+
Триггер на таблице AC_ENTRY вставит в таблицу AC_ENTRY_BALANCE дельта-запись, данные примут вид:
 
{| class="standard"
 
{| class="standard"
 
  !Счет
 
  !Счет
Строка 88: Строка 102:
 
Предварительный текст триггера:
 
Предварительный текст триггера:
  
   CREATE OR ALTER TRIGGER ac_entry_do_saldo FOR ac_entry
+
   CREATE OR ALTER TRIGGER ac_entry_do_balance FOR ac_entry
 
   ACTIVE AFTER INSERT OR UPDATE OR DELETE POSITION 15
 
   ACTIVE AFTER INSERT OR UPDATE OR DELETE POSITION 15
 
   AS
 
   AS
Строка 95: Строка 109:
 
         AND (NEW.debitncu > 0) OR (NEW.debitcurr > 0) OR (NEW.creditncu > 0) OR (NEW.creditcurr > 0)) THEN
 
         AND (NEW.debitncu > 0) OR (NEW.debitcurr > 0) OR (NEW.creditncu > 0) OR (NEW.creditcurr > 0)) THEN
 
     BEGIN
 
     BEGIN
       INSERT INTO AC_ENTRY_SALDO
+
       INSERT INTO AC_ENTRY_BALANCE
 
         (companykey, accountkey, currkey,
 
         (companykey, accountkey, currkey,
 
         debitncu, debitcurr, debiteq,
 
         debitncu, debitcurr, debiteq,
Строка 123: Строка 137:
 
         OR (OLD.debitcurr <> NEW.debitcurr) OR (OLD.creditcurr <> NEW.creditcurr)) THEN
 
         OR (OLD.debitcurr <> NEW.debitcurr) OR (OLD.creditcurr <> NEW.creditcurr)) THEN
 
     BEGIN
 
     BEGIN
       INSERT INTO AC_ENTRY_SALDO
+
       INSERT INTO AC_ENTRY_BALANCE
 
         (companykey, accountkey, currkey,
 
         (companykey, accountkey, currkey,
 
         debitncu, debitcurr, debiteq,
 
         debitncu, debitcurr, debiteq,
Строка 150: Строка 164:
 
         AND (OLD.debitncu > 0) OR (OLD.debitcurr > 0) OR (OLD.creditncu > 0) OR (OLD.creditcurr > 0)) THEN
 
         AND (OLD.debitncu > 0) OR (OLD.debitcurr > 0) OR (OLD.creditncu > 0) OR (OLD.creditcurr > 0)) THEN
 
     BEGIN
 
     BEGIN
       INSERT INTO AC_ENTRY_SALDO
+
       INSERT INTO AC_ENTRY_BALANCE
 
         (companykey, accountkey, currkey,
 
         (companykey, accountkey, currkey,
 
         debitncu, debitcurr, debiteq,
 
         debitncu, debitcurr, debiteq,
Строка 175: Строка 189:
 
   END
 
   END
  
Где <code>CAST('01.01.2008' AS DATE)</code> - дата закрытия. Триггер и все метаданные, зависящие от даты закрытия периода будут перестраиваться при каждой процедуре закрытия, с подстановкой новой даты закрытия периода.
+
Где <code>CAST('01.01.2008' AS DATE)</code> - дата последнего расчета сальдо. Эту дату можно хранить так же, как хранится дата блокировки периода. То есть хранить в генераторе (например [[GD_G_ENTRY_BALANCE_DATE]]) кол-во дней, прошедших с определенной даты (например 17.11.1858) до даты расчета сальдо. Обновлять значение генератора необходимо после каждой процедуры расчета сальдо.  
  
При следующем выполнении процедуры закрытия периода на дату NewCloseDate, данные о проводках до даты CloseDate прошлого закрытия брать из таблицы AC_ENTRY_SALDO, а данные за промежуток CloseDate - NewCloseDate -- из таблицы AC_ENTRY.
+
При следующем выполнении процедуры закрытия периода на дату NewCloseDate, данные о проводках до даты CloseDate прошлого закрытия брать из таблицы AC_ENTRY_BALANCE, а данные за промежуток CloseDate - NewCloseDate из таблицы AC_ENTRY.
 +
 
 +
Иногда будет необходимо перегруппировать данные в таблице AC_ENTRY_BALANCE путем слияния первоначальной и дельта-записей в одну запись. В момент построения бухгалтерского отчета необходимо проверять количество дельта-записей. Если оно превысит некоторый лимит, то устанавливать флаг, по состоянию которого перестраивать таблицу AC_ENTRY_BALANCE. Это можно делать каждый раз перед/после построения бухгалтерского отчета, или в период простоя Гедемина. Если процедура расчета сальдо будет выполнятся переодически (например, раз в месяц), то данные можно перегруппировать в момент следующего расчета сальдо.
 +
 
 +
=== Группировка данных ===
 +
 
 +
Перед заполнением таблицы AC_ENTRY_BALANCE данные о проводках необходимо сгруппировать. По умолчанию данные группируются по компании, счету и валюте. Также проводки необходимо группировать по аналитикам. Однако, если группировать данные по всем аналитикам, мы не получим большого уменьшения кол-ва записей, так как многие аналитики не закрываются. Поэтому необходимо дать пользователю выбирать по каким аналитикам необходимо группировать данные при выполнении процедуры расчета сальдо.
 +
 
 +
Планируется добавить в План счетов дополнительные флажки, по которым и определять необходимость включения данной аналитики в группировку по конкретному счету.
 +
 
 +
Если при построении бухгалтерского отчета пользователь выберет в группировке аналитику которая не выбрана в Плане счетов, то есть, по которой не рассчитывалось сальдо, то выполнять расчет старым методом (предупредить пользователя?). Можно выделять аналитики по которым было рассчитано сальдо другим цветом.
  
Иногда будет необходимо перегруппировать данные в таблице AC_ENTRY_SALDO путем слияния первоначальной и дельта-записей в одну запись. В момент построения бухгалтерского отчета необходимо проверять количество дельта-записей. Если оно превысит некоторый лимит, то устанавливать флаг, по состоянию которого перестраивать таблицу AC_ENTRY_SALDO. Это можно делать каждый раз перед/после построения бухгалтерского отчета, или в период простоя Гедемина.
 
  
 
== Стандартные отчеты ==
 
== Стандартные отчеты ==
Строка 188: Строка 211:
 
*Оборотная ведомость
 
*Оборотная ведомость
  
Необходимо переделать механизм построения бухгалтерских отчетов с применением таблицы AC_ENTRY_SALDO и новых возможностей Firebird 2.5 (EXECUTE BLOCK и др.)
+
Необходимо переделать механизм построения бухгалтерских отчетов с применением таблицы AC_ENTRY_BALANCE и новых возможностей Firebird 2.5 (EXECUTE BLOCK и др.)
 +
 
 +
=== Журнал-ордер ===
 +
Пример: журнал ордер по счету 41.01, группировка по Подразделению.
 +
 
 +
Оригинальный запрос (с некоторыми упрощениями):
 +
<pre>
 +
SELECT
 +
  SUBSTRING(c0.name FROM 1 FOR 180) AS s0,
 +
  SUBSTRING(c0.id FROM 1 FOR 180) AS c0,
 +
  CAST(1 AS INTEGER) AS sortfield,
 +
  CAST(IIF(SUM(e1.debitncu - e1.creditncu) > 0, SUM(e1.debitncu - e1.creditncu) / 1, 0) AS NUMERIC(15, 2)) AS ncu_begin_debit,
 +
  CAST(IIF(SUM(e1.creditncu - e1.debitncu) > 0, SUM(e1.creditncu - e1.debitncu) / 1, 0) AS NUMERIC(15, 2)) AS ncu_begin_credit,
 +
  CAST(IIF(SUM(e2.debitncu) <> 0, SUM(e2.debitncu) / 1, 0) AS NUMERIC(15, 2)) AS ncu_debit,
 +
  CAST(IIF(SUM(e2.creditncu) <> 0, SUM(e2.creditncu) / 1, 0) AS NUMERIC(15, 2)) AS ncu_credit,
 +
  CAST(IIF(SUM(e.debitncu-e.creditncu) > 0, SUM(e.debitncu - e.creditncu) / 1, 0) AS NUMERIC(15, 2)) AS ncu_end_debit,
 +
  CAST(IIF(SUM(e.creditncu-e.debitncu) > 0, SUM(e.creditncu - e.debitncu) / 1, 0) AS NUMERIC(15, 2)) AS ncu_end_credit
 +
FROM
 +
  ac_entry e
 +
  LEFT JOIN ac_entry e1 ON e1.recordkey = e.recordkey AND e1.id = e.id
 +
    AND e1.entrydate < :begindate
 +
  LEFT JOIN ac_entry e2 ON e2.recordkey = e.recordkey AND e2.id = e.id
 +
    AND e2.entrydate >= :begindate AND e2.entrydate <= :enddate
 +
  LEFT JOIN gd_contact c0 ON c0.id = e.usr$gs_department
 +
WHERE
 +
  e.accountkey IN (344101)
 +
  AND e.entrydate <= :enddate
 +
  AND e.companykey IN (147000001)
 +
GROUP BY
 +
  c0.name, c0.id
 +
HAVING
 +
  SUM(e2.debitncu) <> 0
 +
  OR SUM(e2.creditncu) <> 0
 +
  OR SUM(e1.debitncu - e1.creditncu) <> 0
 +
ORDER BY
 +
  c0.name, c0.id
 +
</pre>
 +
 
 +
Запрос сформированный с учетом расчитанного сальдо из таблицы AC_ENTRY_BALANCE (примерный текст):
 +
<pre>
 +
SELECT
 +
  main.c0,
 +
  CAST(IIF(SUM(main.NCU_BEGIN_DEBIT - main.NCU_BEGIN_CREDIT) > 0,
 +
    SUM(main.NCU_BEGIN_DEBIT - main.NCU_BEGIN_CREDIT), 0) AS NUMERIC(15, 2)) AS NCU_BEGIN_DEBIT,
 +
  CAST(IIF(SUM(main.NCU_BEGIN_CREDIT - main.NCU_BEGIN_DEBIT) > 0,
 +
    SUM(main.NCU_BEGIN_CREDIT - main.NCU_BEGIN_DEBIT), 0) AS NUMERIC(15, 2)) AS NCU_BEGIN_CREDIT,
 +
  CAST(SUM(main.NCU_DEBIT) AS NUMERIC(15, 2)) AS NCU_DEBIT,
 +
  CAST(SUM(main.NCU_CREDIT) AS NUMERIC(15, 2)) AS NCU_CREDIT,
 +
  CAST(IIF((IIF(SUM(main.NCU_BEGIN_DEBIT - main.NCU_BEGIN_CREDIT) > 0,
 +
    SUM(main.NCU_BEGIN_DEBIT - main.NCU_BEGIN_CREDIT), 0) + SUM(main.NCU_DEBIT)) -
 +
    (IIF(SUM(main.NCU_BEGIN_CREDIT - main.NCU_BEGIN_DEBIT) > 0,
 +
    SUM(main.NCU_BEGIN_CREDIT - main.NCU_BEGIN_DEBIT), 0) + SUM(main.NCU_CREDIT)) > 0,
 +
    (IIF(SUM(main.NCU_BEGIN_DEBIT - main.NCU_BEGIN_CREDIT) > 0,
 +
    SUM(main.NCU_BEGIN_DEBIT - main.NCU_BEGIN_CREDIT), 0) + SUM(main.NCU_DEBIT)) -
 +
    (IIF(SUM(main.NCU_BEGIN_CREDIT - main.NCU_BEGIN_DEBIT) > 0,
 +
    SUM(main.NCU_BEGIN_CREDIT - main.NCU_BEGIN_DEBIT), 0) + SUM(main.NCU_CREDIT)), 0) AS NUMERIC(15, 2)) AS NCU_END_DEBIT,
 +
  CAST(IIF((IIF(SUM(main.NCU_BEGIN_CREDIT - main.NCU_BEGIN_DEBIT) > 0,
 +
    SUM(main.NCU_BEGIN_CREDIT - main.NCU_BEGIN_DEBIT), 0) + SUM(main.NCU_CREDIT)) -
 +
    (IIF(SUM(main.NCU_BEGIN_DEBIT - main.NCU_BEGIN_CREDIT) > 0,
 +
    SUM(main.NCU_BEGIN_DEBIT - main.NCU_BEGIN_CREDIT), 0) + SUM(main.NCU_DEBIT)) > 0,
 +
    (IIF(SUM(main.NCU_BEGIN_CREDIT - main.NCU_BEGIN_DEBIT) > 0,
 +
    SUM(main.NCU_BEGIN_CREDIT - main.NCU_BEGIN_DEBIT), 0) + SUM(main.NCU_CREDIT)) -
 +
    (IIF(SUM(main.NCU_BEGIN_DEBIT - main.NCU_BEGIN_CREDIT) > 0,
 +
    SUM(main.NCU_BEGIN_DEBIT - main.NCU_BEGIN_CREDIT), 0) + SUM(main.NCU_DEBIT)), 0) AS NUMERIC(15, 2)) AS NCU_END_CREDIT
 +
FROM
 +
(
 +
  SELECT
 +
    bal.USR$GS_DEPARTMENT AS c0,
 +
    bal.debitncu AS NCU_BEGIN_DEBIT,
 +
    bal.creditncu AS NCU_BEGIN_CREDIT,
 +
    CAST(0 AS NUMERIC(15, 2)) AS NCU_DEBIT,
 +
    CAST(0 AS NUMERIC(15, 2)) AS NCU_CREDIT
 +
  FROM
 +
    ac_entry_balance bal
 +
  WHERE
 +
    bal.accountkey in (344101)
 +
    AND bal.companykey IN (147000001)
 +
 
 +
  UNION ALL
 +
 
 +
  SELECT
 +
    e.USR$GS_DEPARTMENT AS c0,
 +
    - e.debitncu AS NCU_BEGIN_DEBIT,
 +
    - e.creditncu AS NCU_BEGIN_CREDIT,
 +
    CAST(0 AS NUMERIC(15, 2)) AS NCU_DEBIT,
 +
    CAST(0 AS NUMERIC(15, 2)) AS NCU_CREDIT
 +
  FROM
 +
    ac_entry e
 +
  WHERE
 +
    e.accountkey IN (344101)
 +
    AND e.entrydate >= :begindate
 +
    AND e.entrydate < :closedate
 +
    AND e.companykey IN (147000001)
 +
 
 +
  UNION ALL
 +
 
 +
  SELECT
 +
    e2.USR$GS_DEPARTMENT AS c0,
 +
    CAST(0 AS NUMERIC(15, 2)) AS NCU_BEGIN_DEBIT,
 +
    CAST(0 AS NUMERIC(15, 2)) AS NCU_BEGIN_CREDIT,
 +
    e2.debitncu AS NCU_DEBIT,
 +
    e2.creditncu AS NCU_CREDIT
 +
  FROM
 +
    ac_entry e2
 +
  WHERE
 +
    e2.accountkey IN (344101)
 +
    AND e2.entrydate >= :begindate
 +
    AND e2.entrydate <= :enddate
 +
    AND e2.companykey IN (147000001)
 +
 
 +
) main
 +
GROUP BY
 +
  main.c0 
 +
</pre>
 +
 
 +
Примечание: Второй SELECT в подзапросе используется для расчета изменения начального сальдо между начальной даты построения журнала-ордера BeginDate и даты расчета сальдо CloseDate.
 +
 
 +
Если BeginDate < CloseDate:
 +
<pre>
 +
  SELECT
 +
    e.USR$GS_DEPARTMENT AS c0,
 +
    - e.debitncu AS NCU_BEGIN_DEBIT,
 +
    - e.creditncu AS NCU_BEGIN_CREDIT,
 +
    CAST(0 AS NUMERIC(15, 2)) AS NCU_DEBIT,
 +
    CAST(0 AS NUMERIC(15, 2)) AS NCU_CREDIT
 +
  FROM
 +
    ac_entry e
 +
  WHERE
 +
    e.accountkey IN (344101)
 +
    AND e.entrydate >= :begindate
 +
    AND e.entrydate < :closedate
 +
    AND e.companykey IN (147000001)
 +
</pre>
 +
 
 +
Если BeginDate > CloseDate:
 +
<pre>
 +
  SELECT
 +
    e.USR$GS_DEPARTMENT AS c0,
 +
    e.debitncu AS NCU_BEGIN_DEBIT,
 +
    e.creditncu AS NCU_BEGIN_CREDIT,
 +
    CAST(0 AS NUMERIC(15, 2)) AS NCU_DEBIT,
 +
    CAST(0 AS NUMERIC(15, 2)) AS NCU_CREDIT
 +
  FROM
 +
    ac_entry e
 +
  WHERE
 +
    e.accountkey IN (344101)
 +
    AND e.entrydate >= :closedate
 +
    AND e.entrydate < :begindate
 +
    AND e.companykey IN (147000001)
 +
</pre>
 +
 
 +
Если BeginDate = CloseDate, то второй SELECT не нужен.
 +
 
 +
=== Карта счета ===
 +
 
 +
В карте счета расчитывается сальдо на начало и конец периода.
 +
 
 +
Пример: карта счета 41.01.
 +
 
 +
Оригинальный запрос (с некоторыми упрощениями):
 +
<pre>
 +
SELECT
 +
  CAST((SUM(e.debitncu - e.creditncu) / 1) AS NUMERIC(15, 2)) AS Saldo
 +
FROM
 +
  ac_entry e
 +
WHERE
 +
  e.accountkey IN (344101)
 +
  AND e.entrydate < :datebegin
 +
  AND e.companykey IN (147000001)
 +
</pre>
 +
 
 +
Запрос сформированный с учетом расчитанного сальдо из таблицы AC_ENTRY_BALANCE (примерный текст):
 +
<pre>
 +
SELECT
 +
  CAST((SUM(main.NCU_BEGIN_DEBIT - main.NCU_BEGIN_CREDIT) / 1) AS NUMERIC(15, 2)) AS Saldo
 +
FROM
 +
(
 +
  SELECT
 +
    bal.debitncu AS NCU_BEGIN_DEBIT,
 +
    bal.creditncu AS NCU_BEGIN_CREDIT
 +
  FROM
 +
    ac_entry_balance bal
 +
  WHERE
 +
    bal.accountkey in (344101)
 +
    AND bal.companykey + 0 IN (147000001)
 +
 
 +
  UNION ALL
 +
 
 +
  SELECT
 +
    e.debitncu AS NCU_BEGIN_DEBIT,
 +
    e.creditncu AS NCU_BEGIN_CREDIT
 +
  FROM
 +
    ac_entry e
 +
  WHERE
 +
    e.accountkey IN (344101)
 +
    AND e.entrydate >= :closedate
 +
    AND e.entrydate < :begindate
 +
    AND e.companykey + 0 IN (147000001)
 +
 
 +
) main
 +
</pre>
 +
 
 +
=== Анализ счета ===
 +
 
 +
В анализе счета, так же как и в карте счета, рассчитывается сальдо на начало и конец периода. Разница в запросах заключается в группировке по счету.
 +
 
 +
Пример: анализ счета 43.
 +
 
 +
Оригинальный запрос (с некоторыми упрощениями):
 +
 
 +
<pre>
 +
SELECT
 +
  e.accountkey AS id,
 +
  CAST(SUM(e.debitncu - e.creditncu) / 1 AS NUMERIC(15, 2)) AS Saldo
 +
FROM
 +
  ac_entry e
 +
WHERE
 +
  e.accountkey IN (344300)
 +
  AND e.accountkey <> 300003
 +
  AND e.entrydate < :datebegin
 +
  AND e.companykey + 0 IN (147035939)
 +
GROUP BY
 +
  e.accountkey
 +
</pre>
 +
 
 +
Запрос сформированный с учетом расчитанного сальдо из таблицы AC_ENTRY_BALANCE (примерный текст):
 +
 
 +
<pre>
 +
SELECT
 +
  main.accountkey,
 +
  CAST((SUM(main.NCU_BEGIN_DEBIT - main.NCU_BEGIN_CREDIT) / 1) AS NUMERIC(15, 2)) AS Saldo
 +
FROM
 +
(
 +
  SELECT
 +
    bal.accountkey,
 +
    bal.debitncu AS NCU_BEGIN_DEBIT,
 +
    bal.creditncu AS NCU_BEGIN_CREDIT
 +
  FROM
 +
    ac_entry_balance bal
 +
  WHERE
 +
    bal.accountkey in (344300)
 +
    AND bal.accountkey <> 300003
 +
    AND bal.companykey + 0 IN (147035939)
 +
 
 +
  UNION ALL
 +
 
 +
  SELECT
 +
    e.accountkey,
 +
    - e.debitncu AS NCU_BEGIN_DEBIT,
 +
    - e.creditncu AS NCU_BEGIN_CREDIT
 +
  FROM
 +
    ac_entry e
 +
  WHERE
 +
    e.accountkey IN (344300)
 +
    AND e.accountkey <> 300003
 +
    AND e.entrydate >= :begindate
 +
    AND e.entrydate < :closedate
 +
    AND e.companykey + 0 IN (147035939)
 +
 
 +
) main
 +
GROUP BY
 +
  main.accountkey
 +
</pre>
 +
 
 +
=== Главная книга ===
 +
Необходимо исправить процедуры AC_G_L_S и AC_ACCOUNTEXSALDO с учетом данных из таблицы AC_ENTRY_BALANCE.
 +
 
 +
=== Оборотная ведомость ===
 +
Необходимо исправить процедуры AC_CIRCULATIONLIST и AC_ACCOUNTEXSALDO с учетом данных из таблицы AC_ENTRY_BALANCE.
  
 
== Встроенные бухгалтерские функции ==
 
== Встроенные бухгалтерские функции ==
Строка 248: Строка 539:
 
Кредитовое сальдо. Параметры: счет, дата, список имен и значений аналитик.
 
Кредитовое сальдо. Параметры: счет, дата, список имен и значений аналитик.
  
Во всех этих и некоторых других закрытых методах класса TobjGSFunction необходимо поправить расчет сальдо с учетом таблицы AC_ENTRY_SALDO.
+
Во всех этих и некоторых других закрытых методах класса TobjGSFunction необходимо поправить расчет сальдо с учетом таблицы AC_ENTRY_BALANCE.
  
 
== Другие макросы и отчеты ==
 
== Другие макросы и отчеты ==
После реализации механизма закрытия периода, необходимо найти в макросах и отчетах код работы с таблицей AC_ENTRY и обновить его с учетом таблицы AC_ENTRY_SALDO.
+
После реализации механизма расчета сальдо, необходимо найти в макросах и отчетах код работы с таблицей AC_ENTRY и обновить его с учетом таблицы AC_ENTRY_BALANCE.
 +
 
 +
== Статистика по новому механизму ==
 +
На примере базы Березы приведем статистику по работе Гедемина с расчетом сальдо.
 +
Расчет сальдо был произведен на дату 01.01.2008.
 +
 
 +
{| border="1" style="border-collapse:collapse;"
 +
!Параметр
 +
!без AC_ENTRY_BALANCE
 +
!с AC_ENTRY_BALANCE
 +
|-
 +
!Время построения:
 +
|
 +
|
 +
|-
 +
|<i>Карта счета</i>
 +
|
 +
|
 +
|-
 +
|<i>Анализ счета</i>
 +
|
 +
|
 +
|-
 +
|<i>Журнал-ордер</i>
 +
|
 +
|
 +
|-
 +
|<i>Главная книга (4. Готовая продукция, без расшифровки, 01.01.2008-01.01.2009)</i>
 +
|  20 сек
 +
|  5 сек
 +
|-
 +
|<i>Главная книга (4. Готовая продукция, с расшифровкой, 01.01.2008-01.01.2009)</i>
 +
|  290 сек
 +
|  19 сек
 +
|-
 +
|<i>Оборотная ведомость (2. Производственные запасы, 01.01.2008-01.01.2009)</i>
 +
| 4.3 сек
 +
| 1.5 сек
 +
|-
 +
!Размер базы
 +
|
 +
|
 +
|-
 +
|
 +
|
 +
|-}
  
[[Category: Постановка]]
+
[[Category: Постановка-Сделано]]

Текущая версия на 11:26, 17 июня 2014

Для ускорения работы бухгалтерских отчетов (Журнал-ордер, Анализ счета, Карта счета, Оборотная ведомость, Главная книга) и функций работающих с проводками необходимо реализовать механизм переодического расчета сальдо. Механизм подразумевает выбор проводок за заданный период, их группировка по счетам и соответствующим аналитикам, запись полученного сальдо в новую таблицу. В дальнейшем при построении бухгалтерских отчетов начальное и конечное сальдо должно будет вычисляться на основании данных из этой таблицы.

Содержание

[править] Расчет сальдо

[править] Механизм расчета

Таблица в которую будет производится запись сгруппированных данных по проводкам будет называться AC_ENTRY_BALANCE. Ее структура будет идентична таблице AC_ENTRY, за исключением некоторых полей:

 CREATE TABLE AC_ENTRY_BALANCE (
   --------------------------------
   -- Эти поля аналогичны AC_ENTRY
   --------------------------------
   ID                       DINTKEY,
   COMPANYKEY               DINTKEY,
   ACCOUNTKEY               DINTKEY,
   CURRKEY                  DINTKEY,
   DEBITNCU                 DCURRENCY,
   DEBITCURR                DCURRENCY,
   DEBITEQ                  DCURRENCY,
   CREDITNCU                DCURRENCY,
   CREDITCURR               DCURRENCY,
   CREDITEQ                 DCURRENCY,

   ---------------------------------
   -- Наличие полей аналитических 
   -- признаков зависит от 
   -- конфигурации учета на текущей
   -- базе данных            
   ---------------------------------
   USR$GS_CUSTOMER          USR$GS_DCUSTOMER,
   USR$GS_DEPARTMENT        USR$GS_DDEPARTMENT,
   USR$FA_INVCARDKEY        USR$FA_INVCARD,
   USR$GS_GOOD              USR$GS_DGOOD,
   USR$GS_DOCUMENT          USR$GS_DDOCUMENT,
   USR$GS_SERVICE           USR$GS_DSERVICE,
   USR$GS_EMPLOYEE          USR$GS_DEMPLOYEE,
   USR$VATTYPE_KEY          USR$VATTYPEKEY,
   USR$FA_GROUPKEY          USR$FA_CIPHERKEY,
   USR$GS_CONTRACT          USR$INV_DCONTRACT,
   USR$GS_EXPENSES          USR$GS_DEXPENSES,
   USR$GS_ECONOMICACTIVITY  USR$DECONOMICACTIVITY,
   USR$GS_SALETAXRATE       DCURRENCY,
   ---------------------------------
   -- Следующие поля AC_ENTRY
   -- не попадут в таблицу итоговых
   -- значений
   ---------------------------------
   ENTRYDATE                DDATE,
   RECORDKEY                DMASTERKEY,
   TRANSACTIONKEY           DINTKEY,
   DOCUMENTKEY              DMASTERKEY,
   MASTERDOCKEY             DINTKEY,
   ACCOUNTPART              DACCOUNTPART,
   DISABLED                 DBOOLEAN DEFAULT 0,
   RESERVED                 DINTEGER,
   ISSIMPLE                 DBOOLEAN_NOTNULL NOT NULL
 );

При изменении структуры таблицы AC_ENTRY, например в случае добавления новой аналитики, структура таблицы AC_ENTRY_BALANCE также будет обновляться.

Сальдо в стандартных отчетах будет считаться исходя из AC_ENTRY_BALANCE + AC_ENTRY. Например, расчет сальдо был сделан на дату CloseDate = 01.01.2008. Мы хотим построить журнал-ордер на дату Date = 01.05.2008. Сальдо на дату Date будет вычислятся как сальдо на дату CloseDate из таблицы AC_ENTRY_BALANCE плюс сальдо за период 01.01.2008 – 01.05.2008 рассчитанное по таблице AC_ENTRY старым методом. То же самое, если нам понадобится сальдо на дату Date = 01.07.2007. Берем сальдо из AC_ENTRY_BALANCE на дату CloseDate и отнимаем сальдо за период 01.07.2007 – 01.01.2008 рассчитанное по таблице AC_ENTRY.

После первого выполнения процедуры расчета сальдо на таблицу AC_ENTRY должен быть повешен универсальный триггер AFTER INSERT OR UPDATE OR DELETE, который будет обновлять данные в таблице AC_ENTRY_BALANCE в соответствии с изменениями в проводках за период предшедствующий расчету. Здесь может возникнуть проблема блокировки, когда с базой работает несколько пользователей и одновременно создается несколько проводок, которые попадают в одну запись таблицы AC_ENTRY_BALANCE. Поэтому было решено отказаться от обновления записей таблицы AC_ENTRY_BALANCE в пользу добавления дельта-записей содержащих величину изменения сальдо по конкретному счету в разрезе соответствующих аналитик.

Например, в AC_ENTRY добавилась проводка:

Счет Дебет Кредит
51 1500 0

В таблице AC_ENTRY_BALANCE по 51 счету содержится следующая запись:

Счет Дебет Кредит
51 25000 15000

Триггер на таблице AC_ENTRY вставит в таблицу AC_ENTRY_BALANCE дельта-запись, данные примут вид:

Счет Дебет Кредит
51 25000 15000
51 1500 0

Предварительный текст триггера:

 CREATE OR ALTER TRIGGER ac_entry_do_balance FOR ac_entry
 ACTIVE AFTER INSERT OR UPDATE OR DELETE POSITION 15
 AS
 BEGIN
   IF (INSERTING AND NEW.entrydate <= CAST('01.01.2008' AS DATE)
       AND (NEW.debitncu > 0) OR (NEW.debitcurr > 0) OR (NEW.creditncu > 0) OR (NEW.creditcurr > 0)) THEN
   BEGIN
     INSERT INTO AC_ENTRY_BALANCE
       (companykey, accountkey, currkey,
        debitncu, debitcurr, debiteq,
        creditncu, creditcurr, crediteq,
        usr$gs_customer, usr$fa_groupkey, usr$gs_department,
        usr$fa_invcardkey, usr$gs_good, usr$gs_document)
     VALUES
       (NEW.companykey,
        NEW.accountkey,
        NEW.currkey,
        NEW.debitncu,
        NEW.debitcurr,
        NEW.debiteq,
        NEW.creditncu,
        NEW.creditcurr,
        NEW.crediteq,
        NEW.usr$gs_customer,
        NEW.usr$fa_groupkey,
        NEW.usr$gs_department,
        NEW.usr$fa_invcardkey,
        NEW.usr$gs_good,
        NEW.usr$gs_document);
   END
   ELSE
   IF (UPDATING AND OLD.entrydate <= CAST('01.01.2008' AS DATE)
       AND (OLD.debitncu <> NEW.debitncu) OR (OLD.creditncu <> NEW.creditncu)
       OR (OLD.debitcurr <> NEW.debitcurr) OR (OLD.creditcurr <> NEW.creditcurr)) THEN
   BEGIN
     INSERT INTO AC_ENTRY_BALANCE
       (companykey, accountkey, currkey,
        debitncu, debitcurr, debiteq,
        creditncu, creditcurr, crediteq,
        usr$gs_customer, usr$fa_groupkey, usr$gs_department,
        usr$fa_invcardkey, usr$gs_good, usr$gs_document)
     VALUES
       (OLD.companykey,
        OLD.accountkey,
        OLD.currkey,
        NEW.debitncu-OLD.debitncu,
        NEW.debitcurr-OLD.debitcurr,
        NEW.debiteq-OLD.debiteq,
        NEW.creditncu-OLD.creditncu,
        NEW.creditcurr-OLD.creditcurr,
        NEW.crediteq-OLD.crediteq,
        OLD.usr$gs_customer,
        OLD.usr$fa_groupkey,
        OLD.usr$gs_department,
        OLD.usr$fa_invcardkey,
        OLD.usr$gs_good,
        OLD.usr$gs_document);
   END
   ELSE
   IF (DELETING AND OLD.entrydate <= CAST('01.01.2008' AS DATE)
       AND (OLD.debitncu > 0) OR (OLD.debitcurr > 0) OR (OLD.creditncu > 0) OR (OLD.creditcurr > 0)) THEN
   BEGIN
     INSERT INTO AC_ENTRY_BALANCE
       (companykey, accountkey, currkey,
        debitncu, debitcurr, debiteq,
        creditncu, creditcurr, crediteq,
        usr$gs_customer, usr$fa_groupkey, usr$gs_department,
        usr$fa_invcardkey, usr$gs_good, usr$gs_document)
     VALUES
       (OLD.companykey,
        OLD.accountkey,
        OLD.currkey,
        -OLD.debitncu,
        -OLD.debitcurr,
        -OLD.debiteq,
        -OLD.creditncu,
        -OLD.creditcurr,
        -OLD.crediteq,
        OLD.usr$gs_customer,
        OLD.usr$fa_groupkey,
        OLD.usr$gs_department,
        OLD.usr$fa_invcardkey,
        OLD.usr$gs_good,
        OLD.usr$gs_document);
   END
 END

Где CAST('01.01.2008' AS DATE) - дата последнего расчета сальдо. Эту дату можно хранить так же, как хранится дата блокировки периода. То есть хранить в генераторе (например GD_G_ENTRY_BALANCE_DATE) кол-во дней, прошедших с определенной даты (например 17.11.1858) до даты расчета сальдо. Обновлять значение генератора необходимо после каждой процедуры расчета сальдо.

При следующем выполнении процедуры закрытия периода на дату NewCloseDate, данные о проводках до даты CloseDate прошлого закрытия брать из таблицы AC_ENTRY_BALANCE, а данные за промежуток CloseDate - NewCloseDate — из таблицы AC_ENTRY.

Иногда будет необходимо перегруппировать данные в таблице AC_ENTRY_BALANCE путем слияния первоначальной и дельта-записей в одну запись. В момент построения бухгалтерского отчета необходимо проверять количество дельта-записей. Если оно превысит некоторый лимит, то устанавливать флаг, по состоянию которого перестраивать таблицу AC_ENTRY_BALANCE. Это можно делать каждый раз перед/после построения бухгалтерского отчета, или в период простоя Гедемина. Если процедура расчета сальдо будет выполнятся переодически (например, раз в месяц), то данные можно перегруппировать в момент следующего расчета сальдо.

[править] Группировка данных

Перед заполнением таблицы AC_ENTRY_BALANCE данные о проводках необходимо сгруппировать. По умолчанию данные группируются по компании, счету и валюте. Также проводки необходимо группировать по аналитикам. Однако, если группировать данные по всем аналитикам, мы не получим большого уменьшения кол-ва записей, так как многие аналитики не закрываются. Поэтому необходимо дать пользователю выбирать по каким аналитикам необходимо группировать данные при выполнении процедуры расчета сальдо.

Планируется добавить в План счетов дополнительные флажки, по которым и определять необходимость включения данной аналитики в группировку по конкретному счету.

Если при построении бухгалтерского отчета пользователь выберет в группировке аналитику которая не выбрана в Плане счетов, то есть, по которой не рассчитывалось сальдо, то выполнять расчет старым методом (предупредить пользователя?). Можно выделять аналитики по которым было рассчитано сальдо другим цветом.


[править] Стандартные отчеты

  • Журнал-ордер
  • Карта счета
  • Анализ счета
  • Главная книга
  • Оборотная ведомость

Необходимо переделать механизм построения бухгалтерских отчетов с применением таблицы AC_ENTRY_BALANCE и новых возможностей Firebird 2.5 (EXECUTE BLOCK и др.)

[править] Журнал-ордер

Пример: журнал ордер по счету 41.01, группировка по Подразделению.

Оригинальный запрос (с некоторыми упрощениями):

SELECT
  SUBSTRING(c0.name FROM 1 FOR 180) AS s0,
  SUBSTRING(c0.id FROM 1 FOR 180) AS c0,
  CAST(1 AS INTEGER) AS sortfield,
  CAST(IIF(SUM(e1.debitncu - e1.creditncu) > 0, SUM(e1.debitncu - e1.creditncu) / 1, 0) AS NUMERIC(15, 2)) AS ncu_begin_debit,
  CAST(IIF(SUM(e1.creditncu - e1.debitncu) > 0, SUM(e1.creditncu - e1.debitncu) / 1, 0) AS NUMERIC(15, 2)) AS ncu_begin_credit,
  CAST(IIF(SUM(e2.debitncu) <> 0, SUM(e2.debitncu) / 1, 0) AS NUMERIC(15, 2)) AS ncu_debit,
  CAST(IIF(SUM(e2.creditncu) <> 0, SUM(e2.creditncu) / 1, 0) AS NUMERIC(15, 2)) AS ncu_credit,
  CAST(IIF(SUM(e.debitncu-e.creditncu) > 0, SUM(e.debitncu - e.creditncu) / 1, 0) AS NUMERIC(15, 2)) AS ncu_end_debit,
  CAST(IIF(SUM(e.creditncu-e.debitncu) > 0, SUM(e.creditncu - e.debitncu) / 1, 0) AS NUMERIC(15, 2)) AS ncu_end_credit
FROM
  ac_entry e
  LEFT JOIN ac_entry e1 ON e1.recordkey = e.recordkey AND e1.id = e.id
    AND e1.entrydate < :begindate
  LEFT JOIN ac_entry e2 ON e2.recordkey = e.recordkey AND e2.id = e.id
    AND e2.entrydate >= :begindate AND e2.entrydate <= :enddate
  LEFT JOIN gd_contact c0 ON c0.id = e.usr$gs_department
WHERE
  e.accountkey IN (344101)
  AND e.entrydate <= :enddate
  AND e.companykey IN (147000001)
GROUP BY
  c0.name, c0.id
HAVING
  SUM(e2.debitncu) <> 0
  OR SUM(e2.creditncu) <> 0
  OR SUM(e1.debitncu - e1.creditncu) <> 0
ORDER BY
  c0.name, c0.id

Запрос сформированный с учетом расчитанного сальдо из таблицы AC_ENTRY_BALANCE (примерный текст):

SELECT
  main.c0,
  CAST(IIF(SUM(main.NCU_BEGIN_DEBIT - main.NCU_BEGIN_CREDIT) > 0, 
    SUM(main.NCU_BEGIN_DEBIT - main.NCU_BEGIN_CREDIT), 0) AS NUMERIC(15, 2)) AS NCU_BEGIN_DEBIT,
  CAST(IIF(SUM(main.NCU_BEGIN_CREDIT - main.NCU_BEGIN_DEBIT) > 0, 
    SUM(main.NCU_BEGIN_CREDIT - main.NCU_BEGIN_DEBIT), 0) AS NUMERIC(15, 2)) AS NCU_BEGIN_CREDIT,
  CAST(SUM(main.NCU_DEBIT) AS NUMERIC(15, 2)) AS NCU_DEBIT,
  CAST(SUM(main.NCU_CREDIT) AS NUMERIC(15, 2)) AS NCU_CREDIT,
  CAST(IIF((IIF(SUM(main.NCU_BEGIN_DEBIT - main.NCU_BEGIN_CREDIT) > 0,
    SUM(main.NCU_BEGIN_DEBIT - main.NCU_BEGIN_CREDIT), 0) + SUM(main.NCU_DEBIT)) -
    (IIF(SUM(main.NCU_BEGIN_CREDIT - main.NCU_BEGIN_DEBIT) > 0,
    SUM(main.NCU_BEGIN_CREDIT - main.NCU_BEGIN_DEBIT), 0) + SUM(main.NCU_CREDIT)) > 0,
    (IIF(SUM(main.NCU_BEGIN_DEBIT - main.NCU_BEGIN_CREDIT) > 0,
    SUM(main.NCU_BEGIN_DEBIT - main.NCU_BEGIN_CREDIT), 0) + SUM(main.NCU_DEBIT)) -
    (IIF(SUM(main.NCU_BEGIN_CREDIT - main.NCU_BEGIN_DEBIT) > 0,
    SUM(main.NCU_BEGIN_CREDIT - main.NCU_BEGIN_DEBIT), 0) + SUM(main.NCU_CREDIT)), 0) AS NUMERIC(15, 2)) AS NCU_END_DEBIT,
  CAST(IIF((IIF(SUM(main.NCU_BEGIN_CREDIT - main.NCU_BEGIN_DEBIT) > 0,
    SUM(main.NCU_BEGIN_CREDIT - main.NCU_BEGIN_DEBIT), 0) + SUM(main.NCU_CREDIT)) -
    (IIF(SUM(main.NCU_BEGIN_DEBIT - main.NCU_BEGIN_CREDIT) > 0,
    SUM(main.NCU_BEGIN_DEBIT - main.NCU_BEGIN_CREDIT), 0) + SUM(main.NCU_DEBIT)) > 0,
    (IIF(SUM(main.NCU_BEGIN_CREDIT - main.NCU_BEGIN_DEBIT) > 0,
    SUM(main.NCU_BEGIN_CREDIT - main.NCU_BEGIN_DEBIT), 0) + SUM(main.NCU_CREDIT)) -
    (IIF(SUM(main.NCU_BEGIN_DEBIT - main.NCU_BEGIN_CREDIT) > 0,
    SUM(main.NCU_BEGIN_DEBIT - main.NCU_BEGIN_CREDIT), 0) + SUM(main.NCU_DEBIT)), 0) AS NUMERIC(15, 2)) AS NCU_END_CREDIT
FROM
(
  SELECT
    bal.USR$GS_DEPARTMENT AS c0,
    bal.debitncu AS NCU_BEGIN_DEBIT,
    bal.creditncu AS NCU_BEGIN_CREDIT,
    CAST(0 AS NUMERIC(15, 2)) AS NCU_DEBIT,
    CAST(0 AS NUMERIC(15, 2)) AS NCU_CREDIT
  FROM
    ac_entry_balance bal
  WHERE
    bal.accountkey in (344101)
    AND bal.companykey IN (147000001)
  
  UNION ALL
  
  SELECT
    e.USR$GS_DEPARTMENT AS c0,
    - e.debitncu AS NCU_BEGIN_DEBIT,
    - e.creditncu AS NCU_BEGIN_CREDIT,
    CAST(0 AS NUMERIC(15, 2)) AS NCU_DEBIT,
    CAST(0 AS NUMERIC(15, 2)) AS NCU_CREDIT
  FROM
    ac_entry e
  WHERE
    e.accountkey IN (344101)
    AND e.entrydate >= :begindate
    AND e.entrydate < :closedate
    AND e.companykey IN (147000001)

  UNION ALL

  SELECT
    e2.USR$GS_DEPARTMENT AS c0,
    CAST(0 AS NUMERIC(15, 2)) AS NCU_BEGIN_DEBIT,
    CAST(0 AS NUMERIC(15, 2)) AS NCU_BEGIN_CREDIT,
    e2.debitncu AS NCU_DEBIT,
    e2.creditncu AS NCU_CREDIT
  FROM
    ac_entry e2
  WHERE
    e2.accountkey IN (344101)
    AND e2.entrydate >= :begindate
    AND e2.entrydate <= :enddate
    AND e2.companykey IN (147000001)

) main
GROUP BY
  main.c0  

Примечание: Второй SELECT в подзапросе используется для расчета изменения начального сальдо между начальной даты построения журнала-ордера BeginDate и даты расчета сальдо CloseDate.

Если BeginDate < CloseDate:

  SELECT
    e.USR$GS_DEPARTMENT AS c0,
    - e.debitncu AS NCU_BEGIN_DEBIT,
    - e.creditncu AS NCU_BEGIN_CREDIT,
    CAST(0 AS NUMERIC(15, 2)) AS NCU_DEBIT,
    CAST(0 AS NUMERIC(15, 2)) AS NCU_CREDIT
  FROM
    ac_entry e
  WHERE
    e.accountkey IN (344101)
    AND e.entrydate >= :begindate
    AND e.entrydate < :closedate
    AND e.companykey IN (147000001)

Если BeginDate > CloseDate:

  SELECT
    e.USR$GS_DEPARTMENT AS c0,
    e.debitncu AS NCU_BEGIN_DEBIT,
    e.creditncu AS NCU_BEGIN_CREDIT,
    CAST(0 AS NUMERIC(15, 2)) AS NCU_DEBIT,
    CAST(0 AS NUMERIC(15, 2)) AS NCU_CREDIT
  FROM
    ac_entry e
  WHERE
    e.accountkey IN (344101)
    AND e.entrydate >= :closedate
    AND e.entrydate < :begindate
    AND e.companykey IN (147000001)

Если BeginDate = CloseDate, то второй SELECT не нужен.

[править] Карта счета

В карте счета расчитывается сальдо на начало и конец периода.

Пример: карта счета 41.01.

Оригинальный запрос (с некоторыми упрощениями):

SELECT
  CAST((SUM(e.debitncu - e.creditncu) / 1) AS NUMERIC(15, 2)) AS Saldo
FROM
  ac_entry e
WHERE
  e.accountkey IN (344101)
  AND e.entrydate < :datebegin
  AND e.companykey IN (147000001)

Запрос сформированный с учетом расчитанного сальдо из таблицы AC_ENTRY_BALANCE (примерный текст):

SELECT
  CAST((SUM(main.NCU_BEGIN_DEBIT - main.NCU_BEGIN_CREDIT) / 1) AS NUMERIC(15, 2)) AS Saldo
FROM
(
  SELECT
    bal.debitncu AS NCU_BEGIN_DEBIT,
    bal.creditncu AS NCU_BEGIN_CREDIT
  FROM
    ac_entry_balance bal
  WHERE
    bal.accountkey in (344101)
    AND bal.companykey + 0 IN (147000001)
  
  UNION ALL
  
  SELECT
    e.debitncu AS NCU_BEGIN_DEBIT,
    e.creditncu AS NCU_BEGIN_CREDIT
  FROM
    ac_entry e
  WHERE
    e.accountkey IN (344101)
    AND e.entrydate >= :closedate
    AND e.entrydate < :begindate
    AND e.companykey + 0 IN (147000001)

) main

[править] Анализ счета

В анализе счета, так же как и в карте счета, рассчитывается сальдо на начало и конец периода. Разница в запросах заключается в группировке по счету.

Пример: анализ счета 43.

Оригинальный запрос (с некоторыми упрощениями):

SELECT
  e.accountkey AS id,
  CAST(SUM(e.debitncu - e.creditncu) / 1 AS NUMERIC(15, 2)) AS Saldo
FROM
  ac_entry e
WHERE
  e.accountkey IN (344300)
  AND e.accountkey <> 300003
  AND e.entrydate < :datebegin
  AND e.companykey + 0 IN (147035939)
GROUP BY
  e.accountkey

Запрос сформированный с учетом расчитанного сальдо из таблицы AC_ENTRY_BALANCE (примерный текст):

SELECT
  main.accountkey,
  CAST((SUM(main.NCU_BEGIN_DEBIT - main.NCU_BEGIN_CREDIT) / 1) AS NUMERIC(15, 2)) AS Saldo
FROM
(
  SELECT
    bal.accountkey,
    bal.debitncu AS NCU_BEGIN_DEBIT,
    bal.creditncu AS NCU_BEGIN_CREDIT
  FROM
    ac_entry_balance bal
  WHERE
    bal.accountkey in (344300)
    AND bal.accountkey <> 300003
    AND bal.companykey + 0 IN (147035939)
  
  UNION ALL
  
  SELECT
    e.accountkey,
    - e.debitncu AS NCU_BEGIN_DEBIT,
    - e.creditncu AS NCU_BEGIN_CREDIT
  FROM
    ac_entry e
  WHERE
    e.accountkey IN (344300)
    AND e.accountkey <> 300003
    AND e.entrydate >= :begindate
    AND e.entrydate < :closedate
    AND e.companykey + 0 IN (147035939)

) main
GROUP BY
  main.accountkey

[править] Главная книга

Необходимо исправить процедуры AC_G_L_S и AC_ACCOUNTEXSALDO с учетом данных из таблицы AC_ENTRY_BALANCE.

[править] Оборотная ведомость

Необходимо исправить процедуры AC_CIRCULATIONLIST и AC_ACCOUNTEXSALDO с учетом данных из таблицы AC_ENTRY_BALANCE.

[править] Встроенные бухгалтерские функции

O(const AccDeb: WideString; const AccCred: WideString;
  BDate: TDateTime; EDate: TDateTime; const AnalyticsDeb: WideString;
  const AnalyticsCred: WideString): Currency
V_O(const AccDeb, AccCred: WideString; BDate,
  EDate: TDateTime; const AnalyticsDeb, AnalyticsCred: WideString;
  CurrKey: Integer): Currency
K_O(ValueKey: Integer; const AccDeb: WideString;
  const AccCred: WideString; BDate: TDateTime; EDate: TDateTime;
  const AnalyticsDeb: WideString; const AnalyticsCred: WideString): Currency

Корреспондентский оборот. Параметры: счет по дебету, счет по кредиту, дата начала, дата окончания, список имен и значений аналитик по дебету, список имен и значений аналитик по кредиту.

OD(const Account: WideString;
  BDate: TDateTime; EDate: TDateTime; const Analytics: WideString): Currency
V_OD(const Account: WideString;
  BDate: TDateTime; EDate: TDateTime; const Analytics: WideString): Currency
K_OD(ValueKey: Integer;
  const Account: WideString; BDate, EDate: TDateTime;
  const Analytics: WideString): Currency

Оборот дебетовый. Параметры: счет, дата начала, дата окончания, список имен и значений аналитик.

OK(const Account: WideString;
  BDate: TDateTime; EDate: TDateTime; const Analytics: WideString): Currency
V_OK(const Account: WideString;
  BDate: TDateTime; EDate: TDateTime; const Analytics: WideString): Currency
K_OK(ValueKey: Integer;
  const Account: WideString; BDate, EDate: TDateTime;
  const Analytics: WideString): Currency

Оборот кредитовый. Параметры: счет, дата начала, дата окончания, список имен и значений аналитик.

SD(const Account: WideString;
  OnDate: TDateTime; const Analytics: WideString): Currency
V_SD(const Account: WideString;
  OnDate: TDateTime; const Analytics: WideString): Currency
K_SD(ValueKey: Integer;
  const Account: WideString; OnDate: TDateTime;
  const Analytics: WideString): Currency

Дебетовое сальдо. Параметры: счет, дата, список имен и значений аналитик.

SK(const Account: WideString;
  OnDate: TDateTime; const Analytics: WideString): Currency
V_SK(const Account: WideString;
  OnDate: TDateTime; const Analytics: WideString): Currency
K_SK(ValueKey: Integer;
  const Account: WideString; OnDate: TDateTime;
  const Analytics: WideString): Currency

Кредитовое сальдо. Параметры: счет, дата, список имен и значений аналитик.

Во всех этих и некоторых других закрытых методах класса TobjGSFunction необходимо поправить расчет сальдо с учетом таблицы AC_ENTRY_BALANCE.

[править] Другие макросы и отчеты

После реализации механизма расчета сальдо, необходимо найти в макросах и отчетах код работы с таблицей AC_ENTRY и обновить его с учетом таблицы AC_ENTRY_BALANCE.

[править] Статистика по новому механизму

На примере базы Березы приведем статистику по работе Гедемина с расчетом сальдо. Расчет сальдо был произведен на дату 01.01.2008.

Параметр без AC_ENTRY_BALANCE с AC_ENTRY_BALANCE
Время построения:
Карта счета
Анализ счета
Журнал-ордер
Главная книга (4. Готовая продукция, без расшифровки, 01.01.2008-01.01.2009) 20 сек 5 сек
Главная книга (4. Готовая продукция, с расшифровкой, 01.01.2008-01.01.2009) 290 сек 19 сек
Оборотная ведомость (2. Производственные запасы, 01.01.2008-01.01.2009) 4.3 сек 1.5 сек
Размер базы
Персональные инструменты
Пространства имён

Варианты
Действия
Навигация
Инструменты