P4A 3 Framework: Gestione Fatture 2, un’applicazione completa

Gestione fatture 2

Ho deciso di riscrivere in larga parte il codice dell’applicazione Gestione Fatture che avevo pubblicato in questo articolo, per renderla compatibile con la nuova versione di P4A (disponibile qui) (la 3.8.4) ed anche per correggere diversi bug che sono emersi nell’utilizzo.

Pur mantenendo tutte le caratteristiche della precedente versione, l’attuale non è compatibile con quella precedente per via di alcune modifiche sostanziali che ho dovuto apportare alla struttura del database.

Oltre a poter essere utile proprio per la gestione delle fatture delle ditte individuale e dei professionisti, credo che questo codice possa essere utile anche a tutti coloro che si avvicinano al framework P4A, in quanto all’interno ci sono diversi esempi di come risolvere la maggior parte dei problemi che si incontrano sviluppando con questo framework.

Alcune delle nuove caratteristiche sono:

  • Riscritto lo schema del database (non è più compatibile con la versione precedente)
  • Possibilità di inserire il saldo o il saldo parziale riscosso della fattura emessa per il controllo dei pagamenti
  • Nuova funzionalità per monitorare le fatture saldate interamente o parzialmente (conteggio dei soldi in cassa e dell’importo da riscuotere)
  • Nuova funzionalità per il filtraggio delle fatture
  • Possibilità di emettere note di credito
  • Nuova funzionalità per fatture ricorrenti
  • Corretto il codice della classe ezPDF (i file sono allegati nella dir. Libraries) per la compatibilità con PHP 5.3.x
  • Possibilità di inserire automaticamente la descrizione di prestazioni già inserite in fatture precedenti

A chi è rivolto:

  • Soggetti senza P.IVA che rilasciano la sola ritenuta di acconto
  • Soggetti con P.IVA iscritti alla Camera di Commercio (Ditte individuali)
  • Professionisti senza Cassa previdenziale autonoma
  • Professionisti con Cassa previdenziale autonoma

Per la mancanza di una gestione del magazzino è sconsigliata ai commercianti che hanno a che fare con un magazzino merce, inventario e via dicendo.

L’applicazione viene distribuita con licenza LGPL 3, in questo link potete trovare la traduzione non ufficiale in italiano.

Installazione:

  • Installare il framework p4a 3.8.4 (requisito obbligatorio)
  • Scompattare l’archivio “gestionefatture2.zip” all’interno della directory “p4a/applications”
  •   Generare un database con il nome: “gestionefatture2” ed importare il dump SQL:  “gestionefatture2.sql” che si trova all’interno della directory “_private”
  • Modificare il file “index.php” sostituendo nella riga di codice:

define(“P4A_DSN”, ‘mysql://yourdbuser:yourdbpassword@localhost/gestionefatture2’);

yourdbuser = l’utente MySQL con il quale accedere al vostro database

yourdbpassword = la password del suddetto utente.

Infine per accedere all’applicazione i parametri di login sono:

Username = admin

Password = admin

E’ importante mantenere nella directory “/libraries” i file di libreria di ezPdf che sono contenuti nel pacchetto, perché ho dovuto correggere alcune linee di codice (purtroppo ezPdf è stata abbandonata dal suo autore…) per renderla compatibile con PHP 5.3.x.

La applicazione richiede che sia installato il PHP 5.3.x + MySQL 5.1.x o superiore.

DOWNLOAD: Gestione Fatture 2

Sono graditi commenti, suggerimenti e correzioni!

 

 

 

P4A 3 Framework: helper per sincronizzare le tabelle sequence in MySQL

P4A 3 LogoChi utilizza l’RDBMS MySQL in P4A avrà certamente notato che il framework produce in certi casi, delle tabelle il cui nome termina in ‘_seq’. Queste tabelle servono ad avere una compatibilità nella gestione di tutti gli RDBMS supportati (MySQL, PostgreSQL, SQLite, Oracle). PostgreSQL e Oracle, non hanno lo stesso tipo di gestione delle chiavi primarie con l’attributo ‘AUTOINCREMENT‘, rispetto a MySQL e SQLite. La soluzione adottata è di costruire, per ogni tabella con chiave primaria di tipo ‘AUTOINCREMENT’, delle tabelle accessorie che hanno un campo ‘id’ di tipo ‘AUTOINCREMENT’ e di riferirsi a quest’ultime per ottenre il ‘LAST INSERT ID‘. In questo modo viene ricalcato il comportamento delle chiavi primarie di tipo ‘SERIAL’ in PostgreSQL, e anche quelle di Oracle (leggermente diverse).

Prima di tutto una precisazione: questo articolo è riferito esclusivamente agli utenti MySQL.
Se si pensa di utilizzare esclusivamente P4A Framework per la gestione dei dati del nostro database, sarebbe bene in fase di progettazione evitare di usare gli AUTOINCREMENT perché, come detto, non necessari. Nel caso in cui il framework venga utilizzato come ‘backoffice’ per la gestione di dati che vengono alimentati da un form di un sito web, oppure si abbia la necessità di utilizzare una struttura dati pre-esistente con tanto di chiavi primarie ‘AUTOINCREMENT’, potremmo prima o poi trovarci di fronte ad un problema di disallineamento dei valori fra la chiave primaria della tabella e l’id’ della tabella ‘_seq’ associata.

Immaginiamo di avere una tabella “test” con questi due campi:

+----+---------+
| id | name    |
+----+---------+

con ‘id’ chiave primaria, P4A creerà automaticamente una tabella “test_id_seq” con una campo ‘id’ chiave primaria e ‘AUTOINCREMENT’, ed userà i valori forniti da quest’ultima sia per l’inserimento di nuovi record nella tabella “test“, che per altre operazioni sulla chiave primaria. Dunque utilizzando un programma esterno al framework per fare degli inserimenti e volendo mantenere allineate le tabelle principali e le tabelle “_seq” sarà necessario, per ogni “INSERT” nella tabella principale, fare altrettanto nella “_seq”!
Anche utilizzando questo metodo, potrebbe verificarsi prima o poi il problema di un disallineamento, in questo caso ho pensato potesse utile scrivere un metodo della classe “P4A_DB_SOURCE” da utilizzare in extremis, per risistemare le cose.

Per maggiori informazioni sull’utilizzo degli ‘helper’ in P4A suggerisco questo link

Ecco il codice dell’helper, in pratica viene prelevato il valore massimo della chiave primaria ‘AUTOINCREMENT’ della tabella che funge da sorgente dati, quindi viene eliminata la tabella ‘_seq’ associata e successivamente ricostruita con il valore corretto.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
 function p4a_db_source_resync_seq($source)
 
 { 
	$table = $source->getTable();
	$pKField = $source->getPk();
	$seqTable =  $table."_".$pKField."_seq";
	$lastId = P4A_DB::singleton()->fetchOne("SELECT MAX($pKField) FROM $table");
	$query = "DROP TABLE IF EXISTS `$seqTable`";
	$resQ1 = P4A_DB::singleton()->query($query);
	$query = "CREATE TABLE `$seqTable` (
	`id` int(11) NOT NULL auto_increment,
	PRIMARY KEY  (`id`)
	) TYPE=MyISAM AUTO_INCREMENT=$lastId";
 
	$resQ2 = P4A_DB::singleton()->query($query);
	$query = "INSERT INTO `$seqTable` VALUES ($lastId)";
	$resQ3 = P4A_DB::singleton()->query($query);
  return ($resQ1 && $resQ2 && $resQ3); 
 
 }

Questo codice deve essere inserito in un file con il nome: “p4a_db_source_resync_seq.php” che deve essere posizionato nella directory “libraries” della nostra applicazione P4A.

Ecco infine un po’ di codice di esempio da aggiungere alla nostra ipotetica maschera di manutenzione del db:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
class test extends P4A_Base_Mask
{
	public function __construct()
 
	{
		parent::__construct();
 
		// DB Source
		$this->build("p4a_db_source", "source")
			->setTable("test")
			->setPk("id")
			->load();
		$this->setSource($this->source);
 
		// ....
 
	    $this->build("p4a_button", "btn_resync")
			->setLabel("resync")
			->implement("onclick", $this, "resync_seq_table");
 
		// ....
	}
 
	public function resync_seq_table()
	{
		$res = $this->source->resync_seq();	
	}
 
	// ....
}

Conclusioni

Questo metodo dovrebbe essere usato con una certa cautela, e solo come procedura di emergenza. Non consiglio l’utilizzo se c’è la possibilità di accesso in scrittura alla tabella coinvolta da parte di altri utenti.

Riferimenti ed approfondimenti:

Gestione fatture: un’applicazione completa in P4A

Screenshot di Gestione fatture
Screenshot di Gestione fatture

Questa applicazione web si basa sul framework PHP: P4A 3. Si tratta di una versione migliorata e corretta del codice già presentato in questo post. E’ un’applicazione completa per la gestione delle fatture, pensata soprattutto per chi eroga prestazioni, più che prodotti, in quanto non contempla una gestione del magazzino. Può essere utile per chi, come me, fa consulenze informatiche e realizza software, oppure per piccole aziende di autotrasporto che lavorano principalmente conto terzi o per artigiani e professionisti che non utilizzano un magazzino.
Non può essere utilizzata però da coloro i quali sono iscritti ad un albo professionale, in quanto, da informazioni ricevute da un commercialista, mi risulta che il calcolo della ritenuta d’acconto e delle trattenute INPS sia leggermente differente.

Maschere:

  • Gestione azienda: in questa maschera è possibile definire la ragione sociale, i dati anagrafici e il logo dell’azienda, definire l’utente e la password e impostare il tipo di fatturazione: IVA fissa, IVA variabile, ritenuta d’acconto, contributo INPS (queste ultime due opzioni sono possibili solo con IVA fissa).
  • Gestione clienti: in questa maschera vengono immessi i dati anagrafici dei clienti.
  • Fatture: è la maschera principale per creare e modificare le fatture. E’ divisa in due parti selezionabili attraverso delle ‘linguette’ come per gli schedari. La sezione ‘fatture’ permette di inserire una nuova fattura vuota, indicando la data, il numero, il cliente e la tipologia di pagamento. E’ anche possibile indicare se la fattura è stata pagata attraverso un flag ed inserire eventuali note. Il numero viene suggerito automaticamente seguendo la progressione dell’anno in corso, è però possibile immetterlo manualmente, in questo caso esiste un controllo per evitare duplicati.
    La sezione ‘Dettaglio fattura’ serve per inserire la lista di prestazioni o prodotti da fatturare. E’ possibile raggruppare una lista attraverso il campo ‘sezione’. Gli altri campi da riempire sono la descrizione, la quantità il prezzo e l’IVA (se non si è scelta la modalità IVA fissa). In fondo alla maschera vengono riportati i valori del totale imponibile, totale IVA e totale fattura. (totale ritenuta d’acconto e contributo INPS, solo se lo si è attivato nella Gestione azienda).
    Attraverso il pulsante di stampa, viene generato un documento pdf stampabile con la fattura impaginata in una o più pagine (in questo caso numerate) e la dicitura del destinatario allineata con l’apertura delle buste a ‘finestra’ standard.
  • Lista fatture: attraverso questo report è possibile filtrare le fatture di un certo periodo, visualizzare e stampare su pdf l’elenco e i totali dell’imponibile, delle fatture e i totali di quelle pagate e quelle no.
  • Tipo pagamenti: E’ possibile inserire le varie modalità di pagamento (assegno, bonifico, riba ecc.)
  • Unità di misura: E’ possibile inserire le unità di misura (ore, pezzi, kg, ecc.)

Alcune note sull’utilizzo:
Per aggiungere un nuovo record, è sempre necessario utilizzare il pulsante ‘Inserisci un nuovo elemento’, e una volta compilati i campi, premere il pulsante ‘Conferma e salva’. Nel caso di inserimento di una nuova fattura, dopo aver salvato e prima di inserire la lista delle prestazioni, è necessario selezionare con il puntatore (triangolino nero) la fattura appena creata. Per creare dei blocchi di prestazioni, inserire una dicitura nel campo ‘sezione’, in questo modo, i nuovi record creati con la stessa dicitura nel campo sezione, saranno raggruppati e ordinati alfabeticamente in fattura.

Installazione

Deve innazitutto essere installato il framework P4A versione 3.2.x (dettagli per il download e l’installazione). Poi è sufficiente scompattare l’archivio compresso nella direcory ‘applications’ che si trova sotto la directory ‘P4A’, caricare il dump .sql del database che si trova nella directory ‘_private’ in un server ‘MySQL’ e impostare i parametri per la connessione nel file ‘index.php’ (Nella maggioranza dei casi questo potrebbe non essere necessario). Chi utilizza linux, deve ricordarsi di dare i permessi di scrittura alla directory ‘uploads’ e alle sue subdirectories. Se il server web è installato localmente, per accedere all’applicazione digitare la url ‘http://localhost/p4a/applications/gestionefatture/’
Infine, volendo personalizzare l’aspetto grafico dell’applicazione, suggerisco questo articolo.

Il nome utente e la password per l’accesso iniziale sono: user = ‘utente’ e password = ‘utente’

Demo:

La demo non è disponibile.

Download

  • gestione fatture in formato compresso zip
  • gestione fatture in formato compresso tar bz2

Licenza

La licenza applicata è la LGPLv3

Conclusioni:

Considerando che l’applicazione viene fornita gratuitamente, non garantisco nessun supporto ufficiale e non mi assumo alcuna responsabilità per eventuali anomalie di funzionamento. Sono comunque disponibile a correggere gli errori che mi segnalerete e a valutare eventuali upgrade, compatibilmente con il tempo richiesto.

Riferimenti ed approfondimenti:

 

 

P4A3 framework: il widget Countdown rinnovato e con funzione timer

Widget p4a CountdownQuesto widget per il framework P4A è l’aggiornamento di quello descritto in questo post.
L’aggiornamento deriva dal fatto che la nuova versione del codice originale per jQuery, presenta cambiamenti importanti e ha richiesto la riscrittura di una buona parte del widget. La versione del Countdown for jQuery attualmente installata è la 1.4.3.

Ho pensato di cogliere l’occasione per rendere un poco più interattivo il widget, facendo scattare un evento gestibile dall’utente attraverso un metodo personalizzato, allo scadere del contatempo. Inoltre, ho utilizzato l’integrazione di P4A con i18n, per impostare automaticamente la lingua per gli output delle etichette e il formato della data e dell’ora.

Questo è l’elenco dei metodi fino ad esso implementati:

Elenco dei metodi:
NomeTipoDefaultNote
setSince()integer"null"Imposta la data e l’ora di avvio in formato UNIX timestamp
setUntil()integer"null"Imposta la data e l’ora di stop in formato UNIX timestamp.
setDisplayFormat()string"dHMS"‘Y’ anni, ‘O’ mesi, ‘W’ settimane, ‘D’ giorni, ‘H’ ore, ‘M’ minuti, ‘S’ secondi. I caratteri minuscoli impostano la visualizzazione opzionale
setCompactFormat()string"false"Imposta il formato ridotto.
setDescription()string""Imposta la descrizione del contatempo.
setServerTime()stringnullImposta l’offset per il fuso orario. Valori di esempio: ‘+1’, ‘+2’, ‘+3’, ‘-1’, ‘-2’, ‘-3’. etc.
setLayout()string''Imposta un layout personalizzabile attraverso tag HTML e parametri per esprimere la data e l’ora.
Le singole sezioni sono delimitate da %x…%x, dove x è ‘Y’ per definire gli anni, ‘O’ per i mesi,
‘W’ per le settimane, e ‘D’ per i giorni, ‘H’ per le ore, ‘M’ per i minuti, e ‘S’ per i secondi.
All’interno di queste sezioni, è possibile utilizzare ‘%n’ per determinare il valore del periodo,
‘%nn’ per il valore con un minimo di due caratteri, e ‘%l’ per l’etichetta del periodo (in accordo
con quanto impostato in setCompactFormat()).
setlocale()string'auto'Imposta un valore per la regionalizzazione. Per default viene presa l’impostazione di P4A_LOCALE.
In alternativa è possibile impostarla manualmente. Le traduzioni disponibili sono:
Chinese – Simplified “zh-CN”, Chinese – Traditional “zh-TW”, Czech “cs”, Danish “da”, Dutch “nl”, French “fr”, German “de”, Hebrew “he”, Hungarian “hu”, Indonesian “id”, Italian “it”, Norwegian “nb”, Persian/Farsi “fa”, Polish “pl”, Portuguese/Brazilian “pt-BR”, Romanian “ro”, Russian “ru”, Slovak “sk”, Spanish “es”, Swedish “sv”, Turkish “tr”, Ukranian “uk”
setPauseResumeType()stringnullSe impostato con i valori: “lap” o “pause” mostra un pulsante che ferma o riavvia il contatempo.
“lap” ferma solo la visualizzazione, “pause” ferma anche il conteggio. Se null il pulsante non viene mostrato.
setPauseResumeLabels()string'pause,resume'Imposta le etichette per il pulsante “Pause/resume”. I valori per l’azione toggle devono essere separati da una virgola.
onExpiry()booleanfalseImposta se deve scattare un evento allo scadere del countdown (funziona solo quando è impostato setUntil()).
setMessageOnExpire()string""Imposta il testo del messaggio che viene visualizzato allo scadere del countdown.
messageOnExpire()voidvoidSe è impostato un messaggio, lo mostra e restituisce un handle per l’evento actionOnExpire.
Questo metodo viene attivato quando onExpiry(true)

Ecco un po’ di codice di esempio per inserire il contatempo in una maschera e utilizzare l’evento actionOnExpire:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
class test_countdown extends p4a_base_mask
{
 public function __construct()
 {
   parent::__construct();
   $this->setTitle("test Countdown");
   $this->build("P4A_jCountdown", "countdown")
    ->setStyleProperty("width","400px")
    ->setStyleProperty("float","none")
    ->setStyleProperty("margin","auto")    
    ->setDescription("test countdown")
    ->countdown->setUntil(time()+11)
    ->countdown->onExpiry(true)
    ->countdown->setMessageOnExpire("Il tempo e' scaduto!");
 
    $this->countdown->implement('actionOnExpire',$this,'show');
 
    $this->frame->anchorCenter($this->countdown);
  }
 
	public function show ()
	{
		$this->info("Questa e' una prova!");
		//Enable code below for looping
		//$this->countdown->setUntil(time()+11);
	}
 
}

Il pacchetto completo della maschera di esempio è scaricabile qui

Note:

L’impostazione di setLocale() non è in genere necessaria per il fatto che quando viene “costruito” il contatempo la regionalizzazione viene individuata automaticamente. Nel caso si volesse impostare questo parametro manualmente, si consiglia di non cambiarlo successivamente a run-time. Questo perché è stato scelto di caricare l’intero set di impostazioni per la regionalizzazione tramite codice javascript esterno, mediante files di libreria. Per questo metodo quindi, i cambiamenti a run-time generano codice non pulito, che sconsiglio, almeno fino a che non trovo il tempo di migliorare questa soluzione.
Come nella precedente versione, è consigliabile aggiungere un secondo quando si utilizza:->setUntil() e decrementare di un secondo quando si utilizza ->setSince(time())per evitare una non perfetta sincronizzazione fra il tempo in cui viene mostrato il widget e lo scattare del conteggio.
Infine è possibile rendere invisibile il widget, semplicemente con ->setVisible(false) e mantenere attivo il contatempo. Questo permette di utilizzare comunque l’handle per l’evento actionOnExpire anche senza visualizzare il widget.

Conclusioni:

Questi ultimi giorni sono stati davvero impietosi con il mio (già scarso) tempo libero, e non ho potuto sviluppare il codice come avrei voluto… spero di poterci dedicare ancora del tempo, perché mi sembra un progetto interessante e, spero utile a molti. Ci sono ancora alcune caratteristiche da integrare e miglioramenti da fare nel codice, spero nell’aiuto degli utenti! Nel frattempo cercherò anche di ampliare e migliorare la documentazione (già presente nel pacchetto).

Riferimenti ed approfondimenti:

P4A 3 framework: personalizzare il tema grafico con icone e colori

Le icone di P4ASulla personalizzazione dell’aspetto grafico delle maschere di P4A, esiste già questo interessante screencast di Fabrizio Balliano. Trovo interessante poter cambiare la grafica perché l’aspetto di default, sebbene gradevole e riposante, in alcuni casi, per esempio sugli schermi dei netbook appare un po’ troppo poco contrastato. Il tema alternativo proposto nello screencast è “Human” per Gnome, davvero molto bello!
Il set di impostazioni per i colori e il set di icone vengono generati a partire da script PHP. Entrambi gli script sono disponibili in P4A Wiki nella sezione: “Theme customizations”, il requisito è di farli girare su una macchina Linux, che sia dotata del necessario software di conversione da SVG a PNG. Ho pensato di scrivere questo post, anche se in gran parte è una ripetizione dello screencast di Fabrizio, perché qualcuno si potrebbe trovare in difficoltà scoprendo al primo approccio che lo script che genera il set di icone, per funzionare correttamente, necessita di una particolare libreria.

Dunque, la situazione migliore è che possediamo una distro “Ubuntu“, quindi con installato il Desktop Gnome. Per prima cosa, ci dobbiamo accertare che sia installato il programma rsvg che fa parte della libreria librsvg. Se non è presente (in genere non lo è…), l’installazione è davvero molto semplice utilizzando apt-get:

sudo apt-get install librsvg2-2

invece, se volete perdere tempo e avete già installate tutte le librerie per il supporto alle manipolazioni dei formati SVG, potete installare il pacchetto manualmente. Queste librerie sono comunque necessarie: libxml2 e libxml2-dev

Questo è il link per l’installazione del software rsvg:
http://ftp.gnome.org/pub/GNOME/sources/librsvg/2.22/librsvg-2.22.3.tar.bz2

scompattate il pacchetto con:

tar -xjvf librsvg-2.22.3.tar.gz.bz2

ed infine compilate:

  • sudo ./configure
  • sudo make
  • sudo make install

Ci siamo, ora possiamo lanciare lo script di Fabrizio che genera il set di icone, in questo caso il set Human per Gnome:

php build_icon_theme.php /home/directory/che/volete /usr/share/icons/Human /usr/share/icons/gnome

Adesso copiate le icone generate che saranno raggruppate nelle cartelle con il nome 16 e 32 nella directory human che si deve trovare all’interno di p4a/icons e aggiungete il seguente codice all’interno del file index.php della vostra applicazione P4A, prima della riga di codice: require_once dirname(__FILE__) . '/../../p4a.php'; e con le icone abbiamo finito.

define('P4A_ICONS_NAME', 'human');

In pratica lo script recupera le icone che servono a p4a e le copia, creando la struttura di directory necessaria, nella cartella /directory/che/volete. Se non sono disponibili nel formato richiesto, le genera dai modelli scalabili in SVG, oppure le cerca fra quelle del tema Gnome. Naturalmente, è sempre possibile aggiustare alcuni set a mano. Per esempio, ho notato che nella generazione del tema “Human”, l’icona “folder open”, risulta di colore grigio ed è piuttosto differente da “folder”, così l’ho sostituita con quella generata per il tema “Tangerine”.

Per quanto riguarda lo schema dei colori, dovete procurarvi lo script PHP: gtkrc2p4a.php per importare gli schemi Gnome gtkrc. Per generare il set di colori che armonizza le icone “Human”, digitate da linea di comando:

php gtkrc2p4a.php /usr/share/themes/Human/gtk-2.0/gtkrc

L’esecuzione genera il seguente set di impostazioni da copiare e incollare dentro index.php (sempre prima di: require_once dirname(__FILE__) . '/../../p4a.php';):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
define('P4A_THEME_FG', '#101010');
define('P4A_THEME_BG', '#EFEBE7');
define('P4A_THEME_BORDER', '#d7d3cf');
define('P4A_THEME_INPUT_FG', '#1A1A1A');
define('P4A_THEME_INPUT_BG', '#FFF');
define('P4A_THEME_INPUT_BORDER', '#e5e5e5');
define('P4A_THEME_SELECTED_FG', '#1A1A1A');
define('P4A_THEME_SELECTED_BG', '#FFA443');
define('P4A_THEME_SELECTED_BORDER', '#e5933c');
define('P4A_THEME_TOOLTIP_FG', '#000');
define('P4A_THEME_TOOLTIP_BG', '#F5F5B5');
define('P4A_THEME_TOOLTIP_BORDER', '#dcdca2');
define('P4A_THEME_EVEN_ROW', '#eee');
define('P4A_THEME_ODD_ROW', '#fff');

Sembra fatta, ma c’è ancora qualcosa di imperfetto. Se nella vostra applicazione è presente un “tab-panel” i bordi rimangono colorati dell’azzurro di default, e lo sfondo del bottoncino per il passaggio da un pannello all’altro, rimane azzurro chiaro. Così per essere pignoli rimane da modificare un poco il CSS in questo modo:

Create un file provacss.php con le seguenti istruzioni per il CSS (io l’ho messo nella directory libraries della mia applicazione):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<?php
header('Content-type: text/css');
?>
.p4a_tab_pane ul.tabs {
	border-bottom: 1px solid <?php echo $_GET['input_border'] ?>;
}
.p4a_tab_pane ul.tabs li a {
	border: 1px solid <?php echo $_GET['input_border'] ?>;
}
.p4a_tab_pane ul.tabs a:hover {
	background: <?php echo $_GET['selected_bg'] ?>;
}
.p4a_tab_pane div.p4a_tab_pane_page {
	border: 1px solid <?php echo $_GET['input_border'] ?>;
}

Nel file principale della vostra applicazione, quello che estende la classe base p4a, inserite questo codice:

$this->addCss(P4A_APPLICATION_LIBRARIES_PATH."provacss.php?". $this->getCssConstants());

E il gioco è fatto! In pratica, è possibile aggiungere un CSS dinamico che carica, mediante querystring, le costanti determinate dal tema adottato.

Ecco uno screeshot della mia applicazione per la gestione delle fatture “vestita” con Human-gnome:

Screenshot di gestione fatture con tema Human
Screenshot di gestione fatture con tema Human

Download

Per chi non avesse a disposizione un ambiente Linux (ma cosa aspetta a farlo?) metto a disposizione il set di icone Human che ho generato qui

Conclusioni

Una volta compreso il meccanismo, personalizzare p4a è piuttosto semplice. Mi sono divertito anche a creare un tema “Vista like”, tanto per non spiazzare troppo i clienti “allineati” a M$…

Riferimenti ed approfondimenti:

  • Screencast di Fabrizio Balliano: “Theme customizations in RC5”
  • P4A Wiki

Fabrizio Balliano ha scritto:

ottimo articolo come sempre, vedo però di risolvere il problema del tab pane perché va fixato :)
23.02.09 09:41
Fabrizio Balliano ha scritto:

risolto e committato :)

P4A 3 framework: db_navigator helper per estrarre un ramo da un dbtree

Esempio di db_navigatorQuesto helper deriva naturalmente dalla funzione descritta nel precedente post.P4A mette a disposizione un widget chiamato P4A_DB_Navigator che si basa su archivi di tipo albero a liste di adiacenza e fornisce un output grafico della lista dei nodi, con un buon grado di interattività. Esiste, per esempio, un metodo che si chiama getPath() che restituisce in un array, il percorso dalla root al nodo fornito in input attraverso la chiave primaria. Purtroppo però, non esiste nessun metodo per estrarre l’insieme di nodi figli da un certo nodo parentale, così ho pensato di adottare la funzione presentata nel precedente post.

I parametri di input sono:

  • $navigator – l’oggetto da cui discende (implicito)
  • $id – l’identificativo del nodo da cui partire
  • $table – il nome della tabella che rappresenta l’albero
  • $pk – il nome della chiave primaria
  • $recursor – il nome del campo che identifica il nodo parentale

Ecco il codice:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
// File: P4A_db_navigator_getBranch.php
<?php
function P4A_db_navigator_getBranch ($navigator, $params)
{
  list($id, $table, $pk, $recursor) = $params;
  $arr = p4a_db::singleton()->getAll("SELECT * FROM $table");
  $pksArr = array();
  foreach ($arr as $rec) {
    $pksArr[$rec[$pk]]=$rec[$recursor];
  }
  $branchIds = array($id);
  $i=0;
  while ($i<count($branchIds)) {
    $newKeys = array_keys($pksArr,$branchIds[$i]);
    if (!empty($newKeys)) {
      foreach ($newKeys as $newKey){
        array_push($branchIds, $newKey);
      }
    }
    ++$i;
  }
  $res = array();
  foreach ($arr as $child) {
    if (in_array($child[$pk], $branchIds)) {
      $res[] = $child;
    }
  }
  return $res;
}
?>

Come esempio ho costruito una semplicissima maschera nella quale, ogni volta che viene selezionato un nodo, viene mostrato un messaggio con l’array dei nodi figli.

Ecco il codice:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
class dbtree extends P4A_Base_Mask
{
  public function __construct()
  {
    parent::__construct();
    $this->setTitle('Test dbTree');
    //Source
    $this->build("p4a_db_source","dbtree")
      ->setTable("tree")
      ->setPk("id")
      ->load()
      ->firstRow();
    $this->setSource($this->dbtree);
    // db_navigator
    $this->build("p4a_db_navigator","navigator")
      ->setSource($this->dbtree)
      ->setRecursor("parent_id")
      ->setDescription("nome")
      ->setStyleProperty("height","85%")
      ->setStyleProperty("overflow","auto")
      ->collapse(true);
    // Display
    $this->display("sidebar_left",$this->navigator);
    // Intercept action afterMoveRow
    $this->intercept($this->dbtree,"afterMoveRow","showBranch");
  }
	public function showBranch()
  {
    $idCommessa = $this->dbtree->fields->id->getNewValue();
    $arr = $this->navigator->getBranch ($idCommessa, "tree", "id", "parent_id");
    $this->info(print_r($arr,true));
  }
}

L’esempio completo è scaricabile qui

Conclusioni

Lancio l’idea di mettere questa funzione fra i metodi del P4A_db_navigator, sempre che non esca fuori qualche dannato baco :-).

Riferimenti ed approfondimenti: