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

Материал из GedeminWiki
(Различия между версиями)
Перейти к: навигация, поиск
(Статистика по новому механизму)
 
(не показаны 19 промежуточных версий 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. Например, мы хотим построить журнал-ордер на дату 01.05.2008. Сальдо будет вычислятся как сальдо из таблицы AC_ENTRY_SALDO минус сальдо за период 01.05.2008 - NOW рассчитанное по таблице 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"
 
  !Счет
 
  !Счет
Строка 87: Строка 101:
  
 
Предварительный текст триггера:
 
Предварительный текст триггера:
   CREATE OR ALTER trigger ac_entry_do_saldo for ac_entry
+
 
   active after insert or update or delete position 15
+
   CREATE OR ALTER TRIGGER ac_entry_do_balance FOR ac_entry
 +
   ACTIVE AFTER INSERT OR UPDATE OR DELETE POSITION 15
 
   AS
 
   AS
 
   BEGIN
 
   BEGIN
     IF (INSERTING AND (NEW.debitncu > 0) OR (NEW.debitcurr > 0) OR (NEW.creditncu > 0) OR (NEW.creditcurr > 0)) THEN
+
     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
 
     BEGIN
       INSERT INTO AC_ENTRY_SALDO
+
       INSERT INTO AC_ENTRY_BALANCE
 
         (companykey, accountkey, currkey,
 
         (companykey, accountkey, currkey,
 
         debitncu, debitcurr, debiteq,
 
         debitncu, debitcurr, debiteq,
Строка 117: Строка 133:
 
     END
 
     END
 
     ELSE
 
     ELSE
     IF (UPDATING AND (OLD.debitncu <> NEW.debitncu) OR (OLD.creditncu <> NEW.creditncu)
+
     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
 
         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,
Строка 144: Строка 161:
 
     END
 
     END
 
     ELSE
 
     ELSE
     IF (DELETING AND (OLD.debitncu > 0) OR (OLD.debitcurr > 0) OR (OLD.creditncu > 0) OR (OLD.creditcurr > 0)) THEN
+
     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
 
     BEGIN
       INSERT INTO AC_ENTRY_SALDO
+
       INSERT INTO AC_ENTRY_BALANCE
 
         (companykey, accountkey, currkey,
 
         (companykey, accountkey, currkey,
 
         debitncu, debitcurr, debiteq,
 
         debitncu, debitcurr, debiteq,
Строка 171: Строка 189:
 
   END
 
   END
  
Иногда будет необходимо перегруппировать данные в таблице AC_ENTRY_SALDO путем слияния первоначальной и дельта-записей в одну запись. Это можно делать каждый раз перед/после построения бухгалтерского отчета, или в период простоя Гедемина.
+
Где <code>CAST('01.01.2008' AS DATE)</code> - дата последнего расчета сальдо. Эту дату можно хранить так же, как хранится дата блокировки периода. То есть хранить в генераторе (например [[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_SALDO.
 
  
 
== Стандартные отчеты ==
 
== Стандартные отчеты ==
Строка 182: Строка 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.
  
 
== Встроенные бухгалтерские функции ==
 
== Встроенные бухгалтерские функции ==
Строка 242: Строка 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 сек
Размер базы
Персональные инструменты
Пространства имён

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