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

SF.net SVN: ledger-smb:[2812] addons/1.3



Revision: 2812
          http://ledger-smb.svn.sourceforge.net/ledger-smb/?rev=2812&view=rev
Author:   einhverfr
Date:     2009-12-10 20:42:23 +0000 (Thu, 10 Dec 2009)

Log Message:
-----------
The following fixes are included:
1)  Separate field to store when depreciation starts
2)  Searching on assets now works
3)  Leap year on annual depreciation problems solved (and test cases added)
4)  Basic refactoring of depreciation logic complete (UI to follow probably today)

Modified Paths:
--------------
    addons/1.3/assets/trunk/LedgerSMB/DBObject/Asset.pm
    addons/1.3/assets/trunk/UI/asset/edit_asset.html
    addons/1.3/assets/trunk/UI/asset/search_asset.html
    addons/1.3/assets/trunk/scripts/asset.pl
    addons/1.3/assets/trunk/sql/modules/Assets-tables.sql
    addons/1.3/assets/trunk/sql/modules/Assets.sql
    addons/1.3/base/trunk/sql/modules/Util.sql

Added Paths:
-----------
    addons/1.3/base/trunk/sql/modules/test/
    addons/1.3/base/trunk/sql/modules/test/Util.sql
    addons/1.3/base/trunk/t/
    addons/1.3/base/trunk/t/43-dbtest-utils.t

Modified: addons/1.3/assets/trunk/LedgerSMB/DBObject/Asset.pm
===================================================================
--- addons/1.3/assets/trunk/LedgerSMB/DBObject/Asset.pm	2009-12-09 17:05:21 UTC (rev 2811)
+++ addons/1.3/assets/trunk/LedgerSMB/DBObject/Asset.pm	2009-12-10 20:42:23 UTC (rev 2812)
@@ -33,9 +33,9 @@
     return $ref;
 }
 
-sub search_assets {
+sub search {
     my ($self) = @_;
-    my @results = $self->exec_method(funcname => 'asset__search');
+    my @results = $self->exec_method(funcname => 'asset_item__search');
     $self->{search_results} = ..hidden..;
     return @results;
 }

Modified: addons/1.3/assets/trunk/UI/asset/edit_asset.html
===================================================================
--- addons/1.3/assets/trunk/UI/asset/edit_asset.html	2009-12-09 17:05:21 UTC (rev 2811)
+++ addons/1.3/assets/trunk/UI/asset/edit_asset.html	2009-12-10 20:42:23 UTC (rev 2812)
@@ -103,11 +103,23 @@
 } ?>
 </span>
 </div>
+<div class="inputrow" id="startdeprow">
+<span class="inputgroup" id="startdepgroup">
+<?lsmb PROCESS input element_data = {
+	label = text("Depreciation Starts") #"
+	name = "start_depreciation"
+	value = start_depreciation
+	type = "text"
+	size = 12
+        class = "date"
+} ?>
+</span>
+</div>
 <div class="inputrow" id="business_row">
 <span class="inputgroup" id="locationgroup">
 <?lsmb PROCESS select element_data = {
 	name = "warehouse_id"
-	options = warehouses
+	options = locations
 	value_attr = "id"
 	text_attr = "description"
 	default_values = [warehouse_id]

Modified: addons/1.3/assets/trunk/UI/asset/search_asset.html
===================================================================
--- addons/1.3/assets/trunk/UI/asset/search_asset.html	2009-12-09 17:05:21 UTC (rev 2811)
+++ addons/1.3/assets/trunk/UI/asset/search_asset.html	2009-12-10 20:42:23 UTC (rev 2812)
@@ -1,7 +1,34 @@
-<?lsmb INCLUDE 'ui-header.html' ?>
+<?lsmb INCLUDE 'ui-header.html' 
+      include_stylesheet = ["UI/asset/asset.css"] 
+?>
 <?lsmb PROCESS 'elements.html' ?>
-<div class="listtop"><?lsmb text('Search Assets') ?></div>
+<body>
+<div class="listtop"><?lsmb title ?></div>
 <form action="<?lsmb script ?>" method="post">
+<!-- These are for Javascript automation of defaults -CT -->
+<?lsmb PROCESS input element_data = {
+	type = "hidden"
+	name = "id"
+	value = id
+} ?>
+<?lsmb FOREACH a_class IN asset_classes -?>
+<?lsmb PROCESS input element_data = {
+       type = "hidden",
+       name = "asset_account_default_$a_class.id",
+       value = a_class.asset_account_id,
+} ?>
+<?lsmb PROCESS input element_data = {
+       type = "hidden",
+       name = "dep_account_default_$a_class.id",
+       value = a_class.dep_account_id,
+} ?>
+<?lsmb- END # For a_class ?>
+<?lsmb PROCESS input element_data = {
+       type = "hidden"
+       name = "last_class_id"
+       value = asset_class
+} ?>
+<!-- end set for javascript automation -CT -->
 <div class="inputrow" id="tagrow">
 <?lsmb PROCESS input element_data = {
 	type = "text"
@@ -9,10 +36,11 @@
 	name = "tag"
 	value = tag
 	label = text('Tag:')
+	size = 32
 } ?>
+</div>
 <div class="inputrow" id="classrow">
-<?lsmb asset_classes.push({});
-	PROCESS select element_data = {
+<?lsmb PROCESS select element_data = {
 	name = "asset_class"
 	class = "class"
 	options = asset_classes
@@ -30,6 +58,7 @@
 	value = description
 	type = "text"
 } ?>
+</div>
 <div class="inputrow" id="purchaserow">
 <span class="inputgroup" id="purchasedategroup">
 <?lsmb PROCESS input element_data = {
@@ -38,6 +67,7 @@
 	class = "date"
 	value = purchase_date
 	type = "text"
+	size = 12
 } ?>
 </span>
 <span class="inputgroup" id="purchasevaluegroup">
@@ -47,6 +77,7 @@
 	class = "money"
 	value = purchase_value
 	type = "text"
+	size = 16
 } ?>
 </span>
 </div>
@@ -57,6 +88,7 @@
 	name = "usable_life"
 	value = usable_life
 	type = "text"
+	size = 10
 } ?>
 </span>
 <span class="inputgroup" id="salvagevaluegroup">
@@ -66,17 +98,88 @@
 	class = "money"
 	value = salvage_value
 	type = "text"
+	size = 16
 } ?>
 </span>
-<span class="inputgroup" id="usablelifegroup">
+</div>
+<div class="inputrow" id="startdeprow">
+<span class="inputgroup" id="startdepgroup">
 <?lsmb PROCESS input element_data = {
-	label = text("Usable Life:") #"
-	name = "usable_life"
-	class = "money"
-	value = usable_life
+	label = text("Depreciation Starts") #"
+	name = "start_depreciation"
+	value = start_depreciation
 	type = "text"
+	size = 12
+        class = "date"
 } ?>
+</span>
 </div>
+<div class="inputrow" id="business_row">
+<span class="inputgroup" id="locationgroup">
+<?lsmb PROCESS select element_data = {
+	name = "warehouse_id"
+	options = locations
+	value_attr = "id"
+	text_attr = "description"
+	default_values = [warehouse_id]
+	label = text('Location')
+} ?>
+</span>
+<span class="inputgroup" id="departmentgroup">
+<?lsmb PROCESS select element_data = {
+	name = "department_id"
+	options = departments
+	value_attr = "id"
+	text_attr = "description"
+	default_values = [department_id]
+	label = text('Department')
+} ?>
+</span>
+</div>
+<div class="inputrow" id="accountsrow">
+<span class="inputgroup" id="assetaccgroup">
+<?lsmb PROCESS select element_data = {
+	label = text('Asset Account') #'
+	options = asset_accounts
+	name = "asset_account_id"
+	default_values = [asset_account_id]
+	value_attr = 'id'
+	text_attr = 'text'
+} ?>
+</span>
+<span class="inputgroup" id="depaccgroup">
+<?lsmb PROCESS select element_data = {
+	label = text('Depreciation Account') #'
+	options = dep_accounts
+	name = "dep_account_id"
+	default_values = [dep_account_id]
+	value_attr = 'id'
+	text_attr = 'text'
+} ?>
+</span>
+</div>
+<div class="inputrow" id="invoicerow">
+<span class="inputgroup" id="vendorgroup">
+<?lsmb PROCESS input element_data = {
+	label = text('Vendor Number') #'
+	type = "text"
+	class = "identifier"
+	size = 20
+	value = meta_number
+	name = "meta_number"
+} ?>
+</span>
+<span class="inputgroup" id="invgroup">
+<?lsmb PROCESS input element_data = {
+	label = text('Invoice Number') #'
+	type = "text"
+	class = "identifier"
+	size = 20
+	value = invnumber
+	name = "invnumber"
+} ?>
+</span>
+</div>
 <div class="inputrow" id="buttonrow">
 <?lsmb PROCESS button element_data = {
 	text = text("Search")

Modified: addons/1.3/assets/trunk/scripts/asset.pl
===================================================================
--- addons/1.3/assets/trunk/scripts/asset.pl	2009-12-09 17:05:21 UTC (rev 2811)
+++ addons/1.3/assets/trunk/scripts/asset.pl	2009-12-10 20:42:23 UTC (rev 2812)
@@ -63,7 +63,6 @@
     my @classes = $ac->list_asset_classes();
     my $locale = $request->{_locale};
     $ac->get_metadata;
-    $ac->debug({file => '/tmp/aclass'});
     my $template = LedgerSMB::Template->new(
         user =>$request->{_user}, 
         locale => $request->{_locale},
@@ -123,6 +122,7 @@
     if (!$asset->{tag}){
         $asset->get_next_tag;
     }
+    $asset->debug({file => '/tmp/asset'});
     $asset->{title} = $request->{_locale}->text('Add Asset') 
                  unless $asset->{title};
     my $template = LedgerSMB::Template->new(
@@ -135,6 +135,68 @@
     $template->render($asset);
 }
 
+sub asset_results { 
+    my ($request) = @_;
+    my $locale = $request->{_locale};
+    my $asset = LedgerSMB::DBObject::Asset->new(base => $request);
+    $asset->get_metadata;
+    if (!$asset->{usable_life}){
+       delete $asset->{usable_life};
+    }
+    my @items = $asset->search();
+    my $columns = ['tag', 'description', 'class', 'purchase_date', 
+                  'purchase_value', 'usable_life', 'location', 'department'];
+    my $heading = { tag            => $locale->text('Tag'),
+                    description    => $locale->text('Description'),
+                    purchase_date  => $locale->text('Purchase Date'),
+                    purchase_value => $locale->text('Purchase Value'),
+                    class          => $locale->text('Class'),
+                    usable_life    => $locale->text('Usable Life'),
+                    location       => $locale->text('Location'),
+                    department     => $locale->text('Department'),
+    };
+    my $asset_classes = {};
+    for my $ac(@{$asset->{asset_classes}}){
+        $asset_classes->{$ac->{id}} = $ac;
+    }
+    my $departments = {};
+    for my $dept(@{$asset->{departments}}){
+        $departments->{$dept->{id}} = $dept;
+    }
+    my $locations = {};
+    for $loc(@{$asset->{asset_classes}}){
+        $locations->{$loc->{id}} = $loc;
+    }
+    my $rows = [];
+    for my $item (@items){
+        my $ref = {};
+        for my $label (qw(id tag description purchase_date purchase_value 
+                   usable_life)){
+            $ref->{$label} = $item->{$label};
+        }
+        for my $label (qw(purchase_value usable_life)){
+            $ref->{$label} = $asset->format_amount({amount => $ref->{$label}});
+        }
+        $ref->{class} = $asset_classes->{$item->{asset_class_id}}->{label};
+        $ref->{department} 
+          = $departments->{$item->{department_id}}->{description};
+        $ref->{location} = $locations->{$item->{location_id}}->{description};
+        push @$rows, $ref;
+    }
+    my $template = LedgerSMB::Template->new(
+        user =>$request->{_user}, 
+        locale => $request->{_locale},
+        path => 'UI',
+        template => 'form-dynatable',
+        format => 'HTML'
+    );
+    $template->render({
+         form    => $asset,
+         heading => $heading,
+         rows    => $rows,
+         columns => $columns,
+   });
+}
 sub asset_save {
     my ($request) = @_;
     my $asset = LedgerSMB::DBObject::Asset->new(base => $request);
@@ -153,6 +215,13 @@
 
 sub asset_search {
     my ($request) = @_;
+    my $asset = LedgerSMB::DBObject::Asset->new(base => $request);
+    $asset->get_metadata;
+    unshift @{$asset->{asset_classes}}, {}; 
+    unshift @{$asset->{locations}}, {}; 
+    unshift @{$asset->{departments}}, {}; 
+    unshift @{$asset->{asset_accounts}}, {}; 
+    unshift @{$asset->{dep_accounts}}, {}; 
     my $template = LedgerSMB::Template->new(
         user =>$request->{_user}, 
         locale => $request->{_locale},
@@ -160,13 +229,9 @@
         template => 'search_asset',
         format => 'HTML'
     );
-    $template->render($request);
+    $template->render($asset);
 }
 
-sub asset_results {
-    my ($request) = @_;
-}
-
 sub new_report {
     my ($request) = @_;
     my $report = LedgerSMB::DBObject::Asset_Report->new(base => $request);

Modified: addons/1.3/assets/trunk/sql/modules/Assets-tables.sql
===================================================================
--- addons/1.3/assets/trunk/sql/modules/Assets-tables.sql	2009-12-09 17:05:21 UTC (rev 2811)
+++ addons/1.3/assets/trunk/sql/modules/Assets-tables.sql	2009-12-10 20:42:23 UTC (rev 2812)
@@ -18,8 +18,11 @@
 $$ These are keyed to specific stored procedures.  Currently only "straight_line" is supported$$;
 
 INSERT INTO asset_dep_method(method, unit_class, sproc) 
-values ('Straight Line', 1, 'asset_dep_straight_line');
+values ('Annual Straight Line', 1, 'asset_dep_straight_line_yr');
 
+INSERT INTO asset_dep_method(method, unit_class, sproc) 
+values ('Whole Month Straight Line', 1, 'asset_dep_straight_line_whl_m');
+
 CREATE TABLE asset_class (
 	id serial not null unique,
 	label text primary key,
@@ -41,6 +44,7 @@
 	salvage_value numeric,
 	usable_life numeric,
 	purchase_date date  not null,
+        start_depreciation date not null,
 	location_id int references warehouse(id),
 	department_id int references department(id),
 	invoice_id int references ap(id),

Modified: addons/1.3/assets/trunk/sql/modules/Assets.sql
===================================================================
--- addons/1.3/assets/trunk/sql/modules/Assets.sql	2009-12-09 17:05:21 UTC (rev 2811)
+++ addons/1.3/assets/trunk/sql/modules/Assets.sql	2009-12-10 20:42:23 UTC (rev 2812)
@@ -1,51 +1,20 @@
-CREATE OR REPLACE FUNCTION asset_dep__straight_line
-(in_report_id int, in_asset_id int)
+CREATE OR REPLACE FUNCTION asset_dep__straight_line_base
+(in_life numeric, in_used numeric, in_basis numeric)
 returns numeric as $$
-DECLARE 
-	annual_amount numeric;
-	depreciation_interval interval;
-	depreciation_years numeric;
-	retval numeric;
-	value_left numeric;
-	depreciation_amount numeric;
-BEGIN
-	SELECT (purchase_amount - salvage_amount) / usable_life::numeric  
-	INTO annual_amount 
-	FROM asset_item 
-	WHERE id = in_asset_id;
+SELECT in_life/in_used * basis;
+$$ language sql;
 
-	SELECT purchase_amount - salvage_amount - sum(amount) 
-	INTO value_left
-	FROM asset_item i 
-	JOIN asset_report_line l ON (i.id = l.asset_id)
-	GROUP BY puchase_amount, salvage_amount;
+CREATE OR REPLACE FUNCTION asset_dep__used_months
+(in_last_dep date, in_dep_date date, in_total_used numeric, in_usable_life numeric)
+RETURNS numeric AS
+$$
+select CASE WHEN extract('MONTHS' FROM (in_dep_date - in_last_date)) 
+                 > in_usable_life
+            THEN in_usable_life
+            ELSE extract('MONTHS' FROM (in_dep_date - in_last_date))
+            END;
+$$ language sql;
 
-	SELECT (select report_date FROM asset_report where id = in_id) - 
-		CASE WHEN report_date > purchase_date THEN report_date
-	             ELSE purchase_date END
-	INTO depreciation_interval
-	FROM asset_item i 
-	LEFT JOIN asset_report_line l ON (i.id = l.asset_id)
-	LEFT JOIN asset_report r ON (l.report_id = r.id)
-	WHERE r.approved IS NULL OR r.approved IS TRUE
-	ORDER BY r.report_date limit 1;
-
-	depreciation_years := extract('years' from depreciation_interval);
-	depreciation_years := depreciation_years + 
-                              extract('months' from depreciation_interval) / 12;
-	depreciation_years := depreciation_yers +
-                              extract('days' from depreciation_interval) / 365;
-
-	depreciation_amount := annual_amount * depreciation_years;
-
-	INSERT INTO asset_report_line (asset_id, report_id, amount)
-	VALUES (in_asst_id, in_report_id, depreciation_amount);
-
-	PERFORM asset_report__generate_gl(in_report_id);
-	RETURN NULL;
-end;	
-$$ language plpgsql;
-
 CREATE OR REPLACE FUNCTION asset_report__generate_gl(in_report_id int)
 RETURNS INT AS
 $$
@@ -244,7 +213,8 @@
 CREATE OR REPLACE FUNCTION asset__save
 (in_id int, in_asset_class int, in_description text, in_tag text, 
 in_purchase_date date, in_purchase_value numeric,
-in_usable_life numeric, in_salvage_value numeric, in_warehouse_id int, 
+in_usable_life numeric, in_salvage_value numeric, 
+in_start_depreciation date, in_warehouse_id int, 
 in_department_id int, in_invoice_id int, 
 in_asset_account_id int, in_dep_account_id int)
 returns asset_item AS
@@ -263,6 +233,8 @@
 		invoice_id = in_invoice_id,
 		salvage_value = in_salvage_value,
                 asset_account_id = in_asset_account_id,
+                start_depreciation = 
+                         coalesce(in_start_depreciation, in_purchase_date),
                 dep_account_id = in_dep_account_id
 	WHERE id = in_id;
 	IF FOUND THEN
@@ -272,11 +244,13 @@
 
 	INSERT INTO asset_item (asset_class_id, description, tag, purchase_date,
 		purchase_value, usable_life, salvage_value, department_id,
-		location_id, invoice_id, asset_account_id, dep_account_id)
+		location_id, invoice_id, asset_account_id, dep_account_id,
+                start_depreciation)
 	VALUES (in_asset_class, in_description, in_tag, in_purchase_date,
 		in_purchase_value, in_usable_life, in_salvage_value,
 		in_department_id, in_warehouse_id, in_invoice_id,
-                in_asset_account_id, in_dep_account_id);
+                in_asset_account_id, in_dep_account_id,
+                coalesce(in_start_depreciation, in_purchase_date));
 
 	SELECT * INTO ret_val FROM asset_item 
 	WHERE id = currval('asset_item_id_seq');
@@ -284,6 +258,44 @@
 END;
 $$ language plpgsql;
 
+CREATE OR REPLACE FUNCTION asset_item__search
+(in_id int, in_asset_class int, in_description text, in_tag text, 
+in_purchase_date date, in_purchase_value numeric,
+in_usable_life numeric, in_salvage_value numeric, 
+in_start_depreciation date, in_warehouse_id int, 
+in_department_id int, in_invoice_id int, 
+in_asset_account_id int, in_dep_account_id int)
+returns setof asset_item as
+$$
+DECLARE retval asset_item;
+BEGIN
+    FOR retval IN
+         SELECT * FROM asset_item
+          WHERE (id = in_id or in_id is null)
+                and (asset_class_id = in_asset_class or in_asset_class is null)
+                and (description like '%'||in_description||'%'
+                     or in_description is null)
+                and (tag like '%' || in_tag || '%' or in_tag is null)
+                and (purchase_value = in_purchase_value 
+                    or in_purchase_value is null)
+                and (in_purchase_date = purchase_date 
+                    or in_purchase_date is null)
+                and (start_depreciation = in_start_depreciation
+                    or in_start_depreciation is null)
+                and (in_warehouse_id = location_id OR in_warehouse_id is null)
+                and (department_id = in_department_id 
+                    or in_department_id is null)
+                and (in_invoice_id = invoice_id OR in_invoice_id IS NULL)
+                and (asset_account_id = in_asset_account_id
+                    or in_asset_account_id is null)
+                and (dep_account_id = in_dep_account_id
+                    or in_dep_account_id is null)
+   LOOP
+       return next retval;
+   end loop;
+END;
+$$ language plpgsql;
+
 CREATE OR REPLACE FUNCTION asset_report__save
 (in_id int, in_asset_class int, in_report_date date, in_report_class int,
 in_submit bool, in_asset_items int[])

Modified: addons/1.3/base/trunk/sql/modules/Util.sql
===================================================================
--- addons/1.3/base/trunk/sql/modules/Util.sql	2009-12-09 17:05:21 UTC (rev 2811)
+++ addons/1.3/base/trunk/sql/modules/Util.sql	2009-12-10 20:42:23 UTC (rev 2812)
@@ -8,6 +8,77 @@
 SELECT * FROM warehouse order by description;
 $$ language sql;
 
+CREATE OR REPLACE FUNCTION is_leapyear(in_date date) returns bool as
+$$
+    select extract('day' FROM (
+                           (extract('year' FROM $1)::text 
+                           || '-02-28')::date + '1 day'::interval)::date) 
+           = 29;
+$$ language sql;
+
+CREATE OR REPLACE FUNCTION leap_days(in_year_from int, in_year_to int)
+RETURNS int AS
+$$
+   SELECT count(*)::int
+   FROM generate_series($1, $2)
+   WHERE is_leapyear((generate_series::text || '-01-01')::date);
+$$ LANGUAGE SQL;
+
+CREATE OR REPLACE FUNCTION next_leap_year_calc(in_date date, is_end bool)
+returns int as
+$$
+SELECT 
+          (CASE WHEN extract('doy' FROM $1) < 59
+          THEN extract('year' FROM $1)
+          ELSE extract('year' FROM $1) + 1
+          END)::int
+          -
+          CASE WHEN $2 THEN 1 ELSE 0 END;
+$$ LANGUAGE SQL;
+
+CREATE OR REPLACE FUNCTION get_fractional_year 
+(in_date_from date, in_date_to date)
+RETURNS numeric AS
+$$
+   select ($2 - $1
+            - leap_days(next_leap_year_calc($1, false), 
+                       next_leap_year_calc($2, true)))
+            /365::numeric;
+$$ LANGUAGE SQL;
+
+CREATE OR REPLACE FUNCTION days_in_month(in_date date)
+returns int AS
+$$
+SELECT (extract(DOM FROM date_trunc('month', $1)
+                         + '1 month - 1 second'::interval)
+      )::int;
+
+$$ language sql;
+
+CREATE OR REPLACE FUNCTION is_same_month (in_date1 date, in_date2 date) 
+returns bool as
+$$
+SELECT is_same_year($1, $2) 
+       and extract ('MONTH' from $1) = extract ('MONTH' from $2);
+$$ language sql;
+
+CREATE OR REPLACE FUNCTION get_fractional_month
+(in_date_first date, in_date_second date)
+RETURNS NUMERIC AS
+$$
+SELECT CASE WHEN is_same_month($1, $2)
+            THEN ($2 - $1)::numeric
+                 / days_in_month($1)
+            ELSE (get_fractional_month(
+                   $1, (date_trunc('MONTH', $1) 
+                       + '1 month - 1 second'::interval)::date)
+                 + get_fractional_month(date_trunc('MONTH', $2)::date, $2)
+                 + (extract ('YEAR' from $2) - extract ('YEAR' from $1) * 12)
+                 + extract ('MONTH' from $1) - extract ('MONTH' from $2) 
+                 - 1)::numeric
+            END;
+$$ language sql;
+
 CREATE OR REPLACE FUNCTION invoice__get_by_vendor_number
 (in_meta_nunber text, in_invoice_number text)
 RETURNS ap AS

Added: addons/1.3/base/trunk/sql/modules/test/Util.sql
===================================================================
--- addons/1.3/base/trunk/sql/modules/test/Util.sql	                        (rev 0)
+++ addons/1.3/base/trunk/sql/modules/test/Util.sql	2009-12-10 20:42:23 UTC (rev 2812)
@@ -0,0 +1,65 @@
+BEGIN;
+\i Base.sql
+
+INSERT INTO test_result(test_name, success)
+SELECT 'generate_series(2009, 2008) generates empty set',
+       count(*) = 0 FROM generate_series(2009, 2008);
+
+INSERT INTO test_result (test_name, success)
+SELECT '2009 is not leap year', not is_leapyear('2009-01-01');
+
+INSERT INTO test_result (test_name, success)
+SELECT '2008 is leap year', is_leapyear('2008-01-01');
+
+INSERT INTO test_result (test_name, success)
+SELECT '2000 is leap year', is_leapyear('2000-01-01');
+
+INSERT INTO test_result (test_name, success)
+SELECT '2100 is not leap year', not is_leapyear('2100-01-01');
+
+INSERT INTO test_result (test_name, success)
+SELECT 'get_fractional_year returns 1 on full year', 
+       get_fractional_year('2009-01-01', '2010-01-01') = 1;
+
+INSERT INTO test_result (test_name, success)
+SELECT 'get_fractional_year returns 1 on full year on leap year 1',
+       get_fractional_year('2007-01-01', '2008-01-01') = 1;
+
+INSERT INTO test_result (test_name, success)
+SELECT 'get_fractional_year returns 1 on full year on leap year 1',
+       get_fractional_year('2008-01-01', '2009-01-01') = 1;
+
+INSERT INTO test_result(test_name, success)
+select 'monthly fractional returns on normal year total to 1 to within 1x10^-19',
+        abs(1 - (get_fractional_year('2006-01-01', '2006-02-01')
+        + get_fractional_year('2006-02-01', '2006-03-01')
+        + get_fractional_year('2006-03-01', '2006-04-01')
+        + get_fractional_year('2006-04-01', '2006-05-01')
+        + get_fractional_year('2006-05-01', '2006-06-01')
+        + get_fractional_year('2006-06-01', '2006-07-01')
+        + get_fractional_year('2006-07-01', '2006-08-01')
+        + get_fractional_year('2006-08-01', '2006-09-01')
+        + get_fractional_year('2006-09-01', '2006-10-01')
+        + get_fractional_year('2006-10-01', '2006-11-01')
+        + get_fractional_year('2006-11-01', '2006-12-01')
+        + get_fractional_year('2006-12-01', '2007-01-01')))
+        < 0.0000000000000000001;
+
+INSERT INTO test_result(test_name, success)
+select 'monthly fractional returns on leap year total to 1 to within 1x10^-19',
+        abs(1 - (get_fractional_year('2008-01-01', '2008-02-01')
+        + get_fractional_year('2008-02-01', '2008-03-01')
+        + get_fractional_year('2008-03-01', '2008-04-01')
+        + get_fractional_year('2008-04-01', '2008-05-01')
+        + get_fractional_year('2008-05-01', '2008-06-01')
+        + get_fractional_year('2008-06-01', '2008-07-01')
+        + get_fractional_year('2008-07-01', '2008-08-01')
+        + get_fractional_year('2008-08-01', '2008-09-01')
+        + get_fractional_year('2008-09-01', '2008-10-01')
+        + get_fractional_year('2008-10-01', '2008-11-01')
+        + get_fractional_year('2008-11-01', '2008-12-01')
+        + get_fractional_year('2008-12-01', '2009-01-01')))
+        < 0.0000000000000000001;
+
+SELECT * FROM test_result;
+ROLLBACK;

Added: addons/1.3/base/trunk/t/43-dbtest-utils.t
===================================================================
--- addons/1.3/base/trunk/t/43-dbtest-utils.t	                        (rev 0)
+++ addons/1.3/base/trunk/t/43-dbtest-utils.t	2009-12-10 20:42:23 UTC (rev 2812)
@@ -0,0 +1,29 @@
+use Test::More;
+use strict;
+
+if (!defined $ENV{LSMB_TEST_DB}){
+	plan skip_all => 'Skipping all.  Told not to test db.';
+}
+else {
+	plan tests => 11;
+	if (defined $ENV{LSMB_NEW_DB}){
+		$ENV{PGDATABASE} = $ENV{LSMB_NEW_DB};
+	}
+	if (!defined $ENV{PGDATABASE}){
+		die "We were told to run tests, but no database specified!";
+        }
+}
+
+my @testscripts = qw(Util);
+
+chdir 'sql/modules/test/';
+
+for my $testscript (@testscripts){
+	open (TEST, '-|', "psql -f $testscript.sql");
+	my @testlines = grep /\|\s+(t|f)\s?$/, <TEST>;
+	cmp_ok(scalar @testlines, '>', 0, "$testscript.sql returned test results");
+	for my $test (@testlines){
+		my @parts = split /\|/, $test;
+		like($parts[1], qr/t\s?$/, $parts[0]);
+	}
+}


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