Example #1
0
def process_area_access_record_with_parents(user: User):
    show_not_qualified_areas = get_customization(
        'dashboard_display_not_qualified_areas')
    records = AreaAccessRecord.objects.filter(end=None, staff_charge=None)
    if not user.is_staff and show_not_qualified_areas != 'enabled':
        records = records.filter(area__in=user.accessible_areas())
    records = records.prefetch_related('customer', 'project', 'area')
    no_occupants = not records.exists()
    area_items = None
    area_model_tree = get_area_model_tree()
    if not no_occupants:
        areas_and_parents = area_model_tree.get_ancestor_areas(
            area_model_tree.get_areas([record.area.id for record in records]),
            include_self=True)
        # Sort to have area without children before others
        areas_and_parents.sort(key=lambda x: f'{x.tree_category}zz'
                               if x.is_leaf else f'{x.tree_category}/aa')
        area_summary = create_area_summary(area_model_tree=area_model_tree,
                                           add_resources=False,
                                           add_outages=False,
                                           add_occupants=True)
        area_summary_dict = {area['id']: area for area in area_summary}
        for area_item in areas_and_parents:
            area_item.item = area_summary_dict[area_item.id]
        area_items = area_tree_helper(areas_and_parents, records)
    return area_items, no_occupants
Example #2
0
    def render(self, name, value, attrs=None, renderer=None):
        """
		This widget takes a list of items (tools/areas) and creates nested unordered lists in a hierarchical manner.
		The parameters name and attrs are not used.
		'value' is a dictionary which must contain a 'tools' or 'areas' key with a value that is a QuerySet of all tools/areas to be put in the list.
		A collection of unordered HTML lists is returned with various callbacks and properties attached to each nested element.

		For a more concrete example, suppose the following tools are input to the item tree:
		Packaging/Dicing Saw
		Chemical Vapor Deposition/PECVD
		Gen Furnaces/Sinter

		The following unordered HTML list would be produced:
		<ul>
			<li>
				<a href="javascript:void(0);" onclick="on_item_tree_click($(this.nextSibling))" class="node">Packaging</a>
				<ul class="collapsed">
					<li><a href="javascript:void(0);" onclick="on_item_tree_click($(this))" class="leaf node">Dicing saw</a></li>
				</ul>
			</li>
			<li>
				<a href="javascript:void(0);" onclick="on_item_tree_click($(this.nextSibling))" class="node">Chemical Vapor Deposition</a>
				<ul class="collapsed">
					<li><a href="javascript:void(0);" onclick="on_item_tree_click($(this))" class="leaf node">PECVD</a></li>
				</ul>
			</li>
			<li>
				<a href="javascript:void(0);" onclick="on_item_tree_click($(this.nextSibling))" class="node">Gen Furnaces</a>
				<ul class="collapsed">
					<li><a href="javascript:void(0);" onclick="on_item_tree_click($(this))" class="leaf node">Sinter</a></li>
				</ul>
			</li>
		</ul>
		"""
        area_tree = ItemTreeHelper(None, ReservationItemType.AREA)
        tool_tree = ItemTreeHelper(None, ReservationItemType.TOOL)
        user: User = value['user'] if 'user' in value else None
        model_tree = get_area_model_tree()
        area_tree_items: List[TreeItem] = model_tree.get_areas(
            [area.id for area in value.get('areas', [])])
        tools: List[Tool] = value.get('tools', [])
        tool_parent_ids = Tool.objects.filter(
            parent_tool__isnull=False).values_list('parent_tool_id', flat=True)
        user_accessible_areas = [] if not user or not area_tree_items else user.accessible_areas(
        )
        user_qualified_tool_ids = [] if not user or not tools else user.qualifications.all(
        ).values_list('id', flat=True)
        parent_areas_dict = {}
        if area_tree_items:
            # Create a lookup of area name to area with all the parents (in order to display info about category-parents)
            parent_areas_dict = {
                area_tree_item.name: area_tree_item
                for area_tree_item in model_tree.get_ancestor_areas(
                    area_tree_items)
            }
            # Sort areas by complete category
            area_tree_items = list(area_tree_items)
            area_tree_items.sort(key=lambda area: area.tree_category)

        display_all_areas = get_customization(
            'calendar_display_not_qualified_areas') == 'enabled'
        for area in area_tree_items:
            category = area.tree_category + '/' if area.tree_category else ''
            is_qualified = True if not display_all_areas else (
                user and user.is_staff) or (
                    user and area.item in user_accessible_areas)
            area_tree.add(ReservationItemType.AREA, category + area.name,
                          area.id, is_qualified)
        for tool in tools:
            is_qualified = (user and user.is_staff) or (
                user and tool.id in user_qualified_tool_ids)
            tool_tree.add(
                ReservationItemType.TOOL, tool.category + '/' +
                tool.name_or_child_in_use_name(parent_ids=tool_parent_ids),
                tool.id, is_qualified)

        legend = True if area_tree_items and tools else False
        result = ""
        if area_tree_items:
            result += area_tree.render(legend=legend,
                                       category_items_lookup=parent_areas_dict)
        if tools:
            result += tool_tree.render(legend=legend)
        return mark_safe(result)
Example #3
0
def create_area_summary(area_model_tree: ModelTreeHelper = None,
                        add_resources=True,
                        add_occupants=True,
                        add_outages=True):
    if area_model_tree is None:
        area_model_tree = get_area_model_tree()
    area_items = area_model_tree.items.values()
    result = {}
    for area in area_items:
        result[area.id] = {
            'name': area.name,
            'id': area.id,
            'maximum_capacity': area.maximum_capacity,
            'warning_capacity': area.item.warning_capacity(),
            'danger_capacity': area.item.danger_capacity(),
            'count_staff_in_occupancy': area.count_staff_in_occupancy,
            'count_service_personnel_in_occupancy':
            area.count_service_personnel_in_occupancy,
            'occupancy_count': 0,
            'occupancy': 0,
            'occupancy_staff': 0,
            'occupancy_service_personnel': 0,
            'occupants': '',
            'required_resource_is_unavailable': False,
            'scheduled_outage': False,
        }

    if add_resources:
        unavailable_resources = Resource.objects.filter(
            available=False).prefetch_related(
                Prefetch('dependent_areas', queryset=Area.objects.only('id')))
        for resource in unavailable_resources:
            for area in resource.dependent_areas.all():
                if area.id in result:
                    result[area.id]['required_resource_is_unavailable'] = True
    if add_outages:
        scheduled_outages = ScheduledOutage.objects.filter(
            start__lte=timezone.now(),
            end__gt=timezone.now(),
            tool__isnull=True).only('area_id', 'resource_id')
        for outage in scheduled_outages:
            if outage.area_id:
                result[outage.area_id]['scheduled_outage'] = True
            elif outage.resource_id:
                for t in outage.resource.dependent_areas.values_list(
                        'id', flat=True):
                    result[t]['scheduled_outage'] = True

    if add_occupants:
        occupants: List[AreaAccessRecord] = AreaAccessRecord.objects.filter(
            end=None, staff_charge=None).prefetch_related(
                Prefetch('customer',
                         queryset=User.objects.all().only(
                             'first_name', 'last_name', 'username',
                             'is_staff')))
        for occupant in occupants:
            # Get ids for area and all the parents (so we can add occupants info on parents)
            area_ids = area_model_tree.get_area(
                occupant.area_id).ancestor_ids(include_self=True)
            if occupant.customer.is_staff:
                customer_display = f'<span class="success-highlight">{str(occupant.customer)}</span>'
            elif occupant.customer.is_service_personnel:
                customer_display = f'<span class="warning-highlight">{str(occupant.customer)}</span>'
            elif occupant.customer.is_logged_in_area_without_reservation():
                customer_display = f'<span class="danger-highlight">{str(occupant.customer)}</span>'
            else:
                customer_display = str(occupant.customer)
            for area_id in area_ids:
                if area_id in result:
                    result[area_id]['occupancy'] += 1
                    if occupant.customer.is_staff:
                        result[area_id]['occupancy_staff'] += 1
                    if occupant.customer.is_service_personnel:
                        result[area_id]['occupancy_service_personnel'] += 1
                    if (not occupant.customer.is_staff
                            or result[area_id]['count_staff_in_occupancy']
                        ) and (not occupant.customer.is_service_personnel
                               or result[area_id]
                               ['count_service_personnel_in_occupancy']):
                        result[area_id]['occupancy_count'] += 1
                    result[area_id][
                        'occupants'] += customer_display if not result[
                            area_id]['occupants'] else f'<br>{customer_display}'
    area_summary = list(result.values())
    area_summary.sort(key=lambda x: x['name'])
    return area_summary