{% extends "allianceauth/base-bs5.html" %} {% load i18n %} {% load static %} {% load humanize %} {% block header_nav_collapse_left %} {% include 'corptools/top_menu.html' %} {% endblock %} {% block content %} {% if structures %}

Corporation Logistics

Structure and Fuel Stats

Filter structures, review block and Magmatic Gas demand, and size refuels from one view.

Minimum 30 days.
Filtered Structures
0
Systems
0
Constellations
0
Regions
0
Current Blocks
0
Current Magmatic Gas
0
Fuel Demand

Blocks Usage

Per Hour 0
Per Day 0
Per Month 0
Refuel For 90d 0
Fuel Demand

Magmatic Gas Usage

Per Hour 0
Per Day 0
Per Month 0
Refuel For 90d 0
Filtered Inventory

Structure Mix

{% for structure in structures %} {% empty %} {% endfor %}
Structure Blocks Usage Gas Usage Current Stock Time Left Services System Constellation Region Corp Type
{{ structure.structure.type_name.name }}
{{ structure.structure.name }}
{{ structure.structure.type_name.name }}
{{ structure.structure.corporation.corporation.corporation_name }} - {{ structure.structure.system_name.name }}
Per Hour {{ structure.fuel_req|intcomma }}
Per Day {{ structure.fuel_req_day|intcomma }}
Per Month {{ structure.fuel_req_30d|intcomma }}
Refuel For 90d {{ structure.90day|intcomma }}
Per Hour {{ structure.gas_req|intcomma }}
Per Day {{ structure.gas_req_day|intcomma }}
Per Month {{ structure.gas_req_30d|intcomma }}
Refuel For 90d {{ structure.gas_90day|intcomma }}
Current Blocks {{ structure.current_blocks|intcomma }}
Current Gas {{ structure.current_metenox_gas|intcomma }}
{% if structure.extra_fuel_info %}
Blocks
{{ structure.structure.fuel_expires|date:"Y-m-d H:i" }}
{{ structure.block_duration_left }} left
{{ structure.extra_fuel_info.name }}
{{ structure.extra_fuel_info.expires|date:"Y-m-d H:i" }}
{{ structure.gas_duration_left }} left
{% else %}
Blocks
{{ structure.structure.fuel_expires|date:"Y-m-d H:i" }}
{{ structure.block_duration_left }} left
{% endif %}
{% for service in structure.structure.structureservice_set.all %} {% if service.state == 'online' %} {{ service.name }} {% else %} {{ service.name }} {% endif %} {% endfor %}
{{ structure.structure.system_name.name }} {{ structure.structure.system_name.constellation.name }} {{ structure.structure.system_name.constellation.region.name }} {{ structure.structure.corporation.corporation.corporation_name }} {{ structure.structure.type_name.name }}
{% else %}
{% translate "No Structures Available" %}
{% endif %} {% endblock content %} {% block extra_javascript %} {% include "bundles/datatables-js-bs5.html" %} {% include "bundles/filterdropdown-js.html" %} {% endblock extra_javascript %} {% block extra_script %} function numberWithCommas(x) { return (Number(x) || 0).toLocaleString('en-US'); } $(document).ready(function() { const durationTitles = document.querySelectorAll('.duration-title, #totalDaysTitle, #totalGasDaysTitle'); const fuelDurationInput = document.getElementById('fuelDuration'); const fuelDurationSummary = document.getElementById('fuelDurationSummary'); const tableElement = document.getElementById('table-structs'); const tableWrapper = tableElement.closest('.table-responsive'); const structureTypeBreakdown = document.getElementById('structure_type_breakdown'); const defaultRefuelDays = 90; const minimumRefuelDays = 30; // Keep refuel sizing on the original day-based flow and enforce the // same 30-day floor when the dashboard recalculates totals. function getRefuelDays(value, fallbackDays) { const parsed = Number(value); if (!Number.isFinite(parsed)) { return fallbackDays; } return Math.max(Math.ceil(parsed), minimumRefuelDays); } function updateDurationTitles(durationLabel) { durationTitles.forEach(function(elem) { elem.innerText = durationLabel; }); } function updateFuelDurationSummary(refuelDays) { fuelDurationSummary.innerText = 'Minimum 30 days. Current window: ' + refuelDays + 'd.'; } function calculateRefuelNeed(hourly, currentStock, hours) { return Math.max(Math.ceil((hourly * hours) - currentStock), 0); } // Recalculate each row against the selected target so filtered totals // and visible row values stay in sync without another server request. function recalculateRowRefuel(row, hours) { const blockHourly = Number(row.dataset.blockHourly || 0); const blockCurrent = Number(row.dataset.blockCurrent || 0); const gasHourly = Number(row.dataset.gasHourly || 0); const gasCurrent = Number(row.dataset.gasCurrent || 0); const blockRefuel = calculateRefuelNeed(blockHourly, blockCurrent, hours); const gasRefuel = calculateRefuelNeed(gasHourly, gasCurrent, hours); const blockCell = row.querySelector('.blocks-till'); const gasCell = row.querySelector('.gas-till'); row.dataset.blockRefuel = blockRefuel; row.dataset.gasRefuel = gasRefuel; if (blockCell) { blockCell.innerText = numberWithCommas(blockRefuel); } if (gasCell) { gasCell.innerText = numberWithCommas(gasRefuel); } } function renderTypeBreakdown(typeCounts) { const entries = Object.entries(typeCounts).sort(function(a, b) { if (b[1] !== a[1]) { return b[1] - a[1]; } return a[0].localeCompare(b[0]); }); if (!entries.length) { structureTypeBreakdown.innerHTML = '
No structures in the current filter.
'; return; } structureTypeBreakdown.innerHTML = entries.map(function(entry) { return '
' + entry[0] + '' + numberWithCommas(entry[1]) + '
'; }).join(''); } function updateDashboardStats(table) { const rows = table.rows({ search: 'applied' }).nodes().toArray(); const systems = new Set(); const constellations = new Set(); const regions = new Set(); const typeCounts = {}; const totals = { structures: 0, currentBlocks: 0, currentGas: 0, blockHour: 0, blockDay: 0, blockMonth: 0, blockRefuel: 0, gasHour: 0, gasDay: 0, gasMonth: 0, gasRefuel: 0 }; rows.forEach(function(row) { totals.structures += 1; totals.currentBlocks += Number(row.dataset.blockCurrent || 0); totals.currentGas += Number(row.dataset.gasCurrent || 0); totals.blockHour += Number(row.dataset.blockHourly || 0); totals.blockDay += Number(row.dataset.blockDay || 0); totals.blockMonth += Number(row.dataset.blockMonth || 0); totals.blockRefuel += Number(row.dataset.blockRefuel || 0); totals.gasHour += Number(row.dataset.gasHourly || 0); totals.gasDay += Number(row.dataset.gasDay || 0); totals.gasMonth += Number(row.dataset.gasMonth || 0); totals.gasRefuel += Number(row.dataset.gasRefuel || 0); if (row.dataset.system) { systems.add(row.dataset.system); } if (row.dataset.constellation) { constellations.add(row.dataset.constellation); } if (row.dataset.region) { regions.add(row.dataset.region); } if (row.dataset.typeName) { typeCounts[row.dataset.typeName] = (typeCounts[row.dataset.typeName] || 0) + 1; } }); document.getElementById('total_str').innerText = numberWithCommas(totals.structures); document.getElementById('total_system').innerText = numberWithCommas(systems.size); document.getElementById('total_const').innerText = numberWithCommas(constellations.size); document.getElementById('total_region').innerText = numberWithCommas(regions.size); document.getElementById('total_current_blocks').innerText = numberWithCommas(totals.currentBlocks); document.getElementById('total_current_gas').innerText = numberWithCommas(totals.currentGas); document.getElementById('total_block_hour').innerText = numberWithCommas(totals.blockHour); document.getElementById('total_block_day').innerText = numberWithCommas(totals.blockDay); document.getElementById('total_block_month').innerText = numberWithCommas(totals.blockMonth); document.getElementById('total_fuel_refuel').innerText = numberWithCommas(totals.blockRefuel); document.getElementById('total_gas_hour').innerText = numberWithCommas(totals.gasHour); document.getElementById('total_gas_day').innerText = numberWithCommas(totals.gasDay); document.getElementById('total_gas_month').innerText = numberWithCommas(totals.gasMonth); document.getElementById('total_gas_refuel').innerText = numberWithCommas(totals.gasRefuel); renderTypeBreakdown(typeCounts); } function updateTableDensity() { if (!tableWrapper) { return; } // If the table starts to overrun its card, squeeze the services column first. tableElement.classList.remove('fuel-table-tight', 'fuel-table-tightest'); if (tableWrapper.scrollWidth > tableWrapper.clientWidth + 1) { tableElement.classList.add('fuel-table-tight'); } if (tableWrapper.scrollWidth > tableWrapper.clientWidth + 1) { tableElement.classList.add('fuel-table-tightest'); } } function refreshDashboard(table, overrideDays, syncInputValue) { const currentDays = getRefuelDays(fuelDurationInput.value, defaultRefuelDays); const refuelDays = getRefuelDays( typeof overrideDays === 'undefined' ? currentDays : overrideDays, currentDays ); const durationLabel = refuelDays + 'd'; if (syncInputValue) { fuelDurationInput.value = refuelDays; } updateDurationTitles(durationLabel); updateFuelDurationSummary(refuelDays); Array.from(tableElement.querySelectorAll('tbody tr')).forEach(function(row) { recalculateRowRefuel(row, refuelDays * 24); }); updateDashboardStats(table); updateTableDensity(); } const table = $('#table-structs').DataTable({ filterDropDown: { columns: [{ idx: 11 }, { idx: 7 }, { idx: 8 }, { idx: 9 }, { idx: 10 }], bootstrap: true, bootstrap_version: 5 }, columnDefs: [ { searchable: false, targets: [0] }, { orderable: false, targets: [0, 2, 3, 4, 5, 6] }, { visible: false, targets: [7, 8, 9, 10, 11] }, { width: "100px", targets: [0] } ], order: [[1, 'asc']], paging: false, responsive: true, pageLength: -1, drawCallback: function() { refreshDashboard(this.api(), undefined, false); } }); fuelDurationInput.addEventListener('input', function(e) { if (e.target.value !== '') { refreshDashboard(table, e.target.value, false); } }); fuelDurationInput.addEventListener('change', function(e) { refreshDashboard(table, e.target.value, true); }); window.addEventListener('resize', function() { updateTableDensity(); }); refreshDashboard(table, undefined, true); }); {% endblock extra_script %} {% block extra_css %} {% include "bundles/datatables-css-bs5.html" %} {% endblock extra_css %}