232 lines
9.2 KiB
Python
232 lines
9.2 KiB
Python
from django.utils.translation import gettext as _, gettext_lazy
|
|
|
|
from .form_builder import (
|
|
LOCKED_SECTION_RULES,
|
|
OFFBOARDING_PAGE_ORDER,
|
|
ensure_form_conditional_rule_configs,
|
|
get_section_definitions,
|
|
)
|
|
|
|
ONBOARDING_GROUPS = {
|
|
'business-card-box': ['business_card_name', 'business_card_title', 'business_card_email', 'business_card_phone'],
|
|
'employment-end-box': ['employment_end_date'],
|
|
'group-mailboxes-box': ['group_mailboxes'],
|
|
'extra-hardware-box': ['additional_hardware_multi', 'additional_hardware_other'],
|
|
'extra-software-box': ['additional_software_multi', 'additional_software'],
|
|
'extra-access-box': ['additional_access_text'],
|
|
'successor-box': ['successor_name', 'inherit_phone_number_choice'],
|
|
}
|
|
|
|
ONBOARDING_INLINE_CHECKS = {'order_business_cards', 'agreement_confirm'}
|
|
ONBOARDING_CHECKBOX_LISTS = {
|
|
'needed_devices_multi',
|
|
'additional_hardware_multi',
|
|
'needed_software_multi',
|
|
'additional_software_multi',
|
|
'needed_accesses_multi',
|
|
'needed_workspace_groups_multi',
|
|
'needed_resources_multi',
|
|
}
|
|
|
|
CONDITIONAL_RULE_OPERATOR_CHOICES = [
|
|
('checked', _('ist aktiviert')),
|
|
('equals', _('ist gleich')),
|
|
('not_equals', _('ist nicht gleich')),
|
|
]
|
|
|
|
ONBOARDING_SECTION_META = {
|
|
'stammdaten': {'title': gettext_lazy('Stammdaten'), 'subtitle': gettext_lazy('Person, Rolle, Abteilung')},
|
|
'vertrag': {'title': gettext_lazy('Vertrag'), 'subtitle': gettext_lazy('Beschäftigung und Termine')},
|
|
'itsetup': {'title': gettext_lazy('IT-Setup'), 'subtitle': gettext_lazy('Geräte, Software und Zugänge')},
|
|
'abschluss': {'title': gettext_lazy('Abschluss'), 'subtitle': gettext_lazy('Notizen und Freigabe')},
|
|
}
|
|
|
|
OFFBOARDING_SECTION_META = {
|
|
'mitarbeitende': {'title': gettext_lazy('Mitarbeitende'), 'subtitle': gettext_lazy('Person, Rolle und Bereich')},
|
|
'austritt': {'title': gettext_lazy('Austritt'), 'subtitle': gettext_lazy('Letzter Arbeitstag')},
|
|
'abschluss': {'title': gettext_lazy('Abschluss'), 'subtitle': gettext_lazy('Hinweise und Abschlussnotizen')},
|
|
}
|
|
|
|
|
|
def field_rule_summary(*, is_visible: bool, is_required, locked: bool) -> str:
|
|
if locked:
|
|
return str(_('Fixes Kernfeld, immer sichtbar.'))
|
|
if not is_visible:
|
|
return str(_('Ausgeblendet, erscheint nicht im Formular.'))
|
|
if is_required is True:
|
|
return str(_('Sichtbar und als Pflichtfeld markiert.'))
|
|
if is_required is False:
|
|
return str(_('Sichtbar und optional.'))
|
|
return str(_('Sichtbar mit Standardverhalten.'))
|
|
|
|
|
|
def conditional_clause_sentence(clause: dict, field_label_map: dict[str, str]) -> str:
|
|
field_name = (clause.get('field') or '').strip()
|
|
operator = (clause.get('operator') or '').strip()
|
|
value = clause.get('value')
|
|
if not field_name or not operator:
|
|
return ''
|
|
field_label = field_label_map.get(field_name, field_name)
|
|
if operator == 'checked':
|
|
return _('%(field)s ist aktiviert') % {'field': field_label}
|
|
if operator == 'equals':
|
|
if value not in (None, ''):
|
|
return _('%(field)s ist gleich %(value)s') % {'field': field_label, 'value': value}
|
|
return _('%(field)s ist gleich') % {'field': field_label}
|
|
if operator == 'not_equals':
|
|
if value not in (None, ''):
|
|
return _('%(field)s ist nicht gleich %(value)s') % {'field': field_label, 'value': value}
|
|
return _('%(field)s ist nicht gleich') % {'field': field_label}
|
|
return _('%(field)s erfüllt die Bedingung') % {'field': field_label}
|
|
|
|
|
|
def conditional_rule_summary(clauses: list[dict], field_label_map: dict[str, str]) -> str:
|
|
active_clauses = [clause for clause in clauses if clause.get('field') and clause.get('operator')]
|
|
if not active_clauses:
|
|
return str(_('Immer sichtbar.'))
|
|
parts = [str(conditional_clause_sentence(clause, field_label_map)) for clause in active_clauses]
|
|
return str(_('Sichtbar, wenn %(conditions)s.') % {'conditions': ' und '.join(parts)})
|
|
|
|
|
|
def normalized_conditional_rule_payload(form_type: str) -> dict[str, dict]:
|
|
configs = ensure_form_conditional_rule_configs(form_type)
|
|
payload = {}
|
|
for target_key, cfg in configs.items():
|
|
if not cfg.is_active:
|
|
continue
|
|
clauses = [clause for clause in (cfg.clauses or []) if clause.get('field') and clause.get('operator')]
|
|
if clauses:
|
|
payload[target_key] = {'all': clauses}
|
|
return payload
|
|
|
|
|
|
def active_conditional_target_keys(form_type: str) -> set[str]:
|
|
return set(normalized_conditional_rule_payload(form_type).keys())
|
|
|
|
|
|
def translate_choice_list(choices):
|
|
return [(value, str(label)) for value, label in choices]
|
|
|
|
|
|
def build_onboarding_layout(form) -> list[dict]:
|
|
ordered_names = list(form.fields.keys())
|
|
group_by_field = {}
|
|
for group_id, group_fields in ONBOARDING_GROUPS.items():
|
|
for name in group_fields:
|
|
group_by_field[name] = group_id
|
|
conditional_target_keys = active_conditional_target_keys('onboarding')
|
|
|
|
rendered_groups = set()
|
|
consumed = set()
|
|
blocks = []
|
|
|
|
for field_name in ordered_names:
|
|
if field_name in consumed:
|
|
continue
|
|
|
|
group_id = group_by_field.get(field_name)
|
|
if group_id:
|
|
if group_id in rendered_groups:
|
|
continue
|
|
group_fields = [form[name] for name in ONBOARDING_GROUPS[group_id] if name in form.fields]
|
|
if not group_fields:
|
|
continue
|
|
blocks.append(
|
|
{
|
|
'kind': 'group',
|
|
'id': group_id,
|
|
'hidden_default': group_id in conditional_target_keys,
|
|
'fields': group_fields,
|
|
}
|
|
)
|
|
rendered_groups.add(group_id)
|
|
consumed.update([f.name for f in group_fields])
|
|
continue
|
|
|
|
if field_name.startswith('custom__') and field_name in conditional_target_keys:
|
|
blocks.append(
|
|
{
|
|
'kind': 'group',
|
|
'id': field_name,
|
|
'hidden_default': True,
|
|
'fields': [form[field_name]],
|
|
}
|
|
)
|
|
consumed.add(field_name)
|
|
continue
|
|
|
|
blocks.append({'kind': 'field', 'field': form[field_name]})
|
|
consumed.add(field_name)
|
|
|
|
return blocks
|
|
|
|
|
|
def section_for_block(block: dict, field_pages: dict[str, str]) -> str:
|
|
if block['kind'] == 'field':
|
|
return field_pages.get(block['field'].name, 'abschluss')
|
|
fields = block.get('fields') or []
|
|
if not fields:
|
|
return 'abschluss'
|
|
return field_pages.get(fields[0].name, 'abschluss')
|
|
|
|
|
|
def build_onboarding_sections(blocks: list[dict], field_pages: dict[str, str], visible_section_keys: set[str] | None = None) -> list[dict]:
|
|
section_defs = get_section_definitions('onboarding')
|
|
section_order = [item['key'] for item in section_defs]
|
|
section_titles = {item['key']: item['title'] for item in section_defs}
|
|
grouped = {key: [] for key in section_order}
|
|
for block in blocks:
|
|
section_key = section_for_block(block, field_pages)
|
|
if section_key not in grouped:
|
|
section_key = 'abschluss'
|
|
grouped[section_key].append(block)
|
|
visible_keys = visible_section_keys or set(section_order)
|
|
sections = []
|
|
custom_section_keys = {item['key'] for item in section_defs if item.get('is_custom')}
|
|
for key in section_order:
|
|
if key not in visible_keys:
|
|
continue
|
|
blocks_for_section = grouped[key]
|
|
has_custom_checkbox_fields = False
|
|
for block in blocks_for_section:
|
|
candidate_fields = [block['field']] if block['kind'] == 'field' else (block.get('fields') or [])
|
|
for bound_field in candidate_fields:
|
|
widget_type = getattr(getattr(bound_field.field, 'widget', None), 'input_type', '')
|
|
if bound_field.name.startswith('custom__') and widget_type == 'checkbox':
|
|
has_custom_checkbox_fields = True
|
|
break
|
|
if has_custom_checkbox_fields:
|
|
break
|
|
sections.append(
|
|
{
|
|
'key': key,
|
|
'title': section_titles.get(key, ONBOARDING_SECTION_META.get(key, {}).get('title', key)),
|
|
'subtitle': ONBOARDING_SECTION_META.get(key, {}).get('subtitle', ''),
|
|
'blocks': blocks_for_section,
|
|
'is_custom': key in custom_section_keys,
|
|
'has_custom_checkbox_fields': has_custom_checkbox_fields,
|
|
}
|
|
)
|
|
return sections
|
|
|
|
|
|
def build_offboarding_sections(form, visible_section_keys: set[str] | None = None) -> list[dict]:
|
|
field_pages = getattr(form, '_field_page_keys', {})
|
|
grouped = {key: [] for key in OFFBOARDING_PAGE_ORDER}
|
|
for field_name in form.fields.keys():
|
|
section_key = field_pages.get(field_name, 'abschluss')
|
|
if section_key not in grouped:
|
|
section_key = 'abschluss'
|
|
grouped[section_key].append(form[field_name])
|
|
visible_keys = visible_section_keys or set(OFFBOARDING_PAGE_ORDER)
|
|
return [
|
|
{
|
|
'key': key,
|
|
'title': OFFBOARDING_SECTION_META[key]['title'],
|
|
'subtitle': OFFBOARDING_SECTION_META[key]['subtitle'],
|
|
'fields': grouped[key],
|
|
}
|
|
for key in OFFBOARDING_PAGE_ORDER
|
|
if key in visible_keys and grouped[key]
|
|
]
|