Saturday, December 1, 2012

Belgian accounting made simple


Today I finally found a name and started to work on a project which has been waiting patiently for so long: Lino Così is yet another attempt to make Belgian accounting simple. An application that offers the bare minimum functionality for startups to do your own accounting in Belgium. And of course you can always extend it later since it is written in Lino.

With Lino Così (when ready) you will be able to
  • manage your contacts (organisations and persons)
  • optionally manage a list of products (sales items)
  • record your sales invoices (optionally printing them)
  • manage your account chart
  • record your purchase invoices
  • declare your VAT statement
  • record your bank statements
  • get your financial situation
About the name: Le but est de proposer enfin un logiciel de comptabilité vraiment simple à utiliser. Une comptabilité simple? “Così” en italien signifie “comme ceci”. Così! c’est comme ça qu’on aime la compta! 

Mais bien sûr il nous reste un peu de travail avant d’y être. Bienvenus les volontaires pour tester http://demo4.lino-framework.org et m’aider à réfléchir.

News about Lino

I did a Google search for "lino", "django" and "extjs" and discovered that the Internet is really obsolete. Google links to pages that I wrote back in the previous decade! Time to change that!

Here is my first post on blogger after more than two years.


Did you know for example that Lino has now his own domain name lino-framework.org? And that you can play there on a few live demo sites?

On saffre-rumma.net, all requests to http://lino.saffre-rumma.net are now automatically being redirected to http://lino-framework.org using a permanent redirect.

Tuesday, February 2, 2010

Adieu wysiwyg blogging

I started to blog on Lino's WikiBlog, and it seems that I like it better than Blogger's wysiwyg editor. Such a self-made WikiBlog is probably less easily readable, but more easily writable.

Tuesday, January 12, 2010

Why doesn't Blogger support any wiki format?

Blogger isn't really my thing because I hate to blog when the blog server doesn't support wiki format.
So today I misused the Lino wiki for blogging.
Result: I write more.
But then I read Wiki markup is dead...
Hmm...

Thursday, January 7, 2010

New ideas for Lino.do_action()

Working on issue 61. Some of my thoughts...

Lino.do_action() does an AJAX call on the specified URL. This URL defines the action that runs on the server. Lino.do_action() then reacts according to the response.
The action may return a "job" (response.job, previously response.call) to be executed by the client.
Maybe "reaction" would be a better name than "job". But let's call it a job because that name is not yet used in Lino's source, and after all this thing becomes a "job" for the client in the meaning that it will continue to run until some other action asks to stop it.

For example a report action, on the server, will check whether the user is allowed to see this data, will load window_config, and then return a Job that will create the Ext.Window with all its components and also call the show() method. The close() method of that job just closes this window.

If response.job is defined, it must be a string of JS code that defines a constructor function.The client will instantiate a new object using this constructor.
The constructor must initialize the new object so that it implements the Job interface:
- stop()
- refresh()
- selected_rows()

Note that there is no start() method. This is because the Job is supposed to start it's work during instantiation.

Lino.do_action() will need a new parameter "caller" (the Job who requests this action), and the parameters reload, close_dialog and job_params can go away since the caller contains them.
The parameter caller may be undefined if the action is called from a main menu item.


Lino.grid_action(), Lino.form_action() and Lino.show_detail() can then go away

Wednesday, December 16, 2009

Implement report windows as actions

Hier ist nochmal ein Bild der aktuellen Situation.



Oberflächliche Probleme:
  • Submit in PersonDetail funktioniert nicht. Traceback "field 'name' may not be null. Das kommt, seit ich django.db.field.to_python für die Konvertierung benutze.
  • The comboBoxes of ForeignKeys don't display the values.
  • Focussing problems: after closing a window, the previous window should get keyboard focus. When a Window with a Grid gets focus, it should forward the focus to it's grid.
  • links.Link should provide a virtual column that offers clickable display of the url, as well as drag&drop to update it.
  • Number of rows displayed in a grid should be as much as fits into the window. Or the window should adapt its size to its grid.
  • PageLayout.layout_for instead of Report.page_layouts
Aber einige dieser Punkte sind wahrscheinlich verknüpft mit einem fundamentalen Problem, das ich deshalb wahrscheinlich als nächstes in Angriff nehme: Implement report windows as actions.
Das bedeutet, dass die Reports nicht mehr wie momentan alle als statische Funktionen im JS vordefiniert sind, sondern dass beim Klick auf einen entsprechenden Menübefehl ein AJAX-Request rausgeht, den der Server mit der Definition des zu öffnenden Fensters beantwortet.

Also statt z.B. der folgenden Funktion, ...

var projects_ProjectTypes = new function() {
  this.main_grid = new function() {
    var main_cols = new Ext.grid.ColumnModel({ columns: [ { header: 'ID', width: 45, editable: false, sortable: true, dataIndex: 'id' }, { header: 'name', sortable: true, editor: { xtype: 'textfield', fieldLabel: 'name', allowBlank: false, maxLength: 200, anchor: '100%', name: 'name' }, width: 180, editable: true, dataIndex: 'name' } ] });
    var buttons = [ { text: 'Delete', handler: Lino.grid_action(this,'lino_DeleteSelected','/grid_action/projects/ProjectTypes/lino_DeleteSelected') }, { text: 'Detail', handler: Lino.show_detail(this,'projects_ProjectTypes2') } ];
    var keys = [ { shift: false, alt: false, handler: Lino.grid_action(this,'lino_DeleteSelected','/grid_action/projects/ProjectTypes/lino_DeleteSelected'), key: 46, ctrl: false }, { shift: false, alt: false, handler: Lino.show_detail(this,'projects_ProjectTypes2'), key: 13, ctrl: true } ];
    this.comp = new Ext.grid.EditorGridPanel({ clicksToEdit: 2, colModel: main_cols, tbar: new Ext.PagingToolbar({ prependButtons: false, items: buttons, pageSize: 10, store: projects_ProjectTypes_store, displayInfo: true }), viewConfig: { showPreview: true, scrollOffset: 200, emptyText: 'Nix gefunden!' }, selModel: new Ext.grid.RowSelectionModel({singleSelect:false}), enableColLock: false, store: projects_ProjectTypes_store, emptyText: 'Nix gefunden...' });
    this.comp.on('afteredit', Lino.grid_afteredit(this,'/grid_afteredit/projects/ProjectTypes','id'));
  }();
  this.show = function(btn,event,unused_master,master_grid) {
    if(this.comp) { this.comp.show() ; return; }
    this.comp = new Ext.Window( { width: 400, layout: 'fit', maximizable: true, title: 'ProjectTypes - List', closeAction: 'hide', items: this.main_grid.comp, tools: [ { handler: Lino.save_window_config('/save_win/projects_ProjectTypes'), id: 'save' } ], id: 'projects_ProjectTypes', height: 300 } );
    projects_ProjectTypes_store.load();
    this.comp.show();
  };
}();

..., die momentan im Menübefehl mit projects_ProjectTypes.show() aufgerufen wird, ruft der Menübefehl die existierende Lino.do_action(), und diese action gibt dann eine JS-Expression "new ext.Window(...).show()" zurück, die die gleiche Wirkung hat. Wobei die "..." natürlich ziemlich lang werden können.

Wednesday, November 25, 2009

Fenstergrößen und -positionen jetzt speicherbar

Gestern Abend vor dem Schlafengehen grübelte ich noch über das Problem nach, wie abartig es doch ist, dass ich die Größe eines Ext.Window anhand seiner Komponenten selber zu ermitteln versuche. Heute morgen suchte ich zuerst nochmal nach, ob Ext.Window tatsächlich keine fertige Methode "sizeToFit()" oder so hat. Hat er scheinbar nicht.

Aber dann fiel mir ein, dass man ja sowieso die Fenstergrößen und -positionen manuell speichern können muss. Wenn das gemacht wäre, wäre es egal, dass Fenster par défaut immer in der Mitte stehen und alle die gleiche Höhe haben. Also machte ich mich an die Implementierung dieses Features. Keine zwei Stunden Arbeit, und alles funktioniert wie gehabt:
neuer tool-Button "save" in allen Fensterrahmen. Wenn man darauf klickt, wird per AJAX die Position und Größe des Fensters gespeichert. Auf dem Server wohlgemerkt. Einfach mit pickle in eine Datei "window_configs.pck". Momentan also immer global für alle Benutzer. Und ich glaube, dass das bis auf weiteres reicht, denn das sind Parameter, die anwendungsspezifisch verwaltet werden. und alle Benutzer sollen das gleiche Erscheinungsbild haben.

ActionContext kann jetzt mit *args und **kw instanziert werden. Was für die neue SaveWindowConfigAction gebraucht wird.

Und noch eine geniale (interne) Neuerung nebenbei: wenn py2js() einen callable kriegt, dann muss das ein Iterator sein, der einzelne JS-Zeilen liefert. Dadurch konnte ich folgenden Code schreiben:

        def save():
            yield "function(event,toolEl,panel,tc) {"
            yield "  console.log(panel.id,panel.getSize(),panel.getPosition());"
            yield "var pos = panel.getPosition();"
            yield "var size = panel.getSize();"
            url = '/save_win/' + self.name
            yield "  Lino.do_action(%r,%r,{x:pos[0],y:pos[1],\

                h:size['height'],w:size['width']});" % (url,url)
            yield "}"
         
        self.options.update(tools=[dict(id='save',handler=save)])


So, und jetzt schlaf ich vielleicht noch mal was...