177 Commits

Author SHA1 Message Date
lizerk
5946173a07 feat(finance): add payroll point source details 2026-07-21 13:33:31 +03:00
lizerk
df2377431d feat: expand documents tasks and procurement workflows 2026-07-17 14:09:06 +03:00
lizerk
786987efe5 Stabilize Celery background jobs 2026-07-16 13:59:50 +03:00
lizerk
01490aa20b Improve employee stats and task card text 2026-07-12 21:22:55 +03:00
lizerk
042952b7a9 feat: link tasks with workplace entities 2026-07-06 15:24:37 +03:00
lizerk
dc35680156 feat: add guest module backend 2026-06-20 12:20:52 +03:00
lizerk
32500e3037 chore: checkpoint current project changes 2026-06-20 10:47:00 +03:00
lizerk
b4de4aa449 chore: prepare EUSRR for public portfolio 2026-06-17 16:21:38 +03:00
lizerk
9cd21a1b1e procurement: add item comments 2026-05-22 14:57:45 +03:00
lizerk
92fb845b70 Fix birthday event sync lifecycle 2026-05-14 16:32:27 +03:00
lizerk
da0cadc50c Handle existing LDAP users during Django sync 2026-05-14 15:06:47 +03:00
lizerk
f0024f7a09 Add attendance aliases and weekly summary 2026-05-03 23:02:33 +03:00
lizerk
3a20c3d86a Normalize personnel events and attendance state 2026-04-29 09:54:11 +03:00
lizerk
1bf3fac8b5 fix migration 2026-04-22 14:18:58 +03:00
lizerk
49002d50a0 Prevent duplicate request employee actions 2026-04-22 14:10:55 +03:00
lizerk
625468090b Add persisted LogStorm attendance integration 2026-04-22 10:21:44 +03:00
lizerk
5700b53f13 feat: add department calendar bindings and cleanup dept permissions 2026-04-16 15:18:43 +03:00
lizerk
64eaecc06e makemigrations 2026-04-16 13:29:05 +03:00
lizerk
beb4b8b86b refactor(departments): unify department feed and discussion flows 2026-04-14 16:14:52 +03:00
lizerk
7a3ebbfdff fix(api): preserve role-only department members 2026-04-14 02:24:14 +03:00
lizerk
8d22156b36 feat(admin): add department role ldap sync action 2026-04-14 01:49:30 +03:00
lizerk
2574b47923 fix(api): enforce single active department membership 2026-04-14 01:18:32 +03:00
lizerk
2d00699831 fix(ldap): nest department role groups into department group 2026-04-14 01:07:13 +03:00
lizerk
274e5767c9 refactor(departments): label role-only members 2026-04-14 00:35:51 +03:00
lizerk
5ab638892b chore: checkpoint workspace changes 2026-04-13 16:00:53 +03:00
lizerk
097a3015e8 fix(profile): stabilize directory login and expand ldap coverage 2026-04-12 04:13:32 +03:00
lizerk
b98a82176c test(ldap): add live integration coverage and fix sync paths 2026-04-12 03:51:52 +03:00
lizerk
81b8d29b38 Refactor department LDAP sync around canonical service flows 2026-04-10 20:54:09 +03:00
lizerk
6ee32111db chore: configure vscode flake8 and commit lint cleanup 2026-03-31 19:17:56 +03:00
lizerk
2815efe069 chore: finalize backend lint cleanup 2026-03-31 17:53:29 +03:00
lizerk
9edb44502a Harden backend warnings and lint policy 2026-03-31 17:19:59 +03:00
lizerk
3f59f8ebb9 Add backend OpenAPI docs and clean test suite 2026-03-31 17:05:31 +03:00
lizerk
f88d90230b refactor: clean architecture, align tests to current API contracts, all tests green [deploy-ready] 2026-03-30 04:27:18 +03:00
lizerk
825726e0f0 chore: commit remaining backend and frontend changes, remove legacy test, add missing migrations 2026-03-30 02:17:28 +03:00
lizerk
540e295ef4 feat: Fix LDAP DN bugs + add password management in admin
BREAKING CHANGES:
- Department.head автоматически очищается при увольнении руководителя
- LDAP managedBy атрибут очищается при увольнении

Fixes:
- DN не перемещался при восстановлении сотрудника (Dismissed → Users)
- DN не перемещался при увольнении сотрудника без отделов
- Ошибка при увольнении из множественных отделов (двойной modify_dn)
- Неправильные URL patterns для LDAP моделей в админке
- Двойное кодирование DN в редиректе смены пароля

Features:
- Добавлен метод _ensure_ldap_dn_location для гарантированного перемещения DN
- Добавлена проверка already_there в sync_department_member_to_ldap
- Управление паролями LDAP пользователей через админку:
  * Кнопка смены пароля в карточке пользователя
  * Массовое действие смены пароля
  * Автосинхронизация с Django password hash
- Автоочистка Department.head и LDAP managedBy при увольнении руководителя
- Добавлены методы set_password() и change_password() в LdapUser

Changed:
- Переписан сигнал sync_department_member_to_ldap с реальными методами
- Исправлены URL patterns: ldap_* → employees_*
2026-03-23 20:32:39 +03:00
lizerk
1a3d533c1d админка + 2026-03-22 13:55:26 +03:00
lizerk
4c5ea98743 админка+ 2026-03-20 14:44:41 +03:00
lizerk
55d0bcf906 Feature: Add validation warnings for missing fields in sync actions
Both LDAP→Django and Django→LDAP sync actions now check for missing
required fields (name, email, employeeNumber) and display warnings
before syncing. Shows up to 10 warnings per action.
2026-03-20 02:35:29 +03:00
lizerk
7a770165f9 Fix: Correct get_action_choices signature (use BLANK_CHOICE_DASH) 2026-03-20 02:31:11 +03:00
lizerk
130dafc5a2 Fix: Replace delete_selected with LDAP-safe custom action
Django's delete_selected passes queryset with dn__in filter that
ldapdb doesn't support. Custom delete_selected_ldap reads DNs from
POST and deletes objects one by one. Also hides standard delete_selected
from action choices.
2026-03-20 02:20:42 +03:00
lizerk
6050cd9d26 Fix: Handle ldapdb unsupported dn__in lookup in admin delete
- Override get_deleted_objects() in LdapUserAdmin to avoid dn__in
  queryset that ldapdb doesn't support
- Also fix phone_number UNIQUE constraint in LDAP auth backend
2026-03-20 02:18:39 +03:00
lizerk
63a96a0122 Fix: Render thumbnailPhoto as image preview in LdapUser admin
Binary thumbnail_photo data caused 500 error when Django admin tried
to render it as a text input. Now displayed as base64 inline image
preview in a readonly field.
2026-03-20 02:03:09 +03:00
lizerk
efc649aeae Feat: Implement department move and position group sync in UserService
- Department move: set ldap_user.base_dn via ModifyDnMixin (replaces DirectoryService)
- Position sync: assign/unassign POS-groups via PositionService on position change
- DB update: position_id saved to Employee in atomic block
- Best-effort: position sync errors logged but don't interrupt update
2026-03-20 01:45:25 +03:00
lizerk
0ba594d317 Style: Fix PEP8 whitespace and line-length in orm_models.py 2026-03-20 01:37:05 +03:00
lizerk
9bc4d70a27 Cleanup: Remove dead position sync code from user_service
- Removed 30 lines of commented-out DirectoryService code
- Removed unused Position import
- Removed unused old_pos/new_pos/pos_in_payload variables
- Fixed stale comment about displayName auto-update in save()
- Position sync remains as a 3-line TODO comment
2026-03-20 01:26:04 +03:00
lizerk
999ecaaadf Fix: Handle RDN rename in ModifyDnMixin.save()
AD forbids modifying RDN (CN/OU) via modify_s - only via rename.
ModifyDnMixin now:
1. Tracks _original_rdn_value (cn/ou) from __init__/from_db
2. On save(), if RDN changed: reverts to old value → save() → modify_dn
3. This fixes NOT_ALLOWED_ON_RDN for both admin and API edits

Simplified user_service: just set ldap_user.cn = new_cn and call save().
The mixin handles the rest automatically.
2026-03-20 01:21:03 +03:00
lizerk
afd66662ce Fix: Don't modify CN via save(), use modify_dn only
AD forbids modifying RDN (CN) through modify_s - must use rename.
- Removed LdapUser.save() override that synced cn→displayName
  (this caused cn to be in modlist → NOT_ALLOWED_ON_RDN error)
- user_service now sets displayName explicitly instead of cn
- CN is only changed via conn.modify_dn() after save()
- Flow: set displayName + other attrs → save() → modify_dn(cn)
2026-03-20 01:11:44 +03:00
lizerk
7b7e071df1 Fix: Auto-sync displayName with cn in LdapUser.save()
- Added save() override in LdapUser to auto-update displayName from cn
- Fixed user_service to set ldap_user.cn BEFORE save() (not after)
- This ensures displayName is synced when givenName/sn change
- Previously displayName wasn't updated because cn was set after save()
- Now: set cn → save() → displayName auto-synced → modify_dn()
2026-03-20 01:09:24 +03:00
lizerk
11e0714411 Fix: Override build_rdn() to fix ldapdb 1.5.1 bug
ldapdb's build_rdn() checks field.primary_key AND field.db_column,
but the 'dn' field has primary_key=True and db_column=None,
while 'cn'/'ou' fields have db_column set but primary_key=False.
No field satisfies both conditions → save() always raises
'Could not build Distinguished Name'.

Fix: ModifyDnMixin.build_rdn() extracts RDN from existing DN
for loaded objects, and builds from rdn_attributes for new ones.
2026-03-20 00:55:56 +03:00
lizerk
c8ae3b3c7b Fix: Use get_ldap_str() in employees admin sync actions
- Added get_ldap_str() import to 3 admin actions
- Updated sync_from_django_to_ldap to safely compare LDAP fields
- Updated sync_from_ldap_to_django to safely extract LDAP values
- Updated show_sync_diff to safely compare LDAP vs Django data
- Prevents 'list' object errors in all admin LDAP sync operations
2026-03-20 00:42:15 +03:00