1. Чому роздрібний реплениш — хороший стрес-тест для ERP
ERP-демо красиві. Реальні операції — ні.
Роздрібне поповнення запасів — один із перших процесів, де ERP-системи перестають бути «формами і документами» і стають рушіями прийняття рішень. Він змушує платформу обробляти:
- дані продажів у часі
- коригування прогнозу (сезонність, промо)
- обмеження постачальників (lead time, MOQ, кратність пакування)
- логіку кількох складів
- автоматичну генерацію документів
- процеси узгодження людьми
- пояснюваність рішень системи
Це робить його ідеальним кейсом для порівняння ERPNext і MyCompany.
Мета цієї статті — не маркетинг. Мета — дати відповідь на практичне питання рівня CTO:
Скільки інженерних зусиль потрібно для реалізації реального роздрібного процесу?
І так — ми будемо рахувати рядки коду.
2. Бізнес-специфікація (практична, не вигадана)
Сценарій
- 15 роздрібних магазинів
- 1 центральний склад
- 4 основні постачальники
- щоденні продажі через POS
- щотижневі промоакції
- змішана стратегія: трансфер / закупівля
Вимоги
Щоночі (02:00):
Для кожного SKU у кожному магазині:
- Розрахувати середні щоденні продажі (останні 28 днів)
- Скоригувати на промо-коефіцієнт (якщо активний)
- Помножити на lead time постачальника
- Відняти:
- поточний залишок
- вхідні замовлення постачальнику
- вхідні трансфери
- Застосувати:
- MOQ (мінімальна кількість замовлення)
- округлення до кратності пакування
- За наявності дефіциту:
- обрати трансфер із центрального складу (якщо є)
- інакше запропонувати замовлення постачальнику
- Створити чернетки документів
- Записати пояснення (чому саме така кількість)
- Надати UI-екран:
- перегляд пропозицій
- затвердження
- відхилення
- перерахунок
Приклад пояснюваності:
«Розрахункова потреба: 94 од. (ADS 4.7 × 14 днів − 32 залишок − 40 вхідних). Округлено до 96 через пакування по 12».
3. Реалізація на ERPNext
ERPNext побудований на фреймворку Frappe (Python-бекенд, JavaScript-фронтенд).
Платформа вже підтримує:
- залишки
- рівні перезамовлення
- матеріальні заявки (Material Requests)
- замовлення постачальникам (Purchase Orders)
- трансфери
Але щойно додаються промо, правила для кількох магазинів, MOQ і кратність пакування, логіка «купувати чи перемістити» та пояснюваність — вбудований реордер швидко закінчується.
3.1 Архітектурний підхід
Типова реалізація:
- кастомний DocType: Replenishment Rule
- завдання за розкладом на Python
- кастомний звіт на серверній стороні
- клієнтські дії в UI
- хуки для автоматизації та зв'язки модулів
3.2 Розширення моделі даних
{
"doctype": "Replenishment Rule",
"fields": [
{ "fieldname": "item", "fieldtype": "Link", "options": "Item" },
{ "fieldname": "warehouse", "fieldtype": "Link", "options": "Warehouse" },
{ "fieldname": "lead_time_days", "fieldtype": "Int" },
{ "fieldname": "promotion_factor", "fieldtype": "Float" },
{ "fieldname": "moq", "fieldtype": "Int" },
{ "fieldname": "pack_size", "fieldtype": "Int" }
]
}
Типовий обсяг: ~120–180 рядків коду разом із метаданими.
3.3 Завдання за розкладом (основна логіка)
# app/replenishment/scheduler.py
import frappe
def nightly_replenishment():
rules = frappe.get_all("Replenishment Rule", fields="*")
for rule in rules:
avg_sales = calculate_average_sales(rule.item, rule.warehouse)
adjusted_sales = avg_sales * (rule.promotion_factor or 1)
required_qty = adjusted_sales * rule.lead_time_days
current_stock = get_stock(rule.item, rule.warehouse)
incoming = get_incoming(rule.item, rule.warehouse)
deficit = required_qty - current_stock - incoming
if deficit > 0:
rounded_qty = round_to_pack(deficit, rule.pack_size, rule.moq)
create_suggestion(rule, rounded_qty)
Допоміжні функції (запити залишків, SQL-джоїни, звіти, округлення, створення документів, ідемпотентність, логування) додають ще ~180–300 рядків.
3.4 Звіт про пропозиції
SELECT
item,
warehouse,
suggested_qty,
explanation
FROM `tabReplenishment Suggestion`
WHERE status = 'Draft';
Типовий обсяг: ~70–120 рядків.
3.5 Клієнтська дія «затвердити»
frappe.ui.form.on("Replenishment Suggestion", {
approve(frm) {
frappe.call({
method: "app.replenishment.approve",
args: { name: frm.doc.name },
callback() {
frm.reload_doc();
}
});
}
});
Типовий обсяг: ~40–80 рядків.
3.6 Підсумок за обсягом коду ERPNext
| Компонент | LOC (приблизно) |
|---|---|
| Основна логіка Python | 250–400 |
| Звіти | 70–120 |
| Клієнтський JS | 40–80 |
| JSON-метадані | 120–200 |
| Усього (LOC у репозиторії) | 480–800 |
Лише бізнес-логіка (LOC): ~320–600
4. Реалізація на MyCompany
MyCompany побудована на lsFusion — декларативній платформі бізнес-логіки.
Замість процедурних завдань ви описуєте:
- властивості даних
- обчислювані вирази
- дії
- форми
4.1 Визначення даних
CLASS Item;
CLASS Warehouse;
CLASS Rule;
item = DATA Item (Rule);
warehouse = DATA Warehouse (Rule);
leadTime = DATA INTEGER (Rule);
promotionFactor = DATA NUMERIC[10,2] (Rule);
moq = DATA INTEGER (Rule);
packSize = DATA INTEGER (Rule);
4.2 Обчислювані властивості
avgSales(Item i, Warehouse w) =
SUM quantity(Sale s)
WHERE s.item = i
AND s.warehouse = w
AND s.date >= currentDate() - 28
/ 28;
requiredQty(Rule r) =
avgSales(item(r), warehouse(r))
* promotionFactor(r)
* leadTime(r);
deficit(Rule r) =
requiredQty(r)
- currentStock(item(r), warehouse(r))
- incoming(item(r), warehouse(r));
4.3 Логіка округлення
roundedQty(Rule r) =
MAX(
moq(r),
CEIL(deficit(r) / packSize(r)) * packSize(r)
)
IF deficit(r) > 0;
4.4 Дія
generateSuggestions() {
FOR r IN Rule DO {
IF deficit(r) > 0 THEN
NEW Suggestion {
rule = r;
quantity = roundedQty(r);
explanation =
"ADS × LT – stock – incoming = " + deficit(r);
};
}
}
4.5 UI
FORM suggestions
OBJECTS s = Suggestion
PROPERTIES s.rule, s.quantity, s.explanation;
4.6 Підсумок за обсягом коду MyCompany
| Компонент | LOC (приблизно) |
|---|---|
| Визначення даних | ~25 |
| Бізнес-логіка (властивості) | ~60–90 |
| Округлення | ~10 |
| Дії | ~30–40 |
| UI | ~20–30 |
| Загалом | ~145–195 |
5. Порівняння поруч
| Метрика | ERPNext | MyCompany |
|---|---|---|
| Парадигма логіки | Процедурна (Python + зв'язки) | Декларативна (властивості + дії) |
| Планування завдань | Явне завдання за розкладом + зв'язки | Модель, орієнтована на дії (зазвичай менше зв'язок) |
| Збірка UI | Часто потребує клієнтських скриптів | Декларативні форми |
| LOC (лише логіка) | ~320–600 | ~100–150 |
| LOC (увесь репозиторій) | ~480–800 | ~145–200 |
6. Архітектурні наслідки
Розширення ERPNext часто розмазують логіку між Python, JavaScript і метаданими. MyCompany, як правило, централізує бізнес-правила як декларативну модель.
Більше рядків коду зазвичай означає:
- вище когнітивне навантаження
- більше інтеграційних «зв'язок»
- більше поверхні для регресій
Це автоматично не робить одну платформу «кращою». Це говорить про те, яку ціну змін ви купуєте.
7. Економіка розробки з ШІ
Є й сучасний вимір, який не можна ігнорувати: обсяг і структура коду впливають на те, наскільки ефективно ШІ-інструменти допомагають, рефакторять і генерують розширення.
- Вартість контексту: більше файлів і шарів-зв'язок зазвичай збільшують обсяг контексту для коректної допомоги ШІ — і піднімають вартість інференсу.
- Вартість верифікації: фрагментована процедурна логіка часто потребує більше тестової обв'язки і перевірок під час виконання.
- Вартість рефакторингу: більше точок зв'язку ускладнює безпечний автоматичний рефакторинг (і для людей, і для ШІ).
- Вартість фіксації знань: розрізнена логіка збільшує обсяг документації, зусилля на промптинг і час супервізії.
Інакше кажучи, LOC — це вже не лише проксі для вартості підтримки людьми. Це дедалі більше проксі для вартості еволюції з ШІ.
8. Коли яка платформа виграє
Обирайте ERPNext, якщо:
- потрібен широкий ERP швидко (облік + закупівлі + залишки) і хочеться велику екосистему;
- правила поповнення відносно стандартні і рідко змінюються;
- надаєте перевагу Python і звичному для спільноти рішенню, а не парадигмі «спочатку модель».
Обирайте MyCompany, якщо:
- конкурентна перевага — у кастомних бізнес-правилах та швидких ітераціях;
- правила часто змінюються, і хочеться, щоб система залишалася пояснюваною;
- хочеться ERP як конструктор: модель, яку ви розвиваєте, а не продукт, який ви патчите.
9. Висновок
Підрахунок рядків коду — не все. Але у складних бізнес-процесах LOC корелює з когнітивним навантаженням, а воно — з вартістю довгострокової підтримки.
У цьому сценарії поповнення:
- ERPNext зазвичай вимагає ~у 2–4 рази більше кастомного коду;
- MyCompany часто виражає ті самі правила на меншій і більш централізованій поверхні логіки.
Додаток A. Симуляція git diff (як чесно це виміряти)
Якщо хочете, щоб порівняння «скільки рядків» було захищеним, вимірюйте його реальним diff репозиторію і LOC-інструментом (наприклад, cloc) із прозорими правилами включення. Нижче — симульований, але структурно реалістичний приклад.
ERPNext (застосунок Frappe) — симульований diff
$ git diff --stat
app/replenishment/hooks.py | 34 +++++++
app/replenishment/scheduler.py | 140 +++++++++++++++++++++
app/replenishment/api.py | 88 +++++++++++++
app/replenishment/utils/sales.py | 74 ++++++++++++
app/replenishment/utils/stock.py | 92 +++++++++++++++
app/replenishment/utils/rounding.py | 38 ++++++++
app/replenishment/doctype/replenishment_rule/replenishment_rule.json | 165 +++++++++++++++++++++++++
app/replenishment/doctype/replenishment_suggestion/replenishment_suggestion.json | 142 +++++++++++++++++++++++
app/replenishment/report/replenishment_suggestions/replenishment_suggestions.py | 76 +++++++++++++
app/replenishment/report/replenishment_suggestions/replenishment_suggestions.js | 58 ++++++++++
app/replenishment/public/js/replenishment_suggestion_form.js | 62 +++++++++++
12 files changed, 971 insertions(+)
Типова інтерпретація:
- LOC лише логіки = scheduler + utils + API + Python звітів + мінімум JS (~320–600).
- Загальний LOC репозиторію включає JSON-метадані (~480–900+ залежно від UI/фікстур звітів).
MyCompany (модуль lsFusion) — симульований diff
$ git diff --stat
modules/replenishment/Replenishment.lsf | 182 +++++++++++++++++++++++++++
modules/replenishment/ReplenishmentForms.lsf | 54 ++++++++
modules/replenishment/ReplenishmentDocs.lsf | 31 ++++
3 files changed, 267 insertions(+)
Дисципліна, яка робить порівняння LOC осмисленими: одна й та сама специфікація, один і той самий метод вимірювання, прозорі правила включення.
Швидкий зворотний зв'язок
Короткий сигнал допомагає нам обирати теми для наступних матеріалів.
Схожі матеріали
Якщо вас хвилюють практичні наслідки архітектури ERP та зменшення залежності від підрядників — більше матеріалів на DevLab Blog: