[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

SF.net SVN: ledger-smb:[4743] trunk



Revision: 4743
          http://ledger-smb.svn.sourceforge.net/ledger-smb/?rev=4743&view=rev
Author:   einhverfr
Date:     2012-05-21 10:19:27 +0000 (Mon, 21 May 2012)
Log Message:
-----------
Merging neglected budget entry in, porting to Moose and business unit framework

Added Paths:
-----------
    trunk/LedgerSMB/DBObject/Budget.pm
    trunk/LedgerSMB/DBObject/Budget_Report.pm
    trunk/LedgerSMB/Scripts/budgets.pm
    trunk/UI/budgetting/
    trunk/UI/budgetting/budget_entry.html
    trunk/UI/budgetting/budgetting.css
    trunk/UI/budgetting/search_criteria.html
    trunk/budgets.pl

Added: trunk/LedgerSMB/DBObject/Budget.pm
===================================================================
--- trunk/LedgerSMB/DBObject/Budget.pm	                        (rev 0)
+++ trunk/LedgerSMB/DBObject/Budget.pm	2012-05-21 10:19:27 UTC (rev 4743)
@@ -0,0 +1,356 @@
+=head1 NAME
+
+LedgerSMB::DBObject::Budget
+
+=cut
+
+package LedgerSMB::DBObject::Budget;
+use strict;
+our $VERSION = 0.1;
+
+=head1 SYNOPSIS
+
+This module provides budget management routines, such as entering budgets,
+approving or rejecting them, and marking them obsolete.  It does not include
+more free-form areas like reporting.  For those, see
+LedgerSMB::DBObject::Budget_Report.
+
+=head1 INHERITANCE
+
+=over
+
+=item LedgerSMB
+
+=item LedgerSMB::DBObject
+
+=back
+
+=cut
+
+use Moose;
+extends LedgerSMB::DBObject_Moose;
+
+=head1 PROPERTIES
+
+=over
+
+=item   $id INT
+   The id of the budget
+
+=cut
+
+has 'id' => (is => 'rw', isa => 'Maybe[Int]');
+
+=item   $start_date date
+   The start date of the budget, inclusive
+
+=cut
+
+has 'start_date' => (is => 'rw', isa => 'Maybe[LedgerSMB::PGDate]');
+
+=item   $end_date date
+   The end date of the budget, inclusive
+
+=cut
+
+has 'end_date' => (is => 'rw', isa => 'Maybe[LedgerSMB::PGDate]');
+
+=item   $reference text
+   This is a text reference identifier for the budget
+
+=cut
+
+has 'reference' => (is => 'rw', isa => 'Maybe[Str]');
+
+=item   $description text
+   This is a text field for the budget description.  It is searchable.
+
+=cut
+
+has 'description' => (is => 'rw', isa => 'Maybe[Str]');
+
+=item   $entered_by int
+   Entity id of the employee or contractor who entered the budget
+
+=cut
+
+has 'entered_by' => (is => 'rw', isa => 'Maybe[Int]');
+
+=item   $approved_by int
+   Entity id of the employee or contractor who approved the budget
+
+=cut
+
+has 'approved_by' => (is => 'rw', isa => 'Maybe[Int]');
+
+=item   $obsolete_by int
+   Entity id for the employee or contractor who marked the budget obsolete
+
+=cut
+
+has 'obsolete_by' => (is => 'rw', isa => 'Maybe[Int]');
+
+=item   $entered_at timestamp
+   Time the budget was entered
+
+=cut
+
+has 'entered_at' => (is => 'rw', isa => 'Maybe[LedgerSMB::PGDate]');
+
+=item   $approved_at timestamp
+   Time the budget was approved
+
+=cut
+
+has 'approved_at' => (is => 'rw', isa => 'Maybe[LedgerSMB::PGDate]');
+
+=item   $obsolete_at timestamp
+   Time the budget was deleted
+
+=cut
+
+has 'obsolete_at' => (is => 'rw', isa => 'Maybe[LedgerSMB::PGDate]');
+
+=item   $entered_by_name text
+   Name of entity who entered the budget. 
+
+=cut
+
+has 'entered_by_name' => (is => 'rw', isa => 'Maybe[Str]');
+
+=item   $approved_by_name text
+   Name of entity who approved the budget
+
+=cut
+
+has 'approved_by_name' => (is => 'rw', isa => 'Maybe[Str]');
+
+=item   $obsolete_by_name text
+   Name of entity who obsoleted the budget
+
+=cut
+
+has 'obsolete_by_name' => (is => 'rw', isa => 'Maybe[Str]');
+
+=item @business_unit_ids
+
+List of id's of business units which the budget covers
+
+=cut
+
+has 'business_unit_ids' => (is => 'rw', isa => 'Maybe[ArrayRef[Int]]');
+
+=item   @lines 
+   These are the actual lines of the budget.  Each one is a hashref containing
+
+=cut
+
+has 'lines' => (is => 'rw', isa => 'Maybe[ArrayRef[Hashref[Any]]]');
+=over
+
+=item $budget_id int
+   Optional.  Don't use.  Use the $id field of the parent instead.
+
+=item $account_id int
+   The id of the chart of accounts entry
+
+=item $accno text
+   The account number for the coa entry
+
+=item $amount numeric
+   The amount budgetted
+
+=item $description text
+   Description of line item
+
+=back
+
+=item @notes
+Where each note is a hashref containing
+
+=over 
+
+=item $subject string
+   Subject of note
+
+=item $note string
+   The body of the note.
+
+=item $created timestamp
+   This is when the note was created
+
+=item $created_by string
+   Username of the individual who created the note at the time of its creation.
+
+=back
+
+=back
+
+=head1 METHODS
+
+=over
+
+=item save
+
+Saves the current budget.
+
+=cut
+
+sub save {
+    my ($self) = @_;
+    my ($ref) = $self->exec_method({funcname => 'budget__save_info'});
+    $self->{details} = [];
+    for my $line (@{$self->lines}){
+       my $l_info = [$line->{account_id}, 
+                     $line->{description}, 
+                     $line->{amount},
+       ];
+       push @{$self->{details}}, $l_info;
+    }
+    $self->exec_method({funcname => 'budget__save_details'});
+    $self->get($ref->{id});
+    $self->{dbh}->commit;
+}
+
+=item 
+
+=item search
+This method uses the object as the search criteria.  Nulls/undefs match all 
+values.  The properties used are:
+
+=over
+
+=item start_date
+Matches the start date of the budget.  Full match only.
+
+=item end_date
+Matches the end date of the budget.  Full match only
+
+=item includes_date
+This date is between start date and end date of budget, inclusive.
+
+=item reference
+Partial match on budget reference
+
+=item description
+Full text search against description
+
+=item entered_by
+Exact match of entered by.
+
+=item approved_by
+Exact match of approved by
+
+=item department_id
+Exact match of department_id
+
+=item project_id
+Exact match of project_id
+
+=item is_approved
+true lists approved budgets, false lists unapproved budgets.  null/undef lists 
+all.
+
+=item is_obsolete
+true lists obsolete budgets. False lists non-obsolete budgets.  null/undef lists
+all.
+
+=back
+
+=cut 
+
+sub search {
+    my ($self) = @_; # self is search criteria here.
+    @{$self->{search_results}}
+       = $self->exec_method({funcname => 'budget__search'});
+    return @{$self->{search_results}}; 
+}
+
+=item get(id)
+takes a new (base) object and populates with info for the budget.
+
+=cut
+
+sub get {
+   my ($self, $id) = @_;
+   my ($info) = $self->call_procedure(
+          procname => 'budget__get_info', args => [$id]
+   );
+   $self = $self->new(%$info);
+   @{$self->{lines}} = $self->exec_method({funcname => 'budget__get_details'});
+   @{$self->{notes}} = $self->exec_method({funcname => 'budget__get_notes'});
+}
+
+=item approve
+Marks the budget as approved.
+
+=cut
+
+sub approve {
+   my ($self) = @_;
+   $self->exec_method({funcname => 'budget__approve'});
+   $self->{dbh}->commit;
+}
+
+=item reject
+Reject and deletes the budget.
+
+=cut
+
+sub reject {
+   my ($self) = @_;
+   $self->exec_method({funcname => 'budget__reject'});
+   $self->{dbh}->commit;
+}
+
+=item obsolete
+Marks the budget as obsolete/superceded.
+
+=cut
+
+sub obsolete {
+   my ($self) = @_;
+   $self->exec_method({funcname => 'budget__mark_obsolete'});
+   $self->{dbh}->commit;
+}
+
+=item save_note(subject string, note string)
+Attaches a note with this subject and content to the budget.
+
+=cut
+
+sub save_note {
+   my ($self, $subject, $note) = @_;
+   my ($info) = $self->call_procedure(
+          procname => 'budget__save_note', 
+           args => [$self->{id}, $subject, $note]
+   );
+}
+
+=back
+
+=head1 SEE ALSO
+
+=over
+
+=item LedgerSMB
+
+=item LedgerSMB::DBObject
+
+=item LedgerSMB::DBObject::Budget_Report
+
+=back
+
+=head1 COPYRIGHT AND LICENSE
+
+Copyright (C) 2011 LedgerSMB Core Team.  This file is licensed under the GNU 
+General Public License version 2, or at your option any later version.  Please
+see the included License.txt for details.
+
+=cut
+
+__PACKAGE__->meta->make_immutable;
+return 1;
+
+
+

Added: trunk/LedgerSMB/DBObject/Budget_Report.pm
===================================================================
--- trunk/LedgerSMB/DBObject/Budget_Report.pm	                        (rev 0)
+++ trunk/LedgerSMB/DBObject/Budget_Report.pm	2012-05-21 10:19:27 UTC (rev 4743)
@@ -0,0 +1,150 @@
+=head1 NAME
+
+LedgerSMB::DBObject::Budget_Report
+
+=cut
+
+package LedgerSMB::DBObject::Budget_Report;
+use strict;
+
+=head1 SYNOPSIS
+
+Reporting routines for budgets.  Currently only displays a variance report.
+
+=head1 INHERITANCE
+
+=cut
+
+=over
+
+=item LedgerSMB
+
+=item LedgerSMB::DBObject
+
+=back
+
+=cut
+
+use base qw(LedgerSMB::DBObject);
+
+=head1 PROPERTIES
+
+=over
+
+=item id
+The id of the budget
+
+=item start_date
+The start date of the budget, inclusive
+
+=item end_date
+The end date of the budget, inclusive
+
+=item reference
+The reference or control code of the budget
+
+=item description
+Description of the budget
+
+=item entered_by
+entity id of the one who entered the budget
+
+=item approved_by
+entity id of the one who approved the budget
+
+=item obsolete_by
+entity id of the one who marked the budget obsolete
+
+=item entered_at
+Timestamp when the budget was saved
+
+=item approved_at
+Timestamp when the budget was approved
+
+=item obsolete_at
+Timestamp when the budget was marked obsolete
+
+=item entered_by_name
+Name of the entity who entered the budget
+
+=item approved_by_name
+Name of the entity who approved the budget
+
+=item obsolete_by_name
+Name of the entity who marked the budget obsolete
+
+=item department_id
+The ID of the department for which this budget was written
+
+=item department_name
+Name of the department for which this budget was written
+
+=item project_id
+ID of project for which this budget was written
+
+=item projectnumber
+Project number for which this budget was written
+
+=item lines
+Lines of the report.  Each line is a hashref containing:
+
+=over
+
+=item accno
+Account number for the account in question
+
+=item account_label
+Description for the account in question
+
+=item account_id
+ID for the account in question
+
+=item budget_description
+Description for the line item of the budget
+
+=item budget_amount
+The amount budgetted
+
+=item used_amount
+The amount actually used
+
+=item variance
+budgetted - used
+
+=back
+
+=back
+
+=head1 METHODS
+
+=over
+
+=item run_report($id);
+
+Takes a blank (base) object and populates with the variance report data provided
+by the id argument.
+
+=cut
+
+sub run_report {
+    my ($self) =  @_;
+   my ($info) = $self->call_procedure(
+          procname => 'budget__get_info', args => [$self->{id}]
+   );
+   $self->merge($info);
+   @{$self->{lines}} = $self->exec_method(
+          {funcname => 'budget__variance_report'}
+   );
+
+   return @{$self->{lines}};
+}
+
+1;
+
+=back
+
+=head1 COPYRIGHT AND LICENSE
+
+Copyright (C) 2011 LedgerSMB Core Team.  This file is licensed under the GNU 
+General Public License version 2, or at your option any later version.  Please
+see the included License.txt for details.

Added: trunk/LedgerSMB/Scripts/budgets.pm
===================================================================
--- trunk/LedgerSMB/Scripts/budgets.pm	                        (rev 0)
+++ trunk/LedgerSMB/Scripts/budgets.pm	2012-05-21 10:19:27 UTC (rev 4743)
@@ -0,0 +1,441 @@
+=head1 NAME
+LedgerSMB::Scripts::budgets
+
+=cut
+
+package LedgerSMB::Scripts::budgets;
+use strict;
+
+=head1 SYNOPSYS
+Budget workflow scripts.
+
+=head1 REQUIRES
+
+=over
+
+=item LedgerSMB::DBObject::Budget
+=item LedgerSMB::DBObject::Budget_Report
+
+=cut
+
+use LedgerSMB::DBObject::Budget;
+use LedgerSMB::DBObject::Budget_Report;
+use LedgerSMB::DBObject::Business_Unit;
+use LedgerSMB::DBObject::Business_Unit_Class;
+
+=head1 METHODS
+
+=over
+
+=item variance_report
+Requires id field to be set.
+
+=cut
+
+sub variance_report {
+    my ($request) = @_;
+    my $report = LedgerSMB::DBObject::Budget_Report->new({base => $request});
+    my @rows = $report->run_report();
+    my @cols = qw(accno account_label budget_description budget_amount 
+               used_amount variance);
+    my $heading = {
+          budget_description => $request->{_locale}->text('Description'),
+                       accno => $request->{_locale}->text('Account Number'),
+               account_label => $request->{_locale}->text('Account Label'),
+               budget_amount => $request->{_locale}->text('Amount Budgetted'),
+                 used_amount => $request->{_locale}->text('- Used'),
+                    variance => $request->{_locale}->text('= Variance'),
+    };
+    for my $row(@rows){
+        $row->{budget_amount} = $report->format_amount(
+                {amount => $row->{budget_amount}, money => 1}
+        );
+        $row->{used_amount} = $report->format_amount(
+                {amount => $row->{used_amount}, money => 1}
+        );
+        $row->{variance} = $report->format_amount(
+                {amount => $row->{variance}, money => 1}
+        );
+    }
+    my $template = LedgerSMB::Template->new(
+        user     => $request->{_user},
+        locale   => $request->{_locale},
+        path     => 'UI',
+        template => 'form-dynatable',
+        format   => ($report->{format}) ? $report->{format} : 'HTML',
+    );
+    $template->render({
+           form => $report,
+        columns => ..hidden..,
+           rows => ..hidden..,
+        heading => $heading,
+    });
+
+}
+
+=item new_budget 
+No inputs provided.  LedgerSMB::DBObject::Budget properties can be used to set
+defaults however.
+
+=cut
+
+sub new_budget {
+    my ($request) = @_;
+    my $budget = LedgerSMB::DBObject::Budget->new(%$request);
+    _render_screen($budget);
+}
+
+
+# Private method _render_screen
+# used by new_budget, view_budget, and update
+# Prepares and renders screen with budget info.
+
+sub _render_screen {
+    my ($budget) = @_;
+    my $additional_rows = 5;
+    $additional_rows +=20 unless $budget->{rowcount};
+    $additional_rows = 0 if $budget->{id};
+    $request->{class_id} = 0 unless $request->{class_id};
+    $request->{control_code} = '' unless $request->{control_code};
+    my $buc = LedgerSMB::DBObject::Business_Unit_Class->new(%$request);
+    my $bu = LedgerSMB::DBObject::Business_Unit->new(%$request);
+    @{$request->{bu_classes}} = $buc->list(1, 'gl');
+    for my $bc (@{$request->{bu_classes}}){
+        @{$request->{b_units}->{$bc->{id}}}
+            = $bu->list($bc->{id}, undef, 0, undef);
+        for my $bu (@{$request->{b_units}->{$bc->{id}}}){
+            $bu->{text} = $bu->control_code . ' -- '. $bu->description;
+        }
+    }
+    $budget->{rowcount} ||= 0;
+    for my $row (@{$budget->{display_rows}}){
+        $row->{debit} = $budget->format_amount(amount => $row->{debit},
+                                               money  => 1) if $row->{debit} ;
+        $row->{credit} = $budget->format_amount(amount => $row->{credit},
+                                                 money  => 1) if $row->{credit};
+    }
+    for (1 .. $additional_rows) {
+        push @{$budget->{display_rows}}, 
+             {accnoset => 0, index => $_ + $budget->{rowcount}};
+        ++$budget->{rowcount};
+    }
+    $budget->error('Invalid object') 
+         unless $budget->isa('LedgerSMB::DBObject::Budget');
+    # The button logic is kinda complicated here.  The basic idea is that there
+    # are three stages in the handling of the budget:  Initial entry, review and
+    # approval, and review with the possibility of obsolescence.
+    #
+    # In the initial entry, there is no budget yet.  Therefore id is not set.
+    # One can update the screen and save, but nothing else.
+    #
+    # Once id is set, if the budget has not been approved, it can be approved or
+    # rejected.  Rejecting deletes the budgets in the current implementation,
+    # but other options are possible as customizations.
+    #
+    # Once the budget is approved, it can no longer be deleted.  If
+    # circumstances change, however, it can still be marked obsolete.  Obsolete
+    # budgets are available for review, but one would not generally run variance
+    # reports against them.
+    if (!$budget->{id}){
+       $budget->{buttons} = [
+             {   name => 'action',
+                 text => $budget->{_locale}->text('Update'),
+                 type => 'submit',
+                value => 'update',
+                class => 'submit',
+             },
+             {   name => 'action',
+                 text => $budget->{_locale}->text('Save'),
+                 type => 'submit',
+                value => 'save',
+                class => 'submit',
+             },
+       ];
+     } elsif (!$budget->{approved_by}){
+         $budget->{buttons} = [
+             {   name => 'action',
+                 text => $budget->{_locale}->text('Approve'),
+                 type => 'submit',
+                value => 'approve',
+                class => 'submit',
+             },
+             {   name => 'action',
+                 text => $budget->{_locale}->text('Reject'),
+                 type => 'submit',
+                value => 'reject',
+                class => 'submit',
+             },
+         ];
+     } else {
+         $budget->{buttons} = [
+             {   name => 'action',
+                 text => $budget->{_locale}->text('Obsolete'),
+                 type => 'submit',
+                value => 'obsolete',
+                class => 'submit',
+             },
+        ];
+    }
+    my $template = LedgerSMB::Template->new(
+        user     => $budget->{_user},
+        locale   => $budget->{_locale},
+        path     => 'UI/budgetting',
+        template => 'budget_entry',
+        format   => 'HTML'
+    );
+    $budget->{hiddens} = {
+           rowcount => $budget->{rowcount},
+                 id => $budget->{id},
+    };
+    $template->render($budget);
+}
+
+=item update
+Updates the screen.  Part of initial entry workflow only.
+
+=cut
+
+sub update {
+    my ($request) = @_;
+    for (1 .. $request->{rowcount}){
+        push @{$request->{display_rows}}, 
+             { account_id => $request->{"account_id_$_"},
+               debit => $request->{"debit_$_"},
+               credit => $request->{"credit_$_"},
+               description => $request->{"description_$_"},
+             } if ($request->{"debit_$_"} or $request->{"credit_$_"});
+             
+    }
+    $request->{rowcount} = scalar @{$request->{display_rows}};
+    new_budget(@_); 
+}
+
+=item view_budget
+Reuuires id to be set.  Displays a budget for review.
+
+=cut
+
+sub view_budget {
+    my ($request) = @_;
+    my $budget = LedgerSMB::DBObject::Budget->new(%$request);
+    $budget->get($request->{id});
+    $budget->{display_rows} = [];
+    for my $line (@{$budget->{lines}}){
+        my $row = {};
+        $row->{description} = $line->{description};
+        if ($line->{amount} < 0 ) {
+            $row->{debit} = $line->{amount} * -1;
+        } else {
+            $row->{credit} = $line->{amount};
+        }
+        my ($account) = $budget->call_procedure( 
+                          procname => 'account_get',
+                              args => [$line->{account_id}]
+        );
+        $row->{account_id} = "$account->{accno}--$account->{description}";
+        push @{$budget->{display_rows}}, $row;
+    }
+    _render_screen($budget);
+}
+
+=item save
+LedgerSMB::DBObject::Budget properties required.  Lines represented by
+[property]_[line number] notation.
+
+=cut
+
+sub save {
+    my ($request) = @_;
+    my $budget = LedgerSMB::DBObject::Budget->new({base => $request});
+    for my $rownum (1 .. $request->{rowcount}){
+         my $line = {};
+         $request->{"debit_$rownum"} = $request->parse_amount(
+                    amount => $request->{"debit_$rownum"}
+         );
+         $request->{"debit_$rownum"} = $request->format_amount(
+                    {amount => $request->{"debit_$rownum"}, format => '1000.00'}
+         );
+         $request->{"credit_$rownum"} = $request->parse_amount(
+                    amount => $request->{"credit_$rownum"}
+         );
+         $request->{"credit_$rownum"} = $request->format_amount(
+                   {amount => $request->{"credit_$rownum"}, format => '1000.00'}
+         );
+         if ($request->{"debit_$rownum"} and $request->{"credit_$rownum"}){
+             $request->error($request->{_locale}->text(
+                 'Cannot specify both debits and credits for budget line [_1]',
+                 $rownum
+             )); 
+         } elsif(!$request->{"debit_$rownum"} and !$request->{"credit_$rownum"}){
+             next;
+         } else {
+             $line->{amount} = $request->{"credit_$rownum"} 
+                             - $request->{"debit_$rownum"};
+         }
+         my ($accno) = split /--/, $request->{"account_id_$rownum"};
+         my ($ref) = $request->call_procedure(
+                       procname => 'account__get_from_accno',
+                           args => [$accno]
+          );
+         $line->{description} = $request->{"description_$rownum"};
+         $line->{account_id} = $ref->{id};
+         push @{$budget->{lines}}, $line;
+    }
+    $budget->save();
+    view_budget($budget); 
+} 
+
+=item approve
+Requires id.  Approves the budget.
+
+=cut
+
+sub approve {
+    my ($request) = @_;
+    my $budget = LedgerSMB::DBObject::Budget->new(%$request);
+    $budget->approve;
+    view_budget($request);
+} 
+
+=item reject
+Requires id.  Rejects unapproved budget and deletes it.
+
+=cut
+
+sub reject {
+    my ($request) = @_;
+    my $budget = LedgerSMB::DBObject::Budget->new(%$request);
+    $budget->reject;
+    begin_search($request);
+} 
+
+=item obsolete
+Requires id, Marks budget obsolete.
+
+=cut
+
+sub obsolete {
+    my ($request) = @_;
+    my $budget = LedgerSMB::DBObject::Budget->new(%$request);
+    $budget->obsolete;
+    view_budget($request);
+} 
+
+=item add_note
+Requires id, subject, and note.  Adds a note to the budget.
+
+=cut
+
+sub add_note {
+    my ($request) = @_;
+    my $budget = LedgerSMB::DBObject::Budget->new(%$request);
+    $budget->save_note($request->{subject}, $request->{note});
+    view_budget($request);
+} 
+
+=item begin_search
+No inputs expected or used
+
+=cut
+
+sub begin_search{
+    my ($request) = @_;
+    my $budget = LedgerSMB::DBObject::Budget->new(%$request);
+    @{$budget->{projects}} = $budget->list_projects;
+    unshift @{$budget->{projects}}, {};
+    @{$budget->{departments}} = $budget->list_departments;
+    unshift @{$budget->{departments}}, {};
+    my $template = LedgerSMB::Template->new(
+        user     => $request->{_user},
+        locale   => $request->{_locale},
+        path     => 'UI/budgetting',
+        template => 'search_criteria',
+        format   => 'HTML'
+    );
+
+    $template->render($budget);
+}
+
+1;
+
+=item search
+See LedgerSMB::Budget's search routine for expected inputs.
+
+=cut
+
+sub search {
+    my ($request)  = @_;
+    my $budget = LedgerSMB::DBObject::Budget->new({base => $request});
+    my @rows = $budget->search;
+    my $cols = ['start_date',
+                'end_date',
+                'reference',
+                'description',
+                'entered_by_name',
+                'approved_by_name',
+                'obsolete_by_name',
+                'department_name',
+                'project_number',
+    ];
+    my $heading = {
+                      start_date => $budget->{_locale}->text('Start Date'),
+                        end_date => $budget->{_locale}->text('End Date'),
+                       reference => $budget->{_locale}->text('Reference'),
+                     description => $budget->{_locale}->text('Description'),
+                 entered_by_name => $budget->{_locale}->text('Entered by'),
+                approved_by_name => $budget->{_locale}->text('Approved By'),
+                obsolete_by_name => $budget->{_locale}->text('Obsolete By'),
+                 department_name => $budget->{_locale}->text('Department'),
+                  project_number => $budget->{_locale}->text('Project'),
+    };
+
+    my $base_url = 'budgets.pl';
+
+    for my $row (@rows){
+           $row->{reference} = { href => $base_url 
+                                         . '?action=view_budget'
+                                         . '&id=' . $row->{id},
+                                 text => $row->{reference},
+                               };
+           $row->{start_date} = { href => $base_url
+                                          . '?action=variance_report'
+                                          . '&id=' . $row->{id},
+                                   text => $row->{start_date},
+                                 };
+           $row->{end_date} = { href => $row->{start_date}->{href},
+                                text => $row->{end_date}
+                              };
+
+    }
+    my $template = LedgerSMB::Template->new(
+        user     => $request->{_user},
+        locale   => $request->{_locale},
+        path     => 'UI',
+        template => 'form-dynatable',
+        format   => ($budget->{format}) ? $budget->{format} : 'HTML',
+    );
+    $template->render({
+           form => $budget,
+        columns => $cols,
+           rows => ..hidden..,
+        heading => $heading,
+    });
+}
+
+=back
+
+=head1 SEE ALSO
+
+=over
+
+=item LedgerSMB::DBObject::Budget
+=item LedgerSMB::DBObject::Budget_Report
+
+=back
+
+=head1 COPYRIGHT AND LICENSE
+
+Copyright (C) 2011 LedgerSMB Core Team.  This file is licensed under the GNU 
+General Public License version 2, or at your option any later version.  Please
+see the included License.txt for details.
+

Added: trunk/UI/budgetting/budget_entry.html
===================================================================
--- trunk/UI/budgetting/budget_entry.html	                        (rev 0)
+++ trunk/UI/budgetting/budget_entry.html	2012-05-21 10:19:27 UTC (rev 4743)
@@ -0,0 +1,236 @@
+<?lsmb INCLUDE 'ui-header.html' 
+	include_script = [
+		"UI/ajax/scriptaculous/lib/prototype.js",
+		"UI/ajax/scriptaculous/src/scriptaculous.js?load=builder,effects,dragdrop,controls",
+		"UI/ajax/helpers.js"]
+	stylesheet=stylesheet 
+        include_stylesheet = ["UI/budgetting/budgetting.css"];
+    PROCESS elements.html; ?>
+<body>
+
+<form method="post" action="<?lsmb script ?>">
+<div id="budget-header">
+<div class="listtop"><?lsmb title ?></div>
+<div class="input_row" id = "reference_row">
+<div class="input_group">
+       <?lsmb INCLUDE input element_data = {
+			name = "reference",
+			value = reference,
+			type = "text",
+			size = "20",
+			class = 'reference',
+			label = text('Reference')
+	} ?>
+</div>
+<div class="input_group">
+	  <?lsmb INCLUDE input element_data = {
+			      name = "description",
+			      value = description,
+			      type = "text",
+			      size = "50",
+			      class = 'description'
+			      label = text('Description')
+								      } 
+	   ?>
+</div></div>
+<div class="input_row" id = "date_row">
+<div class="input_group">
+        <?lsmb INCLUDE input element_data = {
+		name = "start_date"
+		value = start_date
+		type = "text"
+		size = "11"
+		class = 'date'
+		label = text('Start Date') #'
+        } ?>
+</div>
+<div class="input_group">
+        <?lsmb INCLUDE input element_data = {
+                name = "end_date"
+                value = end_date
+                type = "text"
+                size = "11"
+                class = 'date'
+                label = text('End Date') #'
+        } ?>
+</div>
+
+</div></div>
+
+<?FOREACH BUC IN bu_classes ?>
+<div class="inputrow"><div class="inputgroup">
+          <?lsmb PROCESS select element_data = {
+                   name = 'business_unit_' _ loop.count
+                options = b_units.${BUC.id}
+              text_attr = 'text'
+             value_attr = 'id'
+                  class = 'business_unit'
+                  label = text(BUC.label)
+              } ?>
+</div></div>
+<?lsmb END # FOREACH BUC ?>
+
+         <!-- Move notes to bottom and add subject line 
+	<tr>
+	  <th align="right"><?lsmb text('Notes') ?></th>
+	  <td colspan="3">
+			<?lsmb IF colrownotes ==1 ?>
+			      <?lsmb INCLUDE textarea element_data={
+							name = "notes"
+							rows = form.rowsnotes
+							cols = form.colsnotes
+							value = form.notes
+							id = "not_1"
+                                                 	    } 
+			       ?>
+			<?lsmb ELSE ?>
+				  <?lsmb INCLUDE input element_data = {
+						      name = "notes",
+						      value = form.notes,
+						      type = "text",
+						      size = "50",
+						      class = 'notes'
+						      id = "not_1"
+                                                          } 
+				   ?>
+
+			<?lsmb END ?>
+
+
+	  </td>
+	</tr> -->
+      <table width="100%">
+	  <tr class="listheading">
+	  <th class="listheading"><?lsmb text('Account') ?></th>
+	  <?lsmb IF transfer == 1 ?>
+	     <th class="listheading"><?lsmb text('FX') ?></th>
+	  <?lsmb END ?>
+          <th class="listheading"><?lsmb text('Debit') ?></th>
+	  <th class="listheading"><?lsmb text('Credit') ?></th>
+	  <th class="listheading"><?lsmb text('Description') ?></th>
+	</tr>
+	<?lsmb FOREACH displayrow IN display_rows ?> 
+	<tr>
+		<?lsmb INDEX= loop.count ?>
+		  <td>
+			<?lsmb IF displayrow.accnoset == 0 ?>
+              			<?lsmb PROCESS ajaxselect element_data = {
+		                     name = "account_id_$INDEX"
+		                     initial_value = ${"accno_$INDEX"}
+		                     text_attr = 'accno'
+		                     value_attr = 'id'
+		                     ajax_target = 'journal.pl'
+		              } ?> 
+			   
+			  <?lsmb ELSE ?>
+			      
+				      <?lsmb PROCESS input element_data = {
+					label = displayrow.account_id
+                                        type = "hidden"
+                                        value = displayrow.account_id
+                                        name = "account_id_$INDEX"
+					id = "acc_$INDEX"
+				      } ?>
+			      
+
+			<?lsmb END ?> 
+	  
+		 </td>
+	      
+		  <td>
+			  <?lsmb PROCESS input element_data = {
+				  value = displayrow.debit
+				  name = "debit_$INDEX"
+				  type = "text"
+				  size = 12
+				  accesskey = displayrow.index
+                                              }  ?>
+		  
+		   </td>
+
+		  <td>
+			  <?lsmb PROCESS input element_data = {
+				  value = displayrow.credit
+				  name = "credit_$INDEX"
+				  type = "text"
+				  size = 12
+                                      }  ?>
+		  
+		   </td>
+
+		    <td>
+			  <?lsmb PROCESS input element_data = {
+				  value = displayrow.description
+				  name = "description_$INDEX"
+				  type = "text"
+				  size = 30
+                                     }  ?>
+		  
+		   </td>
+        </tr>
+	<?lsmb END ?>
+     </table>
+    <hr size="3">
+
+<?lsmb FOREACH hidden IN hiddens.keys;
+	PROCESS input element_data={
+		type = 'hidden',
+		name = hidden,
+		value = hiddens.item(hidden)
+		}; END ?>
+
+<?lsmb FOREACH button IN buttons; PROCESS button element_data=button; END ?>
+</form>
+<?lsmb IF id ?>
+<form name="note" action="<?lsmb script ?>" method="POST">
+<?lsmb PROCESS input element_data = {
+       name = "id"
+      value = id
+       type = "hidden"
+} ?>
+<div class="inputrow">
+<div class="inputgroup">
+<?lsmb PROCESS input element_data = {
+        type = "text"
+        name = "subject"
+        size = "64"
+       label = text('Subject')
+}
+?>
+</div></div>
+<div class="inputrow">
+<div class="inputgroup">
+<?lsmb PROCESS textarea element_data = {
+        name = "note"
+        cols = '64'
+        rows = '5'
+       label = text('Content')
+}
+?>
+</div></div>
+<div class="inputrow">
+<div class="inputgroup">
+<?lsmb PROCESS button element_data = {
+        name = "action"
+       value = 'add_note'
+        type = "submit"
+       class = "submit"
+        text = text('Add Note') #'
+}
+?>
+</div></div>
+</form>
+<?lsmb END # IF id ?>
+<?lsmb FOREACH note IN notes ?>
+<div class="note">
+<div class="note_subject"><label><?lsmb text('Subject') ?>:</label>
+<?lsmb note.subject ?></div>
+<div class="note_entry_info"><label>&nbsp;:</label>
+<?lsmb note.created_by ?>:<?lsmb note.created ?>
+</div>
+<div class="note_content"><label><?lsmb text('Content') ?>:</label>
+<?lsmb note.note ?>
+</div>
+<?lsmb END # FOREACH Note ?>
+</body>
+</html>

Added: trunk/UI/budgetting/budgetting.css
===================================================================
--- trunk/UI/budgetting/budgetting.css	                        (rev 0)
+++ trunk/UI/budgetting/budgetting.css	2012-05-21 10:19:27 UTC (rev 4743)
@@ -0,0 +1,14 @@
+div.input_row {
+    overflow: auto;
+}
+div.input_group {
+    float: left;
+    width: 35em;
+}
+
+div label {
+    text-align: right;
+    width: 5em;
+    display: block;
+    float: left;
+}

Added: trunk/UI/budgetting/search_criteria.html
===================================================================
--- trunk/UI/budgetting/search_criteria.html	                        (rev 0)
+++ trunk/UI/budgetting/search_criteria.html	2012-05-21 10:19:27 UTC (rev 4743)
@@ -0,0 +1,87 @@
+<?lsmb INCLUDE 'ui-header.html' 
+	stylesheet=stylesheet 
+        include_stylesheet = ["UI/budgetting/budgetting.css"] ?>
+<?lsmb PROCESS elements.html ?> 
+<body>
+<form action="<?lsmb script ?>" method="get">
+<div class="listtop"><?lsmb title ?></div>
+<div class="input_row" id = "reference_row">
+<div class="input_group">
+       <?lsmb INCLUDE input element_data = {
+			name = "reference",
+			value = reference,
+			type = "text",
+			size = "20",
+			class = 'reference',
+			label = text('Reference')
+	} ?>
+</div>
+<div class="input_group">
+	  <?lsmb INCLUDE input element_data = {
+			      name = "description",
+			      value = description,
+			      type = "text",
+			      size = "50",
+			      class = 'description'
+			      label = text('Description')
+								      } 
+	   ?>
+</div></div>
+<div class="input_row" id = "date_row">
+<div class="input_group">
+        <?lsmb INCLUDE input element_data = {
+		name = "start_date"
+		value = start_date
+		type = "text"
+		size = "11"
+		class = 'date'
+		label = text('Start Date') #'
+        } ?>
+</div>
+<div class="input_group">
+        <?lsmb INCLUDE input element_data = {
+                name = "end_date"
+                value = end_date
+                type = "text"
+                size = "11"
+                class = 'date'
+                label = text('End Date') #'
+        } ?>
+</div>
+
+</div></div>
+<div class="input_row" id = "description_row">
+<div class="input_group">
+	    <?lsmb INCLUDE select element_data = {
+			text_attr = "description"
+			value_attr = "id"
+			default_values = [department_id]
+			options = departments
+			name = "department_id"
+                        label = text('Department')
+	    } ?>
+
+</div>
+<div class="input_group">
+	    <?lsmb INCLUDE select element_data = {
+			text_attr = "description"
+			value_attr = "id"
+			default_values = [project_id]
+			options = projects
+			name = "project_id"
+                        label = text('Project')
+	    } ?>
+
+</div></div>
+<div class="input_row" id = "button_row">
+<?lsmb PROCESS button element_data = {
+        text = text('Search')
+       value = 'search'
+        name = 'action'
+        type = 'submit'
+       class = 'submit'
+} ?>
+</div>
+</form>
+</body>
+</html>

Copied: trunk/budgets.pl (from rev 4729, trunk/recon.pl)
===================================================================
--- trunk/budgets.pl	                        (rev 0)
+++ trunk/budgets.pl	2012-05-21 10:19:27 UTC (rev 4743)
@@ -0,0 +1,8 @@
+#!/usr/bin/perl
+
+use FindBin;
+BEGIN {
+  lib->import($FindBin::Bin) unless $ENV{mod_perl}
+}
+
+require 'lsmb-request.pl';

This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.