[open-ils-commits] [GIT] Evergreen ILS branch master updated. de7b7f758220db82107f94a90bd1b1602f45426b

Evergreen Git git at git.evergreen-ils.org
Tue Jul 31 09:53:52 EDT 2012


This is an automated email from the git hooks/post-receive script. It was
generated because a ref change was pushed to the repository containing
the project "Evergreen ILS".

The branch, master has been updated
       via  de7b7f758220db82107f94a90bd1b1602f45426b (commit)
       via  ed2cdd9b633999f738bedfa80367706e849cf0d2 (commit)
       via  c25e5a3a9a5de07a6c0614093eaac83d4cc37fc3 (commit)
      from  4fee07d5c7be39a21fa6df602c9b6855d3315fb1 (commit)

Those revisions listed above that are new to this repository have
not appeared on any other notification email; so we list those
revisions in full, below.

- Log -----------------------------------------------------------------
commit de7b7f758220db82107f94a90bd1b1602f45426b
Author: Bill Erickson <berick at esilibrary.com>
Date:   Tue Jul 31 09:14:40 2012 -0400

    Stamping Encumbrance-only rollover DB upgrade
    
    Signed-off-by: Bill Erickson <berick at esilibrary.com>

diff --git a/Open-ILS/src/sql/Pg/002.schema.config.sql b/Open-ILS/src/sql/Pg/002.schema.config.sql
index 420b915..a692969 100644
--- a/Open-ILS/src/sql/Pg/002.schema.config.sql
+++ b/Open-ILS/src/sql/Pg/002.schema.config.sql
@@ -87,7 +87,7 @@ CREATE TRIGGER no_overlapping_deps
     BEFORE INSERT OR UPDATE ON config.db_patch_dependencies
     FOR EACH ROW EXECUTE PROCEDURE evergreen.array_overlap_check ('deprecates');
 
-INSERT INTO config.upgrade_log (version, applied_to) VALUES ('0729', :eg_version); -- tsbere/denials
+INSERT INTO config.upgrade_log (version, applied_to) VALUES ('0730', :eg_version); -- miker/senator/berick
 
 CREATE TABLE config.bib_source (
 	id		SERIAL	PRIMARY KEY,
diff --git a/Open-ILS/src/sql/Pg/upgrade/XXXX.schema.acq-function-dedup.sql b/Open-ILS/src/sql/Pg/upgrade/0730.schema.acq-function-dedup.sql
similarity index 98%
rename from Open-ILS/src/sql/Pg/upgrade/XXXX.schema.acq-function-dedup.sql
rename to Open-ILS/src/sql/Pg/upgrade/0730.schema.acq-function-dedup.sql
index 149c1ce..932d984 100644
--- a/Open-ILS/src/sql/Pg/upgrade/XXXX.schema.acq-function-dedup.sql
+++ b/Open-ILS/src/sql/Pg/upgrade/0730.schema.acq-function-dedup.sql
@@ -1,6 +1,6 @@
 BEGIN;
 
-INSERT INTO config.upgrade_log (version, applied_to) VALUES ('XXXX', :eg_version); -- miker
+SELECT evergreen.upgrade_deps_block_check('0730', :eg_version);
 
 DROP FUNCTION acq.propagate_funds_by_org_tree (INT, INT, INT);
 DROP FUNCTION acq.propagate_funds_by_org_unit (INT, INT, INT);

commit ed2cdd9b633999f738bedfa80367706e849cf0d2
Author: Lebbeous Fogle-Weekley <lebbeous at esilibrary.com>
Date:   Fri Jul 27 13:32:12 2012 -0400

    Finishing off rollover-without-money feature
    
    - Minor correction to make stock schema match upgrade script match.
    - OU setting determining whether to offer rollover-without-money in UI
       and allow it in DB.
    
    Signed-off-by: Lebbeous Fogle-Weekley <lebbeous at esilibrary.com>
    Signed-off-by: Bill Erickson <berick at esilibrary.com>

diff --git a/Open-ILS/src/sql/Pg/200.schema.acq.sql b/Open-ILS/src/sql/Pg/200.schema.acq.sql
index f0a1bf3..c84279b 100644
--- a/Open-ILS/src/sql/Pg/200.schema.acq.sql
+++ b/Open-ILS/src/sql/Pg/200.schema.acq.sql
@@ -1974,7 +1974,7 @@ BEGIN
 		year = old_year
 		AND propagate
 		AND ( ( include_desc AND org IN ( SELECT id FROM actor.org_unit_descendants( org_unit_id ) ) )
-                OR (NOT include_desc AND oldf.org = org_unit_id ) )
+                OR (NOT include_desc AND org = org_unit_id ) )
     
 	LOOP
 		BEGIN
@@ -2028,7 +2028,8 @@ DECLARE
 new_fund    INT;
 new_year    INT := old_year + 1;
 org_found   BOOL;
-xfer_amount NUMERIC;
+perm_ous    BOOL;
+xfer_amount NUMERIC := 0;
 roll_fund   RECORD;
 deb         RECORD;
 detail      RECORD;
@@ -2060,6 +2061,14 @@ BEGIN
 		--
 		IF org_found IS NULL THEN
 			RAISE EXCEPTION 'Org unit id % is invalid', org_unit_id;
+		ELSIF encumb_only THEN
+			SELECT INTO perm_ous value::BOOL FROM
+			actor.org_unit_ancestor_setting(
+				'acq.fund.allow_rollover_without_money', org_unit_id
+			);
+			IF NOT FOUND OR NOT perm_ous THEN
+				RAISE EXCEPTION 'Encumbrance-only rollover not permitted at org %', org_unit_id;
+			END IF;
 		END IF;
 	END IF;
 	--
diff --git a/Open-ILS/src/sql/Pg/950.data.seed-values.sql b/Open-ILS/src/sql/Pg/950.data.seed-values.sql
index ed53b9b..d4b8826 100644
--- a/Open-ILS/src/sql/Pg/950.data.seed-values.sql
+++ b/Open-ILS/src/sql/Pg/950.data.seed-values.sql
@@ -11748,7 +11748,6 @@ INSERT INTO config.org_unit_setting_type (
     'interval'
 );
 
-
 -- kid's opac main search filter
 
 INSERT INTO actor.search_filter_group (owner, code, label) 
@@ -11779,3 +11778,23 @@ INSERT INTO actor.search_filter_group_entry (grp, query, pos)
         (SELECT id FROM actor.search_query WHERE label = 'General/Adult Materials'),
         2
     );
+INSERT into config.org_unit_setting_type
+    (name, grp, label, description, datatype)
+    VALUES (
+        'acq.fund.allow_rollover_without_money',
+        'acq',
+        oils_i18n_gettext(
+            'acq.fund.allow_rollover_without_money',
+            'Allow funds to be rolled over without bringing the money along',
+            'coust',
+            'label'
+        ),
+        oils_i18n_gettext(
+            'acq.fund.allow_rollover_without_money',
+            'Allow funds to be rolled over without bringing the money along.  This makes money left in the old fund disappear, modeling its return to some outside entity.',
+            'coust',
+            'description'
+        ),
+        'bool'
+    );
+
diff --git a/Open-ILS/src/sql/Pg/upgrade/XXXX.schema.acq-function-dedup.sql b/Open-ILS/src/sql/Pg/upgrade/XXXX.schema.acq-function-dedup.sql
index a7167ce..149c1ce 100644
--- a/Open-ILS/src/sql/Pg/upgrade/XXXX.schema.acq-function-dedup.sql
+++ b/Open-ILS/src/sql/Pg/upgrade/XXXX.schema.acq-function-dedup.sql
@@ -1,3 +1,6 @@
+BEGIN;
+
+INSERT INTO config.upgrade_log (version, applied_to) VALUES ('XXXX', :eg_version); -- miker
 
 DROP FUNCTION acq.propagate_funds_by_org_tree (INT, INT, INT);
 DROP FUNCTION acq.propagate_funds_by_org_unit (INT, INT, INT);
@@ -47,7 +50,7 @@ BEGIN
 		year = old_year
 		AND propagate
 		AND ( ( include_desc AND org IN ( SELECT id FROM actor.org_unit_descendants( org_unit_id ) ) )
-                OR (NOT include_desc AND oldf.org = org_unit_id ) )
+                OR (NOT include_desc AND org = org_unit_id ) )
     
 	LOOP
 		BEGIN
@@ -92,6 +95,7 @@ $$ LANGUAGE SQL;
 DROP FUNCTION acq.rollover_funds_by_org_tree (INT, INT, INT);
 DROP FUNCTION acq.rollover_funds_by_org_unit (INT, INT, INT);
 
+
 CREATE OR REPLACE FUNCTION acq.rollover_funds_by_org_tree(
 	old_year INTEGER,
 	user_id INTEGER,
@@ -104,6 +108,7 @@ DECLARE
 new_fund    INT;
 new_year    INT := old_year + 1;
 org_found   BOOL;
+perm_ous    BOOL;
 xfer_amount NUMERIC := 0;
 roll_fund   RECORD;
 deb         RECORD;
@@ -136,6 +141,14 @@ BEGIN
 		--
 		IF org_found IS NULL THEN
 			RAISE EXCEPTION 'Org unit id % is invalid', org_unit_id;
+		ELSIF encumb_only THEN
+			SELECT INTO perm_ous value::BOOL FROM
+			actor.org_unit_ancestor_setting(
+				'acq.fund.allow_rollover_without_money', org_unit_id
+			);
+			IF NOT FOUND OR NOT perm_ous THEN
+				RAISE EXCEPTION 'Encumbrance-only rollover not permitted at org %', org_unit_id;
+			END IF;
 		END IF;
 	END IF;
 	--
@@ -276,4 +289,24 @@ CREATE OR REPLACE FUNCTION acq.rollover_funds_by_org_unit( old_year INTEGER, use
     SELECT acq.rollover_funds_by_org_tree( $1, $2, $3, $4, FALSE );
 $$ LANGUAGE SQL;
 
+INSERT into config.org_unit_setting_type
+    (name, grp, label, description, datatype)
+    VALUES (
+        'acq.fund.allow_rollover_without_money',
+        'acq',
+        oils_i18n_gettext(
+            'acq.fund.allow_rollover_without_money',
+            'Allow funds to be rolled over without bringing the money along',
+            'coust',
+            'label'
+        ),
+        oils_i18n_gettext(
+            'acq.fund.allow_rollover_without_money',
+            'Allow funds to be rolled over without bringing the money along.  This makes money left in the old fund disappear, modeling its return to some outside entity.',
+            'coust',
+            'description'
+        ),
+        'bool'
+    );
 
+COMMIT;
diff --git a/Open-ILS/src/templates/acq/fund/list.tt2 b/Open-ILS/src/templates/acq/fund/list.tt2
index 0173e73..6fa4b0d 100644
--- a/Open-ILS/src/templates/acq/fund/list.tt2
+++ b/Open-ILS/src/templates/acq/fund/list.tt2
@@ -72,13 +72,13 @@
                                 </div>
                             </td>
                         </tr>
-                        <tr>
+                        <tr class="encumb_only hidden">
                             <td><label for="encumb_only">Limit Fiscal Year Close-out Operation to Encumbrances: </label></td>
                             <td>
                                 <input dojoType="dijit.form.CheckBox" name="encumb_only"> </input>
                             </td>
                         </tr>
-                        <tr>
+                        <tr class="encumb_only hidden">
                             <td colspan='2'>
                                 <div style='width:400px;'>
                                 This modifies the above described Close-out Operation, causing funds to be
diff --git a/Open-ILS/web/js/ui/default/acq/financial/list_funds.js b/Open-ILS/web/js/ui/default/acq/financial/list_funds.js
index 4586333..abad41d 100644
--- a/Open-ILS/web/js/ui/default/acq/financial/list_funds.js
+++ b/Open-ILS/web/js/ui/default/acq/financial/list_funds.js
@@ -37,6 +37,21 @@ var cachedFunds = [];
 function initPage() {
     contextOrg = openils.User.user.ws_ou();
 
+    /* Reveal controls for rollover without money if org units say ok.
+     * Actual ability to do the operation is controlled in the database, of
+     * course. */
+    var ouSettings = fieldmapper.aou.fetchOrgSettingBatch(
+        openils.User.user.ws_ou(), ["acq.fund.allow_rollover_without_money"]
+    );
+    if (
+        ouSettings["acq.fund.allow_rollover_without_money"] &&
+        ouSettings["acq.fund.allow_rollover_without_money"].value
+    ) {
+        dojo.query(".encumb_only").forEach(
+            function(o) { openils.Util.show(o, "table-row"); }
+        );
+    }
+
     var connect = function() {
         dojo.connect(contextOrgSelector, 'onChange',
             function() {

commit c25e5a3a9a5de07a6c0614093eaac83d4cc37fc3
Author: Mike Rylander <mrylander at gmail.com>
Date:   Thu Jul 26 09:35:01 2012 -0400

    Allow propagation of encumbrances without funds
    
    Some libraries must return all unspent money to some funding agencies at the
    end of the year.  To support this, we give the year-end close-out operation
    the ability to dump the money from rollover-enabled funds into the void. Funds
    are still created for the next year, and encumbrances are moved to theses
    analogous funds.
    
    Signed-off-by: Mike Rylander <mrylander at gmail.com>
    Signed-off-by: Bill Erickson <berick at esilibrary.com>

diff --git a/Open-ILS/src/perlmods/lib/OpenILS/Application/Acq/Financials.pm b/Open-ILS/src/perlmods/lib/OpenILS/Application/Acq/Financials.pm
index 3fff0c3..df0d3bc 100644
--- a/Open-ILS/src/perlmods/lib/OpenILS/Application/Acq/Financials.pm
+++ b/Open-ILS/src/perlmods/lib/OpenILS/Application/Acq/Financials.pm
@@ -1221,6 +1221,7 @@ __PACKAGE__->register_method (
             {desc => 'Fund Year to roll over', type => 'integer'},
             {desc => 'Org unit ID', type => 'integer'},
             {desc => 'Include Descendant Orgs (boolean)', type => 'integer'},
+            {desc => 'Option hash: limit, offset, encumb_only', type => 'object'},
         ],
         return => {desc => 'Returns a stream of all related funds for the next year including fund summary for each'}
     }
@@ -1277,6 +1278,7 @@ sub process_fiscal_rollover {
     $options ||= {};
 
     my $combined = ($self->api_name =~ /combined/); 
+    my $encumb_only = $U->is_true($options->{encumb_only}) ? 't' : 'f';
 
     my $org_ids = ($descendants) ? 
         [   
@@ -1308,22 +1310,16 @@ sub process_fiscal_rollover {
                 ($descendants) ? 
                     'acq.rollover_funds_by_org_tree' :
                     'acq.rollover_funds_by_org_unit',
-                $year, $e->requestor->id, $org_id
+                $year, $e->requestor->id, $org_id, $encumb_only
             ]
         });
     }
 
     # Fetch all funds for the specified org units for the subsequent year
-    my $fund_ids = $e->search_acq_fund([
-        {
-            year => int($year) + 1, 
+    my $fund_ids = $e->search_acq_fund(
+        [{  year => int($year) + 1, 
             org => $org_ids,
-            propagate => 't'
-        }, {
-            limit => $$options{limit} || 20,
-            offset => $$options{offset} || 0,
-        }
-        ], 
+            propagate => 't' }], 
         {idlist => 1}
     );
 
@@ -1338,7 +1334,7 @@ sub process_fiscal_rollover {
             my $sum = $e->json_query({
                 select => {acqftr => [{column => 'dest_amount', transform => 'sum'}]}, 
                 from => 'acqftr', 
-                where => {dest_fund => $fund->id, note => 'Rollover'}
+                where => {dest_fund => $fund->id, note => { like => 'Rollover%' } }
             })->[0];
 
             $amount = $sum->{dest_amount} if $sum;
diff --git a/Open-ILS/src/sql/Pg/200.schema.acq.sql b/Open-ILS/src/sql/Pg/200.schema.acq.sql
index f4669b9..f0a1bf3 100644
--- a/Open-ILS/src/sql/Pg/200.schema.acq.sql
+++ b/Open-ILS/src/sql/Pg/200.schema.acq.sql
@@ -1929,89 +1929,11 @@ BEGIN
 END;
 $$ LANGUAGE 'plpgsql';
 
-CREATE OR REPLACE FUNCTION acq.propagate_funds_by_org_unit(
-	old_year INTEGER,
-	user_id INTEGER,
-	org_unit_id INTEGER
-) RETURNS VOID AS $$
-DECLARE
---
-new_id      INT;
-old_fund    RECORD;
-org_found   BOOLEAN;
---
-BEGIN
-	--
-	-- Sanity checks
-	--
-	IF old_year IS NULL THEN
-		RAISE EXCEPTION 'Input year argument is NULL';
-	ELSIF old_year NOT BETWEEN 2008 and 2200 THEN
-		RAISE EXCEPTION 'Input year is out of range';
-	END IF;
-	--
-	IF user_id IS NULL THEN
-		RAISE EXCEPTION 'Input user id argument is NULL';
-	END IF;
-	--
-	IF org_unit_id IS NULL THEN
-		RAISE EXCEPTION 'Org unit id argument is NULL';
-	ELSE
-		SELECT TRUE INTO org_found
-		FROM actor.org_unit
-		WHERE id = org_unit_id;
-		--
-		IF org_found IS NULL THEN
-			RAISE EXCEPTION 'Org unit id is invalid';
-		END IF;
-	END IF;
-	--
-	-- Loop over the applicable funds
-	--
-	FOR old_fund in SELECT * FROM acq.fund
-	WHERE
-		year = old_year
-		AND propagate
-		AND org = org_unit_id
-	LOOP
-		BEGIN
-			INSERT INTO acq.fund (
-				org,
-				name,
-				year,
-				currency_type,
-				code,
-				rollover,
-				propagate,
-				balance_warning_percent,
-				balance_stop_percent
-			) VALUES (
-				old_fund.org,
-				old_fund.name,
-				old_year + 1,
-				old_fund.currency_type,
-				old_fund.code,
-				old_fund.rollover,
-				true,
-				old_fund.balance_warning_percent,
-				old_fund.balance_stop_percent
-			)
-			RETURNING id INTO new_id;
-		EXCEPTION
-			WHEN unique_violation THEN
-				--RAISE NOTICE 'Fund % already propagated', old_fund.id;
-				CONTINUE;
-		END;
-		--RAISE NOTICE 'Propagating fund % to fund %',
-		--	old_fund.code, new_id;
-	END LOOP;
-END;
-$$ LANGUAGE plpgsql;
-
 CREATE OR REPLACE FUNCTION acq.propagate_funds_by_org_tree(
 	old_year INTEGER,
 	user_id INTEGER,
-	org_unit_id INTEGER
+	org_unit_id INTEGER,
+    include_desc BOOL DEFAULT TRUE
 ) RETURNS VOID AS $$
 DECLARE
 --
@@ -2051,9 +1973,9 @@ BEGIN
 	WHERE
 		year = old_year
 		AND propagate
-		AND org in (
-			SELECT id FROM actor.org_unit_descendants( org_unit_id )
-		)
+		AND ( ( include_desc AND org IN ( SELECT id FROM actor.org_unit_descendants( org_unit_id ) ) )
+                OR (NOT include_desc AND oldf.org = org_unit_id ) )
+    
 	LOOP
 		BEGIN
 			INSERT INTO acq.fund (
@@ -2089,187 +2011,17 @@ BEGIN
 END;
 $$ LANGUAGE plpgsql;
 
-CREATE OR REPLACE FUNCTION acq.rollover_funds_by_org_unit(
-	old_year INTEGER,
-	user_id INTEGER,
-	org_unit_id INTEGER
-) RETURNS VOID AS $$
-DECLARE
---
-new_fund    INT;
-new_year    INT := old_year + 1;
-org_found   BOOL;
-xfer_amount NUMERIC;
-roll_fund   RECORD;
-deb         RECORD;
-detail      RECORD;
---
-BEGIN
-	--
-	-- Sanity checks
-	--
-	IF old_year IS NULL THEN
-		RAISE EXCEPTION 'Input year argument is NULL';
-    ELSIF old_year NOT BETWEEN 2008 and 2200 THEN
-        RAISE EXCEPTION 'Input year is out of range';
-	END IF;
-	--
-	IF user_id IS NULL THEN
-		RAISE EXCEPTION 'Input user id argument is NULL';
-	END IF;
-	--
-	IF org_unit_id IS NULL THEN
-		RAISE EXCEPTION 'Org unit id argument is NULL';
-	ELSE
-		--
-		-- Validate the org unit
-		--
-		SELECT TRUE
-		INTO org_found
-		FROM actor.org_unit
-		WHERE id = org_unit_id;
-		--
-		IF org_found IS NULL THEN
-			RAISE EXCEPTION 'Org unit id % is invalid', org_unit_id;
-		END IF;
-	END IF;
-	--
-	-- Loop over the propagable funds to identify the details
-	-- from the old fund plus the id of the new one, if it exists.
-	--
-	FOR roll_fund in
-	SELECT
-	    oldf.id AS old_fund,
-	    oldf.org,
-	    oldf.name,
-	    oldf.currency_type,
-	    oldf.code,
-		oldf.rollover,
-	    newf.id AS new_fund_id
-	FROM
-    	acq.fund AS oldf
-    	LEFT JOIN acq.fund AS newf
-        	ON ( oldf.code = newf.code )
-	WHERE
-		    oldf.org = org_unit_id
- 		and oldf.year = old_year
-		and oldf.propagate
-        and newf.year = new_year
-	LOOP
-		--RAISE NOTICE 'Processing fund %', roll_fund.old_fund;
-		--
-		IF roll_fund.new_fund_id IS NULL THEN
-			--
-			-- The old fund hasn't been propagated yet.  Propagate it now.
-			--
-			INSERT INTO acq.fund (
-				org,
-				name,
-				year,
-				currency_type,
-				code,
-				rollover,
-				propagate,
-				balance_warning_percent,
-				balance_stop_percent
-			) VALUES (
-				roll_fund.org,
-				roll_fund.name,
-				new_year,
-				roll_fund.currency_type,
-				roll_fund.code,
-				true,
-				true,
-				roll_fund.balance_warning_percent,
-				roll_fund.balance_stop_percent
-			)
-			RETURNING id INTO new_fund;
-		ELSE
-			new_fund = roll_fund.new_fund_id;
-		END IF;
-		--
-		-- Determine the amount to transfer
-		--
-		SELECT amount
-		INTO xfer_amount
-		FROM acq.fund_spent_balance
-		WHERE fund = roll_fund.old_fund;
-		--
-		IF xfer_amount <> 0 THEN
-			IF roll_fund.rollover THEN
-				--
-				-- Transfer balance from old fund to new
-				--
-				--RAISE NOTICE 'Transferring % from fund % to %', xfer_amount, roll_fund.old_fund, new_fund;
-				--
-				PERFORM acq.transfer_fund(
-					roll_fund.old_fund,
-					xfer_amount,
-					new_fund,
-					xfer_amount,
-					user_id,
-					'Rollover'
-				);
-			ELSE
-				--
-				-- Transfer balance from old fund to the void
-				--
-				-- RAISE NOTICE 'Transferring % from fund % to the void', xfer_amount, roll_fund.old_fund;
-				--
-				PERFORM acq.transfer_fund(
-					roll_fund.old_fund,
-					xfer_amount,
-					NULL,
-					NULL,
-					user_id,
-					'Rollover'
-				);
-			END IF;
-		END IF;
-		--
-		IF roll_fund.rollover THEN
-			--
-			-- Move any lineitems from the old fund to the new one
-			-- where the associated debit is an encumbrance.
-			--
-			-- Any other tables tying expenditure details to funds should
-			-- receive similar treatment.  At this writing there are none.
-			--
-			UPDATE acq.lineitem_detail
-			SET fund = new_fund
-			WHERE
-    			fund = roll_fund.old_fund -- this condition may be redundant
-    			AND fund_debit in
-    			(
-        			SELECT id
-        			FROM acq.fund_debit
-        			WHERE
-            			fund = roll_fund.old_fund
-            			AND encumbrance
-    			);
-			--
-			-- Move encumbrance debits from the old fund to the new fund
-			--
-			UPDATE acq.fund_debit
-			SET fund = new_fund
-			wHERE
-				fund = roll_fund.old_fund
-				AND encumbrance;
-		END IF;
-		--
-		-- Mark old fund as inactive, now that we've closed it
-		--
-		UPDATE acq.fund
-		SET active = FALSE
-		WHERE id = roll_fund.old_fund;
-	END LOOP;
-END;
-$$ LANGUAGE plpgsql;
+CREATE OR REPLACE FUNCTION acq.propagate_funds_by_org_unit( old_year INTEGER, user_id INTEGER, org_unit_id INTEGER ) RETURNS VOID AS $$
+    SELECT acq.propagate_funds_by_org_tree( $1, $2, $3, FALSE );
+$$ LANGUAGE SQL;
+
 
 CREATE OR REPLACE FUNCTION acq.rollover_funds_by_org_tree(
 	old_year INTEGER,
 	user_id INTEGER,
-	org_unit_id INTEGER
+	org_unit_id INTEGER,
+    encumb_only BOOL DEFAULT FALSE,
+    include_desc BOOL DEFAULT TRUE
 ) RETURNS VOID AS $$
 DECLARE
 --
@@ -2331,9 +2083,8 @@ BEGIN
  		    oldf.year = old_year
 		AND oldf.propagate
         AND newf.year = new_year
-		AND oldf.org in (
-			SELECT id FROM actor.org_unit_descendants( org_unit_id )
-		)
+		AND ( ( include_desc AND oldf.org IN ( SELECT id FROM actor.org_unit_descendants( org_unit_id ) ) )
+                OR (NOT include_desc AND oldf.org = org_unit_id ) )
 	LOOP
 		--RAISE NOTICE 'Processing fund %', roll_fund.old_fund;
 		--
@@ -2375,7 +2126,7 @@ BEGIN
 		WHERE fund = roll_fund.old_fund;
 		--
 		IF xfer_amount <> 0 THEN
-			IF roll_fund.rollover THEN
+			IF NOT encumb_only AND roll_fund.rollover THEN
 				--
 				-- Transfer balance from old fund to new
 				--
@@ -2401,7 +2152,7 @@ BEGIN
 					NULL,
 					NULL,
 					user_id,
-					'Rollover'
+					'Rollover into the void'
 				);
 			END IF;
 		END IF;
@@ -2445,6 +2196,10 @@ BEGIN
 END;
 $$ LANGUAGE plpgsql;
 
+CREATE OR REPLACE FUNCTION acq.rollover_funds_by_org_unit( old_year INTEGER, user_id INTEGER, org_unit_id INTEGER, encumb_only BOOL DEFAULT FALSE ) RETURNS VOID AS $$
+    SELECT acq.rollover_funds_by_org_tree( $1, $2, $3, $4, FALSE );
+$$ LANGUAGE SQL;
+
 CREATE OR REPLACE VIEW acq.funding_source_credit_total AS
     SELECT  funding_source,
             SUM(amount) AS amount
diff --git a/Open-ILS/src/sql/Pg/upgrade/XXXX.schema.acq-function-dedup.sql b/Open-ILS/src/sql/Pg/upgrade/XXXX.schema.acq-function-dedup.sql
new file mode 100644
index 0000000..a7167ce
--- /dev/null
+++ b/Open-ILS/src/sql/Pg/upgrade/XXXX.schema.acq-function-dedup.sql
@@ -0,0 +1,279 @@
+
+DROP FUNCTION acq.propagate_funds_by_org_tree (INT, INT, INT);
+DROP FUNCTION acq.propagate_funds_by_org_unit (INT, INT, INT);
+
+CREATE OR REPLACE FUNCTION acq.propagate_funds_by_org_tree(
+	old_year INTEGER,
+	user_id INTEGER,
+	org_unit_id INTEGER,
+    include_desc BOOL DEFAULT TRUE
+) RETURNS VOID AS $$
+DECLARE
+--
+new_id      INT;
+old_fund    RECORD;
+org_found   BOOLEAN;
+--
+BEGIN
+	--
+	-- Sanity checks
+	--
+	IF old_year IS NULL THEN
+		RAISE EXCEPTION 'Input year argument is NULL';
+	ELSIF old_year NOT BETWEEN 2008 and 2200 THEN
+		RAISE EXCEPTION 'Input year is out of range';
+	END IF;
+	--
+	IF user_id IS NULL THEN
+		RAISE EXCEPTION 'Input user id argument is NULL';
+	END IF;
+	--
+	IF org_unit_id IS NULL THEN
+		RAISE EXCEPTION 'Org unit id argument is NULL';
+	ELSE
+		SELECT TRUE INTO org_found
+		FROM actor.org_unit
+		WHERE id = org_unit_id;
+		--
+		IF org_found IS NULL THEN
+			RAISE EXCEPTION 'Org unit id is invalid';
+		END IF;
+	END IF;
+	--
+	-- Loop over the applicable funds
+	--
+	FOR old_fund in SELECT * FROM acq.fund
+	WHERE
+		year = old_year
+		AND propagate
+		AND ( ( include_desc AND org IN ( SELECT id FROM actor.org_unit_descendants( org_unit_id ) ) )
+                OR (NOT include_desc AND oldf.org = org_unit_id ) )
+    
+	LOOP
+		BEGIN
+			INSERT INTO acq.fund (
+				org,
+				name,
+				year,
+				currency_type,
+				code,
+				rollover,
+				propagate,
+				balance_warning_percent,
+				balance_stop_percent
+			) VALUES (
+				old_fund.org,
+				old_fund.name,
+				old_year + 1,
+				old_fund.currency_type,
+				old_fund.code,
+				old_fund.rollover,
+				true,
+				old_fund.balance_warning_percent,
+				old_fund.balance_stop_percent
+			)
+			RETURNING id INTO new_id;
+		EXCEPTION
+			WHEN unique_violation THEN
+				--RAISE NOTICE 'Fund % already propagated', old_fund.id;
+				CONTINUE;
+		END;
+		--RAISE NOTICE 'Propagating fund % to fund %',
+		--	old_fund.code, new_id;
+	END LOOP;
+END;
+$$ LANGUAGE plpgsql;
+
+CREATE OR REPLACE FUNCTION acq.propagate_funds_by_org_unit( old_year INTEGER, user_id INTEGER, org_unit_id INTEGER ) RETURNS VOID AS $$
+    SELECT acq.propagate_funds_by_org_tree( $1, $2, $3, FALSE );
+$$ LANGUAGE SQL;
+
+
+DROP FUNCTION acq.rollover_funds_by_org_tree (INT, INT, INT);
+DROP FUNCTION acq.rollover_funds_by_org_unit (INT, INT, INT);
+
+CREATE OR REPLACE FUNCTION acq.rollover_funds_by_org_tree(
+	old_year INTEGER,
+	user_id INTEGER,
+	org_unit_id INTEGER,
+    encumb_only BOOL DEFAULT FALSE,
+    include_desc BOOL DEFAULT TRUE
+) RETURNS VOID AS $$
+DECLARE
+--
+new_fund    INT;
+new_year    INT := old_year + 1;
+org_found   BOOL;
+xfer_amount NUMERIC := 0;
+roll_fund   RECORD;
+deb         RECORD;
+detail      RECORD;
+--
+BEGIN
+	--
+	-- Sanity checks
+	--
+	IF old_year IS NULL THEN
+		RAISE EXCEPTION 'Input year argument is NULL';
+    ELSIF old_year NOT BETWEEN 2008 and 2200 THEN
+        RAISE EXCEPTION 'Input year is out of range';
+	END IF;
+	--
+	IF user_id IS NULL THEN
+		RAISE EXCEPTION 'Input user id argument is NULL';
+	END IF;
+	--
+	IF org_unit_id IS NULL THEN
+		RAISE EXCEPTION 'Org unit id argument is NULL';
+	ELSE
+		--
+		-- Validate the org unit
+		--
+		SELECT TRUE
+		INTO org_found
+		FROM actor.org_unit
+		WHERE id = org_unit_id;
+		--
+		IF org_found IS NULL THEN
+			RAISE EXCEPTION 'Org unit id % is invalid', org_unit_id;
+		END IF;
+	END IF;
+	--
+	-- Loop over the propagable funds to identify the details
+	-- from the old fund plus the id of the new one, if it exists.
+	--
+	FOR roll_fund in
+	SELECT
+	    oldf.id AS old_fund,
+	    oldf.org,
+	    oldf.name,
+	    oldf.currency_type,
+	    oldf.code,
+		oldf.rollover,
+	    newf.id AS new_fund_id
+	FROM
+    	acq.fund AS oldf
+    	LEFT JOIN acq.fund AS newf
+        	ON ( oldf.code = newf.code )
+	WHERE
+ 		    oldf.year = old_year
+		AND oldf.propagate
+        AND newf.year = new_year
+		AND ( ( include_desc AND oldf.org IN ( SELECT id FROM actor.org_unit_descendants( org_unit_id ) ) )
+                OR (NOT include_desc AND oldf.org = org_unit_id ) )
+	LOOP
+		--RAISE NOTICE 'Processing fund %', roll_fund.old_fund;
+		--
+		IF roll_fund.new_fund_id IS NULL THEN
+			--
+			-- The old fund hasn't been propagated yet.  Propagate it now.
+			--
+			INSERT INTO acq.fund (
+				org,
+				name,
+				year,
+				currency_type,
+				code,
+				rollover,
+				propagate,
+				balance_warning_percent,
+				balance_stop_percent
+			) VALUES (
+				roll_fund.org,
+				roll_fund.name,
+				new_year,
+				roll_fund.currency_type,
+				roll_fund.code,
+				true,
+				true,
+				roll_fund.balance_warning_percent,
+				roll_fund.balance_stop_percent
+			)
+			RETURNING id INTO new_fund;
+		ELSE
+			new_fund = roll_fund.new_fund_id;
+		END IF;
+		--
+		-- Determine the amount to transfer
+		--
+		SELECT amount
+		INTO xfer_amount
+		FROM acq.fund_spent_balance
+		WHERE fund = roll_fund.old_fund;
+		--
+		IF xfer_amount <> 0 THEN
+			IF NOT encumb_only AND roll_fund.rollover THEN
+				--
+				-- Transfer balance from old fund to new
+				--
+				--RAISE NOTICE 'Transferring % from fund % to %', xfer_amount, roll_fund.old_fund, new_fund;
+				--
+				PERFORM acq.transfer_fund(
+					roll_fund.old_fund,
+					xfer_amount,
+					new_fund,
+					xfer_amount,
+					user_id,
+					'Rollover'
+				);
+			ELSE
+				--
+				-- Transfer balance from old fund to the void
+				--
+				-- RAISE NOTICE 'Transferring % from fund % to the void', xfer_amount, roll_fund.old_fund;
+				--
+				PERFORM acq.transfer_fund(
+					roll_fund.old_fund,
+					xfer_amount,
+					NULL,
+					NULL,
+					user_id,
+					'Rollover into the void'
+				);
+			END IF;
+		END IF;
+		--
+		IF roll_fund.rollover THEN
+			--
+			-- Move any lineitems from the old fund to the new one
+			-- where the associated debit is an encumbrance.
+			--
+			-- Any other tables tying expenditure details to funds should
+			-- receive similar treatment.  At this writing there are none.
+			--
+			UPDATE acq.lineitem_detail
+			SET fund = new_fund
+			WHERE
+    			fund = roll_fund.old_fund -- this condition may be redundant
+    			AND fund_debit in
+    			(
+        			SELECT id
+        			FROM acq.fund_debit
+        			WHERE
+            			fund = roll_fund.old_fund
+            			AND encumbrance
+    			);
+			--
+			-- Move encumbrance debits from the old fund to the new fund
+			--
+			UPDATE acq.fund_debit
+			SET fund = new_fund
+			wHERE
+				fund = roll_fund.old_fund
+				AND encumbrance;
+		END IF;
+		--
+		-- Mark old fund as inactive, now that we've closed it
+		--
+		UPDATE acq.fund
+		SET active = FALSE
+		WHERE id = roll_fund.old_fund;
+	END LOOP;
+END;
+$$ LANGUAGE plpgsql;
+
+CREATE OR REPLACE FUNCTION acq.rollover_funds_by_org_unit( old_year INTEGER, user_id INTEGER, org_unit_id INTEGER, encumb_only BOOL DEFAULT FALSE ) RETURNS VOID AS $$
+    SELECT acq.rollover_funds_by_org_tree( $1, $2, $3, $4, FALSE );
+$$ LANGUAGE SQL;
+
+
diff --git a/Open-ILS/src/templates/acq/fund/list.tt2 b/Open-ILS/src/templates/acq/fund/list.tt2
index 95eac5f..0173e73 100644
--- a/Open-ILS/src/templates/acq/fund/list.tt2
+++ b/Open-ILS/src/templates/acq/fund/list.tt2
@@ -73,6 +73,21 @@
                             </td>
                         </tr>
                         <tr>
+                            <td><label for="encumb_only">Limit Fiscal Year Close-out Operation to Encumbrances: </label></td>
+                            <td>
+                                <input dojoType="dijit.form.CheckBox" name="encumb_only"> </input>
+                            </td>
+                        </tr>
+                        <tr>
+                            <td colspan='2'>
+                                <div style='width:400px;'>
+                                This modifies the above described Close-out Operation, causing funds to be
+                                transfered into the void (that is, entirely removed) instead of being transfered
+                                to the analogous funds in the subsequent fiscal year.
+                                </div>
+                            </td>
+                        </tr>
+                        <tr>
                             <td>Context Org Unit:</td>
                             <td><span id='oils-acq-rollover-ctxt-org'></span></td>
                         </tr>
diff --git a/Open-ILS/web/js/ui/default/acq/financial/list_funds.js b/Open-ILS/web/js/ui/default/acq/financial/list_funds.js
index 17873d0..4586333 100644
--- a/Open-ILS/web/js/ui/default/acq/financial/list_funds.js
+++ b/Open-ILS/web/js/ui/default/acq/financial/list_funds.js
@@ -173,6 +173,8 @@ function performRollover(args) {
     var dryRun = args.dry_run[0] == 'on';
     if(dryRun) method += '.dry_run';
 
+    var encumbOnly = args.encumb_only[0] == 'on';
+
     var count = 0;
     var amount_rolled = 0;
     var year = fundFilterYearSelect.attr('value'); // TODO alternate selector?
@@ -186,7 +188,8 @@ function performRollover(args) {
                 openils.User.authtoken, 
                 year,
                 contextOrg,
-                (args.child_orgs[0] == 'on')
+                (args.child_orgs[0] == 'on'),
+                { encumb_only : encumbOnly }
             ],
 
             onresponse : function(r) {

-----------------------------------------------------------------------

Summary of changes:
 .../lib/OpenILS/Application/Acq/Financials.pm      |   18 +-
 Open-ILS/src/sql/Pg/002.schema.config.sql          |    2 +-
 Open-ILS/src/sql/Pg/200.schema.acq.sql             |  296 ++-----------------
 Open-ILS/src/sql/Pg/950.data.seed-values.sql       |   21 ++-
 .../Pg/upgrade/0730.schema.acq-function-dedup.sql  |  312 ++++++++++++++++++++
 Open-ILS/src/templates/acq/fund/list.tt2           |   15 +
 .../web/js/ui/default/acq/financial/list_funds.js  |   20 ++-
 7 files changed, 404 insertions(+), 280 deletions(-)
 create mode 100644 Open-ILS/src/sql/Pg/upgrade/0730.schema.acq-function-dedup.sql


hooks/post-receive
-- 
Evergreen ILS


More information about the open-ils-commits mailing list