## Summary This finishes the org credit line workflow so it behaves like reserved treasury-backed credit instead of a simple member allowance. ## What changed - reserve org funds immediately when a credit line is assigned - track credit lines with: - approved amount - available amount - outstanding principal - interest rate - amount due - consume reserved credit during store checkout without charging org funds a second time - add credit line repayment through the bank app - sync richer credit line state into org and bank payloads/UI - keep legacy `amount` compatibility mapped to available credit for older consumers ## User-facing behavior - assigning a credit line now reduces available org funds immediately - spending on `credit_line` reduces available credit and creates debt with interest - the bank app now shows outstanding credit debt and allows repayment from personal bank funds - the org treasury view now shows reserved credit and outstanding due totals ## Validation - `cargo fmt` - `npm run build:webui` - `cargo test -p forge-services --quiet` - `cargo test -p forge-server --quiet` ## Follow-up checks - validate in-game that assigning a credit line reduces org funds immediately - validate store checkout with `credit_line` updates available credit and debt correctly - validate bank repayment decreases player bank balance, increases org funds, and reduces amount due Co-authored-by: Jacob Schmidt <innovativestudios@outlook.com> Reviewed-on: #2
1 line
7.1 KiB
HTML
1 line
7.1 KiB
HTML
<!doctype html><html><head><meta charset="UTF-8"></head><body><div class="dispatch-shell"><header class="dispatch-header"><div><p class="dispatch-kicker">Dispatch Dashboard</p><h2>Operational Board</h2></div></header><div id="dispatcherStatusMessage" class="dispatch-status"></div><div id="dispatcherDangerAlert" class="dispatch-danger-alert is-hidden"></div><div id="dispatcherRequestAlert" class="dispatch-warning-alert is-hidden"></div><section class="dispatch-metrics"><div class="metric-card"><span class="metric-label">Open Contracts</span> <strong id="metricOpenContracts">0</strong></div><div class="metric-card"><span class="metric-label">Assigned Contracts</span> <strong id="metricAssignedContracts">0</strong></div><div class="metric-card"><span class="metric-label">Active Groups</span> <strong id="metricActiveGroups">0</strong></div><div id="metricOpenRequestsCard" class="metric-card"><span class="metric-label">Open Requests</span> <strong id="metricOpenRequests">0</strong></div><div id="metricDangerGroupsCard" class="metric-card"><span class="metric-label">Groups In Danger</span> <strong id="metricDangerGroups">0</strong></div></section><div class="dispatch-grid"><section class="dispatch-panel dispatch-panel-open"><div class="dispatch-panel-header"><h3>Available Contracts</h3><button id="dispatcherCreateOrderBtn" type="button" class="dispatch-icon-btn" aria-label="Create dispatch order" title="Create dispatch order">+</button></div><div id="dispatcherOpenContracts" class="dispatch-list"></div></section><section class="dispatch-panel dispatch-panel-assigned"><div class="dispatch-panel-header"><h3>Assigned Contracts</h3></div><div id="dispatcherAssignedContracts" class="dispatch-list"></div></section><section class="dispatch-panel dispatch-panel-groups"><div class="dispatch-panel-header"><h3>Group Board</h3></div><div id="dispatcherGroups" class="dispatch-list"></div></section><section class="dispatch-panel dispatch-panel-activity"><div class="dispatch-panel-header"><h3>Requests & Activity</h3></div><div id="dispatcherActivity" class="dispatch-list"></div></section></div><div id="dispatcherGroupModal" class="dispatch-modal is-hidden"><div class="dispatch-modal-backdrop"></div><div class="dispatch-modal-dialog" role="dialog" aria-modal="true" aria-labelledby="dispatcherGroupModalTitle"><div class="dispatch-modal-header"><div><p class="dispatch-kicker">Group Editor</p><h3 id="dispatcherGroupModalTitle">Manage Group</h3></div><button id="dispatcherGroupModalCloseBtn" class="dispatch-icon-btn" type="button" aria-label="Close group editor">x</button></div><div class="dispatch-modal-body"><div class="dispatch-meta-grid"><div><span class="metric-label">Callsign</span> <strong id="dispatcherModalGroupCallsign">-</strong></div><div><span class="metric-label">Leader</span> <strong id="dispatcherModalGroupLeader">-</strong></div><div><span class="metric-label">Current Task</span> <strong id="dispatcherModalGroupTask">None</strong></div><div><span class="metric-label">Org</span> <strong id="dispatcherModalGroupOrg">default</strong></div></div><div class="dispatch-modal-fields"><label class="dispatch-field"><span>Role</span> <select id="dispatcherModalRoleSelect" class="dispatch-select"></select></label> <label class="dispatch-field"><span>Status</span> <select id="dispatcherModalStatusSelect" class="dispatch-select"></select></label></div></div><div class="dispatch-modal-actions"><button id="dispatcherGroupModalSaveBtn" type="button" class="dispatch-btn">Save Changes</button></div></div></div><div id="dispatcherOrderModal" class="dispatch-modal is-hidden"><div class="dispatch-modal-backdrop"></div><div class="dispatch-modal-dialog" role="dialog" aria-modal="true" aria-labelledby="dispatcherOrderModalTitle"><div class="dispatch-modal-header"><div><p class="dispatch-kicker">Dispatch Order</p><h3 id="dispatcherOrderModalTitle">Create Support Order</h3></div><button id="dispatcherOrderModalCloseBtn" class="dispatch-icon-btn" type="button" aria-label="Close dispatch order editor">x</button></div><div class="dispatch-modal-body"><div class="dispatch-modal-fields"><label class="dispatch-field"><span>Assignee Group</span> <select id="dispatcherOrderAssigneeSelect" class="dispatch-select"></select></label> <label class="dispatch-field"><span>Target Group</span> <select id="dispatcherOrderTargetSelect" class="dispatch-select"></select></label> <label class="dispatch-field"><span>Priority</span> <select id="dispatcherOrderPrioritySelect" class="dispatch-select"><option value="routine">routine</option><option value="priority" selected>priority</option><option value="emergency">emergency</option></select></label> <label class="dispatch-field"><span>Order Note</span> <textarea id="dispatcherOrderNoteInput" class="dispatch-textarea" rows="4" placeholder="Optional order note for the assigned group."></textarea></label></div></div><div class="dispatch-modal-actions"><button id="dispatcherOrderModalSaveBtn" type="button" class="dispatch-btn">Create Order</button></div></div></div><div id="dispatcherRequestModal" class="dispatch-modal is-hidden"><div class="dispatch-modal-backdrop"></div><div class="dispatch-modal-dialog" role="dialog" aria-modal="true" aria-labelledby="dispatcherRequestModalTitle"><div class="dispatch-modal-header"><div><p class="dispatch-kicker">Support Request</p><h3 id="dispatcherRequestModalTitle">Request Details</h3></div><button id="dispatcherRequestModalCloseBtn" class="dispatch-icon-btn" type="button" aria-label="Close support request details">x</button></div><div class="dispatch-modal-body"><div class="dispatch-meta-grid"><div><span class="metric-label">Title</span> <strong id="dispatcherRequestTitle">Support Request</strong></div><div><span class="metric-label">Priority</span> <strong id="dispatcherRequestPriority">priority</strong></div><div><span class="metric-label">Group</span> <strong id="dispatcherRequestGroup">Unknown</strong></div><div><span class="metric-label">Type</span> <strong id="dispatcherRequestType">request</strong></div></div><div class="dispatch-field"><span>Summary</span><div id="dispatcherRequestSummary" class="dispatch-detail-block"></div></div><div class="dispatch-field"><span>Submitted Fields</span><div id="dispatcherRequestFields" class="dispatch-detail-list"></div></div></div><div class="dispatch-modal-actions"><button id="dispatcherRequestConvertBtn" type="button" class="dispatch-btn dispatch-btn-secondary">Convert to Order</button> <button id="dispatcherRequestModalDoneBtn" type="button" class="dispatch-btn">Done</button></div></div></div></div><script>window.MapLoader={loadCSS:e=>A3API.RequestFile(e).then(e=>{const d=document.createElement("style");d.textContent=e,document.head.appendChild(d)}),loadJS(path){return A3API.RequestFile(path).then(js=>{eval(js)})},loadAll(e){return e.reduce((e,d)=>e.then(()=>d.endsWith(".css")?this.loadCSS(d):d.endsWith(".js")?this.loadJS(d):Promise.resolve()),Promise.resolve())}},MapLoader.loadAll(["forge\\forge_client\\addons\\cad\\ui\\_site\\cad-common.css","forge\\forge_client\\addons\\cad\\ui\\_site\\cad-dispatcher.css","forge\\forge_client\\addons\\cad\\ui\\_site\\cad-shared.js","forge\\forge_client\\addons\\cad\\ui\\_site\\cad-dispatcher.js"]).catch(e=>console.error("[DISPATCHER] Load error:",e))</script></body></html> |