<div class="display-container panel animate-opacity" id="pnl_offer" style="display:none;"></div>
<div class="display-container panel animate-opacity" id="pnl_templates" style="display:none;"></div>
<div class="display-container panel animate-opacity" id="pnl_transactions" style="display:none;"></div>
-
<div class="display-container panel animate-opacity" id="pnl_bookings" style="display:none;"></div>
<!-- END Page -->
</div><!-- BEGIN global dialogs -->
}
return false;
},
- // cleanform2: function(frmname,choices){
- // var frm = document.getElementById("frm_" + frmname);
- // for (var f in frm){
- // if (frm[f] && frm[f].id){
- // if (frm[f].tagName == 'INPUT'){
- // if (frm[f].type == "checkbox"){
- // frm[f].checked = false;
- // } else if (frm[f].classList.contains("datefield")){
- // if (frm[f]._flatpickr){ frm[f]._flatpickr.clear(); }
- // } else if (frm[f].classList.contains("choices__input")){
- // if (choices[frm[f].id]){
- // choices[frm[f].id].removeActiveItems();
- // }
- // } else {
- // frm[f].value = "";
- // }
- // }
- // if (frm[f].tagName == 'SELECT'){
- // if (frm[f].multiple == true){
- // if (frm[f].classList.contains("choices__input")){
- // choices[frm[f].id].removeActiveItems();
- // }
- // } else {
- // frm[f].value = "";
- // }
-
- // }
- // if (frm[f].tagName == 'TEXTAREA'){
- // if (frm[f].classList.contains("richeditarea")){
- // tinymce.get(frm[f].id).setContent("");
- // } else {
- // frm[f].innerHTML = "";
- // }
- // }
- // }
- // }
- // return false;
- // },
+
fillform: function(dataclass,choices,data){
var frm = document.querySelectorAll('.data_'+ dataclass);
//console.log("frmdata",frm);
defaultdata: {}\r
}\r
\r
+let appdata = {\r
+ invoices: [],\r
+ addresses: [],\r
+ offers: [],\r
+ products: []\r
+}\r
+\r
let myapp = {\r
loadpanel: function(idpanel){\r
return new Promise(\r
});\r
},\r
viewpanel: function( idpanel){\r
+ console.log("View panel:" + idpanel)\r
myapp.loadpanel(idpanel).then(result => {\r
+ console.log("result loadpanel",result);\r
if (result){\r
let panels = document.getElementsByClassName("panel");\r
for (let i=0;i<panels.length;i++){\r
}
return "";
},
+ writeDataset: function(folder,fileid,filedata){
+
+ },
+ getDataSet: function(folder){
+ let dataset =[];
+ let files = fs.readdirSync(folder);
+ files.forEach(function(file) {
+ if (file.match('.*\.json')){
+ let fdata = fs.readFileSync(folder + '/' + file, 'utf-8');
+ if (fdata.startsWith("{") || fdata.startsWith("[")){
+ data = JSON.parse(fdata);
+ data["id"] = file.replace('.json','');
+ dataset.push(data);
+ }
+ }
+ });
+ return dataset;
+ },
getDataSets: function(){
let datasets =[];
//console.log(os.platform());
myapp.viewpanel('addresses');
},
init: function(){
- addresses.tbl = new Tabulator("#tbl_addresses",{
- headerFilterPlaceholder: "filter...",
- height: "calc(100vh - 60px)",
- layout: "fitDataStretch",
- selectable: 1,
- rowClick:function(e, row){
- console.log("Filter selected");
- let fsel = addresses.tbl.getSelectedData();
- console.log(fsel);
- addresses.current_id = fsel[0].id;
- addresses.edit(fsel[0].id);
- //invoices.getsums(fsel);
- },
- rowContext:function(e, row){ e.preventDefault(); },
- columns: [
- {title: "Name", field: "receipient", resizable: false},
- ]
- });
+
addresses.tbl = new Tabulator("#tbl_addresses",{
headerFilterPlaceholder: "filter...",
height: "calc(100vh - 60px)",
-const { fstat } = require("fs");
let invoice = {
current_id: null,
dataform.cleanform('invoice');
if (id != null){
invoice.current_id = id;
- console.log("ID Invoice:",id);
- db.query("SELECT inv.*,sum(bk.netamount) AS netamount,sum(bk.taxamount) AS vatamount,sum(bk.netamount + bk.taxamount) AS grossamount FROM invoices inv JOIN bookings bk ON (inv.id = bk.id_invoices) WHERE inv.id='"+id+"' GROUP BY inv.id;").then(data => {
+ console.log("ID Invoice:",id);
+ db.query("SELECT inv.*,sum(bk.netamount) AS netamount,sum(bk.taxamount) AS vatamount,sum(bk.netamount + bk.taxamount) AS grossamount FROM invoices inv JOIN bookings bk ON (inv.id = bk.id_invoices) WHERE inv.id='"+id+"' GROUP BY inv.id;").then(data => {
console.log("invoicedata",data);
dataform.fillform('invoices',invoice.selects,data);
if (data.pdffile){
dataform.savefield(document.getElementById(instance.element.id));
//console.log("change DATE");
invoice.setDeadlineDate();
- invoice.setReference();
+ invoice.getNewReference();
}
});
newref = moment(strdate).format('YYYYMMDD') + '-' + timecalc.lpad(preferences.defaultdata.invoicesequence,4,'0');
}
}
-
+ document.getElementById("invoices_reference").value=newref;
+ dataform.savefield(document.getElementById("invoices_reference"));
console.log("new Ref",newref);
return newref;
},
grossamount = parseFloat(netamount) + parseFloat(vatamount);
document.getElementById("invoicebooking_grossamount").value = grossamount.toFixed(2);
},
- changedStatus: function(obj){
- if (obj.value == "payed" ){
+ changedStatus: function(){
+ let status = invoice.selects["invoices_status"].selected();
+ if (status == "payed" ){
console.log("Set invoice payed!");
//document.getElementById
document.getElementById("invoices_payedamount").value=invoice.getSumGrossAmount();
},
gettbldata: function(){
+ // console.log(preferences.global);
+ //let newdata = usersystem.getDataSet('C:/Users/ksaff/AppData/Roaming/invoicejournal/dks/data/invoices/2020');
+ //console.log(newdata);
let sel= invoices.tbl.getSelectedData();
/*--(to_char(inv.invoicedate::timestamp with time zone, 'YYYY'::text) || '-Q'::text) || to_char(inv.invoicedate::timestamp with time zone, 'Q'::text) AS quarter, --to_char(inv.invoicedate::timestamp with time zone, 'YYYY-MM'::text) AS month,*/
db.queryarray("SELECT inv.invoicedate, inv.id, inv.accountname, inv.reference, inv.status, sum(COALESCE(bk.netamount, 0.0)) AS netamount, sum(COALESCE(bk.taxamount, 0.0)) AS vatamount, sum(COALESCE(bk.netamount, 0.0) + COALESCE(bk.taxamount, 0.0)) AS grossamount, inv.businessyear, inv.id_accounts, inv.invoicetype FROM invoices inv LEFT JOIN bookings bk ON inv.id = bk.id_invoices GROUP BY inv.id ORDER BY inv.invoicedate DESC;") .then(data => {
- invoices.tbl.setData(data).then(dd => {
+ invoices.tbl.setData(data).then(dd => {
+ //console.log(newdata);
if (sel[0]){
console.log(sel[0]);
invoices.tbl.selectRow(sel[0].id);
// table.scrollToRow(table.getSelectedRows(), "top", false);
// });
}
- });
});
+ });
return false;
},
loadfilterdata: function(data){
init: function(){
products.tbl = new Tabulator("#tbl_products",{
headerFilterPlaceholder: "filter...",
- groupBy:["producttype", "productgroup"],
- groupStartOpen:[true, true],
+ //groupBy:["producttype", "productgroup"],
+ //groupStartOpen:[true, true],
height: "calc(100vh - 60px)",
layout: "fitColumns",
selectable: 1,
]
});
products.gettbldata();
+ myapp.loaddialog("confirm").then(result => {
+
+ });
},
initSelector: function(){
myapp.viewpanel('templates');
},
init: function(){
+ templates.tbl = new Tabulator("#tbl_templates",{
+ headerFilterPlaceholder: "filter...",
+ height: "calc(100vh - 60px)",
+ layout: "fitDataStretch",
+ selectable: 1,
+ rowClick:function(e, row){
+ console.log("Filter selected");
+ let fsel = addresses.tbl.getSelectedData();
+ console.log(fsel);
+ addresses.current_id = fsel[0].id;
+ addresses.edit(fsel[0].id);
+ //invoices.getsums(fsel);
+ },
+ rowContext:function(e, row){ e.preventDefault(); },
+ columns: [
+ {title: "Name", field: "reportname", resizable: false},
+ {title: "Name", field: "reporttype", resizable: false},
+ ]
+ });
+ tinymce.init({
+ selector: '#templates_headerhtml, #templates_contenthtml, #templates_footerhtml',
+ plugins: 'preview paste importcss searchreplace autolink directionality code visualblocks visualchars fullscreen image link media template table charmap hr nonbreaking anchor advlist lists wordcount imagetools textpattern noneditable charmap emoticons autoresize ',
+ imagetools_cors_hosts: ['picsum.photos'],
+ menubar: 'file edit view insert format tools table',
+ toolbar: 'undo redo | bold italic underline strikethrough | fontsizeselect | alignleft aligncenter alignright alignjustify | outdent indent | numlist bullist | forecolor removeformat | charmap emoticons | fullscreen preview | insertfile image media link anchor',
+ toolbar_sticky: true,
+ language: 'de',
+ forced_root_block : '',
+ min_height: 350,
+ branding: false,
+ importcss_append: true,
+ image_advtab: true,
+ image_title: true,
+ automatic_uploads: true,
+ file_picker_types: 'image',
+ file_picker_callback: function (cb, value, meta) {
+ var input = document.createElement('input');
+ input.setAttribute('type', 'file');
+ input.setAttribute('accept', 'image/*');
+ input.onchange = function () {
+ var file = this.files[0];
+
+ var reader = new FileReader();
+ reader.onload = function () {
+ var id = 'blobid' + (new Date()).getTime();
+ var blobCache = tinymce.activeEditor.editorUpload.blobCache;
+ var base64 = reader.result.split(',')[1];
+ var blobInfo = blobCache.create(id, file, base64);
+ blobCache.add(blobInfo);
+ cb(blobInfo.blobUri(), { title: file.name });
+ };
+ reader.readAsDataURL(file);
+ };
+
+ input.click();
+
+ },
+
+
+ image_caption: true,
+
+ noneditable_noneditable_class: "mceNonEditable",
+
+ contextmenu: "link image imagetools table",
+ });
+
console.log("init templates");
}
}
\ No newline at end of file
<button class="bar-item bodybtn" onclick="addresses.viewpanel();"><span class=
"icon-contacts" style="font-size: 24px;"></span>Adressen</button>
<button class="bar-item bodybtn" onclick="products.viewpanel();"><span class="icon-product" style="font-size: 24px;"></span>Produkte</button>
- <button class=
- "bar-item bodybtn" onclick="transactions.viewpanel();"><span class="icon-transactions" style="font-size: 24px;"></span>Transaktionen</button>
- <button class="bar-item bodybtn" onclick="offers.viewpanel();"><span class="icon-box"
- style="font-size: 24px;"></span>Angebote</button>
- <button class="bar-item bodybtn" onclick="bookings.viewpanel();"><span class="icon-box" style="font-size: 24px;"></span>Buchungen</button> <!-- <a class="bar-item bodybtn" href="files.html"/><span class="icon-folder" style="font-size: 24px;"></span>Dateien</a> -->
+ <!-- <button class="bar-item bodybtn" onclick="transactions.viewpanel();"><span class="icon-transactions" style="font-size: 24px;"></span>Transaktionen</button> -->
+ <!-- <button class="bar-item bodybtn" onclick="offers.viewpanel();"><span class="icon-box" style="font-size: 24px;"></span>Angebote</button> -->
+ <!-- <button class="bar-item bodybtn" onclick="bookings.viewpanel();"><span class="icon-box" style="font-size: 24px;"></span>Buchungen</button> <a class="bar-item bodybtn" href="files.html"/><span class="icon-folder" style="font-size: 24px;"></span>Dateien</a> -->
</div>
</div>
<div class="card" style="margin-top: 10px;">
<!-- <a class="bar-item bodybtn" href="users.html"/><span class="icon-userconfig" style="font-size: 24px;"></span>Benutzer</a> -->
<button class="bar-item bodybtn" onclick="datasets.viewpanel();"><span class="icon-datasets" style="font-size: 24px;"></span>Datensätze <button>
<button class="bar-item bodybtn" onclick="templates.viewpanel();"><span class="icon-template" style="font-size: 24px;"></span>Vorlagen</button>
- <button class="bar-item bodybtn" onclick="users.viewpanel();"><span class="icon-userconfig" style="font-size: 24px;"></span>Benutzer</button>
- <button class="bar-item bodybtn" onclick="backup.viewpanel();"><span class="icon-backup" style="font-size: 24px;"></span>Backup</button>
+ <!-- <button class="bar-item bodybtn" onclick="users.viewpanel();"><span class="icon-userconfig" style="font-size: 24px;"></span>Benutzer</button> -->
+ <!-- <button class="bar-item bodybtn" onclick="backup.viewpanel();"><span class="icon-backup" style="font-size: 24px;"></span>Backup</button> -->
</div>
</div>
</div>
\ No newline at end of file
+
<div class="display-container bar toolbar">
<button class="bar-item toolbarbtn" onclick="index.viewpanel();"><span class="icon-back" style="font-size: 16px;"></span>zurück</button>
<div class="bar-item PageHeadTitle">
"font-size: 16px;"></span>dupl</button>
<button class="bar-item toolbarbtn right" onclick="templates.add();"><span class="icon-add" style=
"font-size: 16px;"></span>neu</button>
-</div>
\ No newline at end of file
+ <button class="bar-item toolbarbtn right" onclick="templates.preview();"><span class="icon-add" style=
+ "font-size: 16px;"></span>Vorschau</button>
+</div>
+
+<div class="display-container">
+ <div class="cell-row">
+ <div class="cell" style="width: 400px;">
+ <div id="tbl_templates"></div>
+ </div>
+ <div class="cell">
+ <div class="row" >
+ <div class="cell container" >
+ <form id="frm_templates">
+ <div class="row">
+ <div class="cell container" style="width: 400px;">
+ <div class="">
+ <label class="label" for="templates_reportname">Name</label> <input class="input data_templates border text" data-column="reportname" data-id="" data-table="newreports" id="templates_reportname" onblur="dataform.savefield(this);" type="text">
+ </div>
+ </div>
+ </div>
+ <div class="row">
+ <div class="cell container" style="width: calc( 100vw - 600px);">
+ <label for="templates_headerhtml" class="label">Header</label>
+ <textarea class="input border data_templates richeditarea" style="height: 200px;" data-id="" data-column="headerhtml" data-table="newreports" id="templates_headerhtml"></textarea>
+ </div>
+ </div>
+ <div class="row">
+ <div class="cell container" style="width: calc( 100vw - 600px);">
+ <label for="templates_contenthtml" class="label">Body</label>
+ <textarea class="input border data_templates richeditarea" style="height: 200px;" data-id="" data-column="contenthtml" data-table="newreports" id="templates_contenthtml" ></textarea>
+ </div>
+ </div>
+ <div class="row">
+ <div class="cell container" style="width: calc( 100vw - 600px);">
+ <label for="templates_footerhtml" class="label">Footer</label>
+ <textarea class="input border data_templates richeditarea" style="height: 200px;" data-id="" data-column="footerhtml" data-table="newreports" id="templates_footerhtml" ></textarea>
+ </div>
+ </div>
+ </form>
+ </div>
+ <div class="cell container" style="width: 200px; background-color: #e4e4e4; padding-bottom: 10px;" style="background-color: #e4e4e4; padding-bottom: 10px;">
+ <div class="cell container" style="width: 400px;">
+ <div class="">
+ <label class="label" for="templates_pdfoptions-size">Size</label> <input class="input data_templates border text" data-column="pdfoptions-size" data-id="" data-table="newreports" id="templates_pdfoptions-size" onblur="dataform.savefield(this);" type="text">
+ </div>
+ <div class="">
+ <label class="label" for="templates_pdfoptions-orientation">Size</label> <input class="input data_templates border text" data-column="pdfoptions-orientation" data-id="" data-table="newreports" id="templates_pdfoptions-orientation" onblur="dataform.savefield(this);" type="text">
+ </div>
+ <div class="">
+ <label class="label" for="templates_pdfoptions-top">Top</label> <input class="input data_templates border text" data-column="pdfoptions-top" data-id="" data-table="newreports" id="templates_pdfoptions-top" onblur="dataform.savefield(this);" type="text">
+ </div>
+ <div class="">
+ <label class="label" for="templates_pdfoptions-bottom">Top</label> <input class="input data_templates border text" data-column="pdfoptions-bottom" data-id="" data-table="newreports" id="templates_pdfoptions-bottom" onblur="dataform.savefield(this);" type="text">
+ </div>
+ <div class="">
+ <label class="label" for="templates_pdfoptions-top">Left</label> <input class="input data_templates border text" data-column="pdfoptions-left" data-id="" data-table="newreports" id="templates_pdfoptions-left onblur="dataform.savefield(this);" type="text">
+ </div>
+ <div class="">
+ <label class="label" for="templates_pdfoptions-top">Right</label> <input class="input data_templates border text" data-column="pdfoptions-right" data-id="" data-table="newreports" id="templates_pdfoptions-right" onblur="dataform.savefield(this);" type="text">
+ </div>
+ </div>
+ </div>
+ </div>
+
+ </div>
+ </div>
+</div>
--- /dev/null
+#!C:\Strawberry\perl\bin\perl.exe
+
+
+use strict;
+
+use DBI;
+use DBD::SQLite;
+use Encode;
+use JSON::PP;
+use Data::Dumper;
+
+my $dbfile = "C:/Users/ksaff/AppData/Roaming/invoicejournal/dks/dks.sqlite";
+my $outpath = "C:/Users/ksaff/AppData/Roaming/invoicejournal/dks/data/offers";
+my $dbh = DBI->connect('DBI:SQLite:dbname='.$dbfile,"","",{PrintError=>1,RaiseError=>1,AutoCommit=>1}) or print "dbquery Connection Error!".$!."\n";
+my $sql = "select * from offers;";
+my $res = &dbquerysorted($sql);
+#print Dumper($res);
+foreach my $i (keys(%{$res})){
+ #print Dumper($res->{$i}->{id});
+ my $sqls = "SELECT sum(bk.netamount) AS netamount,sum(bk.taxamount) AS vatamount,sum(bk.netamount + bk.taxamount) AS grossamount FROM offers inv JOIN offerdetails bk ON (inv.id = bk.id_offers) WHERE inv.id='".$res->{$i}->{id}."' GROUP BY inv.id;";
+ my $sums = &dbquerysorted($sqls);
+ #print Dumper($sums);
+ foreach my $x (keys(%{$sums->{0}})){
+ print Dumper($x);
+ $res->{$i}->{$x} = $sums->{0}->{$x};
+ }
+ my $sqlx = "select * from offerdetails where id_offers='".$res->{$i}->{id}."';";
+ #print $sqlx."\n";
+ my $sqlr = "select reportname from newreports where id='".$res->{$i}->{id_template}."';";
+ my $rep = &dbquerysorted($sqlr);
+ $res->{report} = $rep->{0}->{reportname};
+ #print $sqlx."\n";
+ my $res2 = &dbqueryarray($sqlx);
+
+ $res->{$i}->{bookings}= $res2;
+ my $fileid = $res->{$i}->{reference};
+ $fileid =~ s/^\s+//;
+ $fileid =~ s/\s+$//;
+ $fileid = $res->{$i}->{shortname}.'-'.$res->{$i}->{reference};
+ &write_jsonfile($fileid,$res->{$i});
+}
+$dbh->disconnect();
+
+
+sub write_jsonfile(){
+
+ my $id = shift;
+ my $jsondata = shift;
+ if (! -d $outpath){
+ mkdir($outpath);
+ }
+ my $json = JSON::PP::encode_json($jsondata);
+ $json = decode("utf-8",$json);
+ open(JS,">".$outpath.'/'.$id.'.json');
+ print JS $json;
+ close(JS);
+}
+
+sub dbquerysorted(){
+ my $stat = shift;
+ my $retdata = ();
+
+ $stat = encode("utf8", $stat);
+
+ my $sth = $dbh->prepare($stat) or print "Failed prepare: ".$stat."\n";
+
+ $sth->execute() or print "dbquery: ".$sth->errstr."\n";
+ my $count = 0;
+ while(my $data = $sth->fetchrow_hashref())
+ {
+ foreach my $k (keys %{$data}){
+ $retdata->{$count}->{$k} = $data->{$k};
+ }
+ $count++;
+ }
+
+ $sth->finish();
+
+
+ return $retdata;
+}
+
+sub dbqueryarray(){
+ my $stat = shift;
+ my @retdata = ();
+
+ $stat = encode("utf8", $stat);
+
+ my $sth = $dbh->prepare($stat) or print "Failed prepare: ".$stat."\n";
+
+ $sth->execute() or die "dbquery: ".$sth->errstr;
+ my $count = 0;
+ while(my $data = $sth->fetchrow_hashref())
+ {
+ my $ret = {};
+ foreach my $k (keys %{$data}){
+ $ret->{$k} = $data->{$k};
+ }
+ push @retdata,$ret;
+ }
+
+ $sth->finish();
+
+ return \@retdata;
+}
\ No newline at end of file
--- /dev/null
+package sqlite;
+use strict;
+use DBI;
+use DBD::SQLite;
+use Encode;
+use File::Basename;
+
+sub new {
+ my $class = shift;
+ my $p = shift;
+ my $self = bless {}, $class;
+ $self->{dbfile} =$p;
+ return $self;
+}
+
+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 print "dbquery Connection Error!".$!."\n";
+ $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."\n";
+ while(my $data = $sth->fetchrow_hashref())
+ {
+ if (exists $data->{$key}){
+ foreach my $k (keys %{$data}){
+ $retdata->{$data->{$key}}{$k} = $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 print "dbquery Connection Error!".$!."\n";
+ $stat = encode("utf8", $stat);
+ #open FILE,">>/tmp/sql.log";
+ #print "Query Sorted: $stat\n";
+ # close FILE;
+ my $sth = $dbh->prepare($stat) or print "Failed prepare: ".$stat."\n";
+
+ $sth->execute() or print "dbquery: ".$sth->errstr."\n";
+ my $count = 0;
+ while(my $data = $sth->fetchrow_hashref())
+ {
+ foreach my $k (keys %{$data}){
+ $retdata->{$count}->{$k} = $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 print "dbquery Connection Error!".$!."\n";
+ $stat = encode("utf8", $stat);
+ open FILE,">>sqlarray.log";
+ print FILE "$stat\n";
+ close FILE;
+ my $sth = $dbh->prepare($stat) or print "Failed prepare: ".$stat."\n";
+
+ $sth->execute() or die "dbquery: ".$sth->errstr;
+ my $count = 0;
+ while(my $data = $sth->fetchrow_hashref())
+ {
+ my $ret = {};
+ foreach my $k (keys %{$data}){
+ $ret->{$k} = $data->{$k};
+ }
+ push @retdata,$ret;
+ }
+
+ $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 print "dbexec Connection Error!".$!."\n";
+ $stat = encode("utf8", $stat);
+ #print $stat."\n";
+ #open FILE,">>/Users/kilian/sql.log";
+ #print "$stat\n";
+ #close FILE;
+ my $sth = $dbh->prepare($stat);
+ my $rv =$dbh->do($stat) or print "dbexec '".$stat. "\n".$dbh->errstr()." failed!\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($self->{dbfile}).'_'.$xdd.'.db';
+# my $dbh = DBI->connect('DBI:SQLite:dbname='.$self->{dbfile},"","",{PrintError=>1,RaiseError=>1,AutoCommit=>1}) or print "dbexec Connection Error!".$!."\n";
+# $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 print "dbexec Connection Error!".$!."\n";
+# $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;