* jquery removed

* charts auf lokal umgestellt
* Rechnungen mit Anhang
* neues Interface Sync automatische
This commit is contained in:
Markus 2025-05-17 09:06:12 +02:00
parent 842d9050dc
commit 8f28ed82da
10 changed files with 276 additions and 67 deletions

View File

@ -29,6 +29,9 @@ $routes->get('syncScheduled', 'Home::syncScheduled');
$routes->get('viewAccounts', 'Home::viewAccountsTree'); $routes->get('viewAccounts', 'Home::viewAccountsTree');
$routes->get('viewActivities', 'Home::viewAccountActivities'); $routes->get('viewActivities', 'Home::viewAccountActivities');
$routes->get('viewScheduled', 'Home::viewScheduled'); $routes->get('viewScheduled', 'Home::viewScheduled');
$routes->get('viewBill/(:any)', 'Home::viewBill/$1');
$routes->get('viewChart', 'Charts::getData/0');
$routes->get('viewChart/(:num)', 'Charts::getData/$1');
service('auth')->routes($routes); service('auth')->routes($routes);

View File

@ -111,7 +111,7 @@ class Routing extends BaseRouting
* *
* Default: false * Default: false
*/ */
public bool $multipleSegmentsOneParam = false; public bool $multipleSegmentsOneParam = true;
/** /**
* For Auto Routing (Improved). * For Auto Routing (Improved).

131
app/Controllers/Charts.php Normal file
View File

@ -0,0 +1,131 @@
<?php namespace App\Controllers;
use CodeIgniter\Session\Session;
use DateInterval;
use Config\App;
class Charts extends BaseController {
private $db;
public function __construct() {
$this->db = \Config\Database::connect();
}
public function getData($id){
if ($id == 0)
return $this->getAllData();
else
return $this->getDetailData($id);
}
private function getDetailData($id){
$jetzt = date('Y-m-01');
$query = <<<EOD
SELECT
SUM(subamount)*(-1) AS Amount,
description,account_id as id
FROM
finanzen.budget_billdetails, finanzen.budget_bills,finanzen.budget_accounts
WHERE
datum >= '$jetzt'
AND (datum < '$jetzt'::date + interval '1 month')
AND budget_bills.id = bill_id
AND account_id = finanzen.budget_accounts.id
AND (account_id IN (
WITH RECURSIVE subordinates AS (
SELECT
id,
parent_id,
description
FROM
finanzen.budget_accounts
WHERE
id = $id
UNION
SELECT
e.id,
e.parent_id,
e.description
FROM
finanzen.budget_accounts e
INNER JOIN subordinates s ON s.id = e.parent_id)
SELECT
id
FROM
subordinates
))
GROUP BY description, account_id
EOD;
$data = array();
$result = $this->db->query($query);
foreach ($result->getResult() as $row) {
$werte[] = $row->amount;
$ids[] = $row->id;
$labels[] = $row->description;
}
$data['data'] = json_encode($werte);
$data['labels'] = json_encode($labels);
$data['ids'] = json_encode($ids);
$data['title'] = "Kategorieübersicht > ".$jetzt;
return view("charts/monthly", $data);
}
private function getAllData(){
$jetzt = date('Y-m-01');
$query = <<<EOD
SELECT * FROM (
SELECT id, description,sum(amount)as summe FROM (SELECT id,description from finanzen.budget_accounts WHERE parent_id=0 AND type='output' AND LKZ is null) as w,
LATERAL
(SELECT ABS(SUM(subamount)) as amount
FROM finanzen.budget_billdetails, finanzen.budget_bills
WHERE datum >= '$jetzt'
AND budget_bills.id = bill_id
AND (account_id IN
(
WITH RECURSIVE subordinates AS (
SELECT
id,
parent_id,
description
FROM
finanzen.budget_accounts
WHERE
id = w.id
UNION
SELECT
e.id,
e.parent_id,
e.description
FROM
finanzen.budget_accounts e
INNER JOIN subordinates s ON s.id = e.parent_id)
SELECT
id
FROM
subordinates
))
) AS x GROUP BY description, id) as i WHERE summe is not null;
EOD;
$data = array();
$result = $this->db->query($query);
foreach ($result->getResult() as $row) {
$werte[] = $row->summe;
$ids[] = $row->id;
$labels[] = $row->description;
}
$data['data'] = json_encode($werte);
$data['labels'] = json_encode($labels);
$data['ids'] = json_encode($ids);
$data['title'] = "Monatsübersicht > ".$jetzt;
return view("charts/monthly", $data);
// SELECT description,amount FROM (SELECT id,description from finanzen.budget_accounts WHERE parent_id=0 AND type='output' AND LKZ is null) as w,
// LATERAL
// (SELECT subamount as amount
// FROM finanzen.budget_billdetails, finanzen.budget_bills
// WHERE datum >= DATE_TRUNC('month',current_date)
// AND budget_bills.id = bill_id
// AND (account_id IN
// (SELECT id from finanzen.budget_accounts WHERE (id = w.id OR parent_id = w.id))
// )
// ) AS x
}
}

View File

@ -0,0 +1,68 @@
<?= $this->extend('layout'); ?>
<?= $this->section('menu'); ?>
<?= $this->include('sidebar') ?>
<?= $this->endSection(); ?>
<?= $this->section('css'); ?>
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-QWTKZyjpPEjISv5WaRU9OFeRpok6YctnYmDr5pNlyT2bRjXh0JMhjY6hW+ALEwIH" crossorigin="anonymous">
<?= $this->endSection(); ?>
<?= $this->section('content'); ?>
<div class="page-content col-xxl-4 col-12">
<div class="row" id="chart">
<canvas id="myAreaChart"></canvas>
</div>
</div>
<?= $this->endSection(); ?>
<?= $this->section('scripts'); ?>
<script src="https://cdn.jsdelivr.net/npm/chart.js@4.4.5/dist/chart.umd.min.js"></script>
<script src="https://smarthome.mawim.at/assets/luxon.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/chartjs-adapter-luxon/1.3.0/chartjs-adapter-luxon.umd.js" integrity="sha512-IUw+YyQA3lci8gHiGIbkEA5pHnSy9LJeujqIDBHQMhxTk019nRXvDrKi2WcEr5nf5+RNffKMqSagdI0tzXvBiA==" crossorigin="anonymous" referrerpolicy="no-referrer"></script>
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/js/bootstrap.bundle.min.js" integrity="sha384-YvpcrYf0tY3lHB60NNkmXc5s9fDVZLESaAA55NDzOxhy9GkcIdslK1eN7N6jIeHz" crossorigin="anonymous"></script>
<script>
const data = {
labels: <?=$labels?>,
datasets: [
{
label: '€',
data: <?=$data?>,
id:<?=$ids?>,
hoverOffset: 8
}
]
};
const configDonut = {
type: 'doughnut',
data: data,
options: {
responsive: true,
plugins: {
legend: {
position: 'left',
},
title: {
display: true,
text: '<?=$title?>',
font: { size: 20 }
}
},
onClick: (e) => {
let ele = document.getElementById("myChartModal");
const canvasPosition = Chart.helpers.getRelativePosition(e, window.myLineChart);
// Substitute the appropriate scale IDs
const data = window.myLineChart.getActiveElements(e);
document.getElementById("modalChartBody").innerHTML = `<a href="/viewChart/${window.myLineChart.data.datasets[0].id[data[0].index]}">Zeige Details von ${window.myLineChart.data.labels[data[0].index]}</a>`;
bootstrap.Modal.getOrCreateInstance(ele).show();
const name = window.myLineChart.data.labels[data[0].index];
//const dataY = chart.scales.y.getValueForPixel(canvasPosition.y);
// alert(`http://mqtt.mawim.at/viewChart/${window.myLineChart.data.datasets[0].id[data[0].index]}`);
}
},
};
(async function () {
Chart.defaults.font.size = 16;
window.myLineChart = new Chart(document.getElementById('myAreaChart'), configDonut);
})();
</script>
<?= $this->endSection(); ?>

View File

@ -64,6 +64,22 @@
</div> </div>
</div> </div>
</div> </div>
<div class="modal fade" id="myChartModal" tabindex="-1" aria-labelledby="Chart Link Window" aria-hidden="true">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<h1 class="modal-title fs-5" id="modalTitle">Modal title</h1>
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
</div>
<div id="modalChartBody" class="modal-body">
<p>Please Wait.</p>
</div>
<div class="modal-footer d-none">
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Close</button>
</div>
</div>
</div>
</div>
</div> </div>
</div> </div>
<!-- <script src="/assets/vendors/perfect-scrollbar/perfect-scrollbar.min.js"></script> <!-- <script src="/assets/vendors/perfect-scrollbar/perfect-scrollbar.min.js"></script>
@ -74,6 +90,7 @@
<script defer src="/assets/fontawesome6.4.0/js/brands.js"></script> <script defer src="/assets/fontawesome6.4.0/js/brands.js"></script>
<script defer src="/assets/fontawesome6.4.0/js/regular.js"></script> <script defer src="/assets/fontawesome6.4.0/js/regular.js"></script>
<script src="/assets/DataTables/datatables.min.js"></script> <script src="/assets/DataTables/datatables.min.js"></script>
<script src="/js/menue.js"></script>
<script src="/assets/js/main.js"></script> <script src="/assets/js/main.js"></script>
<?= $this->renderSection('scripts') ?> <?= $this->renderSection('scripts') ?>
</body> </body>

View File

@ -2,7 +2,6 @@
<?= $this->section('css'); ?> <?= $this->section('css'); ?>
<link rel="stylesheet" href="/css/mawim.css"> <link rel="stylesheet" href="/css/mawim.css">
<link rel="stylesheet" href="/assets/jquery-ui-1.13.2.custom/jquery-ui.css">
<?= $this->endSection(); ?> <?= $this->endSection(); ?>
<?= $this->section('menu'); ?> <?= $this->section('menu'); ?>
<?= $this->include('sidebar') ?> <?= $this->include('sidebar') ?>
@ -15,7 +14,7 @@
<div class="col-md-8 col-12"> <div class="col-md-8 col-12">
<div class="card"> <div class="card">
<div class="card-header pb-0"> <div class="card-header pb-0">
<h4 class="card-title">Neue Rechnung</h4> <h4 class="card-title"><?= ($transfer?'Neuer Transfer':($isScheduled?'Neue Terminbuchung':'Neue Rechnung'))?></h4>
<?php if (! empty($validation)) : ?> <?php if (! empty($validation)) : ?>
<div class='alert alert-danger mt-2'> <div class='alert alert-danger mt-2'>
<div class="errors" role="alert"> <div class="errors" role="alert">
@ -30,7 +29,8 @@
</div> </div>
<div class="card-content"> <div class="card-content">
<div class="card-body"> <div class="card-body">
<form class="form form-vertical" id="newbill" method="post" action="<?= base_url() ?>/newBill"> <?= form_open_multipart('newBill','class="form form-vertical" onsubmit="logData(event)" id="newbill"') ?>
<!-- <form class="form form-vertical" id="newbill" method="post" enctype="multipart/form-data" onsubmit="logData(event)" action="<?= base_url() ?>newBill"> -->
<input type="hidden" value="<?= $id ?>" name="id"> <input type="hidden" value="<?= $id ?>" name="id">
<input type="hidden" value="<?= $transfer?'1':'0' ?>" name="transfer"> <input type="hidden" value="<?= $transfer?'1':'0' ?>" name="transfer">
<div class="form-body"> <div class="form-body">
@ -41,7 +41,15 @@
<input class="form-check-input" type="checkbox" id="multi" value="on" name="multi" <?= set_checkbox('multi', 'on', $multi??false) ?>> <input class="form-check-input" type="checkbox" id="multi" value="on" name="multi" <?= set_checkbox('multi', 'on', $multi??false) ?>>
</div> </div>
</div> </div>
<div class="col-12 <?= ($transfer?' d-none':'') ?>"> <div class="col-12 <?= ($transfer?' d-none':($isScheduled?' d-none':'')) ?>">
<label for="billfile">Rechnung</label>
<?php if (!isset($billfile)): ?>
<input type="file" id="billfile" name="billfile" class="form-control" capture="environment" accept="image/*, application/pdf">
<?php else: ?>
<input type="text" disabled="disabled" name="temp" id="billfile1" class="form-control" value="<?= set_value('billfile1', $billfile??'') ?>">
<?php endif; ?>
</div>
<div class="col-12 <?= ($transfer?' d-none':'d-none') ?>">
<div class='form-check'> <div class='form-check'>
<div class="checkbox"> <div class="checkbox">
<label for="renummer">Re-Nr.</label> <label for="renummer">Re-Nr.</label>
@ -50,8 +58,8 @@
</div> </div>
</div> </div>
<div class="col-12"> <div class="col-12">
<label for="datepicker">Datum</label> <label for="datum">Datum</label>
<input type="text" class="form-control" id="datepicker" data-date-format="mm.dd.yyyy" name="datum" value="<?= $datum ?>"/> <input type="date" class="form-control" id="datum" name="datum" value="<?= $datum ?>" onclick="openBox(this);"/>
</div> </div>
</div> </div>
<div class="col-12 <?= ($transfer?' d-none':'') ?>"> <div class="col-12 <?= ($transfer?' d-none':'') ?>">
@ -130,36 +138,10 @@
<?= $this->endSection(); ?> <?= $this->endSection(); ?>
<?= $this->section('scripts'); ?> <?= $this->section('scripts'); ?>
<script> <script>
function openBox(e) {
e.showPicker();
}
subsdata = <?= $subsdata; ?>; subsdata = <?= $subsdata; ?>;
</script> </script>
<script src="/assets/jquery-ui-1.13.2.custom/jquery-ui.js"></script>
<script src="/js/billing.js"></script> <script src="/js/billing.js"></script>
<script>
$.datepicker.regional['de'] = {clearText: 'löschen', clearStatus: 'aktuelles Datum löschen',
closeText: 'schließen', closeStatus: 'ohne Änderungen schließen',
prevText: '<zurück', prevStatus: 'letzten Monat zeigen',
nextText: 'Vor>', nextStatus: 'nächsten Monat zeigen',
currentText: 'heute', currentStatus: '',
monthNames: ['Januar','Februar','März','April','Mai','Juni',
'Juli','August','September','Oktober','November','Dezember'],
monthNamesShort: ['Jan','Feb','Mär','Apr','Mai','Jun',
'Jul','Aug','Sep','Okt','Nov','Dez'],
monthStatus: 'anderen Monat anzeigen', yearStatus: 'anderes Jahr anzeigen',
weekHeader: 'Wo', weekStatus: 'Woche des Monats',
dayNames: ['Sonntag','Montag','Dienstag','Mittwoch','Donnerstag','Freitag','Samstag'],
dayNamesShort: ['So','Mo','Di','Mi','Do','Fr','Sa'],
dayNamesMin: ['So','Mo','Di','Mi','Do','Fr','Sa'],
dayStatus: 'Setze DD als ersten Wochentag', dateStatus: 'Wähle D, M d',
dateFormat: 'dd.mm.yy', firstDay: 1,
initStatus: 'Wähle ein Datum', isRTL: false};
$.datepicker.setDefaults($.datepicker.regional['de']);
$('#datepicker').datepicker(
{
format: "dd.mm.yyyy",
language: 'de-DE',
weekStart: 1,
autoclose: true,
todayHighlight: false});
</script>
<?= $this->endSection(); ?> <?= $this->endSection(); ?>

View File

@ -54,7 +54,7 @@
</a> </a>
</li> </li>
<li class="sidebar-item active"> <li class="sidebar-item active">
<a href="http://mqtt.mawim.at:3000/d/6nnjNisVz/monatsuebersicht?orgId=1&from=1682671795200&to=1682693395200" class='sidebar-link' target="_blank"> <a href="/viewChart" class='sidebar-link'>
<i class="fa-solid fa-tachometer-alt"></i> <i class="fa-solid fa-tachometer-alt"></i>
<span>Monatschart</span> <span>Monatschart</span>
</a> </a>

View File

@ -1,14 +1,23 @@
var datatable; var datatable;
var colomnspez = columns; var colomnspez = columns;
colomnspez.splice(3, 0, { title: "Quelle",orderable:false, data: "source",className:"dt-source" }); function createSearchData(data, type, row){
let details = "";
data.forEach(function(item){
details += item.comment+' '+item.description+' ';
details += new Intl.NumberFormat('de-DE', { style: 'currency', currency: 'EUR' }).format(item.subamount);
});
return details;
}
colomnspez.splice(3, 0, { title: "Quelle",orderable:false, data: "source",className:"dt-source" });
colomnspez.splice(6, 0, { title: "Details",orderable:false, visible:false, searchable:true, data: "details",className:"",render: createSearchData});
$(document).ready(function(){ $(document).ready(function(){
datatable = $('#bookings').DataTable({ datatable = $('#bookings').DataTable({
paging: false, paging: false,
searching:true, searching:true,
scrollX:false, scrollX:false,
info:false, info:false,
order: [[ 1, 'desc' ]], order: [[ 1, 'desc' ],[ 0, 'desc' ]],
"processing": true, "processing": true,
ajax: { ajax: {
type : 'POST', type : 'POST',
@ -22,7 +31,7 @@ $(document).ready(function(){
layout: { layout: {
topStart: { topStart: {
buttons: [ buttons: [
{text:'Neu Rechnung',className:'btn-sm',action: function ( e, dt, node, config ) { {text:'Neue Rechnung',className:'btn-sm',action: function ( e, dt, node, config ) {
location.href = '/newBill/'; location.href = '/newBill/';
}}, }},
{text:'Neuer Transfer',className:'btn-sm mx-2',action: function ( e, dt, node, config ) { {text:'Neuer Transfer',className:'btn-sm mx-2',action: function ( e, dt, node, config ) {

26
public/js/menue.js Normal file
View File

@ -0,0 +1,26 @@
function syncScheduled(){
$('#mySnycModal').modal('show');
$('#mySnycModal').find('.modal-title').html("Synchronisierte Einträge!");
$.ajax({
type: "GET",
url: "/syncScheduled/",
data: {}, // serializes the form's elements.
success: function(data){
const myModale = document.querySelector('#mySnycModal');
var modalText = myModale.querySelector('.modal-body');
var modalFenster = myModale.querySelector('.modal-dialog');
modalText.innerHTML = data;
$('#todos').DataTable().ajax.reload();
},
error: function(data){
const myModale = document.querySelector('#mySnycModal');
var modalText = myModale.querySelector('.modal-body');
var modalFenster = myModale.querySelector('.modal-dialog');
modalFenster.classList.add("alert");
modalFenster.classList.add("alert-danger");
modalText.textContent = 'Fehler bei der Ausführung!';
$('#todos').DataTable().ajax.reload();
}
});
// location.href = '/syncScheduled/';
}

View File

@ -1,33 +1,6 @@
var datatable; var datatable;
var todos; var todos;
function syncScheduled(){
$('#mySnycModal').modal('show');
$('#mySnycModal').find('.modal-title').html("Synchronisierte Einträge!");
$.ajax({
type: "GET",
url: "/syncScheduled/",
data: {}, // serializes the form's elements.
success: function(data){
const myModale = document.querySelector('#mySnycModal');
var modalText = myModale.querySelector('.modal-body');
var modalFenster = myModale.querySelector('.modal-dialog');
modalText.innerHTML = data;
$('#todos').DataTable().ajax.reload();
},
error: function(data){
const myModale = document.querySelector('#mySnycModal');
var modalText = myModale.querySelector('.modal-body');
var modalFenster = myModale.querySelector('.modal-dialog');
modalFenster.classList.add("alert");
modalFenster.classList.add("alert-danger");
modalText.textContent = 'Fehler bei der Ausführung!';
$('#todos').DataTable().ajax.reload();
}
});
// location.href = '/syncScheduled/';
}
$(document).ready(function(){ $(document).ready(function(){
datatable = $('#bookings').DataTable({ datatable = $('#bookings').DataTable({
paging: false, paging: false,