Регістри в K2 ERP: відмінності між версіями
R (обговорення | внесок) Створена сторінка: {{DISPLAYTITLE:ТЗ. Підсистема регістрів K2 ERP}} __TOC__ = 1. Паспорт документа = {| class="wikitable" ! Атрибут !! Значення |- | Назва || Технічне завдання на розробку підсистеми «Регістри» платформи K2 ERP |- | Шифр || K2-ERP-TZ-REG-001 |- | Версія || 1.0 (чернетка на узгодження) |- | Статус || На роз... |
R (обговорення | внесок) Немає опису редагування |
||
| Рядок 11: | Рядок 11: | ||
| Шифр || K2-ERP-TZ-REG-001 | | Шифр || K2-ERP-TZ-REG-001 | ||
|- | |- | ||
| Версія || 1. | | Версія || 1.1 (чернетка на узгодження; +Додаток Д «Каталог прикладів») | ||
|- | |- | ||
| Статус || На розгляді | | Статус || На розгляді | ||
| Рядок 571: | Рядок 571: | ||
recorders: [Документ.НарахуванняЗарплати] | recorders: [Документ.НарахуванняЗарплати] | ||
</syntaxhighlight> | </syntaxhighlight> | ||
{{Note|Розширений каталог із 17 прикладів регістрів усіх типів і підвидів — з деклараціями, даними у фізичних таблицях, запитами, наскрізними сценаріями та антипатернами — див. '''Додаток Д'''.}} | |||
== 6.8. UI конструктора метаданих == | == 6.8. UI конструктора метаданих == | ||
| Рядок 2584: | Рядок 2586: | ||
|- | |- | ||
| В8 || Цільова СКБД для першої черги: тільки PostgreSQL чи одразу обидві? || Архітектор / ІТ-експлуатація || До Е1 | | В8 || Цільова СКБД для першої черги: тільки PostgreSQL чи одразу обидві? || Архітектор / ІТ-експлуатація || До Е1 | ||
|- | |||
| В9 || '''Міжпланова база розрахунку:''' чи потрібна можливість брати базу з ''іншого'' регістру розрахунку (Утримання ← ОсновніНарахування)? Якщо так — ФТ-25 і <code>md_register</code> потребують розширення полем <code>base_register_id</code> (див. Д.7.2) || Методолог ЗП / архітектор || До Е7 | |||
|- | |||
| В10 || Чи прийнятна поведінка підпорядкованого РВ без контролю унікальності за (Період + Вимірювання)? (сумісність із 1С vs. захист від дублів — див. Д.3.2, антипатерн А-6) || Методолог || До Е2 | |||
|} | |} | ||
== Додаток Д. Каталог прикладів регістрів == | |||
Додаток містить прикладні приклади регістрів усіх типів і підвидів. Для кожного наведено: декларацію (DSL), пояснення проєктних рішень, приклад даних у фізичних таблицях і типовий запит. Приклади призначені для: (а) перевірки повноти метамоделі на етапі Е0; (б) формування набору приймальних тестів; (в) навчання прикладних розробників. | |||
=== Д.1. Як обрати тип регістру (дерево рішень) === | |||
<graphviz> | |||
digraph Choose { | |||
rankdir=TB; bgcolor="transparent"; | |||
node [shape=box, style="rounded,filled", fontname="Helvetica", fontsize=9]; | |||
edge [fontname="Helvetica", fontsize=8]; | |||
q1 [label="Що зберігаємо?", shape=diamond, fillcolor="#ffe0b2"]; | |||
q2 [label="Потрібні залишки\n(скільки Є зараз)?", shape=diamond, fillcolor="#ffe0b2"]; | |||
q3 [label="Подвійний запис,\nплан рахунків,\nсубконто?", shape=diamond, fillcolor="#ffe0b2"]; | |||
q4 [label="Періоди дії,\nвитіснення,\nбаза розрахунку?", shape=diamond, fillcolor="#ffe0b2"]; | |||
q5 [label="Значення прив'язане\nдо документа?", shape=diamond, fillcolor="#ffe0b2"]; | |||
ri_i [label="РВ незалежний\n(КурсиВалют,\nШтрихкоди)", fillcolor="#e8f5e9"]; | |||
ri_s [label="РВ підпорядкований\n(ЦіниНоменклатури,\nКадровіДані)", fillcolor="#e8f5e9"]; | |||
ra_b [label="РН «Залишки»\n(ТовариНаСкладах,\nВзаєморозрахунки)", fillcolor="#fff8e1"]; | |||
ra_t [label="РН «Обороти»\n(Продажі,\nВитрати)", fillcolor="#fff8e1"]; | |||
rb [label="РБ\n(Госпрозрахунковий)", fillcolor="#fce4ec"]; | |||
rc [label="РР\n(Нарахування,\nУтримання)", fillcolor="#ede7f6"]; | |||
q1 -> q3 [label="облікові проводки"]; | |||
q3 -> rb [label="так"]; | |||
q3 -> q4 [label="ні"]; | |||
q4 -> rc [label="так"]; | |||
q4 -> q2 [label="ні"]; | |||
q1 -> q2 [label="кількісні/сумові\nрухи"]; | |||
q2 -> ra_b [label="так"]; | |||
q2 -> ra_t [label="ні,\nлише обороти\nза період"]; | |||
q1 -> q5 [label="значення\nатрибута\nв часі"]; | |||
q5 -> ri_s [label="так"]; | |||
q5 -> ri_i [label="ні"]; | |||
} | |||
</graphviz> | |||
'''Контрольні питання при проєктуванні будь-якого регістру:''' | |||
# Чи можна відповісти на всі прикладні питання ''лише'' полями цього регістру, без з'єднання з документами? Якщо ні — бракує реквізиту (не вимірювання!). | |||
# Яка ''кардинальність'' таблиці підсумків = ∏(кількість значень вимірювань) × кількість періодів? Якщо > 10<sup>8</sup> — переглянути склад вимірювань. | |||
# Чи потрібно фільтрувати/групувати за цим полем у звітах? Так → вимірювання. Ні, лише показувати → реквізит. | |||
# Чи підсумовується поле? Так → ресурс. Ні → реквізит або вимірювання. | |||
=== Д.2. Зведений каталог === | |||
{| class="wikitable sortable" | |||
! № !! Регістр !! Тип !! Підвид / режим !! Вимірювання !! Ресурси !! Розділ | |||
|- | |||
| 1 || КурсиВалют || РВ || Періодичний (день), незалежний || Валюта || Курс, Кратність || Д.3.1 | |||
|- | |||
| 2 || ЦіниНоменклатури || РВ || Періодичний (день), підпорядкований || Номенклатура, Характеристика, ТипЦін || Ціна || Д.3.2 | |||
|- | |||
| 3 || ШтрихкодиНоменклатури || РВ || Неперіодичний, незалежний || Штрихкод || Номенклатура, Характеристика, Упаковка || Д.3.3 | |||
|- | |||
| 4 || ГрафікРоботи || РВ || Неперіодичний, незалежний || ВидГрафіка, ДатаГрафіка || Значення, Годин || Д.3.4 | |||
|- | |||
| 5 || КадровіДані || РВ || По позиції реєстратора, підпорядкований || Співробітник || Підрозділ, Посада, Ставка, ВидЗайнятості || Д.3.5 | |||
|- | |||
| 6 || НалаштуванняКористувачів || РВ || Неперіодичний, незалежний || Користувач, Налаштування || Значення (складений) || Д.3.6 | |||
|- | |||
| 7 || ТовариНаСкладах || РН || Залишки || Номенклатура, Склад, Партія, Характеристика || Кількість, Сума || Д.4.1 | |||
|- | |||
| 8 || ВзаєморозрахункиЗКонтрагентами || РН || Залишки || Організація, Контрагент, Договір, Замовлення || Сума, СумаВал || Д.4.2 | |||
|- | |||
| 9 || ТовариВРезерві || РН || Залишки || Номенклатура, Склад, Замовлення, Характеристика || Кількість || Д.4.3 | |||
|- | |||
| 10 || ГрошовіКоштиБезготівкові || РН || Залишки || Організація, БанківськийРахунок || Сума, СумаВал || Д.4.4 | |||
|- | |||
| 11 || Продажі || РН || Обороти (місяць) + агрегати || Номенклатура, Контрагент, Договір, Менеджер, Склад || Кількість, Сума, СумаБезПДВ, Собівартість || Д.5.1 | |||
|- | |||
| 12 || ВитратиЗаСтаттями || РН || Обороти (місяць) || Організація, Підрозділ, СтаттяВитрат, Проєкт || Сума || Д.5.2 | |||
|- | |||
| 13 || Госпрозрахунковий || РБ || З кореспонденцією || Організація (бал.), Підрозділ (небал.) || Сума (бал.), Кількість, ВалютнаСума || Д.6.1 | |||
|- | |||
| 14 || ПодатковийОблік || РБ || Без кореспонденції || Організація, ВидРізниці || Сума || Д.6.2 | |||
|- | |||
| 15 || Бюджетування || РБ || З кореспонденцією || Сценарій, ЦФВ, Проєкт || Сума || Д.6.3 | |||
|- | |||
| 16 || ОсновніНарахування || РР || Період дії + база за періодом дії || Співробітник (баз.), Підрозділ || Результат, ВідпрацьованоДнів, НормаДнів || Д.7.1 | |||
|- | |||
| 17 || Утримання || РР || Без періоду дії, база за періодом реєстрації || Співробітник (баз.), Підрозділ || Результат, БазаОподаткування || Д.7.2 | |||
|} | |||
=== Д.3. Регістри відомостей === | |||
==== Д.3.1. КурсиВалют — періодичний, незалежний ==== | |||
'''Задача:''' зберігати історію курсів валют; отримувати курс на будь-яку дату. | |||
<syntaxhighlight lang="yaml"> | |||
register: | |||
name: КурсиВалют | |||
kind: Information | |||
synonym: "Курси валют" | |||
periodicity: WithinDay # один курс на валюту на день | |||
writeMode: Independent # курси вводяться вручну/завантажуються з НБУ | |||
dimensions: | |||
- { name: Валюта, type: "Довідник.Валюти", master: true, denyEmpty: true } | |||
resources: | |||
- { name: Курс, type: "Число(15,4)", denyEmpty: true } | |||
- { name: Кратність, type: "Число(10,0)", default: 1 } | |||
</syntaxhighlight> | |||
'''Проєктні рішення:''' | |||
* <code>Independent</code> — курс не породжується документом, він є зовнішнім фактом. | |||
* <code>master: true</code> для Валюти — при видаленні валюти курси видаляються; регістр видно у формі елемента довідника. | |||
* Періодичність <code>WithinDay</code>, а не <code>WithinSecond</code> — повторний запис курсу за той самий день ''замістить'' попередній, а не створить дубль. | |||
'''Дані у таблиці <code>rg_i_0007</code>:''' | |||
{| class="wikitable" | |||
! period !! d1_r (Валюта) !! r1 (Курс) !! r2 (Кратність) | |||
|- | |||
| 2026-07-15 00:00:00 || USD || 41.8200 || 1 | |||
|- | |||
| 2026-07-15 00:00:00 || EUR || 45.6100 || 1 | |||
|- | |||
| 2026-07-16 00:00:00 || USD || 41.8500 || 1 | |||
|- | |||
| 2026-07-17 00:00:00 || USD || 41.9000 || 1 | |||
|- | |||
| 2026-07-17 00:00:00 || EUR || 45.7300 || 1 | |||
|} | |||
'''Запит (курс на дату документа):''' | |||
<syntaxhighlight lang="sql"> | |||
ВИБРАТИ Курси.Курс, Курси.Кратність | |||
З РегістрВідомостей.КурсиВалют.ЗрізОстанніх(&ДатаДокумента, Валюта = &Валюта) ЯК Курси | |||
</syntaxhighlight> | |||
<syntaxhighlight lang="csharp"> | |||
// або через менеджер | |||
var курс = Registers.Information["КурсиВалют"] | |||
.GetLast(doc.Дата, new Filter { ["Валюта"] = doc.Валюта }); | |||
decimal сумаГрн = doc.СумаВалюти * курс.Курс / курс.Кратність; | |||
</syntaxhighlight> | |||
==== Д.3.2. ЦіниНоменклатури — періодичний, підпорядкований реєстратору ==== | |||
'''Задача:''' зберігати історію цін; ціна встановлюється наказом (документом), який можна скасувати. | |||
<syntaxhighlight lang="yaml"> | |||
register: | |||
name: ЦіниНоменклатури | |||
kind: Information | |||
synonym: "Ціни номенклатури" | |||
periodicity: WithinDay | |||
writeMode: SubordinateToRecorder # ← ключова відмінність від КурсиВалют | |||
dimensions: | |||
- { name: Номенклатура, type: "Довідник.Номенклатура", master: true, index: true } | |||
- { name: Характеристика, type: "Довідник.ХарактеристикиНоменклатури", nullable: true } | |||
- { name: ТипЦін, type: "Довідник.ТипиЦін", master: true, denyEmpty: true } | |||
resources: | |||
- { name: Ціна, type: "Число(15,2)", denyEmpty: true } | |||
attributes: | |||
- { name: Валюта, type: "Довідник.Валюти" } | |||
- { name: Одиниця, type: "Довідник.ОдиниціВиміру" } | |||
recorders: | |||
- Документ.ВстановленняЦінНоменклатури | |||
</syntaxhighlight> | |||
'''Проєктні рішення:''' | |||
* <code>SubordinateToRecorder</code> — потрібна юридична прив'язка ціни до наказу, можливість скасувати наказ і «відкотити» ціни одним рухом. | |||
* <code>Валюта</code> і <code>Одиниця</code> — '''реквізити''', а не вимірювання: за ними не фільтрують і не будують зрізи, вони визначаються типом цін. ''Помилка новачка'' — зробити Валюту вимірюванням, що подвоїть кількість записів і зламає зріз останніх. | |||
* <code>Характеристика</code> дозволяє порожнє значення — для номенклатури без характеристик. | |||
'''Дані у таблиці <code>rg_i_0010</code>:''' | |||
{| class="wikitable" | |||
! rec_t !! rec_r !! line_no !! period !! active !! d1_r (Номенкл.) !! d2_r (Характ.) !! d3_r (ТипЦін) !! r1 (Ціна) !! a1_r (Валюта) | |||
|- | |||
| 15 || a3f…01 || 1 || 2026-07-01 || true || Кава Lavazza 1кг || ''(порожня)'' || Роздрібна || 480.00 || UAH | |||
|- | |||
| 15 || a3f…01 || 2 || 2026-07-01 || true || Кава Lavazza 1кг || ''(порожня)'' || Оптова || 410.00 || UAH | |||
|- | |||
| 15 || a3f…01 || 3 || 2026-07-01 || true || Чай Ahmad 100г || ''(порожня)'' || Роздрібна || 95.00 || UAH | |||
|- | |||
| 15 || b7c…04 || 1 || 2026-07-15 || true || Кава Lavazza 1кг || ''(порожня)'' || Роздрібна || 495.00 || UAH | |||
|} | |||
{{Note|Зверніть увагу: у підпорядкованому РВ '''немає''' унікальності за (Період + Вимірювання). Два різні документи можуть встановити ціну на ту саму дату — платформа це дозволить, зріз останніх поверне запис із більшим <code>line_no</code> у межах реєстратора з пізнішою позицією. Це '''свідома''' поведінка (сумісність із 1С), але прикладний розробник має контролювати дублі самостійно — див. антипатерн А-6 (Д.10).}} | |||
==== Д.3.3. ШтрихкодиНоменклатури — неперіодичний, незалежний ==== | |||
'''Задача:''' за штрихкодом знайти номенклатуру. Класичний приклад «вимірювання = те, ''за чим'' шукаємо; ресурс = те, що ''знаходимо''». | |||
<syntaxhighlight lang="yaml"> | |||
register: | |||
name: ШтрихкодиНоменклатури | |||
kind: Information | |||
periodicity: Nonperiodical | |||
writeMode: Independent | |||
dimensions: | |||
- { name: Штрихкод, type: "Рядок(30)", denyEmpty: true } # ← ключ пошуку | |||
resources: | |||
- { name: Номенклатура, type: "Довідник.Номенклатура", denyEmpty: true } | |||
- { name: Характеристика, type: "Довідник.ХарактеристикиНоменклатури", nullable: true } | |||
- { name: Упаковка, type: "Довідник.УпаковкиНоменклатури", nullable: true } | |||
</syntaxhighlight> | |||
<syntaxhighlight lang="sql"> | |||
CREATE TABLE rg_i_0011 ( | |||
d1_s varchar(30) NOT NULL, -- Штрихкод | |||
r1_r uuid NOT NULL, -- Номенклатура | |||
r2_r uuid NOT NULL, -- Характеристика | |||
r3_r uuid NOT NULL, -- Упаковка | |||
CONSTRAINT pk_rg_i_0011 PRIMARY KEY (d1_s) -- ← унікальність штрихкоду «безкоштовно» | |||
); | |||
CREATE INDEX ix_rg_i_0011_r1 ON rg_i_0011 (r1_r); -- зворотний пошук: штрихкоди товару | |||
</syntaxhighlight> | |||
'''Проєктне рішення:''' PK за вимірюванням автоматично гарантує, що один штрихкод не може вказувати на два товари. Якби Номенклатуру зробили вимірюванням, а Штрихкод — ресурсом, ця гарантія зникла б, і довелося б писати перевірку в прикладному коді. | |||
==== Д.3.4. ГрафікРоботи — неперіодичний, незалежний (використовується як графік для РР) ==== | |||
<syntaxhighlight lang="yaml"> | |||
register: | |||
name: ГрафікРоботи | |||
kind: Information | |||
periodicity: Nonperiodical | |||
writeMode: Independent | |||
dimensions: | |||
- { name: ВидГрафіка, type: "Довідник.ГрафікиРоботи", master: true, denyEmpty: true } | |||
- { name: ДатаГрафіка, type: "Дата", denyEmpty: true } # ← вимірювання типу Дата, не Період! | |||
resources: | |||
- { name: Значення, type: "Число(1,0)" } # 1 = робочий день, 0 = вихідний | |||
- { name: Годин, type: "Число(4,2)" } # тривалість зміни | |||
</syntaxhighlight> | |||
'''Проєктне рішення (важливе):''' <code>ДатаГрафіка</code> — це '''вимірювання''' типу <code>Дата</code>, а не стандартний реквізит <code>Період</code>. Регістр '''неперіодичний'''. Причина: графік описує ''календар'' (кожна дата — окремий факт), а не ''історію зміни значення''. Якби використали періодичність, зріз останніх повертав би «останній робочий день», що безглуздо. Механізм РР (<code>ДаніГрафіка</code>) очікує саме таку структуру. | |||
'''Дані у таблиці <code>rg_i_0015</code>:''' | |||
{| class="wikitable" | |||
! d1_r (ВидГрафіка) !! d2_d (ДатаГрафіка) !! r1 (Значення) !! r2 (Годин) | |||
|- | |||
| П'ятиденка || 2026-07-01 || 1 || 8.00 | |||
|- | |||
| П'ятиденка || 2026-07-04 || 0 || 0.00 | |||
|- | |||
| П'ятиденка || 2026-07-05 || 0 || 0.00 | |||
|- | |||
| П'ятиденка || 2026-07-06 || 1 || 8.00 | |||
|- | |||
| Змінний 2/2 || 2026-07-01 || 1 || 12.00 | |||
|- | |||
| Змінний 2/2 || 2026-07-03 || 0 || 0.00 | |||
|} | |||
==== Д.3.5. КадровіДані — по позиції реєстратора ==== | |||
'''Задача:''' зберігати актуальні кадрові дані співробітника з історією; підтримати кілька наказів однією датою в правильному порядку. | |||
<syntaxhighlight lang="yaml"> | |||
register: | |||
name: КадровіДані | |||
kind: Information | |||
periodicity: ByRecorderPosition # ← упорядкування за позицією документа, не лише за датою | |||
writeMode: SubordinateToRecorder | |||
dimensions: | |||
- { name: Співробітник, type: "Довідник.Співробітники", master: true, denyEmpty: true } | |||
resources: | |||
- { name: Підрозділ, type: "Довідник.Підрозділи" } | |||
- { name: Посада, type: "Довідник.Посади" } | |||
- { name: Ставка, type: "Число(5,2)" } | |||
- { name: ВидЗайнятості, type: "Перерахування.ВидиЗайнятості" } | |||
- { name: ГрафікРоботи, type: "Довідник.ГрафікиРоботи" } | |||
recorders: | |||
- Документ.ПрийомНаРоботу | |||
- Документ.КадровеПереміщення | |||
- Документ.Звільнення | |||
</syntaxhighlight> | |||
'''Проєктне рішення:''' <code>ByRecorderPosition</code> — коли два накази оформлені однією датою (переміщення + зміна ставки), звичайна періодичність «у межах дня» дала б недетермінований результат зрізу. Позиція реєстратора додає до ключа <code>(rec_t, rec_r, line_no)</code> і впорядковує за моментом часу документа. | |||
'''Фізична схема:''' | |||
<syntaxhighlight lang="sql"> | |||
CREATE TABLE rg_i_0016 ( | |||
period timestamp(0) NOT NULL, | |||
rec_t smallint NOT NULL, | |||
rec_r uuid NOT NULL, | |||
line_no int NOT NULL, | |||
active boolean NOT NULL DEFAULT true, | |||
d1_r uuid NOT NULL, -- Співробітник | |||
r1_r uuid NOT NULL, r2_r uuid NOT NULL, | |||
r3 numeric(5,2) NOT NULL, | |||
r4 smallint NOT NULL, -- Перерахування зберігається як порядковий номер | |||
r5_r uuid NOT NULL, | |||
CONSTRAINT pk_rg_i_0016 PRIMARY KEY (period, rec_t, rec_r, line_no) -- ← Період у ключі ПЕРШИЙ | |||
); | |||
CREATE INDEX ix_rg_i_0016_d1 ON rg_i_0016 (d1_r, period DESC, rec_t, rec_r, line_no DESC) | |||
WHERE active; | |||
</syntaxhighlight> | |||
==== Д.3.6. НалаштуванняКористувачів — складений тип ресурсу ==== | |||
<syntaxhighlight lang="yaml"> | |||
register: | |||
name: НалаштуванняКористувачів | |||
kind: Information | |||
periodicity: Nonperiodical | |||
writeMode: Independent | |||
dimensions: | |||
- { name: Користувач, type: "Довідник.Користувачі", master: true } | |||
- { name: Налаштування, type: "ПланВидівХарактеристик.НалаштуванняКористувачів", master: true } | |||
resources: | |||
- name: Значення | |||
type: ["Рядок(500)", "Число(15,2)", "Дата", "Булево", | |||
"Довідник.Організації", "Довідник.Склади"] # ← складений тип | |||
</syntaxhighlight> | |||
<syntaxhighlight lang="sql"> | |||
CREATE TABLE rg_i_0018 ( | |||
d1_r uuid NOT NULL, | |||
d2_r uuid NOT NULL, | |||
r1_t smallint NOT NULL, -- код типу значення | |||
r1_b boolean, | |||
r1_n numeric(15,2), | |||
r1_s varchar(500), | |||
r1_d timestamp(0), | |||
r1_r uuid, | |||
CONSTRAINT pk_rg_i_0018 PRIMARY KEY (d1_r, d2_r) | |||
); | |||
</syntaxhighlight> | |||
{| class="wikitable" | |||
! d1_r !! d2_r !! r1_t !! r1_b !! r1_n !! r1_s !! r1_d !! r1_r | |||
|- | |||
| Іваненко || ОсновнаОрганізація || 101 || || || || || ТОВ «Альфа» | |||
|- | |||
| Іваненко || ОсновнийСклад || 104 || || || || || Центральний | |||
|- | |||
| Іваненко || ПоказуватиПідказки || 2 || true || || || || | |||
|- | |||
| Петренко || КількістьРядківСписку || 3 || || 50 || || || | |||
|} | |||
=== Д.4. Регістри накопичення, вид «Залишки» === | |||
==== Д.4.1. ТовариНаСкладах ==== | |||
Декларація — розділ 6.7, фізична схема — розділ 8.5, ER — розділ 9.2. Тут — дані. | |||
'''Рухи (<code>rg_a_0012</code>) після проведення трьох документів:''' | |||
{| class="wikitable" | |||
! rec_t !! rec_r !! line_no !! period !! mvt !! d1_r (Номенкл.) !! d2_r (Склад) !! r1 (К-сть) !! r2 (Сума) | |||
|- | |||
| 2 (ПрихНакл) || p1 || 1 || 2026-06-10 || 0 ''Прихід'' || Кава Lavazza || Центральний || 100.000 || 35 000.00 | |||
|- | |||
| 2 (ПрихНакл) || p1 || 2 || 2026-06-10 || 0 ''Прихід'' || Чай Ahmad || Центральний || 200.000 || 12 000.00 | |||
|- | |||
| 3 (ВидНакл) || v1 || 1 || 2026-07-05 || 1 ''Витрата'' || Кава Lavazza || Центральний || 30.000 || 10 500.00 | |||
|- | |||
| 4 (Переміщ) || m1 || 1 || 2026-07-12 || 1 ''Витрата'' || Кава Lavazza || Центральний || 20.000 || 7 000.00 | |||
|- | |||
| 4 (Переміщ) || m1 || 2 || 2026-07-12 || 0 ''Прихід'' || Кава Lavazza || Роздрібний || 20.000 || 7 000.00 | |||
|} | |||
'''Підсумки залишків (<code>rg_a_0012_tb</code>), ТА = 2026-07-31:''' | |||
{| class="wikitable" | |||
! period !! d1_r !! d2_r !! r1 (К-сть ±) !! r2 (Сума ±) !! Коментар | |||
|- | |||
| 2026-07-01 || Кава Lavazza || Центральний || 100.000 || 35 000.00 || залишок ''на початок'' липня | |||
|- | |||
| 2026-07-01 || Чай Ahmad || Центральний || 200.000 || 12 000.00 || | |||
|- | |||
| 2026-08-01 || Кава Lavazza || Центральний || 50.000 || 17 500.00 || 100 − 30 − 20 | |||
|- | |||
| 2026-08-01 || Кава Lavazza || Роздрібний || 20.000 || 7 000.00 || | |||
|- | |||
| 2026-08-01 || Чай Ahmad || Центральний || 200.000 || 12 000.00 || | |||
|- | |||
| '''5999-11-01''' || Кава Lavazza || Центральний || 50.000 || 17 500.00 || '''MAXPERIOD''' — поточний залишок | |||
|- | |||
| '''5999-11-01''' || Кава Lavazza || Роздрібний || 20.000 || 7 000.00 || '''MAXPERIOD''' | |||
|- | |||
| '''5999-11-01''' || Чай Ahmad || Центральний || 200.000 || 12 000.00 || '''MAXPERIOD''' | |||
|} | |||
''(Вимірювання Партія і Характеристика для стислості опущені.)'' | |||
==== Д.4.2. ВзаєморозрахункиЗКонтрагентами ==== | |||
'''Задача:''' облік дебіторської/кредиторської заборгованості в розрізі договорів і замовлень. | |||
<syntaxhighlight lang="yaml"> | |||
register: | |||
name: ВзаєморозрахункиЗКонтрагентами | |||
kind: Accumulation | |||
accumulationKind: Balance | |||
periodicity: WithinSecond | |||
enableBalanceTotals: true | |||
enableTurnoverTotals: true | |||
partitioning: { mode: RangeByPeriod, step: month } | |||
dimensions: | |||
- { name: Організація, type: "Довідник.Організації", denyEmpty: true, index: true } | |||
- { name: Контрагент, type: "Довідник.Контрагенти", master: true, index: true } | |||
- { name: Договір, type: "Довідник.ДоговориКонтрагентів", master: true, index: true } | |||
- { name: Замовлення, type: ["Документ.ЗамовленняПокупця", "Документ.ЗамовленняПостачальнику"], | |||
nullable: true } | |||
resources: | |||
- { name: Сума, type: "Число(15,2)" } # у валюті регламентованого обліку | |||
- { name: СумаВал, type: "Число(15,2)" } # у валюті договору | |||
attributes: | |||
- { name: Коментар, type: "Рядок(200)" } | |||
recorders: | |||
- Документ.ВидатковаНакладна | |||
- Документ.ПрихіднаНакладна | |||
- Документ.ПлатіжнеДоручення | |||
- Документ.КасовийОрдер | |||
- Документ.КоригуванняБоргу | |||
</syntaxhighlight> | |||
'''Угода про знак (обов'язково фіксується в методології!):''' | |||
{| class="wikitable" | |||
! Вид руху !! Сенс !! Приклад документа | |||
|- | |||
| '''Прихід''' || Борг контрагента перед нами '''зростає''' (дебіторка +) || Видаткова накладна | |||
|- | |||
| '''Витрата''' || Борг контрагента перед нами '''зменшується''' (оплата) || Платіжне доручення вхідне | |||
|} | |||
Кредиторська заборгованість = від'ємний залишок. ''Альтернатива'' — два окремих ресурси (СумаДт/СумаКт) або два регістри; обраний варіант — один знаковий ресурс (простіше, менший обсяг підсумків). | |||
'''Приклад даних:''' | |||
{| class="wikitable" | |||
! Документ !! period !! mvt !! Контрагент !! Договір !! r1 (Сума) !! Залишок після | |||
|- | |||
| ВидатковаНакладна №12 || 2026-07-05 || Прихід || ТОВ «Бета» || Основний || 12 000.00 || +12 000 ''(винні нам)'' | |||
|- | |||
| ПлатіжнеДоручення №88 || 2026-07-09 || Витрата || ТОВ «Бета» || Основний || 8 000.00 || +4 000 | |||
|- | |||
| ПлатіжнеДоручення №91 || 2026-07-16 || Витрата || ТОВ «Бета» || Основний || 6 000.00 || −2 000 ''(передоплата)'' | |||
|} | |||
'''Запит (акт звірки):''' | |||
<syntaxhighlight lang="sql"> | |||
ВИБРАТИ | |||
Дані.Контрагент, Дані.Договір, | |||
Дані.СумаПочатковийЗалишок, Дані.СумаПрихід, | |||
Дані.СумаВитрата, Дані.СумаКінцевийЗалишок | |||
З РегістрНакопичення.ВзаєморозрахункиЗКонтрагентами.ЗалишкиІОбороти( | |||
&Початок, &Кінець, Авто, Рух, | |||
Організація = &Організація І Контрагент = &Контрагент | |||
) ЯК Дані | |||
</syntaxhighlight> | |||
==== Д.4.3. ТовариВРезерві — регістр «супутник» ==== | |||
<syntaxhighlight lang="yaml"> | |||
register: | |||
name: ТовариВРезерві | |||
kind: Accumulation | |||
accumulationKind: Balance | |||
periodicity: WithinSecond | |||
dimensions: | |||
- { name: Номенклатура, type: "Довідник.Номенклатура", master: true, index: true } | |||
- { name: Характеристика, type: "Довідник.ХарактеристикиНоменклатури", nullable: true } | |||
- { name: Склад, type: "Довідник.Склади", master: true, index: true } | |||
- { name: Замовлення, type: "Документ.ЗамовленняПокупця", master: true, denyEmpty: true } | |||
resources: | |||
- { name: Кількість, type: "Число(15,3)" } | |||
recorders: | |||
- Документ.ЗамовленняПокупця | |||
- Документ.ВидатковаНакладна | |||
- Документ.ЗакриттяЗамовлень | |||
</syntaxhighlight> | |||
'''Патерн «доступний залишок»''' — з'єднання двох регістрів: | |||
<syntaxhighlight lang="sql"> | |||
ВИБРАТИ | |||
ЄСТЬNULL(Зал.Номенклатура, Рез.Номенклатура) ЯК Номенклатура, | |||
ЄСТЬNULL(Зал.Склад, Рез.Склад) ЯК Склад, | |||
ЄСТЬNULL(Зал.КількістьЗалишок, 0) ЯК ВСкладі, | |||
ЄСТЬNULL(Рез.КількістьЗалишок, 0) ЯК ВРезерві, | |||
ЄСТЬNULL(Зал.КількістьЗалишок, 0) - ЄСТЬNULL(Рез.КількістьЗалишок, 0) ЯК Доступно | |||
З РегістрНакопичення.ТовариНаСкладах.Залишки(&Період, Склад = &Склад) ЯК Зал | |||
ПОВНЕ З'ЄДНАННЯ РегістрНакопичення.ТовариВРезерві.Залишки(&Період, Склад = &Склад) ЯК Рез | |||
ЗА Зал.Номенклатура = Рез.Номенклатура І Зал.Склад = Рез.Склад | |||
</syntaxhighlight> | |||
{{Note|Чому окремий регістр, а не ресурс «Резерв» у <code>ТовариНаСкладах</code>? Тому що резерв ведеться в розрізі '''Замовлення''', а залишок — у розрізі '''Партії'''. Додавання Замовлення як вимірювання до <code>ТовариНаСкладах</code> помножило б таблицю підсумків на кардинальність замовлень (сотні тисяч рядків на товар). Це ілюстрація контрольного питання №2 з Д.1.}} | |||
==== Д.4.4. ГрошовіКоштиБезготівкові ==== | |||
<syntaxhighlight lang="yaml"> | |||
register: | |||
name: ГрошовіКоштиБезготівкові | |||
kind: Accumulation | |||
accumulationKind: Balance | |||
periodicity: WithinDay # достатньо дня: банківська виписка — денна | |||
dimensions: | |||
- { name: Організація, type: "Довідник.Організації", denyEmpty: true } | |||
- { name: БанківськийРахунок, type: "Довідник.БанківськіРахунки", master: true, denyEmpty: true } | |||
resources: | |||
- { name: Сума, type: "Число(15,2)" } | |||
- { name: СумаВал, type: "Число(15,2)" } | |||
recorders: [Документ.ПлатіжнеДоручення, Документ.БанківськаВиписка, Документ.ПереміщенняКоштів] | |||
</syntaxhighlight> | |||
'''Проєктне рішення:''' Валюта — '''не''' вимірювання, тому що вона однозначно визначається банківським рахунком (функціональна залежність). Її додавання як вимірювання створило б надлишковість і ризик неузгоджених даних. Валюта отримується з'єднанням із довідником. | |||
=== Д.5. Регістри накопичення, вид «Обороти» === | |||
==== Д.5.1. Продажі — з агрегатами ==== | |||
<syntaxhighlight lang="yaml"> | |||
register: | |||
name: Продажі | |||
kind: Accumulation | |||
accumulationKind: Turnover # ← залишків не буває: «залишок продажів» безглуздий | |||
periodicity: WithinSecond | |||
turnoverTotalsPeriod: Month | |||
aggregatesMode: Aggregates | |||
partitioning: { mode: RangeByPeriod, step: month } | |||
dimensions: | |||
- { name: Номенклатура, type: "Довідник.Номенклатура", index: true } | |||
- { name: Характеристика, type: "Довідник.ХарактеристикиНоменклатури", nullable: true } | |||
- { name: Контрагент, type: "Довідник.Контрагенти", index: true } | |||
- { name: Договір, type: "Довідник.ДоговориКонтрагентів" } | |||
- { name: Менеджер, type: "Довідник.Користувачі", index: true } | |||
- { name: Склад, type: "Довідник.Склади" } | |||
resources: | |||
- { name: Кількість, type: "Число(15,3)" } | |||
- { name: Сума, type: "Число(15,2)" } | |||
- { name: СумаБезПДВ, type: "Число(15,2)" } | |||
- { name: Собівартість, type: "Число(15,2)" } | |||
recorders: [Документ.ВидатковаНакладна, Документ.ПовернненняВідПокупця, Документ.ЗвітПроРоздрібніПродажі] | |||
aggregates: | |||
- name: ПродажіПоМісяцяхІТоварах | |||
periodicity: Month | |||
dimensions: [Номенклатура, Склад] | |||
realtime: true | |||
- name: ПродажіПоМенеджерах | |||
periodicity: Day | |||
dimensions: [Менеджер] | |||
realtime: false # оновлюється регламентно | |||
- name: ПродажіПоКонтрагентах | |||
periodicity: Quarter | |||
dimensions: [Контрагент, Договір] | |||
realtime: false | |||
</syntaxhighlight> | |||
'''Проєктні рішення:''' | |||
* <code>Turnover</code>, а не <code>Balance</code>: немає <code>ВидРуху</code>, немає таблиці залишків → удвічі менше підсумків і немає кумулятивних оновлень. Повернення відображається '''від'ємною''' сумою, а не «витратою». | |||
* 6 вимірювань → таблиця підсумків надто широка для швидких звітів → компенсуємо агрегатами. | |||
'''Ефект агрегатів:''' | |||
{| class="wikitable" | |||
! Звіт !! Без агрегатів (<code>rg_a_0031_tt</code>) !! З агрегатом !! Виграш | |||
|- | |||
| Продажі по товарах за рік || скан 8 млн рядків підсумків || <code>ag1</code>: 40 тис. рядків || ×200 | |||
|- | |||
| Рейтинг менеджерів за квартал || скан 8 млн рядків || <code>ag2</code>: 1,8 тис. рядків || ×4000 | |||
|- | |||
| Продажі по контрагенту за 3 роки || скан 8 млн рядків || <code>ag3</code>: 60 тис. рядків || ×130 | |||
|- | |||
| Продажі по товару + контрагенту || '''агрегат не покриває''' → підсумки || — || — | |||
|} | |||
<syntaxhighlight lang="sql"> | |||
CREATE TABLE rg_a_0031_ag1 ( -- Місяць × (Номенклатура, Склад) | |||
period timestamp(0) NOT NULL, d1_r uuid NOT NULL, d6_r uuid NOT NULL, | |||
r1 numeric(20,3) NOT NULL, r2 numeric(20,2) NOT NULL, | |||
r3 numeric(20,2) NOT NULL, r4 numeric(20,2) NOT NULL, | |||
CONSTRAINT pk_rg_a_0031_ag1 PRIMARY KEY (period, d1_r, d6_r) | |||
); | |||
CREATE TABLE rg_a_0031_ag2 ( -- День × (Менеджер) | |||
period timestamp(0) NOT NULL, d5_r uuid NOT NULL, | |||
r1 numeric(20,3) NOT NULL, r2 numeric(20,2) NOT NULL, | |||
r3 numeric(20,2) NOT NULL, r4 numeric(20,2) NOT NULL, | |||
CONSTRAINT pk_rg_a_0031_ag2 PRIMARY KEY (period, d5_r) | |||
); | |||
</syntaxhighlight> | |||
==== Д.5.2. ВитратиЗаСтаттями ==== | |||
<syntaxhighlight lang="yaml"> | |||
register: | |||
name: ВитратиЗаСтаттями | |||
kind: Accumulation | |||
accumulationKind: Turnover | |||
periodicity: WithinDay | |||
turnoverTotalsPeriod: Month | |||
dimensions: | |||
- { name: Організація, type: "Довідник.Організації", denyEmpty: true } | |||
- { name: Підрозділ, type: "Довідник.Підрозділи", index: true } | |||
- { name: СтаттяВитрат, type: "Довідник.СтаттіВитрат", master: true, denyEmpty: true, index: true } | |||
- { name: Проєкт, type: "Довідник.Проєкти", nullable: true } | |||
resources: | |||
- { name: Сума, type: "Число(15,2)" } | |||
recorders: [Документ.АвансовийЗвіт, Документ.НадходженняПослуг, Документ.НарахуванняЗарплати, Документ.Амортизація] | |||
</syntaxhighlight> | |||
'''Приклад даних (<code>rg_a_0032_tt</code>, підсумки оборотів за місяць):''' | |||
{| class="wikitable" | |||
! period !! Підрозділ !! СтаттяВитрат !! Проєкт !! r1 (Сума) | |||
|- | |||
| 2026-07-01 || Відділ продажів || Оренда || ''(порожній)'' || 45 000.00 | |||
|- | |||
| 2026-07-01 || Відділ продажів || ЗП і нарахування || ''(порожній)'' || 320 000.00 | |||
|- | |||
| 2026-07-01 || Відділ продажів || Реклама || Запуск «Альфа» || 78 000.00 | |||
|- | |||
| 2026-07-01 || ІТ-відділ || ЗП і нарахування || ''(порожній)'' || 410 000.00 | |||
|- | |||
| 2026-07-01 || ІТ-відділ || Ліцензії ПЗ || ''(порожній)'' || 62 000.00 | |||
|} | |||
=== Д.6. Регістри бухгалтерії === | |||
==== Д.6.1. Госпрозрахунковий — з кореспонденцією ==== | |||
Декларація — розділ 6.7, схема — 8.6, ER — 9.3. Тут — приклад проводок. | |||
'''Господарська операція:''' реалізація товару на 12 000 грн (у т.ч. ПДВ 2 000), собівартість 7 000 грн. | |||
'''Проводки (<code>rg_b_0020</code>, реєстратор = ВидатковаНакладна №12):''' | |||
{| class="wikitable" | |||
! line !! acc_dt !! ed_dt1 !! ed_dt2 !! acc_kt !! ed_kt1 !! ed_kt2 !! r1 (Сума) !! r2_dt !! r2_kt | |||
|- | |||
| 1 || 361 ''Розрах. з покупцями'' || ТОВ «Бета» || Договір №5 || 702 ''Дохід від реалізації'' || Кава Lavazza || ''—'' || 12 000.00 || || 30.000 | |||
|- | |||
| 2 || 702 ''Дохід від реалізації'' || Кава Lavazza || ''—'' || 641 ''Розрах. за податками'' || ПДВ || ''—'' || 2 000.00 || || | |||
|- | |||
| 3 || 902 ''Собівартість реалізації'' || Кава Lavazza || ''—'' || 281 ''Товари на складі'' || Кава Lavazza || Центральний || 7 000.00 || 30.000 || 30.000 | |||
|} | |||
'''Контроль:''' Σ(Сума) по Дт = Σ(Сума) по Кт у межах реєстратора → 12 000 + 2 000 + 7 000 = 21 000 з обох боків. ✔ | |||
'''Підсумки, рівень 0 (<code>rg_b_0020_tb0</code>), на 5999-11-01:''' | |||
{| class="wikitable" | |||
! acc_r !! d1_r (Організація) !! r1 (Сума ±) !! Інтерпретація | |||
|- | |||
| 281 || ТОВ «Альфа» || +28 000.00 || дебетовий залишок (товари є) | |||
|- | |||
| 361 || ТОВ «Альфа» || +12 000.00 || дебетовий (дебіторка) | |||
|- | |||
| 641 || ТОВ «Альфа» || −2 000.00 || кредитовий (винні бюджету) | |||
|- | |||
| 702 || ТОВ «Альфа» || −10 000.00 || кредитовий (дохід) | |||
|- | |||
| 902 || ТОВ «Альфа» || +7 000.00 || дебетовий (собівартість) | |||
|} | |||
'''Підсумки, рівень 2 (<code>rg_b_0020_tb2</code>) — для рахунку 281 (2 субконто: Номенклатура, Склад):''' | |||
{| class="wikitable" | |||
! acc_r !! ed1_r (Номенклатура) !! ed2_r (Склад) !! r1 (Сума) !! r2 (Кількість) | |||
|- | |||
| 281 || Кава Lavazza || Центральний || 17 500.00 || 50.000 | |||
|- | |||
| 281 || Кава Lavazza || Роздрібний || 7 000.00 || 20.000 | |||
|- | |||
| 281 || Чай Ahmad || Центральний || 12 000.00 || 200.000 | |||
|} | |||
Згортка <code>tb2</code> → <code>tb0</code>: 17 500 + 7 000 + 12 000 = '''36 500'''… ''(різниця з таблицею вище — інші операції; у тесті ФТ-Т-08 перевіряється точна рівність)''. | |||
'''Запит (ОСВ по рахунку):''' | |||
<syntaxhighlight lang="sql"> | |||
ВИБРАТИ | |||
Дані.Субконто1 ЯК Номенклатура, Дані.Субконто2 ЯК Склад, | |||
Дані.СумаПочатковийЗалишокДт, Дані.КількістьПочатковийЗалишокДт, | |||
Дані.СумаОборотДт, Дані.СумаОборотКт, | |||
Дані.СумаКінцевийЗалишокДт, Дані.КількістьКінцевийЗалишокДт | |||
З РегістрБухгалтерії.Госпрозрахунковий.ЗалишкиІОбороти( | |||
&Початок, &Кінець, Місяць, | |||
Рахунок = &Рахунок281, | |||
, Організація = &Організація, | |||
, | |||
) ЯК Дані | |||
</syntaxhighlight> | |||
==== Д.6.2. ПодатковийОблік — без кореспонденції ==== | |||
'''Задача:''' податковий облік із розділенням на постійні/тимчасові різниці, де подвійний запис не потрібен (кожен факт реєструється окремо по Дт або по Кт). | |||
<syntaxhighlight lang="yaml"> | |||
register: | |||
name: ПодатковийОблік | |||
kind: Accounting | |||
chartOfAccounts: ПланРахунків.Податковий | |||
correspondence: false # ← уніграфічний облік | |||
periodicity: WithinSecond | |||
dimensions: | |||
- { name: Організація, type: "Довідник.Організації", balance: true, denyEmpty: true } | |||
- { name: ВидРізниці, type: "Перерахування.ВидиРізниць", balance: true } # БУ|ПУ|ПР|ТР | |||
resources: | |||
- { name: Сума, type: "Число(15,2)", balance: true } | |||
attributes: | |||
- { name: Зміст, type: "Рядок(255)" } | |||
recorders: [Документ.БухгалтерськаОперація, Документ.ВидатковаНакладна, Документ.НадходженняПослуг] | |||
</syntaxhighlight> | |||
'''Проводки (<code>rg_b_0021</code>):''' | |||
{| class="wikitable" | |||
! line !! acc_mvt !! acc_r !! ed1 (Номенкл.) !! d1 (Організація) !! d2 (ВидРізниці) !! r1 (Сума) | |||
|- | |||
| 1 || 0 ''Дебет'' || 902.НУ || Кава Lavazza || ТОВ «Альфа» || ПУ ''податковий'' || 7 000.00 | |||
|- | |||
| 2 || 1 ''Кредит'' || 281.НУ || Кава Lavazza || ТОВ «Альфа» || ПУ || 7 000.00 | |||
|- | |||
| 3 || 0 ''Дебет'' || 902.НУ || Кава Lavazza || ТОВ «Альфа» || ПР ''постійна різниця'' || 350.00 | |||
|- | |||
| 4 || 1 ''Кредит'' || 281.НУ || Кава Lavazza || ТОВ «Альфа» || ПР || 350.00 | |||
|} | |||
'''Відмінності від Д.6.1:''' | |||
{| class="wikitable" | |||
! !! З кореспонденцією !! Без кореспонденції | |||
|- | |||
| Один факт = || 1 запис (Дт+Кт) || 2 записи (окремо Дт, окремо Кт) | |||
|- | |||
| Поля рахунків || <code>acc_dt_r</code>, <code>acc_kt_r</code> || <code>acc_r</code> + <code>acc_mvt</code> | |||
|- | |||
| Субконто || 2 набори (Дт, Кт) || 1 набір | |||
|- | |||
| Кількість записів || N || 2N | |||
|- | |||
| Таблиця <code>_tc</code> (кореспонденції) || Є || '''Немає''' — «шахова відомість» неможлива | |||
|- | |||
| Контроль Дт=Кт || У межах реєстратора || Опційно (може бути незбалансовано за задумом) | |||
|- | |||
| Коли обирати || Класичний облік, потрібен аналіз кореспонденцій || Облік без потреби в кореспонденціях, забалансовий, статистичний | |||
|} | |||
==== Д.6.3. Бюджетування ==== | |||
<syntaxhighlight lang="yaml"> | |||
register: | |||
name: Бюджетування | |||
kind: Accounting | |||
chartOfAccounts: ПланРахунків.Бюджетування | |||
correspondence: true | |||
periodicity: WithinMonth # бюджет — помісячний, до секунди не потрібно | |||
dimensions: | |||
- { name: Сценарій, type: "Довідник.СценаріїБюджетування", balance: true, denyEmpty: true } | |||
- { name: ЦФВ, type: "Довідник.ЦентриФінансовоїВідповідальності", balance: true } | |||
- { name: Проєкт, type: "Довідник.Проєкти", balance: true, nullable: true } | |||
resources: | |||
- { name: Сума, type: "Число(15,2)", balance: true } | |||
recorders: [Документ.БюджетнаОперація, Документ.ВведенняБюджету] | |||
</syntaxhighlight> | |||
'''Проєктне рішення:''' <code>Сценарій</code> — вимірювання, а не окремий регістр на кожен сценарій (План/Факт/Прогноз). Це дозволяє план-фактний аналіз одним запитом. Усі три вимірювання '''балансові''' — бюджетна проводка не змінює сценарій/ЦФВ між дебетом і кредитом. | |||
=== Д.7. Регістри розрахунку === | |||
==== Д.7.1. ОсновніНарахування — період дії + витіснення ==== | |||
'''План видів розрахунку <code>ОсновніНарахування</code>:''' | |||
{| class="wikitable" | |||
! Вид розрахунку !! Період дії !! Витісняючі !! Базові !! Залежність від бази | |||
|- | |||
| Оклад || Так || Відпустка, Лікарняний || — || Не залежить | |||
|- | |||
| Відпустка || Так || Лікарняний || Оклад, Премія || За періодом дії | |||
|- | |||
| Лікарняний || Так || — || Оклад || За періодом дії | |||
|- | |||
| Премія || Ні || — || Оклад || За періодом реєстрації | |||
|} | |||
Декларація регістру — розділ 6.7. | |||
'''Записи (<code>rg_c_0040</code>), період реєстрації = липень 2026:''' | |||
{| class="wikitable" | |||
! line !! calc_type !! period !! act_begin !! act_end !! base_begin !! base_end !! d1 (Співробітник) !! r1 (Результат) | |||
|- | |||
| 1 || Оклад || 2026-07-01 || 2026-07-01 || 2026-07-31 || || || Іваненко || 18 000.00 | |||
|- | |||
| 2 || Відпустка || 2026-07-01 || 2026-07-10 || 2026-07-17 || 2026-01-01 || 2026-06-30 || Іваненко || 6 420.00 | |||
|- | |||
| 3 || Лікарняний || 2026-07-01 || 2026-07-14 || 2026-07-22 || 2026-01-01 || 2026-06-30 || Іваненко || 5 180.00 | |||
|- | |||
| 4 || Оклад || 2026-07-01 || 2026-07-01 || 2026-07-31 || || || Петренко || 22 000.00 | |||
|} | |||
'''Фактичні періоди дії (<code>rg_c_0040_ap</code>) — результат витіснення:''' | |||
{| class="wikitable" | |||
! rec/line !! interval_no !! calc_type !! d1 !! fact_begin !! fact_end !! Коментар | |||
|- | |||
| n1 / 1 || 0 || Оклад || Іваненко || 2026-07-01 || 2026-07-09 || до відпустки | |||
|- | |||
| n1 / 1 || 1 || Оклад || Іваненко || 2026-07-23 || 2026-07-31 || після лікарняного | |||
|- | |||
| n1 / 2 || 0 || Відпустка || Іваненко || 2026-07-10 || 2026-07-13 || витіснена лікарняним з 14-го | |||
|- | |||
| n1 / 3 || 0 || Лікарняний || Іваненко || 2026-07-14 || 2026-07-22 || не витісняється нічим | |||
|- | |||
| n1 / 4 || 0 || Оклад || Петренко || 2026-07-01 || 2026-07-31 || витіснення відсутнє | |||
|} | |||
'''Один запис «Оклад» Іваненка → два інтервали''' — ілюстрація зв'язку 1:N у розділі 9.4. | |||
'''Запит (дані графіка для розрахунку окладу):''' | |||
<syntaxhighlight lang="sql"> | |||
ВИБРАТИ | |||
Дані.Співробітник, Дані.НомерРядка, | |||
Дані.ЗначенняФактичногоПеріодуДії ЯК ВідпрацьованоДнів, | |||
Дані.ЗначенняПеріодуДії ЯК НормаДнів | |||
З РегістрРозрахунку.ОсновніНарахування.ДаніГрафіка( | |||
ВидРозрахунку = ЗНАЧЕННЯ(ПланВидівРозрахунку.ОсновніНарахування.Оклад) | |||
І Реєстратор = &Реєстратор | |||
) ЯК Дані | |||
</syntaxhighlight> | |||
'''Результат:''' Іваненко — <code>ВідпрацьованоДнів = 13</code> (робочі дні у 01–09 та 23–31), <code>НормаДнів = 23</code> → Оклад = 18 000 × 13 / 23 = '''10 173,91'''. | |||
'''Запит (база для відпустки):''' | |||
<syntaxhighlight lang="sql"> | |||
ВИБРАТИ База.Співробітник, База.НомерРядка, База.РезультатБаза ЯК Заробіток | |||
З РегістрРозрахунку.ОсновніНарахування.БазаРозрахунку( | |||
, /* вимірювання бази */ | |||
, /* вимірювання основного регістру */ | |||
Співробітник, /* розрізи */ | |||
ВидРозрахунку = ЗНАЧЕННЯ(ПланВидівРозрахунку.ОсновніНарахування.Відпустка) | |||
) ЯК База | |||
</syntaxhighlight> | |||
==== Д.7.2. Утримання — без періоду дії, база за періодом реєстрації ==== | |||
'''План видів розрахунку <code>Утримання</code>:''' | |||
{| class="wikitable" | |||
! Вид розрахунку !! Період дії !! Базові види розрахунку !! Залежність | |||
|- | |||
| ПДФО || Ні || ''(усі з ПВР ОсновніНарахування)'' || За періодом реєстрації | |||
|- | |||
| Військовий збір || Ні || ''(усі з ПВР ОсновніНарахування)'' || За періодом реєстрації | |||
|- | |||
| Аліменти || Ні || Оклад, Премія, Відпустка || За періодом реєстрації | |||
|- | |||
| Профспілковий внесок || Ні || Оклад || За періодом реєстрації | |||
|} | |||
<syntaxhighlight lang="yaml"> | |||
register: | |||
name: Утримання | |||
kind: Calculation | |||
calculationTypesPlan: ПланВидівРозрахунку.Утримання | |||
periodicity: Month | |||
actionPeriod: false # ← утримання не має періоду дії | |||
basePeriod: ByRegistrationPeriod # ← база береться за періодом реєстрації | |||
# schedule: не задається — графік не потрібен | |||
dimensions: | |||
- { name: Співробітник, type: "Довідник.Співробітники", baseDimension: true, master: true, denyEmpty: true } | |||
- { name: Підрозділ, type: "Довідник.Підрозділи" } | |||
resources: | |||
- { name: Результат, type: "Число(15,2)" } | |||
- { name: БазаОподаткування, type: "Число(15,2)" } | |||
recalculations: | |||
- name: ПерерахунокУтримань | |||
dimensions: | |||
- { name: Співробітник, registerDimension: Співробітник } | |||
recorders: [Документ.НарахуванняЗарплати] | |||
</syntaxhighlight> | |||
'''Фізична схема (спрощена — немає полів періоду дії):''' | |||
<syntaxhighlight lang="sql"> | |||
CREATE TABLE rg_c_0041 ( | |||
rec_t smallint NOT NULL, | |||
rec_r uuid NOT NULL, | |||
line_no int NOT NULL, | |||
period timestamp(0) NOT NULL, -- період реєстрації | |||
active boolean NOT NULL DEFAULT true, | |||
reversal boolean NOT NULL DEFAULT false, | |||
calc_type_r uuid NOT NULL, | |||
base_begin timestamp(0) NOT NULL, -- ← є, бо basePeriod ≠ None | |||
base_end timestamp(0) NOT NULL, | |||
-- act_begin / act_end ВІДСУТНІ (actionPeriod: false) | |||
d1_r uuid NOT NULL, | |||
d2_r uuid NOT NULL, | |||
r1 numeric(15,2) NOT NULL DEFAULT 0, | |||
r2 numeric(15,2) NOT NULL DEFAULT 0, | |||
CONSTRAINT pk_rg_c_0041 PRIMARY KEY (rec_t, rec_r, line_no) | |||
); | |||
-- Таблиця rg_c_0041_ap НЕ створюється (немає періоду дії → немає витіснення) | |||
CREATE TABLE rg_c_0041_rc1 ( -- ПерерахунокУтримань | |||
rec_t smallint NOT NULL, rec_r uuid NOT NULL, | |||
calc_type_r uuid NOT NULL, d1_r uuid NOT NULL, | |||
src_rec_t smallint NOT NULL, src_rec_r uuid NOT NULL, | |||
created_at timestamp(0) NOT NULL DEFAULT now(), | |||
CONSTRAINT pk_rg_c_0041_rc1 PRIMARY KEY (rec_t, rec_r, calc_type_r, d1_r) | |||
); | |||
</syntaxhighlight> | |||
{{Note|'''Міжпланова база.''' Базові види розрахунку для ПВР <code>Утримання</code> належать до ''іншого'' ПВР — <code>ОсновніНарахування</code>. Це означає, що віртуальна таблиця <code>БазаРозрахунку</code> регістру <code>Утримання</code> має читати записи регістру <code>ОсновніНарахування</code>. '''Вимога ФТ-25 має бути розширена:''' метамодель повинна дозволяти вказати ''регістр-джерело бази''. Це '''відкрите питання В9''' (див. оновлений Додаток Г) — у 1С механізм працює через відповідність ПВР, а не регістрів, що обмежує сценарії. Пропозиція: додати до <code>md_register</code> поле <code>base_register_id</code>.}} | |||
'''Приклад даних:''' | |||
{| class="wikitable" | |||
! line !! calc_type !! period !! base_begin !! base_end !! Співробітник !! r2 (База) !! r1 (Результат) | |||
|- | |||
| 1 || ПДФО || 2026-07-01 || 2026-07-01 || 2026-07-31 || Іваненко || 21 773.91 || 3 919.30 | |||
|- | |||
| 2 || Військовий збір || 2026-07-01 || 2026-07-01 || 2026-07-31 || Іваненко || 21 773.91 || 326.61 | |||
|- | |||
| 3 || Аліменти || 2026-07-01 || 2026-07-01 || 2026-07-31 || Іваненко || 17 528.00 || 4 382.00 | |||
|} | |||
=== Д.8. Наскрізний приклад: проведення видаткової накладної === | |||
'''Документ:''' Видаткова накладна №12 від 05.07.2026, ТОВ «Бета», 30 кг кави за 400 грн (12 000 грн з ПДВ), собівартість 7 000 грн. | |||
<graphviz> | |||
digraph Posting { | |||
rankdir=LR; bgcolor="transparent"; | |||
node [shape=box, style="rounded,filled", fontname="Helvetica", fontsize=9]; | |||
D [label="Документ\nВидаткова накладна №12\n05.07.2026", fillcolor="#fff8e1", shape=note]; | |||
R1 [label="РН ТовариНаСкладах\n(Залишки)\nВитрата: 30 кг / 7 000 грн", fillcolor="#fff3e0"]; | |||
R2 [label="РН Взаєморозрахунки\n(Залишки)\nПрихід: 12 000 грн", fillcolor="#fff3e0"]; | |||
R3 [label="РН Продажі\n(Обороти)\n30 кг / 12 000 / 10 000 / 7 000", fillcolor="#fff3e0"]; | |||
R4 [label="РН ТовариВРезерві\n(Залишки)\nВитрата: 30 кг", fillcolor="#fff3e0"]; | |||
R5 [label="РБ Госпрозрахунковий\n3 проводки на 21 000", fillcolor="#fce4ec"]; | |||
T1 [label="rg_a_0012_tb\nMAXPERIOD: 80 → 50 кг", fillcolor="#ffe0b2", shape=cylinder]; | |||
T2 [label="rg_a_0013_tb\nMAXPERIOD: 0 → +12 000", fillcolor="#ffe0b2", shape=cylinder]; | |||
T3 [label="rg_a_0031_tt\n2026-07: +30 / +12 000", fillcolor="#ffe0b2", shape=cylinder]; | |||
T5 [label="rg_b_0020_tb0/tb2/tt0/tc", fillcolor="#f8bbd0", shape=cylinder]; | |||
D -> R1; D -> R2; D -> R3; D -> R4; D -> R5; | |||
R1 -> T1; R2 -> T2; R3 -> T3; R5 -> T5; | |||
label="ОДНА транзакція БД: усі 5 регістрів + підсумки + прапорець Проведений"; | |||
labelloc=b; fontname="Helvetica"; fontsize=10; | |||
} | |||
</graphviz> | |||
<syntaxhighlight lang="csharp"> | |||
protected override void OnPosting(PostingContext ctx) | |||
{ | |||
// --- 0. Блокування перед контролем залишків --- | |||
var dl = new DataLock(); | |||
var li = dl.Add("РегістрНакопичення.ТовариНаСкладах.Залишки"); | |||
li.Mode = DataLockMode.Exclusive; | |||
li.DataSource = this.Товари.Unload(new[] { "Номенклатура", "Характеристика" }); | |||
li.UseFromDataSource("Номенклатура", "Номенклатура"); | |||
li.UseFromDataSource("Характеристика", "Характеристика"); | |||
li.SetValue("Склад", this.Склад); | |||
dl.Lock(); | |||
// --- 1. РН ТовариНаСкладах: списання --- | |||
var rsGoods = Movements["ТовариНаСкладах"]; rsGoods.Write = true; rsGoods.Clear(); | |||
foreach (var row in this.Товари) { | |||
var m = rsGoods.Add(); | |||
m.Період = this.Дата; | |||
m.MovementType = AccumulationMovementType.Expense; | |||
m.Номенклатура = row.Номенклатура; m.Характеристика = row.Характеристика; | |||
m.Склад = this.Склад; m.Партія = row.Партія; | |||
m.Кількість = row.Кількість; m.Сума = row.Собівартість; | |||
} | |||
// --- 2. РН Взаєморозрахунки: дебіторка зростає --- | |||
var rsAR = Movements["ВзаєморозрахункиЗКонтрагентами"]; rsAR.Write = true; rsAR.Clear(); | |||
var ar = rsAR.Add(); | |||
ar.Період = this.Дата; | |||
ar.MovementType = AccumulationMovementType.Receipt; // Прихід = борг зростає | |||
ar.Організація = this.Організація; ar.Контрагент = this.Контрагент; | |||
ar.Договір = this.Договір; ar.Замовлення = this.ЗамовленняПокупця; | |||
ar.Сума = this.СумаДокумента; ar.СумаВал = this.СумаДокументаВал; | |||
// --- 3. РН Продажі: оборот (без ВидРуху!) --- | |||
var rsSales = Movements["Продажі"]; rsSales.Write = true; rsSales.Clear(); | |||
foreach (var row in this.Товари) { | |||
var s = rsSales.Add(); | |||
s.Період = this.Дата; | |||
s.Номенклатура = row.Номенклатура; s.Контрагент = this.Контрагент; | |||
s.Договір = this.Договір; s.Менеджер = this.Менеджер; | |||
s.Склад = this.Склад; | |||
s.Кількість = row.Кількість; s.Сума = row.Сума; | |||
s.СумаБезПДВ = row.СумаБезПДВ; s.Собівартість = row.Собівартість; | |||
} | |||
// --- 4. РН ТовариВРезерві: зняття резерву --- | |||
if (!this.ЗамовленняПокупця.IsEmpty()) { /* ... Витрата ... */ } | |||
// --- 5. РБ Госпрозрахунковий: проводки --- | |||
var rsAcc = Movements["Госпрозрахунковий"]; rsAcc.Write = true; rsAcc.Clear(); | |||
foreach (var row in this.Товари) { | |||
var e1 = rsAcc.AddAccountingEntry(); // Дт 361 / Кт 702 | |||
e1.Період = this.Дата; | |||
e1.РахунокДт = Accounts["361"]; e1.РахунокКт = Accounts["702"]; | |||
e1.SubcontoDt[ВидиСубконто.Контрагенти] = this.Контрагент; | |||
e1.SubcontoDt[ВидиСубконто.Договори] = this.Договір; | |||
e1.SubcontoKt[ВидиСубконто.Номенклатура] = row.Номенклатура; | |||
e1.Організація = this.Організація; | |||
e1.Сума = row.Сума; e1.КількістьКт = row.Кількість; | |||
var e2 = rsAcc.AddAccountingEntry(); // Дт 702 / Кт 641 | |||
/* ... ПДВ ... */ | |||
var e3 = rsAcc.AddAccountingEntry(); // Дт 902 / Кт 281 | |||
/* ... собівартість ... */ | |||
} | |||
rsGoods.WriteNow(); // примусовий запис до контролю | |||
ControlNegativeBalances(ctx); // прикладна перевірка | |||
} | |||
</syntaxhighlight> | |||
'''Що відбувається у БД (одна транзакція):''' | |||
{| class="wikitable" | |||
! Крок !! Таблиця !! Операція !! Рядків | |||
|- | |||
| 1 || <code>doc_0003</code> || UPDATE posted = true || 1 | |||
|- | |||
| 2 || <code>rg_a_0012</code> (ТовариНаСкладах) || DELETE + INSERT || 1 | |||
|- | |||
| 3 || <code>rg_a_0012_tb</code> || MERGE (MAXPERIOD + періоди > 07.2026) || 2 | |||
|- | |||
| 4 || <code>rg_a_0013</code> (Взаєморозрахунки) || DELETE + INSERT || 1 | |||
|- | |||
| 5 || <code>rg_a_0013_tb</code> || MERGE || 2 | |||
|- | |||
| 6 || <code>rg_a_0031</code> (Продажі) || DELETE + INSERT || 1 | |||
|- | |||
| 7 || <code>rg_a_0031_tt</code> || MERGE (тільки період 2026-07) || 1 | |||
|- | |||
| 8 || <code>rg_a_0031_ag1</code> || MERGE (realtime-агрегат) || 1 | |||
|- | |||
| 9 || <code>rg_a_0014</code> (Резерв) || DELETE + INSERT || 1 | |||
|- | |||
| 10 || <code>rg_b_0020</code> (проводки) || DELETE + INSERT || 3 | |||
|- | |||
| 11 || <code>rg_b_0020_tb0</code> || MERGE || 10 | |||
|- | |||
| 12 || <code>rg_b_0020_tb1/tb2</code> || MERGE || 8 | |||
|- | |||
| 13 || <code>rg_b_0020_tt0..tt2</code> || MERGE || 12 | |||
|- | |||
| 14 || <code>rg_b_0020_tc</code> || MERGE || 3 | |||
|- | |||
| colspan="3" | '''Разом''' || '''≈ 47 рядків, 1 COMMIT''' | |||
|} | |||
{{Note|'''Спостереження для НФВ-04.''' Один рядок товару в накладній породжує ~47 модифікацій рядків у 14 таблицях. Для накладної зі 100 рядків це ~2 000–4 000 модифікацій. Саме тут — основне навантаження проведення, і саме тому РБ (кроки 10–14) дає ~70 % вартості транзакції. Це аргумент на користь MVP без РБ (розділ 14) і предмет вимірювання в НТ-03.}} | |||
=== Д.9. Наскрізний приклад: розрахунок зарплати === | |||
<pre> | |||
КРОК 1. Документ «Нарахування зарплати» за липень 2026, Іваненко. | |||
Записуємо рухи в РР ОсновніНарахування (Результат = 0). | |||
КРОК 2. Платформа автоматично будує фактичні періоди дії (rg_c_0040_ap): | |||
Оклад → [01.07–09.07], [23.07–31.07] | |||
Відпустка → [10.07–13.07] | |||
Лікарняний → [14.07–22.07] | |||
КРОК 3. Розрахунок «первинних» видів (без бази) — Оклад. | |||
Запит до ДаніГрафіка: | |||
НормаДнів = 23 (робочих днів у липні за П'ятиденкою) | |||
ВідпрацьованоДнів = 13 (робочі дні у фактичних періодах дії) | |||
Результат = 18 000 × 13 / 23 = 10 173,91 | |||
→ UPDATE rg_c_0040 SET r1 = 10173.91, r2 = 13, r3 = 23 WHERE line_no = 1 | |||
КРОК 4. Розрахунок видів із базою — Відпустка, Лікарняний. | |||
Запит до БазаРозрахунку (базовий період 01.01–30.06, база = Оклад+Премія): | |||
Заробіток за 6 міс. = 115 560,00 | |||
Календарних днів = 181 | |||
Середньоденний = 638,45 | |||
Відпустка: 638,45 × 4 дні (10–13.07) = 2 553,80 | |||
Лікарняний: 638,45 × 9 днів × 100 % = 5 746,05 | |||
→ UPDATE rg_c_0040 SET r1 = ... WHERE line_no IN (2, 3) | |||
КРОК 5. Записуємо рухи в РР Утримання (базовий період = період реєстрації, липень). | |||
База ПДФО = 10 173,91 + 2 553,80 + 5 746,05 = 18 473,76 | |||
ПДФО = 18 473,76 × 18 % = 3 325,28 | |||
ВЗ = 18 473,76 × 1,5 % = 277,11 | |||
КРОК 6. Проведення документа → рухи в: | |||
РН ВитратиЗаСтаттями (Обороти): Стаття «ЗП і нарахування» = 18 473,76 | |||
РБ Госпрозрахунковий: Дт 92 / Кт 661 = 18 473,76 | |||
Дт 661 / Кт 641.ПДФО = 3 325,28 | |||
Дт 661 / Кт 642.ВЗ = 277,11 | |||
КРОК 7. Через тиждень бухгалтер змінює Оклад Іваненка за червень (заднім числом). | |||
→ Платформа реєструє в rg_c_0040_rc1 (ПерерахунокЗаБазою): | |||
(Реєстратор = НарахуванняЗП липня, ВидРозрахунку = Відпустка, Співробітник = Іваненко) | |||
(Реєстратор = НарахуванняЗП липня, ВидРозрахунку = Лікарняний, Співробітник = Іваненко) | |||
→ Звіт «Документи до перерахунку» показує липневий документ. | |||
→ Бухгалтер перепроводить → база перераховується → записи перерахунку очищаються. | |||
</pre> | |||
=== Д.10. Антипатерни проєктування регістрів === | |||
{| class="wikitable" | |||
! ID !! Антипатерн !! Чому погано !! Як правильно | |||
|- | |||
| '''А-1''' || Дата як '''вимірювання''' у РН (замість стандартного <code>Період</code>) || Таблиця підсумків множиться на кількість дат і зростає нескінченно; віртуальні таблиці <code>Залишки</code>/<code>Обороти</code> ігнорують це вимірювання і дають безглузді результати || Використовувати стандартний реквізит <code>Період</code>. Виняток — календарі (Д.3.4), де це РВ, а не РН | |||
|- | |||
| '''А-2''' || РН «Залишки» там, де потрібна лише історія значення || Надлишкові таблиці підсумків, кумулятивні оновлення, вид руху без сенсу || РВ періодичний | |||
|- | |||
| '''А-3''' || РН «Залишки» там, де залишок безглуздий (Продажі, Витрати) || Удвічі більший обсяг підсумків, кумулятивні MERGE на всі майбутні періоди || РН «Обороти» + агрегати (Д.5.1) | |||
|- | |||
| '''А-4''' || Реквізит документа продубльовано у вимірювання «щоб фільтрувати у звіті» || Кардинальність підсумків × N; типовий випадок — Менеджер/Валюта/Коментар || Реквізит регістру + з'єднання з документом у звіті; або окремий регістр «Обороти» | |||
|- | |||
| '''А-5''' || > 8 вимірювань в одному РН || Таблиця підсумків стає '''більшою''' за таблицю рухів; проведення сповільнюється в рази || Розділити на регістри за призначенням; частину аналітики — в «Обороти» з агрегатами | |||
|- | |||
| '''А-6''' || Незалежний РВ «у межах секунди» як журнал подій || Два записи в ту саму секунду → другий '''мовчки замістить''' перший; втрата даних || Підпорядкований РВ (реєстратор у ключі) або додати вимірювання-дискримінатор | |||
|- | |||
| '''А-7''' || Ресурс типу <code>Рядок</code>/<code>Посилання</code> у РН || Підсумовування неможливе; підсумки не побудуються || Реквізит (не агрегується) або вимірювання (якщо це розріз) | |||
|- | |||
| '''А-8''' || Прямий <code>UPDATE</code> таблиці підсумків із прикладного коду || Розсинхронізація підсумків і рухів; діагностика — тижні || Тільки через набори записів. Заборона на рівні прав БД (розділ 12.2) | |||
|- | |||
| '''А-9''' || Один «універсальний» регістр із вимірюванням <code>ВидОбліку</code> (БУ/ПУ/УО) замість трьох || Втричі більша таблиця; конкуренція за блокування між незалежними обліками; неможливо окремо перерахувати підсумки || Окремі регістри. Виняток — РБ <code>ПодатковийОблік</code> (Д.6.2), де ВидРізниці — це справді розріз одного обліку | |||
|- | |||
| '''А-10''' || Функціонально залежне поле як вимірювання (Валюта при БанківськомуРахунку) || Надлишковість; ризик неузгоджених даних; зайвий розмір ключа підсумків || З'єднання з довідником у запиті (Д.4.4) | |||
|- | |||
| '''А-11''' || РБ там, де достатньо РН || Замість 1 таблиці — 10; ~70 % вартості проведення (Д.8); складність субконто без потреби || РН. РБ — лише коли потрібні план рахунків, подвійний запис і кореспонденції | |||
|- | |||
| '''А-12''' || Вимірювання з <code>nullable</code> без потреби || Порожнє посилання — окреме значення ключа; підсумки «розмазуються» на два рядки замість одного || <code>denyEmpty: true</code> скрізь, де порожнє значення не має сенсу | |||
|- | |||
| '''А-13''' || Контроль залишків '''до''' запису рухів || Класична гонитва: два сеанси проходять контроль і обидва списують у мінус || Спершу <code>DataLock</code> → <code>WriteNow()</code> → потім контроль (Д.8, ФТ-Т-12) | |||
|- | |||
| '''А-14''' || <code>periodicity: WithinSecond</code> «про всяк випадок» скрізь || Для РВ — неможливість замістити запис за день; для РН — марна точність, більші індекси || Обирати мінімально достатню: день для цін/курсів/виписок, секунда — для складських рухів | |||
|} | |||
=== Д.11. Чек-лист рев'ю нового регістру === | |||
<pre> | |||
□ Тип регістру обґрунтований за деревом Д.1 | |||
□ Кожне вимірювання використовується у фільтрі АБО групуванні звітів | |||
□ Кожен ресурс має сенс при підсумовуванні | |||
□ Немає полів з антипатернів А-1, А-4, А-7, А-10, А-12 | |||
□ Оцінка кардинальності підсумків ≤ 10^8 (калькулятор конструктора, ФТ-К-03) | |||
□ Для вимірювань, де порожнє значення безглузде, стоїть denyEmpty | |||
□ Ведучі (master) вимірювання визначені — інакше «висячі» записи при видаленні об'єктів | |||
□ Склад реєстраторів повний; зайвих типів документів немає | |||
□ Угода про знак / вид руху зафіксована в методологічній документації | |||
□ Періодичність мінімально достатня (А-14) | |||
□ Для РН «Обороти» з >4 вимірюваннями визначено ≥1 агрегат | |||
□ Для РБ: балансові/небалансові вимірювання та ресурси розставлені свідомо | |||
□ Для РР: витісняючі та базові види розрахунку в ПВР заповнені; перерахунки визначені | |||
□ Партиціонування ввімкнене, якщо очікується >100 млн записів | |||
□ Написано тест на проведення + скасування + перерахунок підсумків | |||
</pre> | |||
---- | ---- | ||
''Кінець документа. Версія 1. | ''Кінець документа. Версія 1.1. Підлягає узгодженню з архітектором платформи K2 ERP до затвердження.'' | ||