}
-input.right {
+.right {
text-align: right;
}
.table-hover tbody tr:hover {
.card {
margin: 10px;
+}
+
+.thead-dark tr th select.form-control {
+ background-color: #212529;
+ background-image: url("data:image/svg+xml;utf8,<svg version='1.1' xmlns='http://www.w3.org/2000/svg' xmlns:xlink='http://www.w3.org/1999/xlink' width='24' height='24' viewBox='0 0 24 24'><path fill='#fff' d='M7.406 7.828l4.594 4.594 4.594-4.594 1.406 1.406-6 6-6-6z'></path></svg>");
+ color: #fff;
+ margin: 0px;
+}
+
+.table tbody tr.highlight td {
+ background-color: lightblue;
+}
+
+.noselect {
+ -webkit-touch-callout: none; /* iOS Safari */
+ -webkit-user-select: none; /* Safari */
+ -khtml-user-select: none; /* Konqueror HTML */
+ -moz-user-select: none; /* Firefox */
+ -ms-user-select: none; /* Internet Explorer/Edge */
+ user-select: none; /* Non-prefixed version, currently
+ supported by Chrome and Opera */
}
\ No newline at end of file
--- /dev/null
+{"name":"invoicejournal","type":"local","server":"dks-laptop","dbfile":"invoicejournal","vpn":"","vat":"0,17","currency":"€","mailserver":"","mailencryption":"","mailport":"","maillogin":"","mailpassword":""}
\ No newline at end of file
<select class="form-control list-group-item list-group-item-action bg-primary text-white" id="globaldatasets" onchange="browserapp.loaddataset();">
</select>
<a class="list-group-item list-group-item-action bg-light" href="javascript:browserapp.loadmodule('overview');">Übersicht</a>
+ <a class="list-group-item list-group-item-action bg-light" href="javascript:browserapp.loadmodule('bookings');">Buchungen</a>
<a class="list-group-item list-group-item-action bg-light" href="javascript:browserapp.loadmodule('invoices');">Rechnungen</a>
<a class="list-group-item list-group-item-action bg-light" href="javascript:browserapp.loadmodule('accounts');">Konten</a>
<a class="list-group-item list-group-item-action bg-light" href="javascript:browserapp.loadmodule('bankaccount');">Bankkonto</a>
+ <a class="list-group-item list-group-item-action bg-light" href="javascript:browserapp.loadmodule('documents');">Dokumente</a>
<a class="list-group-item list-group-item-action bg-light" href="javascript:browserapp.loadmodule('offers');">Angebote</a>
<a class="list-group-item list-group-item-action bg-light" href="javascript:browserapp.loadmodule('products');">Produkte</a>
<a class="list-group-item list-group-item-action bg-light" href="javascript:browserapp.loadmodule('templates');">Vorlagen</a>
function createWindow () {
// Create the browser window.
var executablePath = "";
- var parameters = [];
+ var parameters = [];
+ console.log(app.getAppPath());
if (os.platform() == "win32"){
executablePath = "C:\\Strawberry\\perl\\bin\\perl.exe";
- parameters = ["C:\\Users\\ksaff\\Workspace\\dks_server\\dkslocalserver.pl"];
+ parameters = ["C:\\Users\\ksaff\\Workspace\\Apps\\invoicejournal\\\\server\\invoicejournalserver.pl"];
} else { //os.platform() == "darwin"
executablePath = "/Users/kilian/perl5/perlbrew/perls/perl-5.28.1/bin/perl";
parameters = ["/Users/kilian/Workspace/dks_server/dkslocalserver.pl"];
--- /dev/null
+<!DOCTYPE html>
+<html lang="en">
+<head>
+ <meta charset="UTF-8">
+ <meta content="width=device-width, initial-scale=1.0" name="viewport">
+ <link href="../../node_modules/bootstrap/dist/css/bootstrap.min.css" rel="stylesheet">
+ <!-- <link href="../../node_modules/bootstrap-table/dist/bootstrap-table.min.css" rel="stylesheet"> -->
+ <!-- <link href="../../node_modules/bootstrap-datepicker/dist/css/bootstrap-datepicker.min.css" rel="stylesheet"> -->
+ <link href="../../node_modules/@fortawesome/fontawesome-free/css/fontawesome.min.css" rel="stylesheet">
+ <link href="../../css/invoicejournal.epic.css" rel="stylesheet">
+ <link href="../../css/app.css" rel="stylesheet">
+ <title>Konto</title>
+</head>
+<body>
+ <nav class="navbar navbar-expand-md navbar-dark fixed-top bg-dark">
+ <button class="btn btn-primary" onclick="parent.browserapp.loadmodule('accounts');"><i class="fas fa-chevron-left"></i><br>Back</button>
+ <a class="navbar-brand" href="#">Konto</a>
+ <div class="ml-auto">
+ <div aria-label="Basic example" class="btn-group" role="group">
+
+
+ </div>
+ </div>
+ </nav>
+ <div class="cotainer-fluid" style="margin-top: 52px;">
+ <!-- <ul class="nav nav-tabs" id="pagetab" role="tablist">
+ <li class="nav-item"><a aria-controls="invoice" aria-selected="true" class="nav-link active" data-toggle="tab" href="#invoice" id="invoice-tab" role="tab">Rechnung</a></li>
+ <li class="nav-item"><a aria-controls="files" aria-selected="false" class="nav-link" data-toggle="tab" href="#files" id="files-tab" role="tab">Dateien & Bezahlung</a></li>
+ <li class="nav-item"><a aria-controls="notes" aria-selected="false" class="nav-link" data-toggle="tab" href="#notes" id="notes-tab" role="tab">Zusatz-Texte</a></li>
+
+ </ul>
+ <div class="tab-content" id="tabpagecontent">
+ <div aria-labelledby="invoice-tab" class="tab-pane fade show active" id="invoice" role="tabpanel">
+ <div class="row">
+ <div class="col-md-4">
+ <div class="col-md-12">
+ <div class="form-group row">
+ <label for="id_sender" class="col-sm-2 col-form-label">Sender</label>
+ <div class="col-sm-10">
+ <select class="form-control" id="id_sender" name="id_sender"></select>
+ </div>
+ </div>
+ <div class="form-group row">
+ <label for="id_receipient" class="col-sm-2 col-form-label">Receiver</label>
+ <div class="col-sm-10">
+ <select class="form-control" id="id_receipient" name="id_receipient"></select>
+ </div>
+ </div>
+ <div class="form-group row">
+ <label for="payedamount" class="col-sm-2 col-form-label" >Bezahlt</label>
+ <div class="col-sm-6 input-group">
+ <input type="text" class="form-control" id="payedamount" name="payedamount" value="" />
+ <div class="input-group-append">
+ <span class="input-group-text">€</span>
+ </div>
+ </div>
+
+ </div>
+ </div>
+ </div>
+ <div class="col-md-8">
+ <div class="row">
+ <div class="col-md-6">
+ <div class="col-md-12">
+ <div class="form-group row">
+ <label for="date" class="col-sm-2 col-form-label" >Datum</label>
+ <div class="col-sm-4">
+ <input class="form-control datepicker" id="date" name="date" type="text" >
+ </div>
+ <label for="deadlinedate" class="col-sm-2 col-form-label" >Fälligkeit</label>
+ <div class="col-sm-4">
+ <input class="form-control datepicker" id="deadlinedate" name="deadlinedate" type="text">
+ </div>
+ </div>
+ <div class="form-group row">
+ <label for="reference" class="col-sm-2 col-form-label" >Referenz</label>
+ <div class="col-sm-10">
+ <input class="form-control" id="reference" name="reference" type="text">
+ </div>
+ </div>
+ </div>
+ </div>
+ <div class="col-md-6">
+ <div class="col-md-12">
+ <div class="form-group row">
+ <label for="type" class="col-sm-2 col-form-label">Typ</label>
+ <div class="col-sm-10">
+ <select class="form-control" id="type" name="type"></select>
+ </div>
+ </div>
+ <div class="form-group row">
+ <label for="id_template" class="col-sm-2 col-form-label">Template</label>
+ <div class="col-sm-10">
+ <select class="form-control" id="id_template" name="id_template"></select>
+ </div>
+ </div>
+ </div>
+ </div>
+ </div>
+ <div class="col-md-12">
+ <div class="row">
+ <div class="col-md-6">
+ <div class="form-group row">
+ <label for="netamount" class="col-sm-2 col-form-label" >Netto</label>
+ <div class="col-sm-4 input-group">
+ <input type="text" class="form-control" id="netamount" name="netamount" value="" readonly/>
+ <div class="input-group-append">
+ <span class="input-group-text">€</span>
+ </div>
+ </div>
+ <label for="discountamount" class="col-sm-2 col-form-label">Rabatt</label>
+ <div class="col-sm-4 input-group">
+ <input type="text" class="form-control" id="discountamount" name="discountamount" value="" readonly/>
+ <div class="input-group-append">
+ <span class="input-group-text">€</span>
+ </div>
+ </div>
+ </div>
+ </div>
+ <div class="col-md-6">
+ <div class="form-group row">
+ <label for="vatamount" class="col-sm-2 col-form-label" >MwSt</label>
+ <div class="col-sm-4 input-group">
+ <input type="text" class="form-control" id="vatamount" name="vatamount" value="" readonly/>
+ <div class="input-group-append">
+ <span class="input-group-text">€</span>
+ </div>
+ </div>
+ <label for="grossamount" class="col-sm-2 col-form-label">Brutto</label>
+ <div class="col-sm-4 input-group">
+ <input type="text" class="form-control" id="grossamount" name="grossamount" value="" readonly/>
+ <div class="input-group-append">
+ <span class="input-group-text">€</span>
+ </div>
+ </div>
+ </div>
+ </div>
+ </div>
+ </div>
+ </div>
+ </div>
+ <div class="row">
+ <div class="col-md-12">
+ <nav class="navbar navbar-expand-md navbar-dark bg-dark">
+ <a class="navbar-brand" href="#">Positionen</a>
+
+ <div class="ml-auto">
+ <div aria-label="Basic example" class="btn-group" role="group">
+ <button class="btn btn-primary" onclick="position.new();"><i class="fas fa-plus"></i><br> New</button>
+ <button class="btn btn-primary" onclick="position.delete();"><i class="fas fa-trash"></i><br> Delete</button>
+ <button class="btn btn-primary" onclick="position.clone();"><i class="fas fa-copy"></i><br> Dupl.</button>
+ <div class="btn-group">
+ <button class="btn btn-primary" id="status" type="button"><i class="fas fa-box"></i><br> add Product</button>
+ <button aria-expanded="false" aria-haspopup="true" class="btn btn-primary dropdown-toggle dropdown-toggle-split" data-toggle="dropdown" type="button"><span class="sr-only">Toggle Dropdown</span></button>
+ <div class="dropdown-menu" id="productdata"></div>
+ </div>
+ <div class="btn-group">
+ <button class="btn btn-primary" id="status" type="button"><i class="fas fa-business-time"></i><br> add Service</button>
+ <button aria-expanded="false" aria-haspopup="true" class="btn btn-primary dropdown-toggle dropdown-toggle-split" data-toggle="dropdown" type="button"><span class="sr-only">Toggle Dropdown</span></button>
+ <div class="dropdown-menu" id="servicedata"></div>
+ </div>
+ </div>
+ </div>
+ </nav>
+ </div>
+ </div>
+ <div class="row">
+ <table class="table table-bordered table-hover table-striped" id="tbl_invoicedata">
+ <thead class="thead-dark">
+ <tr>
+ <th data-checkbox="true"></th>
+ <th data-sortable="true">Description</th>
+ <th data-sortable="true">Qty</th>
+ <th data-sortable="true">Unit</th>
+ <th data-sortable="true">Price</th>
+ <th data-sortable="true">VAT</th>
+ <th data-sortable="true">Discount</th>
+ <th data-sortable="true">Sums</th>
+ </tr>
+ </thead>
+ </table>
+ </div>
+ </div>
+ <div aria-labelledby="files-tab" class="tab-pane fade" id="files" role="tabpanel">
+ <div class="row">
+ <div class="col-md-8">
+ <table class="table table-bordered table-hover table-striped" id="tbl_payements">
+ <thead class="thead-dark">
+ <tr>
+ <th data-checkbox="true"></th>
+ <th data-sortable="true">Datum</th>
+ <th data-sortable="true">Typ</th>
+ <th data-sortable="true">Sender</th>
+ <th data-sortable="true">Empfänger</th>
+ <th data-sortable="true">KontoAuszug</th>
+ <th data-sortable="true">Betrag</th>
+ </tr>
+ </thead>
+ </table>
+ </div>
+ <div class="col-md-4">
+ <table class="table table-bordered table-hover table-striped" id="tbl_files">
+ <thead class="thead-dark">
+ <tr>
+ <th data-checkbox="true"></th>
+ <th data-sortable="true">Name</th>
+ <th data-sortable="true">Type</th>
+ <th data-sortable="true">Date</th>
+ </tr>
+ </thead>
+ </table>
+ </div>
+
+ </div>
+ </div>
+ <div aria-labelledby="notes-tab" class="tab-pane fade" id="notes" role="tabpanel">
+ <div class="row">
+ <div class="col-md-12">
+ <div class="form-group">
+ <label for="preface">Vorwort</label>
+ <textarea class="form-control richtextedit" style="height: 200px;" id="preface" name="preface"></textarea>
+ </div>
+ </div>
+ </div>
+ <div class="row">
+ <div class="col-md-12">
+ <div class="form-group">
+ <label for="footnote">Nachwort</label>
+ <textarea class="form-control richtextedit" style="height: 200px;" id="footnote" name="footnote"></textarea>
+ </div>
+ </div>
+ </div>
+ </div>
+
+ </div> -->
+ </div>
+ <script> if (typeof module === 'object') {window.module = module; module = undefined;}</script>
+ <script src="../../node_modules/jquery/dist/jquery.min.js"></script>
+ <script src="../../node_modules/bootstrap/dist/js/bootstrap.bundle.min.js"></script>
+ <!-- <script src="../../node_modules/bootstrap-table/dist/bootstrap-table.min.js"></script> -->
+ <!-- <script src="../../node_modules/bootstrap-datepicker/dist/js/bootstrap-datepicker.min.js"></script> -->
+ <script src="../../node_modules/@fortawesome/fontawesome-free/js/all.min.js"></script>
+ <script src="../../node_modules/tinymce/tinymce.min.js"></script>
+ <script src="../../js/moduleglobal.js"></script>
+ <script src="../../js/database.js"></script>
+ <!-- <script src="lib/invoice.js"></script> -->
+ <script src="form_account.js"></script>
+ <script>if (window.module) module = window.module;</script>
+</body>
+</html>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link rel="stylesheet" href="../../node_modules/bootstrap/dist/css/bootstrap.min.css">
-<link rel="stylesheet" href="../../node_modules/bootstrap-table/dist/bootstrap-table.min.css">
<link rel="stylesheet" href="../../node_modules/@fortawesome/fontawesome-free/css/fontawesome.min.css">
<link rel="stylesheet" href="../../css/invoicejournal.epic.css">
<link rel="stylesheet" href="../../css/app.css">
</div>
</div>
</nav>
- <div class="cotainer-fluid" style="margin-top: 52px;">
+ <div class="cotainer-fluid" style="margin-top: 52px;">
+ <table style="width: 100%;" class="noselect">
+ <tr>
+ <td style="padding: 0px; margin: 0px;">
+ <table class="table" style="width: 100%; margin: 0px;" id="tbl_accounts_head">
+ <thead class="thead-dark">
+ <tr>
+ <th>Kunden-Nr.</th>
+ <th>Company / Name</th>
+ <th>Adresse</th>
+ <th>E-mail</th>
+ <th>Telefon</th>
+ </tr>
+ </thead>
+ </table>
+ </td>
+ </tr>
+ <tr>
+ <td>
+ <div style="width: 100%; height: 90.5vh; overflow-y: scroll;">
<table id="tbl_accounts" class="table table-bordered table-hover table-striped">
- <thead class="thead-dark">
- <th data-checkbox="true"></th>
- <th data-sortable="true">Kunden-Nr.</th>
- <th data-sortable="true">Company / Name</th>
- <th data-sortable="true">Adresse</th>
- <th data-sortable="true">E-mail</th>
- <th data-sortable="true">Telefon</th>
- <tfoot></tfoot>
<tbody></tbody>
</table>
+ </div>
+</td>
+</tr>
+</table>
</div>
<script>if (typeof module === 'object') {window.module = module; module = undefined;}</script>
<script src="../../node_modules/jquery/dist/jquery.min.js"></script>
<script src="../../node_modules/bootstrap/dist/js/bootstrap.bundle.min.js"></script>
-<script src="../../node_modules/bootstrap-table/dist/bootstrap-table.min.js"></script>
<script src="../../node_modules/@fortawesome/fontawesome-free/js/all.min.js"></script>
<script src="../../js/moduleglobal.js"></script>
<script src="../../js/database.js"></script>
var winh = Math.max(document.documentElement.clientHeight, window.innerHeight || 0);
var tblh = winh-54;
-
+var shiftdown = false;
+var selection = [];
function initpage(){
// console.log(appdb.url);
var sql = 'SELECT id, company, prename,surname, address, zip, city, country, email, phone, mobile, ident FROM accounts;';
var data = appdb.dbquery(sql);
- console.log(data.sqldata);
+
for (var i in data.sqldata){
- var row = '<tr id="' +data.sqldata[i].id + '">'+
- '<td></td>' +
+ var row = '<tr onclick="setselection(\''+ data.sqldata[i].id +'\');" id="' +data.sqldata[i].id + '">'+
'<td>' + data.sqldata[i].ident+ '</td>' +
'<td>' + data.sqldata[i].company + (( data.sqldata[i].company != null)?'<br/>':'') + data.sqldata[i].surname + ' ' + data.sqldata[i].surname + '</td>' +
'<td>' + data.sqldata[i].address+ ((data.sqldata[i].address != null)?'<br/>':'') + data.sqldata[i].zip + ' ' + data.sqldata[i].city + ((data.sqldata[i].country != null)?'<br/>':'')+ data.sqldata[i].country + '</td>' +
'</tr>';
$("#tbl_accounts").append(row.replace(/null/g,''));
}
- $('#tbl_accounts').bootstrapTable({
- pagination: false,
- search: false,
- height: tblh,
- clickToSelect: true
- });
+ var cols = $("#tbl_accounts > tbody > tr:first-child").children();
+ var colnum = cols.length -1
+ console.log("childnum:" + colnum);
+ for (var i=1;i<=colnum;i++){
+ wx = $("#tbl_accounts > tbody > tr:first-child > td:nth-child("+ i +")").width();
+ wx = wx +3;
+ $("#tbl_accounts_head > thead > tr > th:nth-child("+ i +")").width(wx);
+ }
}
function account_edit(){
- var id= getTableSelectionID();
- if (id){
- parent.browserapp.loadmodulepage('accounts','form_account',{"id":d});
+ if (selection.length >= 1){
+ parent.browserapp.loadmodulepage('accounts','form_account',{"id":selection[0]});
}
}
}
-function getTableSelectionID(){
- var sel = $('#tbl_accounts').bootstrapTable('getSelections');
- var id = null;
-
- if (sel){ id=sel[0]._id; }
- console.log("Selected ID:" + id);
- return id;
+function setselection(id){
+ if (shiftdown === true){
+ if ($("#" + id).hasClass('highlight')){
+ $("#" + id).removeClass('highlight');
+ selection.splice($.inArray(id, selection),1);
+ }else {
+ $("#" + id).addClass('highlight');
+ selection.push(id);
+ }
+ } else {
+ $("#" + id).addClass('highlight').siblings().removeClass('highlight');
+ selection = [id];
+ }
}
-function getTableSelectionIDs(){
- var sel = $('#tbl_accounts').bootstrapTable('getSelections');
- var ids = [];
- if (sel){
- for (var s in sel){
- ids.push(s._id);
- }
+$(document).on('keydown',function(evt){
+ if (evt.key= "Shift"){
+ shiftdown = true;
+ }
+});
+
+$(document).on('keyup',function(evt){
+ if (evt.key = "Shift"){
+ shiftdown = false;
}
- return ids;
-}
\ No newline at end of file
+});
\ No newline at end of file
--- /dev/null
+<!DOCTYPE html>
+<html lang="en">
+<head>
+ <meta charset="UTF-8">
+ <meta content="width=device-width, initial-scale=1.0" name="viewport">
+ <link href="../../node_modules/bootstrap/dist/css/bootstrap.min.css" rel="stylesheet">
+ <link href="../../node_modules/bootstrap-table/dist/bootstrap-table.min.css" rel="stylesheet">
+ <link href="../../node_modules/bootstrap-datepicker/dist/css/bootstrap-datepicker.min.css" rel="stylesheet">
+ <link href="../../node_modules/@fortawesome/fontawesome-free/css/fontawesome.min.css" rel="stylesheet">
+ <link href="../../css/invoicejournal.epic.css" rel="stylesheet">
+ <link href="../../css/app.css" rel="stylesheet">
+ <title>Rechnung</title>
+</head>
+<body>
+ <nav class="navbar navbar-expand-md navbar-dark fixed-top bg-dark">
+ <button class="btn btn-primary" onclick="parent.browserapp.loadmodule('invoices');"><i class="fas fa-chevron-left"></i><br>Back</button>
+ <a class="navbar-brand" href="#">Rechnung</a>
+ <div class="ml-auto">
+ <div aria-label="Basic example" class="btn-group" role="group">
+ <button class="btn btn-primary" onclick="invoice.new();"><i class="fas fa-plus"></i><br>New</button>
+ <button class="btn btn-primary" onclick="invoice.delete();"><i class="fas fa-trash"></i><br>Delete</button>
+ <button class="btn btn-primary" onclick="invoice.clone();"><i class="fas fa-copy"></i><br>Dupl.</button>
+ <button class="btn btn-primary" onclick="invoice.createpdf();"><i class="fas fa-file-pdf"></i><br>PDF</button>
+ <button class="btn btn-primary" onclick="invoice.print();"><i class="fas fa-print"></i><br>Print</button>
+ <button class="btn btn-primary" onclick="invoice.sendinvoice();"><i class="fas fa-envelope"></i><br>Send</button>
+ <button class="btn btn-primary" onclick="invoice.addfile();"><i class="fas fa-file"></i><br>Add File</button>
+ <div class="btn-group">
+ <button class="btn btn-primary" id="status" type="button">Status</button>
+ <button aria-expanded="false" aria-haspopup="true" class="btn btn-primary dropdown-toggle dropdown-toggle-split" data-toggle="dropdown" type="button"><span class="sr-only">Toggle Dropdown</span></button>
+ <div class="dropdown-menu" id="statusdata"></div>
+ </div>
+ </div>
+ </div>
+ </nav>
+ <div class="cotainer-fluid" style="margin-top: 52px;">
+ <ul class="nav nav-tabs" id="pagetab" role="tablist">
+ <li class="nav-item"><a aria-controls="invoice" aria-selected="true" class="nav-link active" data-toggle="tab" href="#invoice" id="invoice-tab" role="tab">Rechnung</a></li>
+ <li class="nav-item"><a aria-controls="files" aria-selected="false" class="nav-link" data-toggle="tab" href="#files" id="files-tab" role="tab">Dateien & Bezahlung</a></li>
+ <li class="nav-item"><a aria-controls="notes" aria-selected="false" class="nav-link" data-toggle="tab" href="#notes" id="notes-tab" role="tab">Zusatz-Texte</a></li>
+
+ </ul>
+ <div class="tab-content" id="tabpagecontent">
+ <div aria-labelledby="invoice-tab" class="tab-pane fade show active" id="invoice" role="tabpanel">
+ <div class="row">
+ <div class="col-md-4">
+ <div class="col-md-12">
+ <div class="form-group row">
+ <label for="id_sender" class="col-sm-2 col-form-label">Sender</label>
+ <div class="col-sm-10">
+ <select class="form-control" id="id_sender" name="id_sender"></select>
+ </div>
+ </div>
+ <div class="form-group row">
+ <label for="id_receipient" class="col-sm-2 col-form-label">Receiver</label>
+ <div class="col-sm-10">
+ <select class="form-control" id="id_receipient" name="id_receipient"></select>
+ </div>
+ </div>
+ <div class="form-group row">
+ <label for="payedamount" class="col-sm-2 col-form-label" >Bezahlt</label>
+ <div class="col-sm-6 input-group">
+ <input type="text" class="form-control" id="payedamount" name="payedamount" value="" />
+ <div class="input-group-append">
+ <span class="input-group-text">€</span>
+ </div>
+ </div>
+
+ </div>
+ </div>
+ </div>
+ <div class="col-md-8">
+ <div class="row">
+ <div class="col-md-6">
+ <div class="col-md-12">
+ <div class="form-group row">
+ <label for="date" class="col-sm-2 col-form-label" >Datum</label>
+ <div class="col-sm-4">
+ <input class="form-control datepicker" id="date" name="date" type="text" >
+ </div>
+ <label for="deadlinedate" class="col-sm-2 col-form-label" >Fälligkeit</label>
+ <div class="col-sm-4">
+ <input class="form-control datepicker" id="deadlinedate" name="deadlinedate" type="text">
+ </div>
+ </div>
+ <div class="form-group row">
+ <label for="reference" class="col-sm-2 col-form-label" >Referenz</label>
+ <div class="col-sm-10">
+ <input class="form-control" id="reference" name="reference" type="text">
+ </div>
+ </div>
+ </div>
+ </div>
+ <div class="col-md-6">
+ <div class="col-md-12">
+ <div class="form-group row">
+ <label for="type" class="col-sm-2 col-form-label">Typ</label>
+ <div class="col-sm-10">
+ <select class="form-control" id="type" name="type"></select>
+ </div>
+ </div>
+ <div class="form-group row">
+ <label for="id_template" class="col-sm-2 col-form-label">Template</label>
+ <div class="col-sm-10">
+ <select class="form-control" id="id_template" name="id_template"></select>
+ </div>
+ </div>
+ </div>
+ </div>
+ </div>
+ <div class="col-md-12">
+ <div class="row">
+ <div class="col-md-6">
+ <div class="form-group row">
+ <label for="netamount" class="col-sm-2 col-form-label" >Netto</label>
+ <div class="col-sm-4 input-group">
+ <input type="text" class="form-control" id="netamount" name="netamount" value="" readonly/>
+ <div class="input-group-append">
+ <span class="input-group-text">€</span>
+ </div>
+ </div>
+ <label for="discountamount" class="col-sm-2 col-form-label">Rabatt</label>
+ <div class="col-sm-4 input-group">
+ <input type="text" class="form-control" id="discountamount" name="discountamount" value="" readonly/>
+ <div class="input-group-append">
+ <span class="input-group-text">€</span>
+ </div>
+ </div>
+ </div>
+ </div>
+ <div class="col-md-6">
+ <div class="form-group row">
+ <label for="vatamount" class="col-sm-2 col-form-label" >MwSt</label>
+ <div class="col-sm-4 input-group">
+ <input type="text" class="form-control" id="vatamount" name="vatamount" value="" readonly/>
+ <div class="input-group-append">
+ <span class="input-group-text">€</span>
+ </div>
+ </div>
+ <label for="grossamount" class="col-sm-2 col-form-label">Brutto</label>
+ <div class="col-sm-4 input-group">
+ <input type="text" class="form-control" id="grossamount" name="grossamount" value="" readonly/>
+ <div class="input-group-append">
+ <span class="input-group-text">€</span>
+ </div>
+ </div>
+ </div>
+ </div>
+ </div>
+ </div>
+ </div>
+ </div>
+ <div class="row">
+ <div class="col-md-12">
+ <nav class="navbar navbar-expand-md navbar-dark bg-dark">
+ <a class="navbar-brand" href="#">Positionen</a>
+
+ <div class="ml-auto">
+ <div aria-label="Basic example" class="btn-group" role="group">
+ <button class="btn btn-primary" onclick="position.new();"><i class="fas fa-plus"></i><br> New</button>
+ <button class="btn btn-primary" onclick="position.delete();"><i class="fas fa-trash"></i><br> Delete</button>
+ <button class="btn btn-primary" onclick="position.clone();"><i class="fas fa-copy"></i><br> Dupl.</button>
+ <div class="btn-group">
+ <button class="btn btn-primary" id="status" type="button"><i class="fas fa-box"></i><br> add Product</button>
+ <button aria-expanded="false" aria-haspopup="true" class="btn btn-primary dropdown-toggle dropdown-toggle-split" data-toggle="dropdown" type="button"><span class="sr-only">Toggle Dropdown</span></button>
+ <div class="dropdown-menu" id="productdata"></div>
+ </div>
+ <div class="btn-group">
+ <button class="btn btn-primary" id="status" type="button"><i class="fas fa-business-time"></i><br> add Service</button>
+ <button aria-expanded="false" aria-haspopup="true" class="btn btn-primary dropdown-toggle dropdown-toggle-split" data-toggle="dropdown" type="button"><span class="sr-only">Toggle Dropdown</span></button>
+ <div class="dropdown-menu" id="servicedata"></div>
+ </div>
+ </div>
+ </div>
+ </nav>
+ </div>
+ </div>
+ <div class="row">
+ <table class="table table-bordered table-hover table-striped" id="tbl_invoicedata">
+ <thead class="thead-dark">
+ <tr>
+ <th data-checkbox="true"></th>
+ <th data-sortable="true">Description</th>
+ <th data-sortable="true">Qty</th>
+ <th data-sortable="true">Unit</th>
+ <th data-sortable="true">Price</th>
+ <th data-sortable="true">VAT</th>
+ <th data-sortable="true">Discount</th>
+ <th data-sortable="true">Sums</th>
+ </tr>
+ </thead>
+ </table>
+ </div>
+ </div>
+ <div aria-labelledby="files-tab" class="tab-pane fade" id="files" role="tabpanel">
+ <div class="row">
+ <div class="col-md-8">
+ <table class="table table-bordered table-hover table-striped" id="tbl_payements">
+ <thead class="thead-dark">
+ <tr>
+ <th data-checkbox="true"></th>
+ <th data-sortable="true">Datum</th>
+ <th data-sortable="true">Typ</th>
+ <th data-sortable="true">Sender</th>
+ <th data-sortable="true">Empfänger</th>
+ <th data-sortable="true">KontoAuszug</th>
+ <th data-sortable="true">Betrag</th>
+ </tr>
+ </thead>
+ </table>
+ </div>
+ <div class="col-md-4">
+ <table class="table table-bordered table-hover table-striped" id="tbl_files">
+ <thead class="thead-dark">
+ <tr>
+ <th data-checkbox="true"></th>
+ <th data-sortable="true">Name</th>
+ <th data-sortable="true">Type</th>
+ <th data-sortable="true">Date</th>
+ </tr>
+ </thead>
+ </table>
+ </div>
+
+ </div>
+ </div>
+ <div aria-labelledby="notes-tab" class="tab-pane fade" id="notes" role="tabpanel">
+ <div class="row">
+ <div class="col-md-12">
+ <div class="form-group">
+ <label for="preface">Vorwort</label>
+ <textarea class="form-control richtextedit" style="height: 200px;" id="preface" name="preface"></textarea>
+ </div>
+ </div>
+ </div>
+ <div class="row">
+ <div class="col-md-12">
+ <div class="form-group">
+ <label for="footnote">Nachwort</label>
+ <textarea class="form-control richtextedit" style="height: 200px;" id="footnote" name="footnote"></textarea>
+ </div>
+ </div>
+ </div>
+ </div>
+
+ </div>
+ </div>
+ <script> if (typeof module === 'object') {window.module = module; module = undefined;}</script>
+ <script src="../../node_modules/jquery/dist/jquery.min.js"></script>
+ <script src="../../node_modules/bootstrap/dist/js/bootstrap.bundle.min.js"></script>
+ <script src="../../node_modules/bootstrap-table/dist/bootstrap-table.min.js"></script>
+ <script src="../../node_modules/bootstrap-datepicker/dist/js/bootstrap-datepicker.min.js"></script>
+ <script src="../../node_modules/@fortawesome/fontawesome-free/js/all.min.js"></script>
+ <script src="../../node_modules/tinymce/tinymce.min.js"></script>
+ <script src="../../js/moduleglobal.js"></script>
+ <script src="../../js/database.js"></script>
+ <script src="lib/invoice.js"></script>
+ <script src="form_invoice.js"></script>
+ <script>if (window.module) module = window.module;</script>
+</body>
+</html>
--- /dev/null
+function initpage(){
+ $(".datepicker").datepicker({});
+ tinymce.init({
+ selector: 'textarea.richtextedit',
+ branding: false,
+ menubar:false,
+ statusbar: false,
+ plugins: 'searchreplace autolink directionality visualblocks visualchars advlist lists textpattern',
+ toolbar: 'bold italic underline strikethrough forecolor backcolor | link | alignleft aligncenter alignright alignjustify | numlist bullist outdent indent | removeformat',
+ image_advtab: true,
+ language: 'de',
+ });
+ getaccounts();
+ if (mpref.cfg.id){
+ getinvoicedata(mpref.cfg.id);
+ } else {
+ //load default new invoice data
+ }
+ console.log("invoice ID:",mpref.cfg.id);
+}
+
+$("#status").onchange(function(data){
+
+ var xtest = $("#status").html();
+ console.log($("#status").html());
+ if ($("#status").html() == 'bezahlt'){
+ $("#status").attr("class","btn btn-success");
+ } else if ($("#status").html() == 'geplant'){
+ $("#status").attr("class","btn btn-secondary");
+ } else if ($("#status").html() == 'überfällig'){
+ $("#status").attr("class","btn btn-danger");
+ } else if ($("#status").html() == 'verschickt'){
+ $("#status").attr("class","btn btn-warning");
+ } else if ($("#status").html() == 'erhalten'){
+ $("#status").attr("class","btn btn-info");
+ }
+})
+
+function getaccounts(){
+ var sql = "select id, company,case when \"type\" like '%kunde%' then 1 else 0 end as receiver,case when \"type\" like '%lieferant%' or \"type\" like '%mitarbeiter%' or \"type\" like '%behörde%' then 1 else 0 end as sender from accounts;";
+ var data = appdb.dbquery(sql);
+ //onsole.log(data.sqldata);
+ for (var i in data.sqldata){
+ if (data.sqldata[i].receiver == 1){
+ $("#id_receipient").append('<option value="'+data.sqldata[i].id+'">' + data.sqldata[i].company+'</option>');
+ }
+ if (data.sqldata[i].sender == 1){
+ $("#id_sender").append('<option value="'+data.sqldata[i].id+'">' + data.sqldata[i].company+'</option>');
+ }
+ }
+}
+
+function getinvoicedata(id){
+ var sql = "select ij.id_sender,ij.id_receipient,ij.id_template,ij.status,ij.reference,ij.type, " +
+ "ij.statement,STRFTIME(\"%d.%m.%Y\",ij.date) as date,STRFTIME(\"%d.%m.%Y\",ij.deadlinedate) as deadlinedate,ij.footertext,ij.headertext, " +
+ "printf(\"%.2f\",CAST(sum(pos.quantity * pos.unitamount) as real)) as netamount, " +
+ "printf(\"%.2f\",CAST(case when pos.taxpercent > 0 then sum(pos.taxpercent * pos.quantity * pos.unitamount) else 0.0 end AS REAL)) as vatamount, " +
+ "printf(\"%.2f\",CAST(sum(pos.quantity * pos.unitamount) + case when pos.taxpercent > 0 then sum(pos.taxpercent * pos.quantity * pos.unitamount) else 0.0 end AS real)) as grossamount, " +
+ "printf(\"%.2f\",COALESCE(ij.payedamount,0.0)) as payedamount " +
+ "from invoicejournal ij left join invoicepositions pos on (ij.id=pos.id_invoice) where ij.id='"+mpref.cfg.id+"' group by pos.id_invoice;";
+ var data = appdb.dbquery(sql);
+ if (data.sqldata){
+ for (var i in data.sqldata[0]){
+ if ($("#" + i).prop("tagName") == "SELECT"){
+ $("#" + i).val(data.sqldata[0][i]);
+ } else if ($("#" + i).prop("tagName") == "INPUT" ) {
+ console.log(i + ">=" + data.sqldata[0][i]);
+ $("#" + i).val(data.sqldata[0][i]);
+ } else {
+ $("#" + i).html(data.sqldata[0][i]);
+ }
+
+ $("#" + i).val(data.sqldata[0][i]);
+ }
+ }
+}
+
+function loadinvoicepositions(){
+
+}
+
--- /dev/null
+<!DOCTYPE html>
+<html lang="en">
+<meta charset="UTF-8">
+<meta name="viewport" content="width=device-width, initial-scale=1.0">
+<link rel="stylesheet" href="../../node_modules/bootstrap/dist/css/bootstrap.min.css">
+<!-- <link rel="stylesheet" href="../../node_modules/bootstrap-table/dist/bootstrap-table.min.css"> -->
+<link rel="stylesheet" href="../../node_modules/@fortawesome/fontawesome-free/css/fontawesome.min.css">
+<link rel="stylesheet" href="../../css/invoicejournal.epic.css">
+<link rel="stylesheet" href="../../css/app.css">
+<title>Buchungen</title>
+</head>
+<body>
+ <nav class="navbar navbar-expand-md navbar-dark fixed-top bg-dark">
+ <a class="navbar-brand" href="#">Buchungen</a>
+ <div class="ml-auto">
+ <div class="btn-group" role="group" aria-label="Basic example">
+ <button class="btn btn-primary" onclick="booking_new();"><i class="fas fa-plus"></i><br/>New</button>
+ <button class="btn btn-primary" onclick="booking_edit();"><i class="fas fa-edit"></i><br/>Edit</button>
+ <button class="btn btn-primary" onclick="booking_delete();"><i class="fas fa-trash"></i><br/>Delete</button>
+ <button class="btn btn-primary" onclick="booking_clone();"><i class="fas fa-clone"></i><br/>Dupl.</button>
+ <div class="btn-group">
+ <button type="button" class="btn btn-primary" id="seltimerange">TimeRange</button>
+ <button type="button" class="btn btn-primary dropdown-toggle dropdown-toggle-split" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
+ <span class="sr-only">Toggle Dropdown</span>
+ </button>
+ <div class="dropdown-menu" id="timerange">
+
+ </div>
+ </div>
+ </div>
+ </div>
+ </nav>
+ <div class="cotainer-fluid" style="margin-top: 52px;">
+ <table style="width: 100%;" class="noselect">
+ <tr>
+ <td style="padding: 0px; margin: 0px;">
+ <table class="table" style="width: 100%; margin: 0px;" id="tbl_bookings_head">
+ <thead class="thead-dark">
+ <tr>
+ <th><select id="daterange" class="form-control" onchange="setfilter('daterange','bookingdate');"></select></th>
+ <th><select id="receipient" class="form-control" onchange="setfilter('receipient','receipient');"></select></th>
+ <th><select id="sender" onchange="setfilter('sender','sender');" class="form-control"></select></th>
+ <th>Beschreibung</th>
+ <th>
+ <select id="status" onchange="setfilter('status','status');" class="form-control">
+ <option hidden>Status</option>
+ <option value=""></option>
+ <option value="bezahlt">bezahlt</option>
+ <option value="verschickt">verschickt</option>
+ <option value="geplant">geplant</option>
+ <option value="überfällig">überfällig</option>
+ </select>
+ </th>
+ <th >Betrag</th>
+ </tr>
+ </thead>
+ </table>
+ </td>
+ </tr>
+ <tr>
+ <td>
+ <div style="width: 100%; height: 80vh; overflow-y: scroll;">
+ <table id="tbl_bookings" style="width: 100%;" class="table table-bordered table-hover table-striped">
+ <!-- <thead class="thead-dark"> <tr>
+
+ <th data-checkbox="true"></th>
+ <th data-sortable="true">Datum</th>
+ <th data-sortable="true" data-filter="true">Empfänger</th>
+ <th data-sortable="true">Sender</th>
+ <th data-sortable="true">Beschreibung</th>
+ <th data-sortable="true">Status</th>
+ <th data-sortable="true" data-align="right">Betrag</th>
+ </tr>
+ </thead> -->
+
+ <tbody></tbody>
+ </table>
+ </div>
+ </td>
+ </tr>
+ </table>
+ <div class="row bg-dark" style="margin: 0px;width: 100%; height: 10vh; overflow:hidden;">
+ <div class="col btn-secondary">
+ <div class="form-group">
+ <label>geplant</label>
+ <div class="form-inline">
+ <div class="input-group" style="margin: 0px !important;">
+ <div class="input-group-prepend">
+ <div class="input-group-text">Σ</div>
+ </div>
+ <input type="text" class="form-control right" id="cnt_planned"/>
+ </div>
+ <div class="input-group" style="margin: 0px !important;">
+ <div class="input-group-prepend">
+ <div class="input-group-text">€</div>
+ </div>
+ <input type="text" class="form-control right" id="sum_planned"/>
+ </div>
+ </div>
+ </div>
+ </div>
+ <div class="col btn-warning">
+ <div class="form-group">
+ <label>verschickt</label>
+ <div class="form-inline">
+ <div class="input-group" style="margin: 0px !important;">
+ <div class="input-group-prepend">
+ <div class="input-group-text">Σ</div>
+ </div>
+ <input type="text" class="form-control right" id="cnt_sended"/>
+ </div>
+ <div class="input-group" style="margin: 0px !important;">
+ <div class="input-group-prepend">
+ <div class="input-group-text">€</div>
+ </div>
+ <input type="text" class="form-control right" id="sum_sended"/>
+ </div>
+ </div>
+ </div>
+ </div>
+ <div class="col btn-success">
+ <div class="form-group">
+ <label>bezahlt</label>
+ <div class="form-inline">
+ <div class="input-group" style="margin: 0px !important;">
+ <div class="input-group-prepend">
+ <div class="input-group-text">Σ</div>
+ </div>
+ <input type="text" class="form-control right" id="cnt_payed"/>
+ </div>
+ <div class="input-group" style="margin: 0px !important;">
+ <div class="input-group-prepend">
+ <div class="input-group-text">€</div>
+ </div>
+ <input type="text" class="form-control right" id="sum_payed"/>
+ </div>
+ </div>
+ </div>
+ </div>
+ <div class="col btn-danger">
+ <div class="form-group">
+ <label>überfällig</label>
+ <div class="form-inline">
+ <div class="input-group" style="margin: 0px !important;">
+ <div class="input-group-prepend">
+ <div class="input-group-text">Σ</div>
+ </div>
+ <input type="text" class="form-control right" id="cnt_delayed"/>
+ </div>
+ <div class="input-group" style="margin: 0px !important;">
+ <div class="input-group-prepend">
+ <div class="input-group-text">€</div>
+ </div>
+ <input type="text" class="form-control right" id="sum_delayed"/>
+ </div>
+ </div>
+ </div>
+ </div>
+ <div class="col btn-dark">
+ <div class="form-group">
+ <label>Total</label>
+ <div class="form-inline">
+ <div class="input-group" style="margin: 0px !important;">
+ <div class="input-group-prepend">
+ <div class="input-group-text">Σ</div>
+ </div>
+ <input type="text" class="form-control right" id="cnt_total"/>
+ </div>
+ <div class="input-group" style="margin: 0px !important;">
+ <div class="input-group-prepend">
+ <div class="input-group-text">€</div>
+ </div>
+ <input type="text" class="form-control right" id="sum_total"/>
+ </div>
+ </div>
+ </div>
+ </div>
+
+ </div>
+ </div>
+<script>if (typeof module === 'object') {window.module = module; module = undefined;}</script>
+<script src="../../node_modules/jquery/dist/jquery.min.js"></script>
+<script src="../../node_modules/bootstrap/dist/js/bootstrap.bundle.min.js"></script>
+<!-- <script src="../../node_modules/bootstrap-table/dist/bootstrap-table.min.js"></script>
+ <script src="../../node_modules/bootstrap-table/dist/extensions/select2-filter/bootstrap-table-select2-filter.min.js"></script>
+ <script src="../../node_modules/select2/dist/js/select2.full.min.js"></script> -->
+<script src="../../node_modules/@fortawesome/fontawesome-free/js/all.min.js"></script>
+<script src="../../js/moduleglobal.js"></script>
+<script src="../../js/database.js"></script>
+<script src="lib/booking.js"></script>
+<script src="index.js"></script>
+<script>if (window.module) module = window.module;</script>
+</body>
+</html>
\ No newline at end of file
--- /dev/null
+var winh = Math.max(document.documentElement.clientHeight, window.innerHeight || 0);
+var tblh = winh-54;
+var pagepref = undefined;
+var selection = [];
+// var cfg = {
+// byear: 2018
+// }
+var sums = { planned: {cnt:0,sum:0},sended: {cnt:0,sum:0},payed: {cnt:0,sum:0},delayed: {cnt:0,sum:0},total: {cnt:0,sum:0}};
+var shiftdown = false;
+function initpage(){
+ console.log(appdb.url);
+ pagepref = parent.usersystem.getPreference("bookings");
+ if (pagepref === null){
+ pagepref= {};
+ }
+ console.log(pagepref);
+ //loadyears();
+ loadtable();
+ load_senders();
+ load_receipients();
+ load_dateranges();
+}
+
+$(document).on('keydown',function(evt){
+ if (evt.key= "Shift"){
+ shiftdown = true;
+ }
+});
+
+$(document).on('keyup',function(evt){
+ if (evt.key = "Shift"){
+ shiftdown = false;
+ }
+});
+
+function loadtable(){
+ var where = '';
+ if (pagepref && pagepref.filter && Object.keys(pagepref.filter).length > 0){
+ var whfilter = [];
+ for (var i in pagepref.filter){
+ console.log(i);
+ if (i == 'bookingdate'){
+ if ($("#daterange :selected").text() != ''){
+ whfilter.push(pagepref.filter[i] + "='" + $("#daterange :selected").text() + "'");
+ }
+
+ } else {
+ whfilter.push(i + "='" + pagepref.filter[i] + "'");
+ }
+
+ }
+ if (whfilter.length > 0){
+ where = ' where ' + whfilter.join( " AND ");
+ }
+
+ }
+ sums = { planned: {cnt:0,sum:0},sended: {cnt:0,sum:0},payed: {cnt:0,sum:0},delayed: {cnt:0,sum:0},total: {cnt:0,sum:0}};
+ var sql = "select strftime('%d.%m.%Y',invoicepositions.bookingdate) as bookingdate, invoicepositions.bookingdate as datesortable,invoicepositions.id,sender.company as sender,receipient.company as receipient, invoicepositions.description,replace(printf('%.2f€',quantity * unitamount),'.',',') as amount,quantity * unitamount as sumamount , invoicejournal.status from invoicepositions left join accounts sender on (invoicepositions.id_sender=sender.id) left join invoicejournal on (invoicepositions.id_invoice=invoicejournal.id) left join accounts receipient on (invoicepositions.id_receipient=receipient.id)" + where + " order by invoicepositions.bookingdate desc;";
+ console.log(sql);
+ //$('#tbl_bookings').bootstrapTable('destroy');
+ $("#tbl_bookings > tbody").html("");
+ var data = appdb.dbquery(sql);
+ //console.log(data.sqldata);
+ for (var i in data.sqldata){
+ var cstatus = "secondary";
+ if (data.sqldata[i].status== "geplant"){
+ sums.planned.cnt = sums.planned.cnt + 1;
+ sums.planned.sum = sums.planned.sum + parseFloat(data.sqldata[i].sumamount);
+ }
+ if (data.sqldata[i].status== "bezahlt"){
+ cstatus = "success";
+ sums.payed.cnt = sums.payed.cnt + 1;
+ sums.payed.sum = sums.payed.sum + parseFloat(data.sqldata[i].sumamount);
+ }
+ if (data.sqldata[i].status== "überfällig"){
+ cstatus = "danger";
+ sums.delayed.cnt = sums.delayed.cnt + 1;
+ sums.delayed.sum = sums.delayed.sum + parseFloat(data.sqldata[i].sumamount);
+ }
+ if (data.sqldata[i].status== "verschickt"){
+ cstatus = "warning";
+ sums.sended.cnt = sums.sended.cnt + 1;
+ sums.sended.sum = sums.sended.sum + parseFloat(data.sqldata[i].sumamount);
+ }
+ sums.total.cnt = sums.total.cnt + 1;
+ sums.total.sum = sums.total.sum + parseFloat(data.sqldata[i].sumamount);
+ var acolor = "";
+ if (data.sqldata[i].amount.startsWith("-")){ acolor = "text-danger"; }
+ var row = '<tr onclick="setselection(\''+ data.sqldata[i].id +'\');" id="' +data.sqldata[i].id + '">'+
+ // '<td></td>' +
+ '<td><span class="d-none">'+data.sqldata[i].datesortable+'</span> ' + data.sqldata[i].bookingdate+ '</td>' +
+ '<td>' + data.sqldata[i].receipient+ '</td>' +
+ '<td>' + data.sqldata[i].sender+ '</td>' +
+ '<td>' + data.sqldata[i].description+ '</td>' +
+ '<td class="btn-'+ cstatus+'">' + data.sqldata[i].status+ '</td>' +
+ '<td class="'+ acolor +' right">' + data.sqldata[i].amount+ '</td>' +
+ '</tr>';
+
+ $("#tbl_bookings > tbody").append(row);
+ }
+ var cols = $("#tbl_bookings > tbody > tr:first-child").children();
+ var colnum = cols.length -1
+ console.log("childnum:" + colnum);
+ for (var i=1;i<=colnum;i++){
+ wx = $("#tbl_bookings > tbody > tr:first-child > td:nth-child("+ i +")").width();
+ wx = wx +3;
+ $("#tbl_bookings_head > thead > tr > th:nth-child("+ i +")").width(wx);
+ }
+ $("#cnt_planned").val(sums.planned.cnt);$("#sum_planned").val(sums.planned.sum.toFixed(2).toString().replace('.',','));
+ $("#cnt_payed").val(sums.payed.cnt);$("#sum_payed").val(sums.payed.sum.toFixed(2).toString().replace('.',','));
+ $("#cnt_delayed").val(sums.delayed.cnt);$("#sum_delayed").val(sums.delayed.sum.toFixed(2).toString().replace('.',','));
+ $("#cnt_total").val(sums.total.cnt);$("#sum_total").val(sums.total.sum.toFixed(2).toString().replace('.',','));
+ $("#cnt_sended").val(sums.sended.cnt);$("#sum_sended").val(sums.sended.sum.toFixed(2).toString().replace('.',','));
+}
+
+function load_senders(){
+ var sql = "select distinct (sender.company) as sender from invoicepositions left join accounts sender on (invoicepositions.id_sender=sender.id) order by sender.company;";
+ $("#sender").html('<option hidden>Sender</option><option value=""></option>');
+ var data = appdb.dbquery(sql);
+
+ for (var i in data.sqldata){
+ $("#sender").append('<option value="'+data.sqldata[i].sender+'">'+data.sqldata[i].sender+'</option>');
+ }
+ if (pagepref && pagepref.filter && pagepref.filter.sender && pagepref.filter.sender != ''){
+ //console.log("set selection:" + pagepref.filter.sender);
+ $("#sender").val(pagepref.filter.sender);
+ }
+}
+
+function load_receipients(){
+ var sql = "select distinct (receipient.company) as receipient from invoicepositions left join accounts receipient on (invoicepositions.id_receipient=receipient.id) order by receipient.company;";
+ $("#receipient").html('<option hidden>Empfänger</option><option value=""></option>');
+ var data = appdb.dbquery(sql);
+
+ for (var i in data.sqldata){
+ $("#receipient").append('<option value="'+data.sqldata[i].receipient+'">'+data.sqldata[i].receipient+'</option>');
+ }
+ if (pagepref && pagepref.filter && pagepref.filter.receipient && pagepref.filter.receipient != ''){
+ //console.log("set selection:" + pagepref.filter.receipient);
+ $("#receipient").val(pagepref.filter.receipient);
+ }
+}
+
+function load_dateranges(){
+ var sql = "select strftime('%Y',bookingdate) as daterange, 'strftime(''%Y'',bookingdate)' as filter from invoicepositions where bookingdate is not null group by daterange union select strftime('%Y %m',bookingdate) as daterange , 'strftime(''%Y %m'',bookingdate)' as filter from invoicepositions where bookingdate is not null group by daterange union select strftime('%Y Q',bookingdate) || (((CAST(strftime('%m',bookingdate) AS INT) -1 ) / 3) +1) as daterange ,'strftime(''%Y Q'',bookingdate) || (((CAST(strftime(''%m'',bookingdate) AS INT) -1 ) / 3) +1)' as filter from invoicepositions where bookingdate is not null group by daterange order by daterange desc;";
+ $("#daterange").html('<option hidden>Datum</option><option value=""></option>');
+ var data = appdb.dbquery(sql);
+
+ for (var i in data.sqldata){
+ $("#daterange").append('<option value="'+data.sqldata[i].filter+'">'+data.sqldata[i].daterange+'</option>');
+ }
+}
+
+
+function setfilter(id,field){
+ console.log("setFilter");
+ if (pagepref['filter'] === undefined){
+ pagepref['filter'] = {};
+ }
+ if ($("#" + id + " :selected").val() != ""){
+ pagepref['filter'][field] = $("#" + id + " :selected").val();
+ }
+ else {
+ delete pagepref['filter'][field];
+ $("#" + id + "").val($("#"+ id +" option:first").val());
+ }
+ parent.usersystem.setPreference('bookings',pagepref);
+ loadtable();
+}
+
+
+function booking_edit(){
+ var inv_id= getTableSelectionID();
+ if (inv_id){
+ parent.browserapp.loadmodulepage('bookings','form_booking',{"id":inv_id});
+ }
+
+}
+
+function booking_delete(){
+
+}
+
+function booking_duplicate(){
+
+}
+
+function setselection(id){
+ if (shiftdown === true){
+ if ($("#" + id).hasClass('highlight')){
+ $("#" + id).removeClass('highlight');
+ }else {
+ $("#" + id).addClass('highlight');
+ }
+ } else {
+ $("#" + id).addClass('highlight').siblings().removeClass('highlight');
+ }
+}
--- /dev/null
+var invoice = {
+ new: function(){
+
+ },
+ duplicate: function(id){
+
+ },
+ delete: function(id){
+
+ },
+ update: function(){
+
+ },
+ print: function(){
+
+ },
+ createpdf: function(){
+
+ },
+}
\ No newline at end of file
--- /dev/null
+<!DOCTYPE html>
+<html lang="en">
+<meta charset="UTF-8">
+<meta name="viewport" content="width=device-width, initial-scale=1.0">
+<link rel="stylesheet" href="../../node_modules/bootstrap/dist/css/bootstrap.min.css">
+<!-- <link rel="stylesheet" href="../../node_modules/bootstrap-table/dist/bootstrap-table.min.css"> -->
+<link rel="stylesheet" href="../../node_modules/@fortawesome/fontawesome-free/css/fontawesome.min.css">
+<link rel="stylesheet" href="../../css/invoicejournal.epic.css">
+<link rel="stylesheet" href="../../css/app.css">
+<title>Dokumente</title>
+</head>
+<body>
+ <nav class="navbar navbar-expand-md navbar-dark fixed-top bg-dark">
+ <a class="navbar-brand" href="#">Dokumente</a>
+ <div class="ml-auto">
+ <div class="btn-group" role="group" aria-label="Basic example">
+ <button class="btn btn-primary" onclick="document_add();"><i class="fas fa-file-upload"></i><br/>Add</button>
+ <button class="btn btn-primary" onclick="document_view();"><i class="fas fa-eye"></i><br/>View</button>
+ <button class="btn btn-primary" onclick="document_parse();"><i class="fas fa-file-import"></i><br/>Parse</button>
+ <button class="btn btn-primary" onclick="document_delete();"><i class="fas fa-trash"></i><br/>Delete</button>
+ </div>
+ </div>
+ </nav>
+ <div class="cotainer-fluid" style="margin-top: 52px;">
+ <table style="width: 100%;" class="noselect">
+ <tr>
+ <td style="padding: 0px; margin: 0px;">
+ <table class="table" style="width: 100%; margin: 0px;" id="tbl_documents_head">
+ <thead class="thead-dark">
+ <tr>
+ <th>Name</th>
+ <th><select id="category" onchange="setfilter('category','category');" class="form-control"><option value="">Kategorie</option></select></th>
+ <th><select id="year" onchange="setfilter('year','year');" class="form-control"><option value="">Jahr</option></select></th>
+ <th><select id="month" onchange="setfilter('month','month');" class="form-control"><option value="">Monat</option></select></th>
+ </tr>
+ </thead>
+ </table>
+ </td>
+ </tr>
+ <tr>
+ <td>
+ <div style="width: 100%; height: 89.5vh; overflow-y: scroll;">
+ <table id="tbl_documents" style="width: 100%;" class="table table-bordered table-hover table-striped">
+ <!-- <thead class="thead-dark"> <tr>
+
+ <th data-checkbox="true"></th>
+ <th data-sortable="true">Datum</th>
+ <th data-sortable="true" data-filter="true">Empfänger</th>
+ <th data-sortable="true">Sender</th>
+ <th data-sortable="true">Beschreibung</th>
+ <th data-sortable="true">Status</th>
+ <th data-sortable="true" data-align="right">Betrag</th>
+ </tr>
+ </thead> -->
+
+ <tbody></tbody>
+ </table>
+ </div>
+ </td>
+ </tr>
+ </table>
+ <div class="row bg-dark" style="margin: 0px;width: 100%; height: 10vh; overflow:hidden;">
+
+ </div>
+ </div>
+<script>if (typeof module === 'object') {window.module = module; module = undefined;}</script>
+<script src="../../node_modules/jquery/dist/jquery.min.js"></script>
+<script src="../../node_modules/bootstrap/dist/js/bootstrap.bundle.min.js"></script>
+<!-- <script src="../../node_modules/bootstrap-table/dist/bootstrap-table.min.js"></script>
+ <script src="../../node_modules/bootstrap-table/dist/extensions/select2-filter/bootstrap-table-select2-filter.min.js"></script>
+ <script src="../../node_modules/select2/dist/js/select2.full.min.js"></script> -->
+<script src="../../node_modules/@fortawesome/fontawesome-free/js/all.min.js"></script>
+<script src="../../js/moduleglobal.js"></script>
+<script src="../../js/database.js"></script>
+<script src="index.js"></script>
+<script>if (window.module) module = window.module;</script>
+</body>
+</html>
\ No newline at end of file
--- /dev/null
+var winh = Math.max(document.documentElement.clientHeight, window.innerHeight || 0);
+var tblh = winh-54;
+var pagepref = undefined;
+var selection = [];
+// var cfg = {
+// byear: 2018
+// }
+// var sums = { planned: {cnt:0,sum:0},sended: {cnt:0,sum:0},payed: {cnt:0,sum:0},delayed: {cnt:0,sum:0},total: {cnt:0,sum:0}};
+shiftdown = false;
+function initpage(){
+ console.log(appdb.url);
+ pagepref = parent.usersystem.getPreference("documents");
+ if (pagepref === null){
+ pagepref= {};
+ }
+ console.log(pagepref);
+ //loadyears();
+ loadtable();
+ load_categories();
+ load_folders();
+}
+
+$(document).on('keydown',function(evt){
+ if (evt.key= "Shift"){
+ shiftdown = true;
+ }
+ console.log("shiftdown: " + shiftdown);
+});
+
+$(document).on('keyup',function(evt){
+ //console.log("shift up x");
+ //console.log(evt.key);
+ if (evt.key = "Shift"){
+ //console.log("shift up");
+ shiftdown = false;
+ }
+ console.log("shiftdown: " + shiftdown);
+});
+
+function loadtable(){
+ // var path = '';
+ // if (pagepref && pagepref.filter && Object.keys(pagepref.filter).length > 0){
+ // var whfilter = [];
+ // for (var i in pagepref.filter){
+ // if (i == 'category' ){
+
+ // }
+ // whfilter.push(i + "='" + pagepref.filter[i] + "'");
+ // }
+ // path = ' where ' + whfilter.join( " AND ");
+ // }
+ $("#tbl_documents > tbody").html("");
+ //console.log(decodeURIComponent(mpref.cfg.serviceurl) + 'filesystem/search?type=f&relative=1');
+
+ $.ajax({
+ encoding:"UTF-8",
+ url:decodeURIComponent(mpref.cfg.serviceurl) + 'filesystem/search?type=f&relative=1',
+ crossDomain: true,
+ success: function (data){
+ console.log(data);
+ result=data.result;
+ for (var i in result){
+ var category = result[i].substring(0,result[i].indexOf("/"));
+ var year = result[i].substring(result[i].indexOf("/")+1,result[i].lastIndexOf("/"));
+ var month = '';
+ if (year.indexOf('/') > 0){
+ month = year.substring(year.indexOf("/")+1);
+ year = result[i].substring(0,year.indexOf("/"));
+ }
+ var file = result[i].substring(result[i].lastIndexOf("/")+1);
+ var row = '<tr onclick="setselection(\'doc_'+ i +'\');" id="doc_'+i+'" data-file="'+result[i]+'">' +
+ '<td>'+file+'</td>' +
+ '<td>'+category+'</td>' +
+ '<td>'+ year +'</td>' +
+ '<td>'+ month +'</td>' +
+ '</tr>'
+ $("#tbl_documents > tbody").append(row);
+ }
+ var cols = $("#tbl_documents > tbody > tr:first-child").children();
+ var colnum = cols.length -1;
+ console.log("childnum:" + colnum);
+ for (var i=1;i<=colnum;i++){
+ wx = $("#tbl_documents > tbody > tr:first-child > td:nth-child("+ i +")").width();
+ wx = wx +3;
+ $("#tbl_documents_head > thead > tr > th:nth-child("+ i +")").width(wx);
+ }
+ },
+ error: function(data){
+ //alert("Error:" + JSON.stringify(data));
+ console.log("Error:" + JSON.stringify(data));
+ },
+ async:false
+ });
+
+
+}
+
+function load_categories(){
+ $.ajax({
+ encoding:"UTF-8",
+ url:decodeURIComponent(mpref.cfg.serviceurl) + 'filesystem/directory/list',
+ crossDomain: true,
+ success: function (data){
+ console.log(data);
+ result=data.result.directory;
+ $("#category").html('<option hidden>Kategorie</option><option value=""></option>');
+ for (var c in result){
+ $("#category").append('<option value="'+result[c]+'">'+result[c]+'</option>');
+ }
+ },
+ error: function(data){
+ //alert("Error:" + JSON.stringify(data));
+ console.log("Error:" + JSON.stringify(data));
+ },
+ async:false
+ });
+
+}
+
+function load_folders(){
+ // var sql = "select distinct (receipient.company) as receipient from invoicepositions left join accounts receipient on (invoicepositions.id_receipient=receipient.id) order by receipient.company;";
+ // $("#receipient").html('<option hidden>Empfänger</option><option value=""></option>');
+ // var data = appdb.dbquery(sql);
+
+ // for (var i in data.sqldata){
+ // $("#receipient").append('<option value="'+data.sqldata[i].receipient+'">'+data.sqldata[i].receipient+'</option>');
+ // }
+}
+
+function setfilter(id,field){
+ console.log("setFilter");
+ if (pagepref['filter'] === undefined){
+ pagepref['filter'] = {};
+ }
+ if ($("#" + id + " :selected").val() != ""){
+ pagepref['filter'][field] = $("#" + id + " :selected").val();
+ }
+ else {
+ delete pagepref['filter'][field];
+ $("#" + id + "").val($("#"+ id +" option:first").val());
+ }
+ parent.usersystem.setPreference('documents',pagepref);
+ loadtable();
+}
+
+function document_add(){
+ docfilter = [
+ { name: 'PDF', extensions: ['pdf'] }
+ ];
+
+ var newfile = parent.usersystem.selectfile("select file",null,docfilter);
+ console.log(newfile);
+}
+
+function document_delete(){
+
+}
+
+function document_view(){
+ window.open
+}
+
+function document_parse(){
+
+}
+// function loadyears(){
+// sql = "select byear from invoicejournal group by byear order by byear asc;";
+// var data = appdb.dbquery(sql);
+// //onsole.log(data.sqldata);
+// for (var i in data.sqldata){
+// $("#timerange").append('<a class="dropdown-item" href="javascript:change_timerange({"byear":"'+data.sqldata[i].byear+'"});">' + data.sqldata[i].byear+'</a>');
+// }
+
+// }
+
+// function booking_edit(){
+// var inv_id= getTableSelectionID();
+// if (inv_id){
+// parent.browserapp.loadmodulepage('bookings','form_booking',{"id":inv_id});
+// }
+
+// }
+
+// function invoice_delete(){
+
+// }
+
+// function invoice_duplicate(){
+
+// }
+
+function setselection(id){
+ if (shiftdown === true){
+ if ($("#" + id).hasClass('highlight')){
+ $("#" + id).removeClass('highlight');
+ }else {
+ $("#" + id).addClass('highlight');
+ }
+ } else {
+ $("#" + id).addClass('highlight').siblings().removeClass('highlight');
+ }
+ //console.log("selected:" +id);
+
+ //.siblings();
+}
+
+
+// function getTableSelectionID(){
+// var sel = $('#tbl_bookings').bootstrapTable('getSelections');
+// var id = null;
+
+// if (sel){ id=sel[0]._id; }
+// console.log("Selected ID:" + id);
+// return id;
+// }
+
+// function getTableSelectionIDs(){
+// var sel = $('#tbl_bookings').bootstrapTable('getSelections');
+// var ids = [];
+// if (sel){
+// for (var s in sel){
+// ids.push(s._id);
+// }
+// }
+// return ids;
+// }
\ No newline at end of file
"integrity": "sha512-aUjdRFISbuFOl0EIZc+9e4FfZp0bDZgAdOOf30bJmw8VM9v84SHyVyxDfbWxpGYbdZD/9XoKxfHVNmxPkhwyGw==",
"dev": true
},
+ "almond": {
+ "version": "0.3.3",
+ "resolved": "https://registry.npmjs.org/almond/-/almond-0.3.3.tgz",
+ "integrity": "sha1-oOfJWsdiTWQXtElLHmi/9pMWiiA=",
+ "dev": true
+ },
"ansi-regex": {
"version": "2.1.1",
"resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz",
"version": "2.1.1",
"resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz",
"integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=",
- "dev": true,
- "optional": true
+ "dev": true
},
"aproba": {
"version": "1.2.0",
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz",
"integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=",
- "dev": true,
- "optional": true
+ "dev": true
},
"brace-expansion": {
"version": "1.1.11",
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz",
"integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==",
"dev": true,
- "optional": true,
"requires": {
"balanced-match": "^1.0.0",
"concat-map": "0.0.1"
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/code-point-at/-/code-point-at-1.1.0.tgz",
"integrity": "sha1-DQcLTQQ6W+ozovGkDi7bPZpMz3c=",
- "dev": true,
- "optional": true
+ "dev": true
},
"concat-map": {
"version": "0.0.1",
"resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz",
"integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=",
- "dev": true,
- "optional": true
+ "dev": true
},
"console-control-strings": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/console-control-strings/-/console-control-strings-1.1.0.tgz",
"integrity": "sha1-PXz0Rk22RG6mRL9LOVB/mFEAjo4=",
- "dev": true,
- "optional": true
+ "dev": true
},
"core-util-is": {
"version": "1.0.2",
"version": "2.0.3",
"resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz",
"integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=",
- "dev": true,
- "optional": true
+ "dev": true
},
"ini": {
"version": "1.3.5",
"resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz",
"integrity": "sha1-754xOG8DGn8NZDr4L95QxFfvAMs=",
"dev": true,
- "optional": true,
"requires": {
"number-is-nan": "^1.0.0"
}
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz",
"integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==",
"dev": true,
- "optional": true,
"requires": {
"brace-expansion": "^1.1.7"
}
"version": "0.0.8",
"resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz",
"integrity": "sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0=",
- "dev": true,
- "optional": true
+ "dev": true
},
"minipass": {
"version": "2.3.5",
"resolved": "https://registry.npmjs.org/minipass/-/minipass-2.3.5.tgz",
"integrity": "sha512-Gi1W4k059gyRbyVUZQ4mEqLm0YIUiGYfvxhF6SIlk3ui1WVxMTGfGdQ2SInh3PDrRTVvPKgULkpJtT4RH10+VA==",
"dev": true,
- "optional": true,
"requires": {
"safe-buffer": "^5.1.2",
"yallist": "^3.0.0"
"resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz",
"integrity": "sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM=",
"dev": true,
- "optional": true,
"requires": {
"minimist": "0.0.8"
}
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/number-is-nan/-/number-is-nan-1.0.1.tgz",
"integrity": "sha1-CXtgK1NCKlIsGvuHkDGDNpQaAR0=",
- "dev": true,
- "optional": true
+ "dev": true
},
"object-assign": {
"version": "4.1.1",
"resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz",
"integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=",
"dev": true,
- "optional": true,
"requires": {
"wrappy": "1"
}
"version": "5.1.2",
"resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz",
"integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==",
- "dev": true,
- "optional": true
+ "dev": true
},
"safer-buffer": {
"version": "2.1.2",
"resolved": "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz",
"integrity": "sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M=",
"dev": true,
- "optional": true,
"requires": {
"code-point-at": "^1.0.0",
"is-fullwidth-code-point": "^1.0.0",
"resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz",
"integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=",
"dev": true,
- "optional": true,
"requires": {
"ansi-regex": "^2.0.0"
}
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz",
"integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=",
- "dev": true,
- "optional": true
+ "dev": true
},
"yallist": {
"version": "3.0.3",
"resolved": "https://registry.npmjs.org/yallist/-/yallist-3.0.3.tgz",
"integrity": "sha512-S+Zk8DEWE6oKpV+vI3qWkaK+jSbIK86pCwe2IF/xwIpQ8jEuxpw9NyaGjmp9+BoJv5FV2piqCDcoCtStppiq2A==",
- "dev": true,
- "optional": true
+ "dev": true
}
}
},
"integrity": "sha512-Ubldcmxp5np52/ENotGxlLe6aGMvmF4R8S6tZjsP6Knsaxd/xp3Zrh50cG93lR6nPXyUFwzN3ZSOQI0wRJNdGg==",
"dev": true
},
+ "jquery-mousewheel": {
+ "version": "3.1.13",
+ "resolved": "https://registry.npmjs.org/jquery-mousewheel/-/jquery-mousewheel-3.1.13.tgz",
+ "integrity": "sha1-BvAzXxbjU6aV5yBr9QUDy1I6buU=",
+ "dev": true
+ },
"jsbn": {
"version": "0.1.1",
"resolved": "https://registry.npmjs.org/jsbn/-/jsbn-0.1.1.tgz",
"ajv-keywords": "^3.1.0"
}
},
+ "select2": {
+ "version": "4.0.6-rc.1",
+ "resolved": "https://registry.npmjs.org/select2/-/select2-4.0.6-rc.1.tgz",
+ "integrity": "sha1-qmwwOKfw8ukf+t448KIcFeGBMnY=",
+ "dev": true,
+ "requires": {
+ "almond": "~0.3.1",
+ "jquery-mousewheel": "~3.1.13"
+ }
+ },
"semver": {
"version": "5.6.0",
"resolved": "https://registry.npmjs.org/semver/-/semver-5.6.0.tgz",
"jquery": "^3.3.1",
"pdfjs-dist": "^2.0.943",
"popper.js": "^1.14.7",
+ "select2": "^4.0.6-rc.1",
"tinymce": "^5.0.1",
"tinymce-i18n": "^19.2.11",
"webpack": "^4.29.4"
var ppath="";
if (os.platform() == "darwin"){
ppath = os.homedir() + '/Library/Application Support/invoicejournal/';
- } else if (os.platform() == "Win32") {
+ } else if (os.platform() == "win32") {
ppath = os.homedir() + '/AppData/Roaming/invoicejournal/';
}
return ppath;
},
- selectfile: function(dlgtitle,lastpath,filefilters=null){
- return dialog.showOpenDialog({title: dlgtitle,defaultPath: lastpath, filters: filefilters, properties: ['openFile'] });
+ selectfile: function(dlgtitle,lastpath,filefilters=null,multiselect=false){
+ var props = ['openFile'];
+ if (multiselect == true){
+ props.push('multiSelections');
+ }
+ return dialog.showOpenDialog({title: dlgtitle,defaultPath: lastpath, filters: filefilters, properties: props });
},
selectdir: function(dlgtitle,lastpath){
return dialog.showOpenDialog({title: dlgtitle,defaultPath: lastpath, filters: filefilters, properties: ['openDirectory'] });
dialog.showErrorBox(errtitle, errmsg);
},
setPreference: function(key,data){
- //console.log("save preferences to: " + this.profilepath() + key + ".json");
+ console.log("sset preference to: " + this.profilepath() + key + ".json");
+ console.log(data);
if ((typeof data == 'object') || (typeof data == 'array')){
data = JSON.stringify(data);
}
return result;
},
getPreference: function(key){
+ console.log("getPreference:" + this.profilepath() + key + ".json");
var data = null;
if (fs.existsSync(this.profilepath() + key + ".json")){
console.log("Read Key:" + key);
},
getLocalDataSets: function(){
var datasets =[];
+ console.log(os.platform());
+ console.log("ProfilePath:" + this.profilepath());
var files = fs.readdirSync(this.profilepath());
files.forEach(function(file) {
if (file.match('db\..*\.json')){
--- /dev/null
+package Module::FileSystem;
+
+use strict;
+use warnings;
+use parent qw(Plack::Component);
+use Plack::Request;
+use Data::Dumper;
+use File::Find::Rule;
+use File::Basename;
+use JSON::PP;
+use File::Path qw(make_path remove_tree);
+use File::Copy;
+use MIME::Types;
+if ($^O eq "MSWin32"){
+ eval('use Win32::File;');
+}
+
+sub call {
+ my($self, $env) = @_;
+ if (($env->{REMOTE_ADDR} =~ "^127\.0\.") &&
+ ($env->{REMOTE_ADDR} =~ "^10\.") &&
+ ($env->{REMOTE_ADDR} =~ "^172\.16\.") &&
+ ($env->{REMOTE_ADDR} =~ "^192\.168\.")) {
+ return [
+ 404,
+ [ 'Content-Type' => "text/html",'Cache-Control' => 'no-store, no-cache, must-revalidate' ],
+ [ "Sorry no remote access allowed!" ]
+ ];
+ }
+ if ($env->{PATH_INFO} =~ /^\/search/){
+ return $self->search($env);
+ } elsif ($env->{PATH_INFO} =~ /^\/directory/) {
+ return $self->directory($env);
+ } elsif ($env->{PATH_INFO} =~ /^\/file/) {
+ return $self->file($env);
+ } elsif ($env->{PATH_INFO} =~ /^\/userenv/){
+ return $self->userenv($env);
+ }
+ return [
+ 404,
+ [ 'Content-Type' => "text/html",'Cache-Control' => 'no-store, no-cache, must-revalidate' ],
+ [ "Unknown System Request!" ]
+ ];
+}
+
+sub search() {
+ my $self = shift;
+ my $env = shift;
+ my $html->{result} = ();
+ # $html->{docroot} = $self->{docpath};
+ my $ct="application/json";
+ my $status=200;
+ my $req = Plack::Request->new($env);
+ my $ff = File::Find::Rule->new;
+ if (exists($req->query_parameters->{name})){
+ my $namesearch = $req->query_parameters->{name};
+ $ff->name($req->query_parameters->{name})
+ }elsif((exists($req->query_parameters->{namelist}))){
+ my @nl = split(",",$req->query_parameters->{namelist});
+ $ff->name(@nl);
+ }
+ if (exists($req->query_parameters->{type})){
+ if ($req->query_parameters->{type} eq 'd'){
+ $ff->directory;
+ } else {
+ $ff->file;
+ }
+ }
+ if (exists($req->query_parameters->{relative})){
+ $ff->relative;
+ }
+ if (exists($req->query_parameters->{osspec})){
+ $ff->canonpath;
+ }
+ my $spath = $self->{docpath};
+ if (exists($req->query_parameters->{path})){
+
+ $spath = $self->{docpath}.'/'.$req->query_parameters->{path};
+ $spath =~ s/..\///g;
+ }
+ my @data = $ff->in($spath);
+ if (exists($req->query_parameters->{sorted})){
+ @data = sort {$a cmp $b} @data;
+ if ($req->query_parameters->{sorted} eq "desc"){
+ @data = reverse(@data);
+ }
+ }
+ my $ret = undef;
+ # if (exists($req->query_parameters->{output}) && $req->query_parameters->{output} eq "text"){
+ # $ct = "text/plain";
+ # $ret = "";
+ # foreach my $d (@data){
+ # $ret .= $d."\n";
+ # }
+ # }
+ # elsif (exists($req->query_parameters->{output}) && $req->query_parameters->{output} eq "fmlist"){
+ # $ct = "text/plain";
+ # $ret = "";
+ # foreach my $d (@data){
+ # $ret .= $d."\r";
+ # }
+ # }
+ # else {
+ $html->{result} = \@data;
+ $ret = JSON::PP::encode_json($html);
+ # }
+
+ return [
+ 200,
+ [ 'Content-Type' => $ct,'Cache-Control' => 'no-store, no-cache, must-revalidate', 'Access-Control-Allow-Origin'=> '*' ],
+ [ $ret ]
+ ];
+}
+
+sub directory() {
+ my $self = shift;
+ my $env = shift;
+ my $html;
+ my $ct="application/json";
+ my $status=200;
+
+ my $req = Plack::Request->new($env);
+ if ($env->{PATH_INFO} =~ /^\/directory\/list/){
+ my $mt = MIME::Types->new();
+ $html->{result} = [];
+ my $dir=$self->{docpath};
+ if (exists($req->query_parameters->{path})){
+ $dir=$self->{docpath}.'/'.$req->query_parameters->{path};
+ $dir =~ s/..\///g;
+ }
+ $html->{result} = {};
+ if (-d $dir){
+ my @dirs = ();
+ my @files = ();
+ opendir(LDIR,$dir);
+ while (my $f = readdir(LDIR)){
+ if ($f =~ /^\./){ next; }
+
+ if (-d $dir.'/'.$f){
+ my $bok =1 ;
+ if ($^O eq "MSWin32"){
+ eval ('my $attr;
+ Win32::File::GetAttributes($dir.\'/\'.$f,$attr);
+ if ($attr & HIDDEN){
+ $bok = 0;
+ }');
+ }
+ if ($bok == 1){
+ push(@dirs,$f);
+ }
+
+ } elsif (-f $dir.'/'.$f) {
+ my $bok =1 ;
+ if ($^O eq "MSWin32"){
+ eval ('my $attr;
+ Win32::File::GetAttributes($dir.\'/\'.$f,$attr);
+ if ($attr & HIDDEN){
+ $bok = 0;
+ }');
+ }
+ if ($bok == 1){
+ print $f."\n";
+ my $fi->{name} = $f;
+ my $mtf = $mt->mimeTypeOf($f);
+ $fi->{mimetype} = (exists($mtf->{MT_simplified})?$mtf->{MT_simplified}:'unknown');
+
+ push(@files,$fi);
+ }
+ }
+ }
+ closedir(LDIR);
+ $html->{result}->{directory} = \@dirs;
+ $html->{result}->{file} = \@files;
+ }
+
+ }
+ if ($env->{PATH_INFO} =~ /^\/directory\/exists/){
+ $html->{result} = 0;
+ if (exists($req->query_parameters->{path})){
+ if (-d $req->query_parameters->{path}){
+ $html->{result} = 1;
+ }
+ }
+ }
+ if ($env->{PATH_INFO} =~ /^\/directory\/make/){
+ make_path($req->query_parameters->{path});
+ $html->{result} = 0;
+ if (-d $req->query_parameters->{path}){
+ $html->{result} = 1;
+ }
+ }
+ if ($env->{PATH_INFO} =~ /^\/directory\/delete/){
+ my $keep_root = 0;
+ if (exists($req->query_parameters->{keep_root})){
+ $keep_root = 1;
+ }
+ $html->{result} = 0;
+ if (-d $req->query_parameters->{path}){
+ remove_tree( $req->query_parameters->{path}, {keep_root => $keep_root} );
+ $html->{result} = 1;
+ }
+ }
+ return [
+ 200,
+ [ 'Content-Type' => $ct,'Cache-Control' => 'no-store, no-cache, must-revalidate', 'Access-Control-Allow-Origin'=> '*' ],
+ [ JSON::PP::encode_json($html) ]
+ ];
+}
+
+sub file() {
+ my $self = shift;
+ my $env = shift;
+ my $html->{result} = ();
+ my $ct="application/json";
+ my $status=200;
+
+ my $req = Plack::Request->new($env);
+ if ($env->{PATH_INFO} =~ /^\/file\/exists/){
+ $html->{result} = 0;
+ if (exists($req->query_parameters->{path})){
+ if (-f $req->query_parameters->{path}){
+ $html->{result} = 1;
+ }
+ }
+ }
+# if ($env->{PATH_INFO} =~ /^\/file\/choose/){
+# # A simple open file with graphic filers
+# my ( @fss, $fss );
+# my ( @parms );
+# push @parms,
+# -filter => [ 'PDF - fichiers PDF', '*.pdf' ],
+# -directory => $ENV{HOME},
+# -title => 'selectionner un fichier PDF';
+# @fss = Win32::GUI::GetOpenFileName ( @parms );
+# if (scalar(@fss) > 0 ){
+# $html->{result} = \@fss;
+# }
+# }
+ if ($env->{PATH_INFO} =~ /^\/file\/write/){
+ $html->{result} = 0;
+ if (exists($req->query_parameters->{path})){
+ if (! -d (dirname($req->query_parameters->{path}))){
+ make_path(dirname($req->query_parameters->{path}))
+ }
+ my $fwrite = ">";
+ if (exists($req->query_parameters->{append})){
+ $fwrite = ">>";
+ }
+ my $datax = $req->body_parameters->{data};
+ print $req->body_parameters->{data}."\n";
+ open(WFI,$fwrite.$req->query_parameters->{path});
+ print WFI $req->body_parameters->{data};
+ close(WFI);
+ $html->{result} = 1;
+ }
+ }
+ if ($env->{PATH_INFO} =~ /^\/file\/read/){
+ $html->{result} = "";
+ if (exists($req->query_parameters->{path})){
+ if (-f $req->query_parameters->{path}){
+ my $rdata = "";
+ open(RFI,$req->query_parameters->{path});
+ while ( my $l = <RFI>){
+ $rdata .= $l;
+ }
+ close(RFI);
+ $html->{result} = $rdata;
+ }
+ }
+ }
+ if ($env->{PATH_INFO} =~ /^\/file\/copy/){
+ $html->{result} = "";
+ if (exists($req->query_parameters->{src})){
+ if (-f $req->query_parameters->{src}){
+ my $dest = $req->query_parameters->{dest};
+ if (! -d dirname($req->query_parameters->{dest})){
+ make_path(dirname($req->query_parameters->{dest}))
+ }
+ if ($req->query_parameters->{src} ne $req->query_parameters->{dest}){
+ my $cp = copy($req->query_parameters->{src},$req->query_parameters->{dest});
+ $html->{result} = $cp;
+ } else {
+ $html->{result} = 1;
+ }
+ }
+ }
+ }
+
+ return [
+ 200,
+ [ 'Content-Type' => $ct,'Cache-Control' => 'no-store, no-cache, must-revalidate', 'Access-Control-Allow-Origin'=> '*' ],
+ [ JSON::PP::encode_json($html) ]
+ ];
+}
+
+
+sub userenv() {
+ my $self = shift;
+ my $env = shift;
+ my $html->{result} = ();
+ my $ct="application/json";
+ my $status=200;
+
+ my $req = Plack::Request->new($env);
+ foreach my $k (keys(%ENV)){
+ $html->{result}->{$k} = $ENV{$k};
+ }
+
+ return [
+ 200,
+ [ 'Content-Type' => $ct,'Cache-Control' => 'no-store, no-cache, must-revalidate', 'Access-Control-Allow-Origin'=> '*' ],
+ [ JSON::PP::encode_json($html) ]
+ ];
+}
+1;
\ No newline at end of file
--- /dev/null
+package Module::OpenVPN;
+
+use strict;
+use warnings;
+use parent qw(Plack::Component);
+use Plack::Request;
+use Data::Dumper;
+use File::Find::Rule;
+use File::Basename;
+use JSON::PP;
+use File::Copy;
+use File::Path qw(make_path);
+
+sub call {
+ my($self, $env) = @_;
+ #$self->_app->($env);
+ if (($env->{REMOTE_ADDR} =~ "^127\.0\.") &&
+ ($env->{REMOTE_ADDR} =~ "^10\.") &&
+ ($env->{REMOTE_ADDR} =~ "^172\.16\.") &&
+ ($env->{REMOTE_ADDR} =~ "^192\.168\.")) {
+ return [
+ 404,
+ [ 'Content-Type' => "text/html",'Cache-Control' => 'no-store, no-cache, must-revalidate' ],
+ [ "Sorry no remote access allowed!" ]
+ ];
+ }
+ if ($env->{PATH_INFO} =~ /^\/connect/){
+ return $self->vpnconnect($env);
+ } elsif ($env->{PATH_INFO} =~ /^\/disconnect/){
+ return $self->vpndisconnect($env);
+ } elsif ($env->{PATH_INFO} =~ /^\/installprofile/){
+ return $self->vpninstallprofile($env);
+ } elsif ($env->{PATH_INFO} =~ /^\/listprofiles/){
+ return $self->vpnprofilelist($env);
+ }
+ return [
+ 404,
+ [ 'Content-Type' => "text/html",'Cache-Control' => 'no-store, no-cache, must-revalidate' ],
+ [ "Unknown System Request!" ]
+ ];
+}
+
+sub vpnconnect(){
+ my $self = shift;
+ my $env = shift;
+ my $html->{result} = 0;
+ my $req = Plack::Request->new($env);
+ my $uprofile = "";
+ #is gui or vpn running
+
+ if (exists($req->query_parameters->{vpnprofile})){
+ my $status = $self->vpnstatus();
+ if (!exists($status->{active}->{$req->query_parameters->{vpnprofile}})){
+ if ($^O eq "MSWin32"){
+ if (exists($status->{gui})){
+ system('taskkill.exe /F /IM openvpn.exe');
+ system('taskkill.exe /F /IM openvpn-gui.exe');
+ sleep(1);
+ }
+ my $st = system('start /b "" "C:\Program Files\OpenVPN\bin\openvpn-gui.exe" --connect '.$req->query_parameters->{vpnprofile}.'.ovpn');
+ if ($st == 0){
+
+ my $bconn = 0;
+ my $i = 30;
+ while ($bconn == 0 || $i > 0){
+ $status = $self->vpnstatus();
+ if (exists($status->{active}->{$req->query_parameters->{vpnprofile}})){
+ $html->{result} = $status;
+ $bconn = 1;
+ }
+ $i--;
+ sleep(1);
+ }
+ }
+ }
+ } else {
+ $html->{result} = $status;
+ }
+ }
+ return [
+ 200,
+ [ 'Content-Type' => "application/json",'Cache-Control' => 'no-store, no-cache, must-revalidate', 'Access-Control-Allow-Origin'=> '*' ],
+ [ JSON::PP::encode_json($html) ]
+ ];
+}
+
+sub vpnstatus(){
+ my $self = shift;
+ my $status = ();
+ if ($^O eq "MSWin32"){
+
+ my $tasklist = `tasklist`;
+ my @task = split("\n",$tasklist);
+ my @ovpntasks = grep(/openvpn-gui\.exe/,@task);
+ if (scalar(@ovpntasks) > 0){
+ $status->{gui} = "running";
+ }
+ @ovpntasks = grep(/openvpn.exe/,@task);
+ #$status->{active_connections} = scalar(@ovpntasks);
+ if (scalar(@ovpntasks) > 0){
+ my $ff = File::Find::Rule->new();
+ $ff->file;
+ $ff->name('*.log');
+ my @loglist =$ff->in($ENV{USERPROFILE}.'/OpenVPN/log');
+ foreach my $c (@loglist){
+ open(CLOG,$c);
+ my @data = <CLOG>;
+ close(CLOG);
+ my $laststate=$data[scalar(@data)-1];
+ chomp($laststate);
+ if ($laststate =~ /CONNECTED/){
+ my ($time,$ip,$server,$port) = $laststate =~ /.+MANAGEMENT:\s>STATE:(\d+),CONNECTED,SUCCESS,(.+),(.+),(.+),,$/;
+ if (!exists($status->{connection}->{$ip})){
+ $status->{connection}->{$ip}->{config} = substr(basename($c),0,-4);;
+ $status->{connection}->{$ip}->{server} = $server;
+ $status->{connection}->{$ip}->{port} = $port;
+ $status->{connection}->{$ip}->{connected_since} = $time;
+ }else {
+ if ($time >= $status->{connection}->{$ip}->{connected_since}){
+ $status->{connection}->{$ip}->{config} = substr(basename($c),0,-4);
+ $status->{connection}->{$ip}->{server}= $server;
+ $status->{connection}->{$ip}->{port} = $port;
+ $status->{connection}->{$ip}->{connected_since} = $time;
+ }
+ }
+ }
+ }
+ my @notactive = ();
+ my $active = ();
+ foreach my $c (keys(%{$status->{connection}})){
+ my $routeslist = `route print -4`;
+ my @routes = split("\n",$routeslist);
+ my @activetest = grep(/$c/,@routes);
+ if (scalar(@activetest) == 0){
+ push @notactive,$c;
+ } else {
+ $active->{$status->{connection}->{$c}->{config}} = $c;
+ }
+ }
+ foreach my $na (@notactive){
+ delete $status->{connection}->{$na};
+ }
+ $status->{active} = $active;
+ }
+ }
+ return $status;
+}
+
+sub vpndisconnect(){
+ my $self = shift;
+ my $env = shift;
+ my $html->{result} = 1;
+ if ($^O eq "MSWin32"){
+ system('taskkill.exe /F /IM openvpn.exe');
+ system('taskkill.exe /F /IM openvpn-gui.exe');
+ }
+ return [
+ 200,
+ [ 'Content-Type' => "application/json",'Cache-Control' => 'no-store, no-cache, must-revalidate', 'Access-Control-Allow-Origin'=> '*' ],
+ [ JSON::PP::encode_json($html) ]
+ ];
+}
+
+sub vpninstallprofile(){
+ my $self = shift;
+ my $env = shift;
+ my $req = Plack::Request->new($env);
+ my $html->{result} = 0;
+ if ($^O eq "MSWin32"){
+ if ( ! -d $ENV{USERPROFILE}.'/OpenVPN'){
+ make_path($ENV{USERPROFILE}.'/OpenVPN');
+ }
+ if (exists($req->query_parameters->{vpnprofile}) && (-e $req->query_parameters->{vpnprofile}) && ($req->query_parameters->{vpnprofile} =~ /\.ovpn$/)){
+ copy(req->query_parameters->{vpnprofile},$ENV{USERPROFILE}.'/OpenVPN/'.basename($req->query_parameters->{vpnprofile}));
+ $html->{result} = 1;
+ }
+ }
+ return [
+ 200,
+ [ 'Content-Type' => "application/json",'Cache-Control' => 'no-store, no-cache, must-revalidate', 'Access-Control-Allow-Origin'=> '*' ],
+ [ JSON::PP::encode_json($html) ]
+ ];
+}
+
+sub vpnprofilelist(){
+ my $self = shift;
+ my $env = shift;
+ my $html->{result} = ();
+ if ($^O eq "MSWin32"){
+ my $ff = File::Find::Rule->new();
+ $ff->file;
+ $ff->name('*.ovpn');
+ my @vpnlist =$ff->in($ENV{USERPROFILE}.'/OpenVPN');
+ foreach (my $p=0;$p<scalar(@vpnlist);$p++){
+ $vpnlist[$p] = substr(basename($vpnlist[$p]),0,-5);
+ }
+ $html->{result} = \@vpnlist;
+ }
+ return [
+ 200,
+ [ 'Content-Type' => "application/json",'Cache-Control' => 'no-store, no-cache, must-revalidate', 'Access-Control-Allow-Origin'=> '*' ],
+ [ JSON::PP::encode_json($html) ]
+ ];
+}
+
+
+1;
\ No newline at end of file
--- /dev/null
+package Module::PDFExtract;
+
+use strict;
+use warnings;
+use parent qw(Plack::Component);
+use Plack::Request;
+use File::Basename;
+use Data::Dumper;
+use PDF::API2;
+use File::Path qw/make_path/;
+
+sub call {
+ my($self, $env) = @_;
+ #$self->_app->($env);
+ my $html->{result} = "unknown function";
+ if (($env->{REMOTE_ADDR} =~ "^127\.0\.") &&
+ ($env->{REMOTE_ADDR} =~ "^10\.") &&
+ ($env->{REMOTE_ADDR} =~ "^172\.16\.") &&
+ ($env->{REMOTE_ADDR} =~ "^192\.168\.")) {
+ return [
+ 404,
+ [ 'Content-Type' => "text/html",'Cache-Control' => 'no-store, no-cache, must-revalidate' ],
+ [ "Sorry no remote access allowed!" ]
+ ];
+ }
+ # if ($env->{PATH_INFO} =~ /^\/pdfsplit/){
+ # return $self->pdfsplit($env);
+ # }
+ # if ($env->{PATH_INFO} =~ /^\/pdfpagenumbers/){
+ # return $self->pdfpagesnumbers($env);
+ # }
+# if ($env->{PATH_INFO} =~ /^\/pdfextract/){
+# return $self->pdfextract($env);
+# }
+ if ($env->{PATH_INFO} =~ /^\/parse/){
+ return $self->parsestatement($env);
+ }
+ # if ($env->{PATH_INFO} =~ /^\/parsestatement/){
+ # return $self->parsestatement($env);
+ # }
+ return [
+ 404,
+ [ 'Content-Type' => 'text/html','Cache-Control' => 'no-store, no-cache, must-revalidate' , 'Access-Control-Allow-Origin'=> '*'],
+ [ "unknown function" ]
+ ];
+}
+
+# sub pdfpagesnumbers(){
+# my $self = shift;
+# my $env = shift;
+# my $ct="application/json";
+# my $status=200;
+# my $req = Plack::Request->new($env);
+# my $html->{result}->{pagenumbers} = 0;
+# if (exists($req->query_parameters->{file}) && ($req->query_parameters->{file} =~ /\.pdf$/)){
+# my $pdf = PDF::API2->open($req->query_parameters->{file});
+# $html->{result}->{pagenumbers} = $pdf->pages;
+# }
+# return [
+# 200,
+# [ 'Content-Type' => $ct,'Cache-Control' => 'no-store, no-cache, must-revalidate' , 'Access-Control-Allow-Origin'=> '*'],
+# [ JSON::PP::encode_json($html) ]
+# ];
+# }
+
+# sub pdfsplit(){
+# my $self = shift;
+# my $env = shift;
+# my $html->{result} = ();
+# my $ct="application/json";
+# my $status=200;
+# my $req = Plack::Request->new($env);
+# my @nfiles = ();
+# my $outputdir = $ENV{TEMP};
+# if (exists($req->query_parameters->{file}) && exists($req->query_parameters->{prefix})){
+# my $basepdf = basename($req->query_parameters->{file});
+# $outputdir =~ s/\\/\//g;
+
+# my $oldpdf = PDF::API2->open($req->query_parameters->{file});
+# my $xx = $oldpdf->pages;
+# for my $page_nb (1..$xx) {
+# my $newpdf = PDF::API2->new;
+# my $page = $newpdf->importpage($oldpdf, $page_nb);
+
+# my $npdfname = $outputdir.'/'.$req->query_parameters->{prefix}.substr($basepdf,0,-4).".".$page_nb.".pdf";
+# push @nfiles,$npdfname;
+# if (-e $npdfname){ unlink($npdfname); }
+# $newpdf->saveas($npdfname);
+# }
+# }
+# foreach my $n (@nfiles){
+# my $r = $self->pdfextract($n);
+# }
+# $html->{result}->{files} = \@nfiles;
+# return [
+# 200,
+# [ 'Content-Type' => $ct,'Cache-Control' => 'no-store, no-cache, must-revalidate' , 'Access-Control-Allow-Origin'=> '*'],
+# [ JSON::PP::encode_json($html) ]
+# ];
+# };
+
+sub pdfextract(){
+ my $self = shift;
+ my $file = shift;
+# my $html->{result} = ();
+# my $ct="application/json";
+# my $status=200;
+# my $req = Plack::Request->new($env);
+ my $pdftotext;
+ my $sep = "/";
+ if ($^O eq "MSWin32") {
+ $sep = "\\";
+ $pdftotext=dirname($0).$sep.'pdftotext.exe';
+ }else {
+ $pdftotext=dirname($0).$sep.'pdftotext';
+ }
+ if (-e $file.'.txt'){
+ unlink($file.'.txt');
+ }
+ my $cmd = 'start /b "" "'.$pdftotext.'" -q -table -eol unix "'.$file.'" "'.$file.'.txt"';
+ my $st = `$cmd`;#'system(1,$cmd)' ;
+ #print $cmd."->".$st."\n";
+ return $st;
+}
+
+
+sub parsestatement(){
+ my $self = shift;
+ my $env = shift;
+ my $html->{result} = ();
+ my $req = Plack::Request->new($env);
+ my $ct="application/json";
+ my $status=200;
+ my $file = $self->{docpath}.'/'.$req->query_parameters->{file};
+ if (! -e $file){
+ $html->{error}->{msg} = "file: ".$file." does not exist!";
+ return [
+ 200,
+ [ 'Content-Type' => $ct,'Cache-Control' => 'no-store, no-cache, must-revalidate' , 'Access-Control-Allow-Origin'=> '*'],
+ [ JSON::PP::encode_json($html) ]
+ ];
+ }
+
+
+
+ my $pxdata = ();
+ my @pdata = ();
+ my $jdata = ();
+ if (-e $file){
+ my $st = $self->pdfextract($file);
+
+ if (($st == 0) && (-e $file.".txt")){
+ open(PDFDATA,$file.".txt");
+ while (my $l = <PDFDATA>) {
+ chomp($l);
+ if ($l ne "") {push @pdata,$l;}
+ }
+ close(PDFDATA);
+ }
+ my $caccount = "";
+ my $stmtnum = "";
+ my $r = 0;
+ my $cpos = "";
+ foreach my $p (@pdata){
+ if ($p =~ /^\s+Konto\s+:/ ) {
+ $cpos = "";
+ ($caccount) = $p =~ m/.+IBAN\s+(.+)$/;
+ next;
+ }elsif ($p =~ /Kontoauszug Nr\./){
+ $cpos = "";
+ ($stmtnum) = $p =~ m/^Kontoauszug Nr\.\s(\d+).+$/;
+ next;
+ }elsif ($p =~ /^\d\d\.\d\d\s+[GUT|UEBER|SEPA]/){
+ $cpos = "";
+ $r++;
+ my ($type,$trdate,$trval,$trsign) = $p =~ m/\d\d\.\d\d\s+(.+)\s+(\d\d\.\d\d\.\d\d)\s+([\d|,|\.]+)\s([+|-])$/;
+ $type =~ s/\s//g;
+ $trsign =~ s/\+//;
+ $trval=~ s/\.//g;
+ $trdate = substr($trdate,0,6).'20'.substr($trdate,-2);
+ $jdata->{$r}->{"Account"} = $caccount;
+ $jdata->{$r}->{"StatementNumber"} = $stmtnum;
+ $jdata->{$r}->{"BookingDate"} = $trdate;
+ $jdata->{$r}->{"Amount"} = $trsign.$trval;
+ $jdata->{$r}->{"TransactionIdent"} = "";
+ $jdata->{$r}->{"Message"} = "";
+ $jdata->{$r}->{"ForeignAccountOwner"} = "";
+ $jdata->{$r}->{"Bank"} = "";
+ $jdata->{$r}->{"TransferAccount"} = "";
+ $jdata->{$r}->{"TransferCosts"} = 0;
+ #$jdata->{$r}->{"BookingType"} = $type;
+ next;
+ }elsif ($p =~ /^\s+Unser Zeichen/){
+ $cpos = "TransactionIdent";
+ my ($trid) = $p =~ m/^\s+Unser Zeichen\s+(.+)$/;
+ $jdata->{$r}->{$cpos} =$trid;
+ }elsif ($p =~ /^\s+Mitteilung/){
+ $cpos = "Message";
+ my ($msg) = $p =~ m/^\s+Mitteilung\s+(.+)$/;
+ $jdata->{$r}->{$cpos} = $msg;
+ }elsif ($p =~ /^\s+Auftraggeber/){
+ $cpos = "ForeignAccountOwner";
+ my ($apl) = $p =~ /^\s+Auftraggeber\s+(.+)$/;
+ $apl =~ s/\s+/\ /g;
+ $jdata->{$r}->{$cpos} =$apl;
+ }elsif ($p =~ /^\s+Bank d. Auftr.gebers/){
+ $cpos = "";
+ }elsif ($p =~ /^\s+BIC-Code Bank d. Auftraggebers/){
+ $cpos = "Bank";
+ my ($trfbank) = $p =~ /^\s+BIC-Code\sBank\sd\.\sAuftraggebers\s+(.+)$/;
+ $jdata->{$r}->{$cpos} =$trfbank;
+ }elsif ($p =~ /^\s+End-to-End-Identifizierung/){
+ $cpos = "";
+ }elsif ($p =~ /^\s+Beg.nstigter/){
+ $cpos = "ForeignAccountOwner";
+ my ($recp) = $p =~ /^\s+Beg.nstigter\s+(.+)$/;
+ $recp =~ s/\s+/\ /g;
+ $jdata->{$r}->{$cpos} =$recp;
+ $cpos="";
+ }elsif ($p =~ /^\s+Konto Nr. Beg.nst./){
+ $cpos = "TransferAccount";
+
+ my ($trfacc) = $p =~ /^\s+Konto\sNr\.\sBeg.nst.\s+(.+)$/;
+ $trfacc =~ s/\///g;
+ $trfacc =~ s/(....)/$1 /sg;
+ $trfacc =~ s/\s+$//;
+ $jdata->{$r}->{$cpos} =$trfacc;
+ $cpos="";
+ }elsif ($p =~ /^\s+bei/){
+ $cpos = "";
+ }elsif ($p =~ /^\s+Transfergeb.hr/){
+ $cpos = "TransferCosts";
+ my ($tramount) = $p =~ /^\s+Transfergeb.hr\s+EUR\s+(.+)$/;
+ $tramount =~ s/\,/\./g;
+ $jdata->{$r}->{$cpos} =$tramount;
+ }elsif ($p =~ /^\s+Durch Ihren Bonus abgedeckt/){
+ $cpos = "TransferCosts";
+ my ($tramount) = $p =~ /^\s+Durch Ihren Bonus abgedeckt\s+EUR\s+(.+)$/;
+ $tramount =~ s/\,/\./g;
+ $jdata->{$r}->{$cpos} = $jdata->{$r}->{$cpos} + $tramount;
+ }elsif ($p =~ /^\s+Zeichen/){
+ $cpos = "";
+ } elsif ($p =~ /^\s+Neuer Kontostand/){
+ $cpos="";
+ }elsif ($cpos ne "") {
+ my ($data) = $p =~ m/\s+(.+)$/;
+ $jdata->{$r}->{$cpos} .= " ".$data;
+ }
+ }
+
+ }
+ if (-e $file.'.txt'){
+ unlink($file.'.txt');
+ }
+ $html->{result} = $jdata;
+ return [
+ 200,
+ [ 'Content-Type' => $ct,'Cache-Control' => 'no-store, no-cache, must-revalidate' , 'Access-Control-Allow-Origin'=> '*'],
+ [ JSON::PP::encode_json($html) ]
+ ];
+}
+
+
+1;
\ No newline at end of file
--- /dev/null
+package Module::PDFExtract;
+
+use strict;
+use warnings;
+use parent qw(Plack::Component);
+use Plack::Request;
+use File::Basename;
+use Data::Dumper;
+use PDF::API2;
+use File::Path qw/make_path/;
+
+sub call {
+ my($self, $env) = @_;
+ #$self->_app->($env);
+ my $html->{result} = "unknown function";
+ if (($env->{REMOTE_ADDR} =~ "^127\.0\.") &&
+ ($env->{REMOTE_ADDR} =~ "^10\.") &&
+ ($env->{REMOTE_ADDR} =~ "^172\.16\.") &&
+ ($env->{REMOTE_ADDR} =~ "^192\.168\.")) {
+ return [
+ 404,
+ [ 'Content-Type' => "text/html",'Cache-Control' => 'no-store, no-cache, must-revalidate' ],
+ [ "Sorry no remote access allowed!" ]
+ ];
+ }
+ if ($env->{PATH_INFO} =~ /^\/pdfsplit/){
+ return $self->pdfsplit($env);
+ }
+ if ($env->{PATH_INFO} =~ /^\/pdfpagenumbers/){
+ return $self->pdfpagesnumbers($env);
+ }
+# if ($env->{PATH_INFO} =~ /^\/pdfextract/){
+# return $self->pdfextract($env);
+# }
+ if ($env->{PATH_INFO} =~ /^\/parsedata/){
+ return $self->parsedata($env);
+ }
+ if ($env->{PATH_INFO} =~ /^\/parsestatement/){
+ return $self->parsestatement($env);
+ }
+ return [
+ 404,
+ [ 'Content-Type' => 'text/html','Cache-Control' => 'no-store, no-cache, must-revalidate' , 'Access-Control-Allow-Origin'=> '*'],
+ [ "unknown function" ]
+ ];
+}
+
+sub pdfpagesnumbers(){
+ my $self = shift;
+ my $env = shift;
+ my $ct="application/json";
+ my $status=200;
+ my $req = Plack::Request->new($env);
+ my $html->{result}->{pagenumbers} = 0;
+ if (exists($req->query_parameters->{file}) && ($req->query_parameters->{file} =~ /\.pdf$/)){
+ my $pdf = PDF::API2->open($req->query_parameters->{file});
+ $html->{result}->{pagenumbers} = $pdf->pages;
+ }
+ return [
+ 200,
+ [ 'Content-Type' => $ct,'Cache-Control' => 'no-store, no-cache, must-revalidate' , 'Access-Control-Allow-Origin'=> '*'],
+ [ JSON::PP::encode_json($html) ]
+ ];
+}
+
+sub pdfsplit(){
+ my $self = shift;
+ my $env = shift;
+ my $html->{result} = ();
+ my $ct="application/json";
+ my $status=200;
+ my $req = Plack::Request->new($env);
+ my @nfiles = ();
+ my $outputdir = $ENV{TEMP};
+ if (exists($req->query_parameters->{file}) && exists($req->query_parameters->{prefix})){
+ my $basepdf = basename($req->query_parameters->{file});
+ $outputdir =~ s/\\/\//g;
+
+ my $oldpdf = PDF::API2->open($req->query_parameters->{file});
+ my $xx = $oldpdf->pages;
+ for my $page_nb (1..$xx) {
+ my $newpdf = PDF::API2->new;
+ my $page = $newpdf->importpage($oldpdf, $page_nb);
+
+ my $npdfname = $outputdir.'/'.$req->query_parameters->{prefix}.substr($basepdf,0,-4).".".$page_nb.".pdf";
+ push @nfiles,$npdfname;
+ if (-e $npdfname){ unlink($npdfname); }
+ $newpdf->saveas($npdfname);
+ }
+ }
+ foreach my $n (@nfiles){
+ my $r = $self->pdfextract($n);
+ }
+ $html->{result}->{files} = \@nfiles;
+ return [
+ 200,
+ [ 'Content-Type' => $ct,'Cache-Control' => 'no-store, no-cache, must-revalidate' , 'Access-Control-Allow-Origin'=> '*'],
+ [ JSON::PP::encode_json($html) ]
+ ];
+};
+
+sub pdfextract(){
+ my $self = shift;
+ my $file = shift;
+# my $html->{result} = ();
+# my $ct="application/json";
+# my $status=200;
+# my $req = Plack::Request->new($env);
+ my $pdftotext;
+ my $sep = "/";
+ if ($^O eq "MSWin32") {
+ $sep = "\\";
+ $pdftotext=dirname($0).$sep.'pdftotext.exe';
+ }else {
+ $pdftotext=dirname($0).$sep.'pdftotext';
+ }
+ if (-e $file.'.txt'){
+ unlink($file.'.txt');
+ }
+ my $cmd = 'start /b "" "'.$pdftotext.'" -q -table -eol unix "'.$file.'" "'.$file.'.txt"';
+ my $st = `$cmd`;#'system(1,$cmd)' ;
+ #print $cmd."->".$st."\n";
+ return $st;
+}
+
+sub parsedata(){
+ my $self = shift;
+ my $env = shift;
+ my $req = Plack::Request->new($env);
+ if (exists($req->query_parameters->{type}) && exists($req->query_parameters->{file})){
+ if ($req->query_parameters->{type} eq "inv"){
+ return $self->parseinvoice($req->query_parameters->{file});
+ } elsif ($req->query_parameters->{type} eq "invold"){
+ return $self->parseoldinvoice($req->query_parameters->{file});
+ } elsif ($req->query_parameters->{type} eq "stmt") {
+ return $self->parsestatement($req->query_parameters->{file});
+ } else {
+ return [
+ 404,
+ [ 'Content-Type' => 'text/html','Cache-Control' => 'no-store, no-cache, must-revalidate' , 'Access-Control-Allow-Origin'=> '*'],
+ [ "unknown function" ]
+ ];
+ }
+ }
+}
+
+sub parseinvoice(){
+ my $self = shift;
+ my $file = shift;
+ my $html->{result} = ();
+ my $ct="application/json";
+ my $status=200;
+ my $pxdata = ();
+ if (-e $file){
+ my @invoicedata = ();
+ open(EXT,$file);
+ while (my $l = <EXT>){
+ chomp($l);
+ push(@invoicedata,$l);
+ }
+ close(EXT);
+ foreach my $p (@invoicedata){
+ if ($p =~ /^N. Facture/) {
+ my ($tmp) = $p =~ m/.+\s(\d{4,}.\d{1,2}.\d{4,})\s.+$/;
+ $pxdata->{reference} = $tmp;
+ }
+ if ($p =~ /^Date de la facture/) {
+ my ($d,$m,$y) = $p =~ m/.+\s(\d{1,2}).(\d{1,2}).(\d{4,}).+$/;
+ if (length($d) == 1) { $d = "0".$d;}
+ if (length($m) == 1) { $m = "0".$m;}
+ $pxdata->{invoicedate} = $y.'-'.$m.'-'.$d;
+ }
+# if (($p =~ /facture/) && ($pxdata->{invoicedate} eq "--")) {
+# my ($d,$m,$y) = $p =~ m/.+\s(\d{1,2}).(\d{1,2}).(\d{4,})$/;
+# if (length($d) == 1) { $d = "0".$d;}
+# if (length($m) == 1) { $m = "0".$m;}
+# $pxdata->{invoicedate} = $y.'-'.$m.'-'.$d;
+# }
+ if ($p =~ /^Enfant/) {
+ my ($tmp) = $p =~ m/.+\s\((\d+)\).+$/;
+ $pxdata->{checkservice} = $tmp;
+ }
+ if (($p =~ /^\s+\(\d+\)$/) && (!defined($pxdata->{checkservice}))) {
+ my ($tmp) = $p =~ m/\s+\((\d+)\)$/;
+ $pxdata->{checkservice} = $tmp;
+ }
+ if ($p =~ /Heures.+\sh\s/) {
+ my ($hrs,$p1,$e1) = $p =~ m/.+Heures.+\s+([\s|\d]+,\d{1,2})\sh\s+([\s|\d]+,\d{1,2})\s+([\s|\d]+,\d{1,2}).+$/;
+ $p1 =~ s/,/\./;
+ $e1 =~ s/,/\./;
+ $p1 =~ s/\ //;
+ $e1 =~ s/\ //;
+ if (exists($pxdata->{hoursamount})){
+ $pxdata->{hoursamount} = $pxdata->{hoursamount} + $p1 + $e1;
+ } else {
+ $pxdata->{hoursamount} = $p1 + $e1;
+ }
+
+ }
+ if ($p =~ /Repas/) {
+ my ($rn,$p1,$e1) = $p =~ m/.+Repas.+\s+(\d+)\s+([\s|\d]+,\d{1,2})\s+([\s|\d]+,\d{1,2}).+$/;
+ $p1 =~ s/,/\./;
+ $e1 =~ s/,/\./;
+ $p1 =~ s/\ //;
+ $e1 =~ s/\ //;
+ $pxdata->{lunchnum} = $rn;
+ $pxdata->{lunchamount} = $p1 + $e1;
+ }
+ if ($p =~ /Participation totale de l.Etat/){
+ my ($e1) = $p =~ m/.+Participation totale de l.Etat\s+([\s|\d]+,\d{1,2}).+$/;
+ $e1 =~ s/,/\./;
+ $e1 =~ s/\ //;
+ $pxdata->{benefitamount} = $e1;
+ }
+ if ($p =~ /Montant\s.\sr.gler/) {
+ my ($m1) = $p =~ m/.+Montant.+\s+([\s|\d]+,\d{1,2}).+$/;
+ $m1 =~ s/,/\./;
+ $m1 =~ s/\ //;
+ $pxdata->{totalamount} = $m1;
+ }
+ #print Dumper(@pdata);
+ }
+ }
+ $html->{result} = $pxdata;
+ return [
+ 200,
+ [ 'Content-Type' => $ct,'Cache-Control' => 'no-store, no-cache, must-revalidate' , 'Access-Control-Allow-Origin'=> '*'],
+ [ JSON::PP::encode_json($html) ]
+ ];
+}
+
+sub parseoldinvoice(){
+ my $self = shift;
+ my $file = shift;
+ my $html->{result} = ();
+ my $ct="application/json";
+ my $status=200;
+ my $pxdata = ();
+ if (-e $file){
+ my @invoicedata = ();
+ open(EXT,$file);
+ while (my $l = <EXT>){
+ chomp($l);
+ push(@invoicedata,$l);
+ }
+ close(EXT);
+ foreach my $p (@invoicedata){
+ if ($p =~ /N. Facture/) {
+ my ($tmp) = $p =~ m/.+\s(\d{4,}.\d{1,2}.\d{4,})\s.+$/;
+ $pxdata->{reference} = $tmp;
+ }
+ if ($p =~ /Date de la/) {
+ my ($d,$m,$y) = $p =~ m/.+\s(\d{1,2}).(\d{1,2}).(\d{4,})$/;
+ if (length($d) == 1) { $d = "0".$d;}
+ if (length($m) == 1) { $m = "0".$m;}
+ $pxdata->{invoicedate} = $y.'-'.$m.'-'.$d;
+ }
+ if (($p =~ /facture/) && ($pxdata->{invoicedate} eq "--")) {
+ my ($d,$m,$y) = $p =~ m/.+\s(\d{1,2}).(\d{1,2}).(\d{4,})$/;
+ if (length($d) == 1) { $d = "0".$d;}
+ if (length($m) == 1) { $m = "0".$m;}
+ $pxdata->{invoicedate} = $y.'-'.$m.'-'.$d;
+ }
+ if ($p =~ /Carte N./) {
+ my ($tmp) = $p =~ m/.+\s(\d+)$/;
+ $pxdata->{checkservice} = $tmp;
+ }
+ if ($p =~ /Heure/) {
+ my ($tmp1,$tmp2) = $p =~ m/.+\s(\d+).(\d+)+$/;
+ $pxdata->{hoursamount} = $tmp1.'.'.$tmp2;
+ }
+ if ($p =~ /Repas/) {
+ my ($tmp1,$tmp2) = $p =~ m/.+\s(\d+).(\d+)+$/;
+ $pxdata->{lunchamount} = $tmp1.'.'.$tmp2;
+ }
+ if ($p =~ /Montant\s.\spayer/) {
+ my ($tmp1,$tmp2) = $p =~ m/.+\s(\d+).(\d+)+$/;
+ $pxdata->{totalamount} = $tmp1.'.'.$tmp2;
+ }
+ #print Dumper(@pdata);
+ }
+ }
+ $html->{result} = $pxdata;
+ return [
+ 200,
+ [ 'Content-Type' => $ct,'Cache-Control' => 'no-store, no-cache, must-revalidate' , 'Access-Control-Allow-Origin'=> '*'],
+ [ JSON::PP::encode_json($html) ]
+ ];
+}
+
+sub parsestatement(){
+ my $self = shift;
+ my $file = shift;
+ my $html->{result} = ();
+ my $ct="application/json";
+ my $status=200;
+ my $sxdata = ();
+ my $cmonth = "none";
+ my $frmonth = {"Janvier" => '01',"F�vrier"=> '02',"Mars" => '03',"Avril" => '04', "Mai" => '05',"Juin" => '06',"Juillet" => '07',"Ao�t" => '08',"Septembre" => '09',"Octobre" => '10',"Novembre" => '11',"D�cembre" => '12'};
+ if (-e $file){
+ my @xstmtdata = ();
+ open(EXT,$file);
+ while (my $l = <EXT>){
+ chomp($l);
+ push(@xstmtdata,$l);
+ }
+ close(EXT);
+ my $sxdata = ();
+
+ foreach my $p (@xstmtdata){
+ if ($p =~ /P.riode/) {
+ my ($m1,$y1,$m2,$y2) = $p =~ m/.+\s(.+)\s+(\d+)\s+.\s+(.+)\s+(\d+)$/;
+ if (($m1 eq $m2) && ($y1 eq $y2)){
+ $cmonth=$y1.'-'.$frmonth->{$m1};
+ }
+ }
+ if ($p =~ /\d{13,}/) {
+ my ($csnum,$am) = $p =~ m/.+\s+(\d{13,})\s+([\d|\ |,]+)$/;
+ $am =~ s/\s+//;
+ $am =~ s/,/./;
+ $sxdata->{$cmonth}->{$csnum}=$am;
+ }
+ }
+ }
+ $html->{result} = $sxdata;
+ return [
+ 200,
+ [ 'Content-Type' => $ct,'Cache-Control' => 'no-store, no-cache, must-revalidate' , 'Access-Control-Allow-Origin'=> '*'],
+ [ JSON::PP::encode_json($html) ]
+ ];
+}
+
+
+#
+#sub importstatementdata(){
+# my $simpdata = shift;
+# my $fname = shift;
+# #print Dumper($simpdata);
+# my $n=0;
+# foreach my $m (keys(%{$simpdata})){
+# $n++;
+# if (-e dirname($fname).$sep."prestation.".$m."-".$n.".pdf"){
+# unlink(dirname($fname).$sep."prestation.".$m."-".$n.".pdf");
+# }
+# rename($fname,dirname($fname).$sep."prestation.".$m."-".$n.".pdf");
+# foreach my $csnum (keys(%{$simpdata->{$m}})){
+# $simpdata->{$m}->{fnum} = $n;
+# }
+# }
+# foreach my $m (keys(%{$simpdata})){
+# $n++;
+# if ($m =~ /\d{4,}-\d{2,}/) {
+# foreach my $csnum (keys(%{$simpdata->{$m}})){
+# print "Import Check-Service no: " + $csnum + "\n";
+# if (defined($db)){
+# my $child = $db->dbquerysorted("select uuid from childs where replace(checkservicenumber,' ','') = '".$csnum."';");
+# if (keys(%{$child}) == 1) {
+# my $accdata = $db->dbquerysorted("select accmonth,childuuid from accounting where childuuid='".$child->{0}->{uuid}."' and accmonth=date('".substr($m,0,4).'-'.substr($m,5,2)."-01');");
+# if (keys(%{$accdata}) == 1) {
+# #make update
+# my @upd = ();
+# push @upd,"benefitamount='".$simpdata->{$m}->{$csnum}."'";
+# push @upd,"benefitfile='prestation.".$m."-".$simpdata->{$m}->{fnum}.".pdf'";
+# my $sql = "update accounting set ".join(',',@upd)." where childuuid='".$child->{0}->{uuid}."' and accmonth=date('".substr($m,0,4).'-'.substr($m,5,2)."-01');";
+# #print $sql."\n";
+# my $r = $db->dbexec($sql);
+# if (($log ne "") && (-e $log)){
+# if (!defined($r)) {
+# open(LOG,">>".$log);
+# print LOG localtime().":ERROR:".$sql."\n";
+# close(LOG);
+# } else {
+# open(LOG,">>".$log);
+# print LOG localtime().":SUCCESS:".$sql."\n";
+# close(LOG);
+# }
+# }
+# }else {
+# my @ins1 = ();
+# my @ins2 = ();
+# push(@ins1,"accmonth");push (@ins2,"date('".substr($m,0,4).'-'.substr($m,5,2)."-01')");
+# push(@ins1,"childuuid");push (@ins2,"'".$child->{0}->{uuid}."'");
+# push(@ins1,"benefitamount");push (@ins2,"".$simpdata->{$m}->{$csnum}."");
+# push(@ins1,"benefitfile");push (@ins2,"'prestation.".$m."-".$simpdata->{$m}->{fnum}.".pdf'");
+#
+# #accmonth,childuuid,invoicedate,invoiceamount,reference
+# my $sql = "insert into accounting (".join(',',@ins1).") VALUES (".join(',',@ins2).");";
+# #print $sql."\n";
+# my $r = $db->dbexec($sql);
+# if (($log ne "") && (-e $log)){
+# if (!defined($r)) {
+# open(LOG,">>".$log);
+# print LOG localtime().":ERROR:".$sql."\n";
+# close(LOG);
+# } else {
+# open(LOG,">>".$log);
+# print LOG localtime().":SUCCESS:".$sql."\n";
+# close(LOG);
+# }
+# }
+# }
+# }
+# }
+# }
+# }
+# }
+#}
+
+1;
\ No newline at end of file
--- /dev/null
+package Module::SQLite;
+
+use strict;
+use warnings;
+use parent qw(Plack::Component);
+use Plack::Request;
+use File::Basename;
+#use Data::Dumper;
+use DBI;
+use DBD::SQLite;
+use Encode;
+use JSON::PP;
+
+sub call {
+ my($self, $env) = @_;
+ if (($env->{REMOTE_ADDR} =~ "^127\.0\.") &&
+ ($env->{REMOTE_ADDR} =~ "^10\.") &&
+ ($env->{REMOTE_ADDR} =~ "^172\.16\.") &&
+ ($env->{REMOTE_ADDR} =~ "^192\.168\.")) {
+ return [
+ 404,
+ [ 'Content-Type' => "text/html",'Cache-Control' => 'no-store, no-cache, must-revalidate' ],
+ [ "Sorry no remote access allowed!" ]
+ ];
+ }
+ #$self->_app->($env);
+ return $self->sqlite($env);
+}
+
+sub sqlite {
+ my $self = shift;
+ my $env = shift;
+ my $html->{result} = ();
+ my $ct="application/json";
+ my $status=200;
+ my $req = Plack::Request->new($env);
+ my $res = ();
+ #print $req->query_parameters->{db}.":".$req->query_parameters->{type}.":".decode_base64($req->query_parameters->{sql})."\n------------------\n";
+
+ if ($env->{PATH_INFO} =~ /^\/\w+/){
+ $self->{dbfile} = $self->{'dbpath'}.'/'.basename($env->{PATH_INFO}).'.sqlite';
+ $html->{req}->{db} = $self->{'dbpath'}.'/'.basename($env->{PATH_INFO}).'.sqlite';
+ }else {
+ if (exists($req->body_parameters->{db})){
+ $self->{dbfile} = $req->body_parameters->{db};
+ $html->{req}->{db} = $req->body_parameters->{db};
+ } else {
+ return [
+ 400,
+ [ 'Content-Type' => $ct.'; charset=utf-8','Cache-Control' => 'no-store, no-cache, must-revalidate', 'Access-Control-Allow-Origin'=> '*' ],
+ [ JSON::PP::encode_json($html) ]
+ ];
+ }
+ }
+
+ $html->{req}->{type} = $req->body_parameters->{type};
+ $html->{req}->{sql} = $req->body_parameters->{sql};
+ #$html->{req}->{sqldecoded} = $req->query_parameters->{sql};
+ if (exists($req->body_parameters->{sql}) && exists($req->body_parameters->{type})) {
+ #$self->{dbfile} = $req->query_parameters->{db};
+ #my $db = sqlite->new();
+ my $q = $req->body_parameters->{sql};
+ my $t = $req->body_parameters->{type};
+ print $q."\n";
+ if ($t eq "query"){
+ $res = $self->dbquery($req->body_parameters->{key},$q);
+ } elsif ($t eq "querysorted"){
+ $res = $self->dbquerysorted($q);
+ } elsif ($t eq "queryarray"){
+ $res = $self->dbqueryarray($q);
+ } elsif ($t eq "exec"){
+ $res = $self->dbexec($q);
+ }
+ $html->{result}->{sqldata} = $res;
+ } else {
+ return [
+ 400,
+ [ 'Content-Type' => $ct.'; charset=utf-8','Cache-Control' => 'no-store, no-cache, must-revalidate', 'Access-Control-Allow-Origin'=> '*' ],
+ [ JSON::PP::encode_json($html) ]
+ ];
+ }
+ return [
+ 200,
+ [ 'Content-Type' => $ct.'; charset=utf-8','Cache-Control' => 'no-store, no-cache, must-revalidate', 'Access-Control-Allow-Origin'=> '*' ],
+ [ JSON::PP::encode_json($html) ]
+ ];
+};
+
+
+
+sub strreplace(){
+ my $self = shift;
+ my $text = shift;
+ $text =~ s/'/''/g;
+ return $text;
+}
+
+sub dbquery(){
+ my $self = shift;
+ my $key = shift;
+ my $stat = shift;
+ my $retdata =();
+ my $dbh = DBI->connect('DBI:SQLite:dbname='.$self->{dbfile},"","",{PrintError=>1,RaiseError=>1,AutoCommit=>1}) or return $retdata->{error} = "dbquery Connection Error!".$!;
+ #$stat = encode("utf8", $stat);
+
+ #open FILE,">>/tmp/sql.log";
+ # print FILE "key:".$key.";$stat\n";
+ # close FILE;
+ my $sth = $dbh->prepare($stat);
+ $sth->execute() or print "dbquery: ".$sth->errstr;
+ while(my $data = $sth->fetchrow_hashref())
+ {
+ if (exists $data->{$key}){
+ foreach my $k (keys %{$data}){
+ $retdata->{$data->{$key}}{$k} = decode( "utf8", $data->{$k});
+ }
+ }
+ }
+ if (keys(%{$retdata}) == 0){
+ $retdata =();
+ }
+ $sth->finish();
+ $dbh->disconnect();
+ return $retdata;
+}
+
+sub dbquerysorted(){
+ my $self = shift;
+ my $stat = shift;
+ my $retdata = ();
+ my $dbh = DBI->connect('DBI:SQLite:dbname='.$self->{dbfile},"","",{PrintError=>1,RaiseError=>1,AutoCommit=>1}) or return $retdata->{error} = "dbquery Connection Error!".$!;
+ #$stat = encode("utf8", $stat);
+ #open FILE,">>/tmp/sql.log";
+ #print "$stat\n";
+ # close FILE;
+ my $sth = $dbh->prepare($stat);
+
+ $sth->execute() or print "dbquery: ".$sth->errstr;
+ my $count = 0;
+ while(my $data = $sth->fetchrow_hashref())
+ {
+ foreach my $k (keys %{$data}){
+ $retdata->{$count}->{$k} = decode( "utf8", $data->{$k});
+ }
+ $count++;
+ }
+
+ $sth->finish();
+ $dbh->disconnect();
+ #%retdata = sort {$a <=> $b} keys %retdata;
+ return $retdata;
+}
+
+sub dbqueryarray(){
+ my $self = shift;
+ my $stat = shift;
+ my @retdata = ();
+ my $dbh = DBI->connect('DBI:SQLite:dbname='.$self->{dbfile},"","",{PrintError=>1,RaiseError=>1,AutoCommit=>1}) or return $retdata[0]->{error} = "dbquery Connection Error!".$!;
+ #$stat = encode("utf8", $stat);
+ #open FILE,">>/tmp/sql.log";
+ #print "$stat\n";
+ # close FILE;
+ my $sth = $dbh->prepare($stat);
+
+ $sth->execute() or print "dbquery: ".$sth->errstr;
+ my $count = 0;
+
+ while(my $valdata = $sth->fetchrow_arrayref())
+ {
+ if (!defined($valdata)){ last;}
+ my @rdata = ();
+ foreach my $k (@{$valdata}){
+ push @rdata,decode( "utf8", $k);
+ }
+ push @retdata,\@rdata;
+ }
+
+ $sth->finish();
+ $dbh->disconnect();
+ #%retdata = sort {$a <=> $b} keys %retdata;
+ return \@retdata;
+}
+
+sub dbexec(){
+ my $self = shift;
+ my $stat = shift;
+ my $dbh = DBI->connect('DBI:SQLite:dbname='.$self->{dbfile},"","",{PrintError=>1,AutoCommit=>1}) or return "dbexec Connection Error!".$!;
+ #$stat = encode("utf8", $stat);
+ #print $stat."\n";
+ #open FILE,">>/Users/kilian/sql.log";
+ #print FILE "$stat\n";
+ #close FILE;
+ my $sth = $dbh->prepare($stat);
+ my $rv =$dbh->do($stat) or print "Failed dbexec:\n'".$stat. "'\n\n";
+ $dbh->disconnect();
+ return $rv;
+}
+
+
+#sub dbbackup(){
+# my $self = shift;
+# my $path = shift;
+# my $type = shift;
+#
+# my @dx = localtime();
+# $dx[5] = $dx[5] +1900;
+# $dx[4] = $dx[4] +1;
+# if ($dx[4] < 10){$dx[4] = '0'.$dx[4];}
+# if ($dx[3] < 10){$dx[3] = '0'.$dx[3];}
+# if ($dx[2] < 10){$dx[2] = '0'.$dx[2];}
+# if ($dx[1] < 10){$dx[1] = '0'.$dx[1];}
+# if ($dx[0] < 10){$dx[0] = '0'.$dx[0];}
+# my $xdd = $dx[5].$dx[4].$dx[3].'_'.$dx[2].$dx[1].$dx[0];
+# my $bfile = "";
+# if ($type eq "binary" ) {
+# $bfile = $path.'/'.basename(substr($self->{dbfile},0,rindex($self->{dbfile},'.'))).'_'.$xdd.'.sqlite';
+# my $dbh = DBI->connect('DBI:SQLite:dbname='.$self->{dbfile},"","",{PrintError=>1,RaiseError=>1,AutoCommit=>1}) or die "dbexec Connection Error!".$!;
+# $dbh->sqlite_backup_to_file($bfile);
+# $dbh->disconnect();
+# }elsif($type eq "sql"){
+# $bfile = $path.'/'.basename($self->{dbfile}).'_'.$xdd.'.sql';
+# my $st = system('sqlite3 "'.$self->{dbfile}.'" ".dump" > '.$bfile);
+# }
+# return $bfile;
+#}
+#
+#sub dbrestore(){
+# my $self = shift;
+# my $file = shift;
+# my $type = shift;
+# if ($type eq "binary" ) {
+# my $dbh = DBI->connect('DBI:SQLite:dbname='.$self->{dbfile},"","",{PrintError=>1,RaiseError=>1,AutoCommit=>1}) or die "dbexec Connection Error!".$!;
+# $dbh->sqlite_backup_from_file($file);
+# $dbh->disconnect();
+# }elsif($type eq "sql"){
+# open(REST,$file) or die "cannot open restore file $file!\n";
+# my $rsql = "";
+# while (my $l = <REST>) {
+# $rsql .= $l;
+# }
+# close(REST);
+# unlink($self->{dbfile});
+# $self->dbexec($rsql);
+# }
+#}
+#
+#sub dbrepair(){
+# my $self = shift;
+# my $bfile = $self->dbbackup($ENV{'TMPDIR'},'sql');
+# $self->dbrestore($bfile,'sql');
+# unlink($bfile);
+#}
+
+
+1;
\ No newline at end of file
--- /dev/null
+package Module::Service;
+
+use strict;
+use warnings;
+use File::Path qw(make_path);
+use File::Basename;
+use parent qw(Plack::Component);
+
+sub call {
+ my($self, $env) = @_;
+ if (($env->{REMOTE_ADDR} =~ "^127\.0\.") &&
+ ($env->{REMOTE_ADDR} =~ "^10\.") &&
+ ($env->{REMOTE_ADDR} =~ "^172\.16\.") &&
+ ($env->{REMOTE_ADDR} =~ "^192\.168\.")) {
+ return [
+ 404,
+ [ 'Content-Type' => "text/html",'Cache-Control' => 'no-store, no-cache, must-revalidate' ],
+ [ "Sorry no access allowed!" ]
+ ];
+ }
+ return $self->service($env);
+}
+
+sub service() {
+ my $self = shift;
+ my $env = shift;
+ my $html = "Unknown service!";
+ my $ct="application/json";
+ my $status=200;
+
+ # if ($env->{PATH_INFO} =~ /^\/info/){
+ # return $self->appinfo($env);
+ # }
+ # if ($env->{PATH_INFO} =~ /^\/preferences/){
+ # return $self->preferences($env);
+ # }
+ if (($env->{PATH_INFO} =~ /^\/stop/) || ($env->{PATH_INFO} =~ /^\/unload/)){
+ warn "Killing the existing server (pid:".$self->{pid}.")\n";
+ kill 'TERM' => $self->{pid};
+
+ if (lc($^O) =~ /mswin32/) {
+ sleep 1;
+ kill 'KILL' => $self->{pid};
+ }
+ # waitpid($self->{pid}, 0);
+ # warn "Successfully killed! Restarting the new server process.\n";
+
+ }
+ # if($env->{PATH_INFO} =~ /^\/getconfig/){
+ # return $self->getconfig($env);
+ # }
+
+ return [
+ 200,
+ [ 'Content-Type' => 'text/html','Cache-Control' => 'no-store, no-cache, must-revalidate' , 'Access-Control-Allow-Origin'=> '*'],
+ [ $html ]
+ ];
+};
+
+# sub preferences(){
+# my $self = shift;
+# my $env =shift;
+# my $name = basename($0);
+# $name =~ s/\srv.pl$//;
+# $name =~ s/\srv.exe$//;
+# my $appcfgpath = $ENV{APPDATA}.'/'.$name;
+# $appcfgpath =~ s/\\/\//g;
+# my $pref->{result}= ();
+# my $req = Plack::Request->new($env);
+# if (exists($req->query_parameters->{page})){
+# if (-e $appcfgpath.'/'.$req->query_parameters->{page}.'.json'){
+# open(PREF,$appcfgpath.'/'.$req->query_parameters->{page}.'.json');
+# my $strpref = "";
+# while (my $l = <PREF>){
+# $strpref .= $l;
+# }
+# close(PREF);
+# $pref->{result}=JSON::PP::decode_json($strpref);
+# }
+# if (exists($req->query_parameters->{set})){
+# my $newpref = JSON::PP::decode_json($req->query_parameters->{set});
+# foreach my $p (keys(%{$newpref})){
+# $pref->{result}->{$p} = $newpref->{$p};
+# }
+# open(PREF,">".$appcfgpath.'/'.$req->query_parameters->{page}.'.json');
+# print PREF JSON::PP::encode_json($pref->{result});
+# close(PREF);
+# }
+# }
+# return [
+# 200,
+# [ 'Content-Type' => "application/json",'Cache-Control' => 'no-store, no-cache, must-revalidate', 'Access-Control-Allow-Origin'=> '*' ],
+# [ JSON::PP::encode_json($pref) ]
+# ];
+# }
+
+# sub appinfo(){
+# my $self = shift;
+# my $env = shift;
+# my $html->{result} = ();
+# my $req = Plack::Request->new($env);
+# my $name = basename($0);
+# $name =~ s/\.pl$//;
+# $name =~ s/\.exe$//;
+# $html->{result}->{OS} = $^O;
+# $html->{result}->{app} = $name;
+# if ($^O eq "MSWin32"){
+# $html->{result}->{home} = $ENV{USERPROFILE};
+# $html->{result}->{user} = $ENV{USERNAME};
+# $html->{result}->{appcfgpath} = $ENV{APPDATA}.'/'.$name;
+# $html->{result}->{hostname} = $ENV{COMPUTERNAME};
+# $html->{result}->{arch} = $ENV{PROCESSOR_ARCHITEW6432};
+# $html->{result}->{appcfgpath} =~ s/\\/\//g;
+# $html->{result}->{home} =~ s/\\/\//g;
+# } else {
+# $html->{result}->{home} = $ENV{HOME};
+# $html->{result}->{user} = $ENV{USER};
+# if ($^O eq "darwin"){
+# $html->{result}->{appcfgpath} = $ENV{HOME}.'/Library/Application Support/'.$name;
+# } else {
+# $html->{result}->{appcfgpath} = $ENV{HOME}.'/.'.$name.'/';
+# }
+# $html->{result}->{hostname} = `hostname -s`;
+# chomp($html->{result}->{hostname});
+# $html->{result}->{arch} = `uname -m`;
+# chomp($html->{result}->{arch});
+# }
+# if (! -e $html->{result}->{appcfgpath}){
+# make_path($html->{result}->{appcfgpath});
+# }
+# if (-e $html->{result}->{appcfgpath}.'/service.json'){
+# open(LCFG,$html->{result}->{appcfgpath}.'/service.json');
+# my $strljs = "";
+# while (my $l = <LCFG>){
+# $strljs .= $l;
+# }
+# close(LCFG);
+# print $strljs."\n--\n";
+# #if ($strljs =~ /^\{.*\}$/){
+# $html->{result}->{appconfig} = JSON::PP::decode_json($strljs);
+# #}
+# }
+# return [
+# 200,
+# [ 'Content-Type' => "application/json",'Cache-Control' => 'no-store, no-cache, must-revalidate', 'Access-Control-Allow-Origin'=> '*' ],
+# [ JSON::PP::encode_json($html) ]
+# ];
+# }
+
+# sub getfileconfig(){
+# my $self = shift;
+# my $strcfg = "";
+# my $apppath = $self->getappconfigpath();
+# if (-e $apppath.'/'.basename($apppath).'.conf'){
+# open(AUTH,$apppath.'/'.basename($apppath).'.conf');
+# while (my $l = <AUTH>){
+# chomp($l);
+# $strcfg .= $l;
+# }
+# close(AUTH);
+# }
+# if ($strcfg eq ""){
+# return undef;
+# }
+# return JSON::decode_json($strcfg);
+# }
+
+# sub getconfig(){
+# my $self = shift;
+# my $env = shift;
+# my $html->{result} = undef;
+# my $req = Plack::Request->new($env);
+# my @sections = ('weblogin','cablenet','wirelessnet','openvpn','extdrives','shares','shareusers');
+# if (exists($req->query_parameters->{section})){
+# @sections = split(',',$req->query_parameters->{section});
+# }
+# foreach my $s (@sections){
+# if ($s eq 'weblogin') {
+# $html->{result}->{$s} = $self->getweblogin();
+# } elsif ($s eq 'cablenet') {
+# $html->{result}->{$s} = $self->getcablenetworkconfig();
+# } elsif ($s eq 'wirelessnet') {
+
+# } elsif ($s eq 'openvpn') {
+# $html->{result}->{$s} = $self->getOpenVPN();
+# } elsif ($s eq 'extdrives') {
+# $html->{result}->{extdrives} = $self->getdrives();
+# } elsif ($s eq 'shares') {
+# $html->{result}->{shares} = $self->getshares();
+# } elsif ($s eq 'shareusers') {
+
+# };
+# }
+# return [
+# 200,
+# [ 'Content-Type' => "application/json",'Cache-Control' => 'no-store, no-cache, must-revalidate', 'Access-Control-Allow-Origin'=> '*' ],
+# [ JSON::PP::encode_json($html) ]
+# ];
+# }
+
+# sub getweblogin(){
+# my $self = shift;
+# my $apppath = $self->getappconfigpath();
+# my $loginname= "";
+# if (-e $apppath.'/'.basename($apppath).'.passwd'){
+# open(AUTH,$apppath.'/'.basename($apppath).'.passwd');
+# while (my $l = <AUTH>){
+# chomp($l);
+# my ($loginname) = $l =~ /^(\w+)\=.*/;
+# }
+# close(AUTH);
+# }
+# return { "user" => $loginname };
+# }
+
+# sub setlogin(){
+# my $self = shift;
+# my $env = shift;
+# my $req = Plack::Request->new($env);
+
+# }
+
+# sub getwifinetworks(){
+# my $self = shift;
+# my $current = `sudo grep ssid /etc/wpa_supplicant/wpa_supplicant.conf`;
+# chomp($current);
+# my $wifi->{ssid} = undef;
+# if ($current ne ""){
+# $wifi->{ssid} = $current;
+# }
+# my $strlist = `sudo iw wlan0 scan | grep SSID | sed \'s/.*SSID: //g\'`;
+# my @list = split("\n",$strlist);
+# $wifi->{networks} = \@list;
+# return $wifi;
+# }
+
+
+
+
+#sub getusers(){
+# my $self = shift;
+# my $cmd = "";
+# if ($^O eq "linux"){
+# $cmd = 'cat /etc/passwd | grep "/bin/bash" | grep -v -e "^root" | awk -F ":" \'{ print $1 }\'';
+# } elsif ($^O eq "darwin"){
+# $cmd = 'ls -1 /Users | grep -v "Shared"';
+# } elsif ($^O eq "MSWin32"){
+#
+# }
+# my $strdata = `$cmd`;
+# my @list = split("\n",$strdata);
+# return \@list;
+#}
+
+# sub getdrives(){
+# my $self = shift;
+# my $connecteddrives = $self->getconnecteddrives();
+# my $mounts = $self->getcurrentmountpoints();
+# my $cfg = $self->getfileconfig();
+# my $fstypes = { ntfs => 'ntfs-3g',exfat => 'exfat', fat32 => 'vfat'};
+# my $drivesdata = ();
+# foreach my $cd (keys(%{$connecteddrives})){
+# if (exists($cfg->{drives}->{$connecteddrives->{$cd}->{serial}})){
+# $drivesdata->{$cd} = $connecteddrives->{$cd};
+# #print $cd." => ".$config->{drives}->{$connecteddrives->{$cd}->{serial}}->{path}."\n";
+# # if (! -d $config->{drives}->{$connecteddrives->{$cd}->{serial}}->{path}){
+# # mkdir($config->{drives}->{$connecteddrives->{$cd}->{serial}}->{path});
+# # }
+# if (exists($mounts->{$connecteddrives->{$cd}->{dev}})){
+# $drivesdata->{$cd}->{mounpoint} = $mounts->{$connecteddrives->{$cd}->{dev}};
+# # my $cmd = "sudo mount -t ".$fstypes->{$connecteddrives->{$cd}->{fs}}." -o uid=".$config->{drives}->{$connecteddrives->{$cd}->{serial}}->{uid}.',gid='.$config->{drives}->{$connecteddrives->{$cd}->{serial}}->{gid}.','.$config->{drives}->{$connecteddrives->{$cd}->{serial}}->{type}." /dev/".$connecteddrives->{$cd}->{dev}." ".$config->{drives}->{$connecteddrives->{$cd}->{serial}}->{path};
+# #print $cmd."\n";
+# # my $res = `$cmd`;
+# }
+# }
+# }
+# return $drivesdata;
+# }
+
+# sub mountdrives(){
+# my $self = shift;
+# #mount -t ntfs-3g -o uid=1001,gid=1001,rw /dev/sdb1 /home/dks/music
+# }
+
+# sub getshares(){
+# my $self = shift;
+# my $shares =();
+# open(SMB,'/etc/samba/smb.conf');
+# my $cgrp = "";
+# while (my $l = <SMB>){
+# chomp($l);
+# if ($l =~ /^\[.*\]$/){
+# $cgrp = $l;
+# $cgrp =~ s /\[//;
+# $cgrp =~ s /\]//;
+# } elsif ($l ne ""){
+# my ($k,$v) = $l =~ m/\s*(.+)\s+\=\s+(.*)$/;
+# if ($cgrp eq "global"){
+# if (($k eq "workgroup") || ($k eq "server string") || ($k eq "netbios name")){
+# $shares->{$cgrp}->{$k} =$v;
+# }
+# }else {
+# if (($k eq "comment") || ($k eq "path") || ($k eq "vialid users")){
+# $shares->{$cgrp}->{$k} =$v;
+# }
+# }
+# }
+# }
+# close(SMB);
+# return $shares;
+# }
+
+# sub setshares(){
+# my $self = shift;
+# }
+
+
+# sub getwifinetworks(){
+# my $self = shift;
+# #iw wlan0 scan | grep SSID | sed 's/.*SSID: //g'
+# # }
+
+# sub setwifinetwork(){
+# my $self = shift;
+# #/etc/wpa_supplicant/wpa_supplicant.conf
+# #network={
+# #ssid="testing"
+# #psk="testingPassword"
+# ##encrypted:
+# #psk=131e1e221f6e06e3911a2d11ff2fac9182665c004de85300f9cac208a6a80531
+# #wpa_passphrase "testing" "testingPassword"
+# #}
+# #wpa_cli -i wlan0 reconfigure
+# ##unsecurd
+# # network={
+# # ssid="testing"
+# # key_mgmt=NONE
+# #}
+# ##HIDDEN
+# # network={
+# # ssid="yourHiddenSSID"
+# # scan_ssid=1
+# # psk="Your_wifi_password"
+# #}
+# ##MULTIPLE with option apriority
+# #network={
+# # ssid="HomeOneSSID"
+# # psk="passwordOne"
+# # priority=1
+# # id_str="homeOne"
+# #}
+# #
+# #network={
+# # ssid="HomeTwoSSID"
+# # psk="passwordTwo"
+# # priority=2
+# # id_str="homeTwo"
+# #}
+# }
+
+# sub configureOpenVPN(){
+# my $self = shift;
+# my $file = shift;
+# }
+
+# sub getOpenVPN(){
+# my $self = shift;
+# opendir(OVPN,'/etc/openvpn');
+# my $ovpndata = ();
+# print "read OPENVPN:\n";
+# while(my $f = readdir(OVPN)){
+# print "OVPN file:".$f."\n";
+# if (($f =~ /\.ovpn$/) || ($f =~ /\.conf$/)){
+# my $name = substr($f,0,-6);
+# $ovpndata->{$name} = undef;
+# }
+# }
+
+# closedir(OVPN);
+# return $ovpndata;
+# }
+
+# sub getOpenVPNstatus(){
+
+# }
+
+# sub getcablenetworkconfig(){
+# my $self = shift;
+# my $cmd = "";
+# my $ncfg->{type} = "dhcp";
+# if ($^O eq "linux"){
+# $cmd = 'cat /etc/dhcpcd.conf | grep -e "^static\|^interface"';
+# my $strdata = `$cmd`;
+# my @data = split("\n",$strdata);
+# foreach my $d (@data){
+# if ($d =~ /static\sip_address/){
+# $ncfg->{ip} = $d =~ /.+=(.+)\/\d{1,2}$/;
+# $ncfg->{subnet} = $d =~ /.+=.+\/(\d{1,2})$/;
+# #substr(Net::CIDR::addrandmask2cidr($stdata->{0}->{networkip}, $stdata->{0}->{networksubnet}),-3)
+# }
+# if ($d =~ /static\srouters/){
+# $ncfg->{gateway} = $d =~ /.+=(.+)$/;
+# }
+# if ($d =~ /static\sdomain_name_servers/){
+# $ncfg->{dns} = $d =~ /.+=(.+)$/;
+# }
+# }
+# } elsif ($^O eq "darwin"){
+# $cmd = '';
+# } elsif ($^O eq "MSWin32"){
+# $cmd = '';
+# }
+# return $ncfg;
+# }
+
+# sub getappconfigpath(){
+# my $self = shift;
+# my $name = basename($0);
+# $name =~ s/\.pl$//;
+# $name =~ s/\.exe$//;
+# my $path = "";
+# if ($^O eq "MSWin32"){
+# $path = $ENV{APPDATA}.'/'.$name;
+# } elsif ($^O eq "darwin"){
+# $path = $ENV{HOME}.'/Library/Application Support/'.$name;
+# } else {
+# $path = $ENV{HOME}.'/.'.$name.'/';
+# }
+# return $path;
+# }
+
+# sub getconnecteddrives(){
+# my $self = shift;
+# my $cmd = 'lsblk -o name,label,size,mountpoint,fstype,SERIAL | grep -e "sd."';
+# my $strdrives = `$cmd`;
+# my $drives = ();
+# my @drives = split("\n",$strdrives);
+# foreach my $l (@drives){
+# $l =~ tr/a-zA-Z0-9 ._-//cd;
+# $l =~ s/\s+/\ /g;
+# my @tmp = split(" ",$l);
+# #print Dumper(@tmp);
+# if ( $l =~ /^sd.\d/ ) {
+# my $drv = substr($tmp[0],0,3);
+# $drives->{$drv}->{dev} = $tmp[0];
+# $drives->{$drv}->{label} = $tmp[1];
+# $drives->{$drv}->{size} = $tmp[2];
+# $drives->{$drv}->{fs} = $tmp[3];
+# } else {
+# #print $l."\n";
+# $drives->{$tmp[0]}->{serial} = $tmp[2];
+# }
+# }
+
+# return $drives;
+# }
+
+# sub getcurrentmountpoints(){
+# my $self = shift;
+# my $cmd = 'mount | grep "/dev/sd"';
+# my $mpoints = ();
+# my $strmounts = `$cmd`;
+# #print $strmounts;
+# my @mdrives = split("\n",$strmounts);
+# foreach my $m (@mdrives){
+# my ($drv,$path) = $m =~ m/^\/dev\/(.+)\son\s(.*)\stype.*$/;
+# $mpoints->{$drv} = $path;
+# }
+# return $mpoints;
+# }
+
+
+1;
\ No newline at end of file
--- /dev/null
+package Module::Test;
+
+use strict;
+use warnings;
+use parent qw(Plack::Component);
+use Plack::Request;
+use Data::Dumper;
+use URI::Encode qw/uri_encode/;
+
+sub call {
+ my($self, $env) = @_;
+ #$self->_app->($env);
+ if (($env->{REMOTE_ADDR} =~ "^127\.0\.") &&
+ ($env->{REMOTE_ADDR} =~ "^10\.") &&
+ ($env->{REMOTE_ADDR} =~ "^172\.16\.") &&
+ ($env->{REMOTE_ADDR} =~ "^192\.168\.")) {
+ return [
+ 404,
+ [ 'Content-Type' => "text/html",'Cache-Control' => 'no-store, no-cache, must-revalidate' ],
+ [ "Sorry no remote access allowed!" ]
+ ];
+ }
+ return $self->test($env);
+}
+
+sub test(){
+ my $self = shift;
+ my $env = shift;
+ my $html = {};
+ my $ct="application/json";
+ my $status=200;
+ my $request = Plack::Request->new($env);
+
+ foreach my $k (keys(%ENV)){
+ $html->{sysenv}->{$k} = $ENV{$k};
+ }
+
+ foreach my $k (keys(%{$env})){
+ $html->{request}->{$k} = uri_encode($env->{$k});
+ }
+ # $html .= "<h1>GET PARAMETERS</h1>";
+ # $html .= Dumper($request->query_parameters);
+ # $html .= "<h1>POST PARAMETERS</h1>";
+ # $html .= Dumper($request->body_parameters);
+ # print "Test Called!\n";
+ return [
+ 200,
+ [ 'Content-Type' => "application/json",'Cache-Control' => 'no-store, no-cache, must-revalidate', 'Access-Control-Allow-Origin'=> '*' ],
+ [ JSON::PP::encode_json($html) ]
+ ];
+};
+
+
+1;
\ No newline at end of file
--- /dev/null
+package Module::Test;
+
+use strict;
+use warnings;
+use parent qw(Plack::Component);
+use Plack::Request;
+use Data::Dumper;
+
+sub call {
+ my($self, $env) = @_;
+ #$self->_app->($env);
+ if (!exists($env->{REMOTE_USER}) ) {
+ return [
+ 404,
+ [ 'Content-Type' => "text/html",'Cache-Control' => 'no-store, no-cache, must-revalidate' ],
+ [ "Access not allowed!" ]
+ ];
+ }
+ if ($env->{PATH_INFO} =~ /^\/server/){
+ return $self->server($env);
+ } elsif ($env->{PATH_INFO} =~ /^\/client/) {
+ return $self->client($env);
+ } else {
+ return $self->clientslist($env)
+ }
+ return return [
+ 404,
+ [ 'Content-Type' => "text/html",'Cache-Control' => 'no-store, no-cache, must-revalidate' ],
+ [ "Access not allowed!" ]
+ ];;
+}
+
+sub server(){
+ my $self = shift;
+ my $env = shift;
+ my $html = "";
+ my $ct="application/json";
+ my $status=200;
+ my $request = Plack::Request->new($env);
+ if ($env->{PATH_INFO} =~ /^\/server\/list/){
+
+ }
+ return [
+ 200,
+ [ 'Content-Type' => "application/json",'Cache-Control' => 'no-store, no-cache, must-revalidate' ],
+ [ $html ]
+ ];
+};
+
+sub client(){
+ my $self = shift;
+ my $env = shift;
+ my $html = "";
+ my $ct="application/json";
+ my $status=200;
+ my $request = Plack::Request->new($env);
+ if ($env->{PATH_INFO} =~ /^\/client\/add/){
+
+ } elsif ($env->{PATH_INFO} =~ /^\/client\/revoke/){
+
+ }
+ return [
+ 200,
+ [ 'Content-Type' => "application/json",'Cache-Control' => 'no-store, no-cache, must-revalidate' ],
+ [ $html ]
+ ];
+};
+
+1;
\ No newline at end of file
--- /dev/null
+#!/usr/bin/env perl
+
+use strict;
+use PDF::API2;
+use PDF::Table;
+use Image::Size;
+use File::Basename;
+use Getopt::Long;
+use utf8;
+use Encode;
+use JSON::PP;
+#use Data::Dumper;
+my $pdf = PDF::API2->new();
+my $strpdfdata ="";
+my $templatedata =();
+my $data = "";
+my $pdfout = "";
+my $lang = "fr";
+# my $datafile=dirname($0).'/pdftest.pdf';
+GetOptions ("data|d=s" => \$data, "pdfoutput|o=s" => \$pdfout, "lang|l=s" =>\$lang);
+if (! -e $datafile){
+ print "file $datafile does not exist!\n";
+ exit(1);
+}
+if (-e $pdfout){
+ unlink($pdfout);
+}
+
+
+
+my $strtemplatedata = '{
+ "section":{
+ "12headerimg":{"x":50,"y":755,"width":160,"type":"image"},
+ "02headerline":{"type":"line","color":"black","width":1,"start":{"x":50,"y":753},"end":{"x":285,"y":753}},
+ "03dkstext":{"type":"text","align":"center","font":{"name":"Helvetica","size":9},"x":200,"y":743},
+ "04dksfooter":{"type":"text","align":"center","font":{"name":"Helvetica","size":10},"x":297.5,"y":25,"lineheight":15},
+ "05adrline":{"type":"line","color":"black","width":1,"start":{"x":52,"y":662},"end":{"x":280,"y":662}},
+ "06header_right":{"type":"text","align":"right","font":{"name":"Helvetica","size":11},"x":550,"y":820,"lineheight":14},
+ "07reporttype":{"type":"text","align":"right","font":{"name":"HelveticaBold","size":30},"x":550,"y":704,"lineheight":14},
+ "08tbladdress":{"type":"table","x":"50","w":"230","font":"Helvetica","font_size":"11","start_y":"680","start_h":"620","next_y":"750","next_h":"500","padding":"2","padding_bottom":"3","padding_top":"3","padding_right":"5","column_props":[{ "min_w":"200", "max_w":"200", "justify":"left" }],"header_props":[{ "font_size":"11", "font":"HelveticaBold", "bg_color":"white", "font_color":"black", "repeat":"1", "justify":"left" }],"border":"0"},
+ "09tblinvoicedata":{"type":"table","x":"390","w":"175","font":"Helvetica","font_size":"11","start_y":"680","start_h":"620","next_y":"750","next_h":"500","padding":"2","padding_bottom":"3","padding_top":"3","padding_right":"5","column_props":[ { "min_w":"70","max_w":"70","justify":"left" },{ "min_w":"90","max_w":"90","justify":"left","font":"HelveticaBold" } ],"border":"0"},
+ "10tblproductdata":{"type":"table","x":"50","w":"500","font":"Helvetica","font_size":"11","start_y":"570","start_h":"300","next_y":"750","next_h":"500","padding":"2","padding_left":"5","padding_bottom":"10","padding_top":"5","padding_right":"5","header_props":[{"font_size":"11","font":"HelveticaBold","bg_color":"#e6e6e6","font_color":"black","repeat":"1","justify":"center" }],"column_props":[ { },{ "min_w":"40","max_w":"40","justify":"right" },{ "min_w":"20","max_w":"20","justify":"right" },{ "min_w":"50","max_w":"50","justify":"right","font":"Helvetica" } ],"border":"0.5"},
+ "11totalsums":{"type":"table","x":"349.5","w":"201","font":"Helvetica","font_size":"11","start_y":"%%10tblproductdata:y%%","start_h":"150","next_y":"750","next_h":"500","padding":"2","padding_left":"5","padding_bottom":"10","padding_top":"5","padding_right":"5","column_props":[ { "justify":"right" },{ "min_w":"70","max_w":"70","justify":"right","font":"HelveticaBold" } ],"border":"0.5"}
+ },
+ "data":{"fr":{
+ "12headerimg":{"src":"'.dirname($0).'/dks_1000.png"},
+ "03dkstext":{"text":["Database Knowledge Solutions - Simplify IT!"]},
+ "04dksfooter":{"text":["DKS, Société à responsabilité limitée, RC Luxembourg,B168572 - TVA: LU 2537 5617 - No. Aut: 10024550 / 0","IBAN: LU25 0020 1100 2783 8700; BIC: BILLLULL"]},
+ "06header_right":{"text":["DKS s.à r.l.","8b, rue du Moulin","6914 Roodt/Syre","Tel: +352 691 504574","info@dks.lu / www.dks.lu"]},
+ "08tbladdress":{"text":[ ["À:"], ["%%RECEPIENT%%"], ["%%ADDRESS"], ["%%COUNTYSHORT%%-%%ZIP%% %%CITY%%"] ]},
+ "07reporttype":{"text":["Facture"]},
+ "09tblinvoicedata":{"text":[ ["NO. Facture","%%REFERENCE%%"], ["Date","%%INVOICEDATE%%"], ["Échéanche","%%REMINDERDATE%%"], ["No Client","%%CLIENTNUMBER%%"], ["Ust-Id","%%VATID%%"] ]},
+ "10tblproductdata":{"text":[ ["Produit", "Qu.","Prix unitaire","Prix Net"], ["%%PRODUCT%%", "%%QUANTIY%% %%UNIT%%","%%UNITAMOUNT%% %%CURRENCY%%","%%NETAMOUNT%% %%CURRENCY%%"] ]},
+ "11totalsums":{"text":[ ["Total Net :","%%SUMNETAMOUNT%% %%CURRENCY%%"], ["TVA (%%VATPERCENT%%%) :","%%SUMVATAMOUNT%% %%CURRENCY%%"], ["Total à payer:","%%SUMGROSSAMOUNT%% %%CURRENCY%%"] ]}
+ },"de":{
+ "12headerimg":{"src":"'.dirname($0).'/dks_1000.png"},
+ "03dkstext":{"text":["Database Knowledge Solutions - Simplify IT!"]},
+ "04dksfooter":{"text":["DKS, Société à responsabilité limitée, RC Luxembourg,B168572 - TVA: LU 2537 5617 - No. Aut: 10024550 / 0","IBAN: LU25 0020 1100 2783 8700; BIC: BILLLULL"]},
+ "06header_right":{"text":["DKS s.à r.l.","8b, rue du Moulin","6914 Roodt/Syre","Tel: +352 691 504574","info@dks.lu / www.dks.lu"]},
+ "08tbladdress":{"text":[ ["An:"], ["%%RECEPIENT%%"], ["%%ADDRESS"], ["%%COUNTYSHORT%%-%%ZIP%% %%CITY%%"] ]},
+ "07reporttype":{"text":["Rechnung"]},
+ "09tblinvoicedata":{"text":[ ["Rechnungs-Nr.","%%REFERENCE%%"], ["Datum","%%INVOICEDATE%%"], ["Fälligkeit","%%REMINDERDATE%%"], ["Kunden-Nr.","%%CLIENTNUMBER%%"], ["Ust-Id","%%VATID%%"] ]},
+ "10tblproductdata":{"text":[ ["Produkt", "Anzahl","EinzelPreis","Netto-Preis"], ["%%PRODUCT%%", "%%QUANTIY%% %%UNIT%%","%%UNITAMOUNT%% %%CURRENCY%%","%%NETAMOUNT%% %%CURRENCY%%"] ]},
+ "11totalsums":{"text":[ ["Gesamt Netto :","%%SUMNETAMOUNT%% %%CURRENCY%%"], ["MwSt. (%%VATPERCENT%%%) :","%%SUMVATAMOUNT%% %%CURRENCY%%€"], ["Gesamt Brutto :","%%SUMGROSSAMOUNT%% %%CURRENCY%%"] ]}
+ },"en":{
+ "12headerimg":{"src":"'.dirname($0).'/dks_1000.png"},
+ "03dkstext":{"text":["Database Knowledge Solutions - Simplify IT!"]},
+ "04dksfooter":{"text":["DKS, Société à responsabilité limitée, RC Luxembourg,B168572 - TVA: LU 2537 5617 - No. Aut: 10024550 / 0","IBAN: LU25 0020 1100 2783 8700; BIC: BILLLULL"]},
+ "06header_right":{"text":["DKS s.à r.l.","8b, rue du Moulin","6914 Roodt/Syre","Tel: +352 691 504574","info@dks.lu / www.dks.lu"]},
+ "08tbladdress":{"text":[ ["To:"],["%%RECEPIENT%%"], ["%%ADDRESS"], ["%%COUNTYSHORT%%-%%ZIP%% %%CITY%%"] ]},
+ "07reporttype":{"text":["Invoice"]},
+ "09tblinvoicedata":{"text":[ ["Reference.","%%REFERENCE%%"], ["Date","%%INVOICEDATE%%"], ["Due Date","%%REMINDERDATE%"], ["Client-Id","%%CLIENTNUMBER%%"], ["VAT-Id","%%VATID%%"] ]},
+ "10tblproductdata":{"text":[ ["Product", "Quantity","Unit Amount","Net Amount"], ["%%PRODUCT%%", "%%QUANTIY%% %%UNIT%%","%%UNITAMOUNT%% %%CURRENCY%%","%%NETAMOUNT%% %%CURRENCY%%"] ]},
+ "11totalsums":{"text":[ ["Net Total :","%%SUMNETAMOUNT%% %%CURRENCY%%"], ["VAT (%%VATPERCENT%%%) :","%%SUMVATAMOUNT%% %%CURRENCY%%€"], ["Total to Pay:","%%SUMGROSSAMOUNT%% %%CURRENCY%%"] ]
+ },
+ }
+}';
+
+
+open(DATA,$strtemplatedata);
+while (my $l = <DATA>){
+ $strpdfdata .= $l;
+}
+close(DATA);
+$templatedata = JSON::PP::decode_json($strpdfdata);
+my $pdfdata->{section} = $templatedata->{section};
+$pdfdata->{data} = $templatedata->{data}->{$lang};
+
+$pdf->preferences({-fitwindow => 1});
+
+
+my $page = $pdf->page();
+$page->mediabox('A4');
+
+
+
+
+my $endpoints = ();
+foreach my $s (sort keys(%{$pdfdata->{section}})){
+ $endpoints->{$s} = {final_y => '', lastpage => 1,pages => 1};
+ if ($pdfdata->{section}->{$s}->{type} eq "image"){
+ #print "Add Image $s\n";
+
+ $endpoints->{$s}->{y} = &addimage($pdf,$page,$pdfdata->{section}->{$s},$pdfdata->{data}->{$s});
+ } elsif ($pdfdata->{section}->{$s}->{type} eq "line"){
+ #print "Add Line $s\n";
+ $endpoints->{$s}->{y} = &addline($page,$pdfdata->{section}->{$s});
+ } elsif ($pdfdata->{section}->{$s}->{type} eq "text"){
+ #print "Add Text $s\n";
+ $endpoints->{$s}->{y} = &addtext($pdf,$page,$pdfdata->{section}->{$s},$pdfdata->{data}->{$s});
+ } elsif ($pdfdata->{section}->{$s}->{type} eq "table"){
+ #print "Add Table $s\n";
+ ($endpoints->{$s}->{lastpage}, $endpoints->{$s}->{pages}, $endpoints->{$s}->{y}) = &addtable($pdf,$page,$pdfdata->{section}->{$s},$pdfdata->{data}->{$s});
+ }
+}
+
+$pdf->saveas($pdfout);
+$pdf->end;
+
+#Functions
+
+sub addimage(){
+ my $pdf = shift;
+ my $page = shift;
+ my $section = shift;
+ my $data = shift;
+ my $gfx = $page->gfx();
+ my ($iw, $ih) = imgsize($data->{src});
+ my $nimgw = $section->{width};
+ my $nimgh = ($nimgw/$iw) * $ih;
+ #print "New Imagesize: w:".$nimgw." h:".$nimgh."\n";
+ $gfx->translate($section->{x},$section->{y});
+ my $img = $pdf->image_png($data->{src});
+ $gfx->image($img,0,0,$nimgw,$nimgh);
+ $gfx->translate(0,0);
+ $gfx->save;
+ return $nimgh + $section->{y};
+}
+
+sub addline(){
+ my $page = shift;
+ my $section = shift;
+ my $line = $page->gfx();
+ $line->translate($section->{x},$section->{y});
+ $line->strokecolor($section->{color});
+ $line->linewidth($section->{width});
+ $line->move( $section->{start}->{x}, $section->{start}->{y} );
+ $line->line( $section->{end}->{x}, $section->{end}->{y} );
+ $line->stroke;
+ $line->save;
+ return $section->{end}->{y};
+}
+
+sub addtext(){
+ my $pdf = shift;
+ my $page = shift;
+ my $section = shift;
+ my $data = shift;
+
+ my $textobj = $page->text();
+
+ #print "X:".$section->{x}." Y:".$section->{y}."\n";
+ $textobj->translate($section->{x}, $section->{y});
+ $textobj->font($pdf->corefont($section->{font}->{name}),$section->{font}->{size});
+ foreach my $d (@{$data->{text}}){
+ if ($section->{align} eq "center"){
+ $textobj->text_center($d);
+ } elsif ($section->{align} eq "right"){
+ $textobj->text_right($d);
+ } else {
+ $textobj->text($d);
+ }
+ $section->{y} = $section->{y} - $section->{lineheight};
+ $textobj->translate($section->{x}, $section->{y});
+ }
+ $textobj->save;
+ return $section->{y};
+}
+
+sub addtable(){
+ my $pdf = shift;
+ my $page = shift;
+ my $section = shift;
+ my $data = shift;
+ my $pdftbl = new PDF::Table;
+ delete($section->{type});
+ if (exists($section->{font})){
+ $section->{font} = $pdf->corefont($section->{font});
+ }
+ if (exists($section->{start_y})){
+ if ($section->{start_y} =~ /^%%.*%%$/){
+ my ($sec,$k) = $section->{start_y} =~ /^%%(.+):(.+)%%$/;
+ $section->{start_y} = $endpoints->{$sec}->{$k};
+ }
+ }
+ #print "HeadProps\n";
+ if (exists($section->{header_props})){
+ foreach (my $i=0;$i<scalar(@{$section->{header_props}});$i++){
+ my $tmpdata = @{$section->{header_props}}[$i];
+ if (exists($tmpdata->{font})){
+ $tmpdata->{font} = $pdf->corefont($tmpdata->{font});
+ }
+ @{$section->{header_props}}[$i] = $tmpdata;
+ }
+ }
+ #print "ColProps\n";
+ if (exists($section->{column_props})){
+ foreach (my $i=0;$i<scalar(@{$section->{column_props}});$i++){
+ my $tmpdata = @{$section->{column_props}}[$i];
+ if (exists($tmpdata->{font})){
+ $tmpdata->{font} = $pdf->corefont($tmpdata->{font});
+ }
+ @{$section->{column_props}}[$i] = $tmpdata;
+ }
+ }
+ #print Dumper($section);
+ #print ref %{$section}."\n";
+ my ($lastpage, $tblpages, $final_y) = $pdftbl->table($pdf,$page, $data->{text}, %{$section});
+ return ($lastpage, $tblpages, $final_y);
+}
+
+
+
+
--- /dev/null
+#!/usr/bin/env perl
+
+use strict;
+use Getopt::Long;
+use File::Basename;
+use Data::Dumper;
+use Encode;
+use Getopt::Long;
+my $file = "";
+my $outfile = "";
+#my $dbfile = "";
+GetOptions("infile|i=s" => \$file, "outfile|o=s" => \$outfile);
+
+my $fdata = "";
+open (FF,$file);
+while (my $l = <FF>){
+ #chomp($l);
+ $l =~ s/\r//g;
+ $l =~ s/\n//g;
+ #print $l."\n\n";
+ $fdata .= $l;
+}
+close(FF);
+#print $fdata;
+$fdata =~ s/<TD><BR><\/TD>/<TD><\/TD>/g;
+my ($tbl) = $fdata =~ m/.*<TABLE BORDER=1>(.*)<\/TABLE>.*/;
+$tbl =~ s/^<TR>//;
+$tbl =~ s/<\/TR>$//;
+
+my @strdata = split('</TR><TR>',$tbl);
+my $strcol = shift(@strdata);
+#print Dumper(@strdata);
+#print Dumper($strcol);
+#get cols;
+my $tablename = substr(basename($file),0,rindex(basename($file),"."));
+
+my @cols = &getheaderarray($strcol);
+my @rows = ();
+foreach my $d (@strdata){
+ my @rdata = &getdataarray($d);
+ push (@rows,\@rdata);
+}
+print Dumper(@rows);
+#print Dumper(@cols);
+open (FOUT,">".$outfile);
+print FOUT &tableddl($tablename,\@cols);
+
+foreach my $r (@rows){
+ my @nr = ();
+ foreach my $d (@{$r}){
+ if ($d eq ""){$d = 'null';}
+ elsif ($d =~ /^\d\d\/\d\d\/\d\d\d\d\s+\d\d:\d\d:\d\d$/){
+ my ($c,$m,$y,$h,$n,$s) = $d =~ m/(\d\d)\/(\d\d)\/(\d\d\d\d)\s+(\d\d):(\d\d):(\d\d)/;
+ $d = "datetime('".$y.'-'.$m.'-'.$c.' '.$h.':'.$n.':'.$s."')";
+ }elsif ($d =~ /^\d+,\d+$/){
+ $d =~ s/,/./;
+ }else {
+ $d =~ s/\r$//;
+ $d =~ s/\n$//;
+ $d = "'".encode('utf-8',$d)."'";
+ }
+ push (@nr,$d);
+ }
+ my $sql = "INSERT INTO ".$tablename." (".join(',',@cols).") VALUES (".join(",",@nr).");";
+ print $sql."\n";
+ print FOUT $sql."\n";
+}
+close(FOUT);
+
+
+sub getheaderarray(){
+ my $strdata = shift;
+ $strdata =~ s/^<TH>//;
+ $strdata =~ s/<\/TH>$//;
+ $strdata = lc($strdata);
+ $strdata =~ s/\s+/\ /g;
+ $strdata =~ s/\s/\_/g;
+ my @data = split('</th><th>',$strdata);
+ return @data;
+}
+
+sub getdataarray(){
+ my $strdata = shift;
+
+ $strdata =~ s/^<TD>//;
+ $strdata =~ s/<\/TD>$//;
+ $strdata =~ s/<BR>/\n/g;
+ my @data = split('</TD><TD>',$strdata);
+ return @data;
+}
+
+sub tableddl(){
+ my $tablename = shift;
+ my $tmpcols = shift;
+ my @cols = @{$tmpcols};
+ my $ddl = 'CREATE TABLE "'.$tablename.'" ('."\n";
+ my @dcol = ();
+ my $pk = "";
+ foreach my $c (@cols){
+ if ($c eq "id"){
+ $pk = "id";
+ }
+ push (@dcol, '"'.$c.'" TEXT');
+ }
+ if ($pk ne ""){
+ push (@dcol,"PRIMARY KEY ('".$pk."')");
+ }
+ $ddl .= "\t".join(",\n\t",@dcol)."\n);";
+ return $ddl;
+}
\ No newline at end of file
--- /dev/null
+#!C:\Strawberry\perl\bin\perl.exe
+use strict;
+use File::Basename;
+use Getopt::Long;
+use Time::HiRes;
+use Data::Dumper;
+use lib (dirname($0));
+#use Win32::HideConsole;
+#hide_console;
+if ($^O eq "MSWin32" ){
+
+ use lib ("C:/Users/ksaff/Workspace/Apps/invoicejournal/server");
+}
+#if ($^O eq "darwin"){
+# use lib ($ENV{HOME}.'/perl5/lib/perl5');
+#}
+use Plack::Builder;
+use Plack::App::Directory;
+use Plack::App::File;
+use Plack::App::WrapCGI;
+use Plack::Middleware::Auth::Basic;
+use Plack::Request;
+use Plack::Runner;
+use Module::Service;
+use Module::Test;
+use Module::SQLite;
+use Module::PDFExtract;
+use Module::FileSystem;
+
+
+print $^O."\n";
+print $^X."\n";
+print "Process:".$$."\n";
+print join(@INC)."\n";
+
+
+my @match = grep { /par-.*inc$/} @INC;
+
+my $basedir = dirname($0);
+if (scalar(@match) > 0){
+ $basedir = $match[0];
+}
+
+my $cfgpath = "";
+print "BASEDIR:".$basedir."\n";
+my $name = basename($0);
+$name =~ s/\.pl$//;
+$name =~ s/\.exe$//;
+
+if ($^O eq "MSWin32"){
+ $cfgpath = $ENV{APPDATA}.'/dks/';
+} elsif ($^O eq "darwin"){
+ $cfgpath = $ENV{HOME}.'/Library/Application Support/dks/';
+} else {
+ $cfgpath = $ENV{HOME}.'/.dks/';
+}
+$cfgpath =~ s/\\/\//g;
+print $cfgpath."\n";
+# sub version {
+# require Twiggy;
+# print "Twiggy $Twiggy::VERSION\n";
+# }
+
+# sub authen_cb {
+# my($username, $password, $env) = @_;
+# my $auth = 0;
+# if (-e $cfgpath.'/'.$name.'.passwd'){
+# open(AUTH,$cfgpath.'/'.$name.'.passwd');
+# while (my $l = <AUTH>){
+# chomp($l);
+# if ($l eq $username.'='.$password){
+# $auth = 1;
+# last;
+# }
+# }
+# close(AUTH);
+# }
+# return $auth;
+# }
+
+my $allapp = builder {
+ mount "/server" => Module::Service->new({pid => $$ });
+ mount "/filesystem" => Module::FileSystem->new({docpath => $cfgpath.'invoicejournal/documents'});
+ mount "/test" => Module::Test->new();
+ mount "/pdfextract" => Module::PDFExtract->new({docpath => $cfgpath.'invoicejournal/documents'});
+ mount "/sqlite" => Module::SQLite->new({dbpath => $cfgpath."db"});
+};
+
+
+my @args = ("-p","6060");
+my $runner = Plack::Runner->new(server => 'Starlight', env => 'deployment');#env => development, test
+$runner->parse_options(@args);
+$runner->run($allapp);
+
+print "Started\n";
--- /dev/null
+#!C:\Perl\bin\perl.exe
+
+use strict;
+use warnings;
+use Getopt::Long;
+use File::Basename;
+my $pdffile="";
+my $toolsdir=dirname($0);
+GetOptions("pdf|p=s" => \$pdffile);
+
+if (! -e $pdffile) {
+ print "incomplete input!\n";
+ exit(1);
+}
+if (-e $pdffile.'.txt'){
+ unlink($pdffile.'.txt');
+}
+if (-e $pdffile.'.csv'){
+ unlink($pdffile.'.csv');
+}
+
+my $sep = '/';
+if ($^O eq "Win32") {
+ $sep = "\\";
+}
+if (! -e $toolsdir.$sep.'pdftotext.exe'){
+ exit(2);
+}
+ my $cmd = '"'.$toolsdir.$sep.'pdftotext.exe" -table -eol unix "'.$pdffile.'" "'.$pdffile.'.txt"';
+ my $st = system($cmd);
+ my $jdata = ();
+ if (($st == 0) && (-e $pdffile.".txt")){
+ my @pdata = ();
+ open(PDFDATA,$pdffile.".txt");
+ while (my $l = <PDFDATA>) {
+ chomp($l);
+ if ($l ne "") {
+ push @pdata,$l;
+ }
+ }
+ close(PDFDATA);
+ my $caccount = "";
+ my $stmtnum = "";
+ my $r = 0;
+ my $cpos = "";
+ foreach my $p (@pdata){
+ if ($p =~ /^\s+Konto\s+:/ ) {
+ $cpos = "";
+ ($caccount) = $p =~ m/.+IBAN\s+(.+)$/;
+ next;
+ }elsif ($p =~ /Kontoauszug Nr\./){
+ $cpos = "";
+ ($stmtnum) = $p =~ m/^Kontoauszug Nr\.\s(\d+).+$/;
+ next;
+ }elsif ($p =~ /^\d\d\.\d\d\s+[GUT|UEBER|SEPA]/){
+ $cpos = "";
+ $r++;
+ my ($type,$trdate,$trval,$trsign) = $p =~ m/\d\d\.\d\d\s+(.+)\s+(\d\d\.\d\d\.\d\d)\s+([\d|,|\.]+)\s([+|-])$/;
+ $type =~ s/\s//g;
+ $trsign =~ s/\+//;
+ $trval=~ s/\.//g;
+ $trdate = substr($trdate,0,6).'20'.substr($trdate,-2);
+ $jdata->{$r}->{"Account"} = $caccount;
+ $jdata->{$r}->{"StatementNumber"} = $stmtnum;
+ $jdata->{$r}->{"BookingDate"} = $trdate;
+ $jdata->{$r}->{"Amount"} = $trsign.$trval;
+ $jdata->{$r}->{"TransactionIdent"} = "";
+ $jdata->{$r}->{"Message"} = "";
+ $jdata->{$r}->{"ForeignAccountOwner"} = "";
+ $jdata->{$r}->{"Bank"} = "";
+ $jdata->{$r}->{"TransferAccount"} = "";
+ $jdata->{$r}->{"TransferCosts"} = 0;
+ #$jdata->{$r}->{"BookingType"} = $type;
+ next;
+ }elsif ($p =~ /^\s+Unser Zeichen/){
+ $cpos = "TransactionIdent";
+ my ($trid) = $p =~ m/^\s+Unser Zeichen\s+(.+)$/;
+ $jdata->{$r}->{$cpos} =$trid;
+ }elsif ($p =~ /^\s+Mitteilung/){
+ $cpos = "Message";
+ my ($msg) = $p =~ m/^\s+Mitteilung\s+(.+)$/;
+ $jdata->{$r}->{$cpos} = $msg;
+ }elsif ($p =~ /^\s+Auftraggeber/){
+ $cpos = "ForeignAccountOwner";
+ my ($apl) = $p =~ /^\s+Auftraggeber\s+(.+)$/;
+ $apl =~ s/\s+/\ /g;
+ $jdata->{$r}->{$cpos} =$apl;
+ }elsif ($p =~ /^\s+Bank d. Auftr.gebers/){
+ $cpos = "";
+ }elsif ($p =~ /^\s+BIC-Code Bank d. Auftraggebers/){
+ $cpos = "Bank";
+ my ($trfbank) = $p =~ /^\s+BIC-Code\sBank\sd\.\sAuftraggebers\s+(.+)$/;
+ $jdata->{$r}->{$cpos} =$trfbank;
+ }elsif ($p =~ /^\s+End-to-End-Identifizierung/){
+ $cpos = "";
+ }elsif ($p =~ /^\s+Beg.nstigter/){
+ $cpos = "ForeignAccountOwner";
+ my ($recp) = $p =~ /^\s+Beg.nstigter\s+(.+)$/;
+ $recp =~ s/\s+/\ /g;
+ $jdata->{$r}->{$cpos} =$recp;
+ $cpos="";
+ }elsif ($p =~ /^\s+Konto Nr. Beg.nst./){
+ $cpos = "TransferAccount";
+
+ my ($trfacc) = $p =~ /^\s+Konto\sNr\.\sBeg.nst.\s+(.+)$/;
+ $trfacc =~ s/\///g;
+ $trfacc =~ s/(....)/$1 /sg;
+ $trfacc =~ s/\s+$//;
+ $jdata->{$r}->{$cpos} =$trfacc;
+ $cpos="";
+ }elsif ($p =~ /^\s+bei/){
+ $cpos = "";
+ }elsif ($p =~ /^\s+Transfergeb.hr/){
+ $cpos = "TransferCosts";
+ my ($tramount) = $p =~ /^\s+Transfergeb.hr\s+EUR\s+(.+)$/;
+ $tramount =~ s/\,/\./g;
+ $jdata->{$r}->{$cpos} =$tramount;
+ }elsif ($p =~ /^\s+Durch Ihren Bonus abgedeckt/){
+ $cpos = "TransferCosts";
+ my ($tramount) = $p =~ /^\s+Durch Ihren Bonus abgedeckt\s+EUR\s+(.+)$/;
+ $tramount =~ s/\,/\./g;
+ $jdata->{$r}->{$cpos} = $jdata->{$r}->{$cpos} + $tramount;
+ }elsif ($p =~ /^\s+Zeichen/){
+ $cpos = "";
+ } elsif ($p =~ /^\s+Neuer Kontostand/){
+ $cpos="";
+ }elsif ($cpos ne "") {
+ my ($data) = $p =~ m/\s+(.+)$/;
+ $jdata->{$r}->{$cpos} .= " ".$data;
+ }
+ }
+
+ }
+if (-e $pdffile.'.txt'){
+ unlink($pdffile.'.txt');
+}
+open(FOUT,">".$pdffile.".csv");
+print FOUT '"Account","StatementNumber","BookingDate","Amount","TransactionIdent","Message","ForeignAccountOwner","Bank","TransferAccount","TransferCosts"'."\n";
+foreach my $r (keys(%{$jdata})){
+ my @data = ();
+ push @data, $jdata->{$r}->{"Account"};
+ push @data, $jdata->{$r}->{"StatementNumber"};
+ push @data, $jdata->{$r}->{"BookingDate"};
+ push @data, $jdata->{$r}->{"Amount"};
+ push @data, $jdata->{$r}->{"TransactionIdent"};
+ $jdata->{$r}->{"Message"} =~ s/\s+/\ /g;
+ push @data, $jdata->{$r}->{"Message"};
+ $jdata->{$r}->{"ForeignAccountOwner"} =~ s/\s+/\ /g;
+ push @data, $jdata->{$r}->{"ForeignAccountOwner"};
+ push @data, $jdata->{$r}->{"Bank"};
+ push @data, $jdata->{$r}->{"TransferAccount"};
+ push @data, $jdata->{$r}->{"TransferCosts"};
+ print FOUT '"'.join('","',@data).'"'."\n";
+}
+close(FOUT);
\ No newline at end of file
--- /dev/null
+#!/usr/bin/env perl
+use strict;
+use PDF::API2;
+use PDF::TextBlock;
+
+my $pdf = PDF::API2->new( -file => "40-demo.pdf" );
+my $tb = PDF::TextBlock->new({
+
+ pdf => $pdf,
+ fonts => {
+ b => PDF::TextBlock::Font->new({
+ pdf => $pdf,
+ font => $pdf->corefont( 'Helvetica-Bold', -encoding => 'latin1' ),
+ }),
+ i => PDF::TextBlock::Font->new({
+ pdf => $pdf,
+ font => $pdf->corefont('Helvetica-Oblique')
+ })
+ },
+});
+$tb->text(
+ ' <b>This fairly lengthy</b>, rather <i>verbose sentence</i> <b>is tagged</b> to appear ' .
+ ' <href="http://www.dks.lu">Click here to visit Omni Hotels.</href> ' . "\n\n" .
+ "New paragraph.\n\n" .
+ "Another paragraph."
+);
+$tb->apply;
+$pdf->save;
+$pdf->end;
\ No newline at end of file
--- /dev/null
+#!/usr/bin/perl
+use strict;
+use File::Basename;
+use Getopt::Long;
+use lib (dirname($0).'/cgi/lib');
+use sqlite;
+use pgsql;
+use localconfig;
+my $sdb = "";
+my $ident = "";
+my $schema = 0;
+my $data = 0;
+GetOptions("database|db=s" => \$sdb,"ident|i=s" => \$ident,"schema|s" => \$schema,"data|d" => \$data);
+my $db = sqlite->new($sdb);
+
+$db->dbbackup(dirname($0).'/cursqlitedb.sql','sql');
+my $cfgpath=dirname($0).'/conf';
+my $cfg = localconfig->new($cfgpath.'/'.$ident.'.conf');
+my $rcfg = $cfg->readconfig();
+my $pg = pgsql->new($rcfg);
+if ($schema == 1){
+ open(SDB,dirname($0).'/cursqlitedb.sql');
+ my $ddlschema = "";
+ while (my $l = <SDB>){
+ #chomp($l);
+ if (($l !~ /^INSERT/) && ($l !~ /^UPDATE/) && ($l !~ /^DELETE/)){
+ $ddlschema .= $l;
+ }
+
+ }
+ my $r = $pg->dbexec("INSERT INTO ".$rcfg->{schema}.".ddlschema (ddlschema) VALUES ('".$pg->strreplace($ddlschema)."');");
+}
+if ($data == 1){
+ my @sqldata = ();
+ open(SDB,dirname($0).'/cursqlitedb.sql');
+ while (my $l = <SDB>){
+ chomp($l);
+ if (($l =~ /^INSERT/) || ($l =~ /^UPDATE/) || ($l =~ /^DELETE/)){
+ push(@sqldata,$l);
+ }
+ }
+ close(SDB);
+
+ foreach my $d (@sqldata){
+ my $r = $pg->dbexec("INSERT INTO ".$rcfg->{schema}.".sqlsync (tsquery,sqlquery,client) VALUES (now(),'".$pg->strreplace($d)."','system');");
+ }
+}
--- /dev/null
+#!/usr/bin/perl
+
+use strict;
+my $homepath=$ENV{HOME};
+my $macpath='osascript -e "set mypath to POSIX path of (choose folder with prompt \"Choose Folder:\" default location \"'.$homepath.'\")"';
+my $mirror='dks@dks-backup:/home/dks/mirror/';
+my $ssh= ' -e "ssh -p 3587" ';
+my $path = `$macpath`;
+
+#todo -> show differences + dryrun + keep newer files
+#todo -> rsync with perl (Net::OpenSSH) or putty
+
+if ($path ne ""){
+ chomp($path);
+ my $relpath = substr($path,length($homepath)+1);
+ print "Path to sync: ".$path." -> ".$relpath."\n";
+ my $cmd = 'rsync -avz --progress --delete-after '.$ssh." ".$path." ".$mirror.$relpath;
+ my $terminalcmd = 'osascript -e "tell application \"Terminal\"
+ set currenttab to do script (\"rsync -avz --delete-after --progress -e \'ssh -p 3587\' '.$path.' '.$mirror.$relpath.' && exit 0\")
+ end tell"';
+
+ print $terminalcmd."\n";
+ system($terminalcmd);
+
+}
+
+