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

Evergreen Git git at git.evergreen-ils.org
Wed Mar 13 16:55:44 EDT 2013


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  3e9df23281892408c62fd610dfa124385eba2685 (commit)
       via  d959739a1f613e55d0f7cccd33daa86486d609af (commit)
       via  f4d33b5a0054e30faf8a95a73c1359353dde4023 (commit)
       via  5650ad93e94f2a58fbc5fd9b9f6249c364bb586c (commit)
       via  f09abe0bc615e79c2fca2afe6a97dba3e41df9e8 (commit)
       via  8780429c3a92e7c89ed4cb37527444104558c641 (commit)
      from  0d8f90b156fd5988a1f434911a971287472211d3 (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 3e9df23281892408c62fd610dfa124385eba2685
Author: Lebbeous Fogle-Weekley <lebbeous at esilibrary.com>
Date:   Wed Mar 13 16:47:11 2013 -0400

    Numering upgrade scripts related to acq batch update
    
    Signed-off-by: Lebbeous Fogle-Weekley <lebbeous 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 3d83609..e615146 100644
--- a/Open-ILS/src/sql/Pg/002.schema.config.sql
+++ b/Open-ILS/src/sql/Pg/002.schema.config.sql
@@ -91,7 +91,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 ('0779', :eg_version); -- berick/miker
+INSERT INTO config.upgrade_log (version, applied_to) VALUES ('0781', :eg_version); -- berick/senator
 
 CREATE TABLE config.bib_source (
 	id		SERIAL	PRIMARY KEY,
diff --git a/Open-ILS/src/sql/Pg/upgrade/0779.schema.acq.distribution_formula.expansion.sql b/Open-ILS/src/sql/Pg/upgrade/0780.schema.acq.distribution_formula.expansion.sql
similarity index 98%
rename from Open-ILS/src/sql/Pg/upgrade/0779.schema.acq.distribution_formula.expansion.sql
rename to Open-ILS/src/sql/Pg/upgrade/0780.schema.acq.distribution_formula.expansion.sql
index dc6ccec..c7af495 100644
--- a/Open-ILS/src/sql/Pg/upgrade/0779.schema.acq.distribution_formula.expansion.sql
+++ b/Open-ILS/src/sql/Pg/upgrade/0780.schema.acq.distribution_formula.expansion.sql
@@ -1,6 +1,6 @@
 BEGIN;
 
-SELECT evergreen.upgrade_deps_block_check('0779', :eg_version);
+SELECT evergreen.upgrade_deps_block_check('0780', :eg_version);
 
 ALTER TABLE acq.distribution_formula_entry
     ADD COLUMN fund INT REFERENCES acq.fund (id),
diff --git a/Open-ILS/src/sql/Pg/upgrade/XXXX.data.acq.distribution_formula.expansion.sql b/Open-ILS/src/sql/Pg/upgrade/0781.data.acq.distribution_formula.expansion.sql
similarity index 88%
rename from Open-ILS/src/sql/Pg/upgrade/XXXX.data.acq.distribution_formula.expansion.sql
rename to Open-ILS/src/sql/Pg/upgrade/0781.data.acq.distribution_formula.expansion.sql
index 9db24d3..b188e98 100644
--- a/Open-ILS/src/sql/Pg/upgrade/XXXX.data.acq.distribution_formula.expansion.sql
+++ b/Open-ILS/src/sql/Pg/upgrade/0781.data.acq.distribution_formula.expansion.sql
@@ -1,6 +1,6 @@
 BEGIN;
 
---SELECT evergreen.upgrade_deps_block_check('XXXX', :eg_version);
+SELECT evergreen.upgrade_deps_block_check('0781', :eg_version);
 
 INSERT INTO config.org_unit_setting_type
     (name, label, description, grp, datatype) 

commit d959739a1f613e55d0f7cccd33daa86486d609af
Author: Bill Erickson <berick at esilibrary.com>
Date:   Fri Mar 8 13:23:06 2013 -0500

    Distribution formula fund rollover setting
    
    Adds an org unit setting (acq.fund.rollover_distrib_forms) which
    controls whether the fund value on distribution formulae is updated to
    use the newly created fund during fiscal year rollover.
    
    Signed-off-by: Bill Erickson <berick at esilibrary.com>
    Signed-off-by: Lebbeous Fogle-Weekley <lebbeous 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 1095513..d32b519 100644
--- a/Open-ILS/src/sql/Pg/200.schema.acq.sql
+++ b/Open-ILS/src/sql/Pg/200.schema.acq.sql
@@ -2032,7 +2032,6 @@ CREATE OR REPLACE FUNCTION acq.propagate_funds_by_org_unit( old_year INTEGER, us
     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,
@@ -2050,6 +2049,7 @@ xfer_amount NUMERIC := 0;
 roll_fund   RECORD;
 deb         RECORD;
 detail      RECORD;
+roll_distrib_forms BOOL;
 --
 BEGIN
 	--
@@ -2212,6 +2212,19 @@ BEGIN
 				fund = roll_fund.old_fund
 				AND encumbrance;
 		END IF;
+
+		-- Rollover distribution formulae funds
+		SELECT INTO roll_distrib_forms value::BOOL FROM
+			actor.org_unit_ancestor_setting(
+				'acq.fund.rollover_distrib_forms', org_unit_id
+			);
+
+		IF roll_distrib_forms THEN
+			UPDATE acq.distribution_formula_entry 
+				SET fund = roll_fund.new_fund_id
+				WHERE fund = roll_fund.old_fund;
+		END IF;
+
 		--
 		-- Mark old fund as inactive, now that we've closed it
 		--
@@ -2222,6 +2235,8 @@ 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;
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 b346956..d693e6c 100644
--- a/Open-ILS/src/sql/Pg/950.data.seed-values.sql
+++ b/Open-ILS/src/sql/Pg/950.data.seed-values.sql
@@ -12583,3 +12583,23 @@ INSERT INTO action_trigger.validator (
         'Tests if a patron is currently not marked as barred'
     );
 
+INSERT INTO config.org_unit_setting_type
+    (name, label, description, grp, datatype) 
+VALUES (
+    'acq.fund.rollover_distrib_forms',
+    oils_i18n_gettext(
+        'acq.fund.rollover_distrib_forms',
+        'Rollover Distribution Formulae Funds',
+        'coust',
+        'label'
+    ),
+     oils_i18n_gettext(
+        'acq.fund.rollover_distrib_forms',
+        'During fiscal rollover, update distribution formalae to use new funds',
+        'coust',
+        'description'
+    ),
+    'acq',
+    'bool'
+);
+
diff --git a/Open-ILS/src/sql/Pg/upgrade/0779.schema.acq.distribution_formula.expansion.sql b/Open-ILS/src/sql/Pg/upgrade/0779.schema.acq.distribution_formula.expansion.sql
index 148677e..dc6ccec 100644
--- a/Open-ILS/src/sql/Pg/upgrade/0779.schema.acq.distribution_formula.expansion.sql
+++ b/Open-ILS/src/sql/Pg/upgrade/0779.schema.acq.distribution_formula.expansion.sql
@@ -7,4 +7,210 @@ ALTER TABLE acq.distribution_formula_entry
     ADD COLUMN circ_modifier TEXT REFERENCES config.circ_modifier (code),
     ADD COLUMN collection_code TEXT ;
 
+
+-- support option to roll distribution formula funds
+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;
+perm_ous    BOOL;
+xfer_amount NUMERIC := 0;
+roll_fund   RECORD;
+deb         RECORD;
+detail      RECORD;
+roll_distrib_forms BOOL;
+--
+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;
+		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;
+	--
+	-- 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;
+
+		-- Rollover distribution formulae funds
+		SELECT INTO roll_distrib_forms value::BOOL FROM
+			actor.org_unit_ancestor_setting(
+				'acq.fund.rollover_distrib_forms', org_unit_id
+			);
+
+		IF roll_distrib_forms THEN
+			UPDATE acq.distribution_formula_entry 
+				SET fund = roll_fund.new_fund_id
+				WHERE fund = roll_fund.old_fund;
+		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;
+
+
 COMMIT;
diff --git a/Open-ILS/src/sql/Pg/upgrade/XXXX.data.acq.distribution_formula.expansion.sql b/Open-ILS/src/sql/Pg/upgrade/XXXX.data.acq.distribution_formula.expansion.sql
new file mode 100644
index 0000000..9db24d3
--- /dev/null
+++ b/Open-ILS/src/sql/Pg/upgrade/XXXX.data.acq.distribution_formula.expansion.sql
@@ -0,0 +1,25 @@
+BEGIN;
+
+--SELECT evergreen.upgrade_deps_block_check('XXXX', :eg_version);
+
+INSERT INTO config.org_unit_setting_type
+    (name, label, description, grp, datatype) 
+VALUES (
+    'acq.fund.rollover_distrib_forms',
+    oils_i18n_gettext(
+        'acq.fund.rollover_distrib_forms',
+        'Rollover Distribution Formulae Funds',
+        'coust',
+        'label'
+    ),
+     oils_i18n_gettext(
+        'acq.fund.rollover_distrib_forms',
+        'During fiscal rollover, update distribution formalae to use new funds',
+        'coust',
+        'description'
+    ),
+    'acq',
+    'bool'
+);
+
+COMMIT;

commit f4d33b5a0054e30faf8a95a73c1359353dde4023
Author: Bill Erickson <berick at esilibrary.com>
Date:   Wed Mar 13 16:16:50 2013 -0400

    LP 1154150 : repair formula entry retrieval
    
    Repair code thinkos in distribution formula entry fleshing call /
    traversal.
    
    Signed-off-by: Bill Erickson <berick at esilibrary.com>
    Signed-off-by: Lebbeous Fogle-Weekley <lebbeous at esilibrary.com>

diff --git a/Open-ILS/src/perlmods/lib/OpenILS/Application/Acq/Lineitem/BatchUpdate.pm b/Open-ILS/src/perlmods/lib/OpenILS/Application/Acq/Lineitem/BatchUpdate.pm
index 620ae06..0a8b9a3 100644
--- a/Open-ILS/src/perlmods/lib/OpenILS/Application/Acq/Lineitem/BatchUpdate.pm
+++ b/Open-ILS/src/perlmods/lib/OpenILS/Application/Acq/Lineitem/BatchUpdate.pm
@@ -410,8 +410,14 @@ sub lineitem_batch_update_api {
         # It's important that we NOT flesh use_count here, if that [ever]
         # does anything.  We're going to abuse that field internally.
 
-        $dist_formula = $e->acq->retrieve_acq_distribution_formula([
-            int($dist_formula), {flesh=>1, flesh_fields=>["entries","fund"]}
+        $dist_formula = $e->retrieve_acq_distribution_formula([
+            int($dist_formula), {
+                flesh=>2, 
+                flesh_fields=>{
+                    acqdf => ["entries"],
+                    acqdfe => ["fund"]
+                }
+            }
         ]) or return $e->die_event;
 
         return $e->die_event unless
@@ -419,11 +425,13 @@ sub lineitem_batch_update_api {
 
         # If the distribution formula has a fund, there's an additional perm
         # test to do before proceeding.
-        if ($dist_formula->fund) {
-            return $e->die_event unless $e->allowed(
-                ["ADMIN_FUND", "MANAGE_FUND"],
-                $dist_formula->fund->org, $dist_formula->fund
-            );
+        for my $entry (@{$dist_formula->entries}) {
+            if ($entry->fund) {
+                return $e->die_event unless $e->allowed(
+                    ["ADMIN_FUND", "MANAGE_FUND"],
+                    $entry->fund->org, $entry->fund
+                );
+            }
         }
 
         # The following sort is crucial later.

commit 5650ad93e94f2a58fbc5fd9b9f6249c364bb586c
Author: Bill Erickson <berick at esilibrary.com>
Date:   Wed Mar 13 16:04:11 2013 -0400

    LP 1154150 DB upgrade stamping
    
    Signed-off-by: Bill Erickson <berick at esilibrary.com>

diff --git a/Open-ILS/src/sql/Pg/upgrade/XXXX.schema.acq.distribution_formula.expansion.sql b/Open-ILS/src/sql/Pg/upgrade/0779.schema.acq.distribution_formula.expansion.sql
similarity index 77%
rename from Open-ILS/src/sql/Pg/upgrade/XXXX.schema.acq.distribution_formula.expansion.sql
rename to Open-ILS/src/sql/Pg/upgrade/0779.schema.acq.distribution_formula.expansion.sql
index 391bcf8..148677e 100644
--- a/Open-ILS/src/sql/Pg/upgrade/XXXX.schema.acq.distribution_formula.expansion.sql
+++ b/Open-ILS/src/sql/Pg/upgrade/0779.schema.acq.distribution_formula.expansion.sql
@@ -1,6 +1,6 @@
 BEGIN;
 
---SELECT evergreen.upgrade_deps_block_check('XXXX', :eg_version);
+SELECT evergreen.upgrade_deps_block_check('0779', :eg_version);
 
 ALTER TABLE acq.distribution_formula_entry
     ADD COLUMN fund INT REFERENCES acq.fund (id),

commit f09abe0bc615e79c2fca2afe6a97dba3e41df9e8
Author: Lebbeous Fogle-Weekley <lebbeous at esilibrary.com>
Date:   Fri Mar 8 14:10:12 2013 -0500

    Acq: Line item batch update UI
    
    This UI enhancement uses the API method in the previous commit to allow
    users to apply changes to the copies on a selected set of line items.
    
    When successful, the updater just reloads the whole page, but it can be
    made smarter later, i.e. by refreshing only the affected line items rows
    in the display.
    
    The UI only appears on POs for now, and is partly disabled if the PO has
    already been activated.  It could appear elsewhere if it seems sensible
    to put it elsewhere.
    
    Signed-off-by: Lebbeous Fogle-Weekley <lebbeous at esilibrary.com>
    Signed-off-by: Bill Erickson <berick at esilibrary.com>

diff --git a/Open-ILS/examples/fm_IDL.xml b/Open-ILS/examples/fm_IDL.xml
index 4443128..1b7cee5 100644
--- a/Open-ILS/examples/fm_IDL.xml
+++ b/Open-ILS/examples/fm_IDL.xml
@@ -8498,7 +8498,7 @@ SELECT  usr,
 	</class>
 	<class id="acqdf" controller="open-ils.cstore open-ils.pcrud" oils_obj:fieldmapper="acq::distribution_formula" oils_persist:tablename="acq.distribution_formula" reporter:label="Distribution Formula">
 		<fields oils_persist:primary="id" oils_persist:sequence="acq.distribution_formula_id_seq">
-			<field reporter:label="Formula ID" name="id" reporter:datatype="id"/>
+			<field reporter:label="Formula ID" name="id" reporter:datatype="id" reporter:selector="name" />
 			<field reporter:label="Formula Owner" name="owner" reporter:datatype="org_unit"/>
 			<field reporter:label="Formula Name" name="name" reporter:datatype="text"/>
 			<field reporter:label="Skip Count" name="skip_count" reporter:datatype="int"/>
diff --git a/Open-ILS/src/templates/acq/common/li_table.tt2 b/Open-ILS/src/templates/acq/common/li_table.tt2
index 064ff52..b19e5c3 100644
--- a/Open-ILS/src/templates/acq/common/li_table.tt2
+++ b/Open-ILS/src/templates/acq/common/li_table.tt2
@@ -6,73 +6,113 @@
     <div id='acq-lit-table-div' class='hidden'>
 
         <!-- Line Item (bib record) list -->
-        <table id='acq-lit-table' class='oils-generic-table'>
-            <thead>
-                <tr>
-                    <th colspan='0'>
-                        <table style='width:100%;'>
-                            <tr>
-                                <td>
-                                    <span>
-                                        <select id="acq-lit-li-actions-selector">
-                                    <!-- mask meanings:
-                                        pl: selection list
-                                        po: pending purchase order
-                                        ao: activated purchase order
-                                        gs: general search
-                                        vp: view/place orders
-                                        fs: MARC federated search
+        <div style="float: left;">
+            <span>
+                <select id="acq-lit-li-actions-selector">
+            <!-- mask meanings:
+                pl: selection list
+                po: pending purchase order
+                ao: activated purchase order
+                gs: general search
+                vp: view/place orders
+                fs: MARC federated search
 
-                                        * for all, otherwise combine with |
-                                    -->
-                                            <option mask='*'  value='_'>[% l('--Actions--') %]</option>
-                                            <option mask='pl|gs|vp|fs' value='save_picklist'>[% l('Save Items To Selection List') %]</option>
-                                            <option mask='pl|gs|vp' value='selector_ready'>[% l('Mark Ready for Selector') %]</option>
-                                            <option mask='pl|gs|vp' value='order_ready'>[% l('Mark Ready for Order') %]</option>
-                                            <option mask='pl|po|gs|vp'  value='delete_selected'>[% l('Delete Selected Items') %]</option>
-                                            <option mask='pl|po'  value='add_brief_record'>[% l('Add Brief Record') %]</option>
-                                            <option mask='pl|po|ao|gs'  value='export_attr_list'>[% l('Export Single Attribute List') %]</option>
-                                            <option mask='*' value='' disabled='disabled'>[% l('----PO----') %]</option>
-                                            <option mask='pl|gs|vp|fs' value='create_order'>[% l('Create Purchase Order') %]</option>
-                                            <option mask='pl|gs|vp|fs' value='add_to_order'>[% l('Add to Purchase Order') %]</option>
-                                            <option mask='po|ao' value='print_po'>[% l('Print Purchase Order') %]</option>
-                                            <option mask='po|ao' value='po_history'>[% l('View PO History') %]</option>
-                                            <option mask='po' value='create_assets'>[% l('Load Bibs and Items') %]</option>
-                                            <!-- <option mask=''  value='batch_apply_funds'>[% l('Apply Funds to Selected Items') %]</option> XXX moving to batch updater -->
-                                            <option mask='ao|gs|vp' value='cancel_lineitems'>[% l('Cancel Selected Line Items') %]</option>
-                                            <option mask='po|ao|gs|vp' value='apply_claim_policy'>[% l('Apply Claim Policy to Selected Line Items') %]</option><!-- can the functionality desired here be covered by the next thing? -->
-                                            <option mask='ao|gs|vp' value='receive_lineitems' id='receive_lineitems' disabled='disabled'>[% l('Mark Selected Line Items as Received') %]</option>
-                                            <option mask='ao|gs|vp' value='rollback_receive_lineitems' id='rollback_receive_lineitems' disabled='disabled'>[% l('Un-Receive Selected Line Items') %]</option>
-                                            <option mask='ao|gs|vp' value='batch_create_invoice'>[% l('Create Invoice From Selected Line Items') %]</option>
-                                            <option mask='ao|gs|vp' value='batch_link_invoice'>[% l('Link Selected Line Items to Invoice') %]</option>
-                                        </select>
-                                        <span id="acq-lit-export-attr-holder" class="hidden">
-                                            <input dojoType="dijit.form.FilteringSelect" id="acq-lit-export-attr" jsId="acqLitExportAttrSelector" labelAttr="description" searchAttr="description" />
-                                            <span dojoType="dijit.form.Button" jsId="acqLitExportAttrButton">[% l('Export List') %]</span>
-                                        </span>
-                                        <span id="acq-lit-cancel-reason" class="hidden">
-                                            <span id="acq-lit-cancel-reason-selector"></span>
-                                            <span dojoType="dijit.form.Button" jsId="acqLitCancelLineitemsButton">[% l('Cancel Line Items') %]</span>
-                                        </span>
-                                    </span>
-                                    <span id='acq-lit-generic-progress' class='hidden'>
-                                        <span dojoType="dijit.ProgressBar" style="width:300px" jsId="litGenericProgress"></span>
-                                    </span>
-                                </td>
-                                <td>
-                                    <div style='width:100%;text-align:right;'>
-                                        <span style='padding-right:15px;'>
-                                            <a href='javascript:void(0);' id='acq-lit-prev' style='visibility:hidden'>[% l('&#171; Previous') %]</a>
-                                            <a href='javascript:void(0);' id='acq-lit-next' style='visibility:hidden'>[% l('Next &#187;') %]</a>
-                                        </span>
-                                    </div>
-                                </td>
-                            </tr>
-                        </table>
-                    </th>
-                </tr>
-            </thead>
-            <tbody><tr><td colspan='0' style='height:20px;'/></tr></tbody>
+                * for all, otherwise combine with |
+            -->
+                    <option mask='*'  value='_'>[% l('--Actions--') %]</option>
+                    <option mask='pl|gs|vp|fs' value='save_picklist'>[% l('Save Items To Selection List') %]</option>
+                    <option mask='pl|gs|vp' value='selector_ready'>[% l('Mark Ready for Selector') %]</option>
+                    <option mask='pl|gs|vp' value='order_ready'>[% l('Mark Ready for Order') %]</option>
+                    <option mask='pl|po|gs|vp'  value='delete_selected'>[% l('Delete Selected Items') %]</option>
+                    <option mask='pl|po'  value='add_brief_record'>[% l('Add Brief Record') %]</option>
+                    <option mask='pl|po|ao|gs'  value='export_attr_list'>[% l('Export Single Attribute List') %]</option>
+                    <option mask='*' value='' disabled='disabled'>[% l('----PO----') %]</option>
+                    <option mask='pl|gs|vp|fs' value='create_order'>[% l('Create Purchase Order') %]</option>
+                    <option mask='pl|gs|vp|fs' value='add_to_order'>[% l('Add to Purchase Order') %]</option>
+                    <option mask='po|ao' value='print_po'>[% l('Print Purchase Order') %]</option>
+                    <option mask='po|ao' value='po_history'>[% l('View PO History') %]</option>
+                    <option mask='po' value='create_assets'>[% l('Load Bibs and Items') %]</option>
+                    <option mask='ao|gs|vp' value='cancel_lineitems'>[% l('Cancel Selected Line Items') %]</option>
+                    <option mask='po|ao|gs|vp' value='apply_claim_policy'>[% l('Apply Claim Policy to Selected Line Items') %]</option><!-- can the functionality desired here be covered by the next thing? -->
+                    <option mask='ao|gs|vp' value='receive_lineitems' id='receive_lineitems' disabled='disabled'>[% l('Mark Selected Line Items as Received') %]</option>
+                    <option mask='ao|gs|vp' value='rollback_receive_lineitems' id='rollback_receive_lineitems' disabled='disabled'>[% l('Un-Receive Selected Line Items') %]</option>
+                    <option mask='ao|gs|vp' value='batch_create_invoice'>[% l('Create Invoice From Selected Line Items') %]</option>
+                    <option mask='ao|gs|vp' value='batch_link_invoice'>[% l('Link Selected Line Items to Invoice') %]</option>
+                </select>
+                <span id="acq-lit-export-attr-holder" class="hidden">
+                    <input dojoType="dijit.form.FilteringSelect" id="acq-lit-export-attr" jsId="acqLitExportAttrSelector" labelAttr="description" searchAttr="description" />
+                    <span dojoType="dijit.form.Button" jsId="acqLitExportAttrButton">[% l('Export List') %]</span>
+                </span>
+                <span id="acq-lit-cancel-reason" class="hidden">
+                    <span id="acq-lit-cancel-reason-selector"></span>
+                    <span dojoType="dijit.form.Button" jsId="acqLitCancelLineitemsButton">[% l('Cancel Line Items') %]</span>
+                </span>
+            </span>
+            <span id='acq-lit-generic-progress' class='hidden'>
+                <span dojoType="dijit.ProgressBar" style="width:300px" jsId="litGenericProgress"></span>
+            </span>
+        </div>
+        <div style="float: right;">
+            <div style='width:100%;text-align:right;'>
+                <span style='padding-right:15px;'>
+                    <a href='javascript:void(0);' id='acq-lit-prev' style='visibility:hidden'>[% l('&#171; Previous') %]</a>
+                    <a href='javascript:void(0);' id='acq-lit-next' style='visibility:hidden'>[% l('Next &#187;') %]</a>
+                </span>
+            </div>
+        </div>
+        <div style="clear: both;">&nbsp;</div><!-- XXX better way to end effects of float: left/right ? -->
+
+        <table id="acq-batch-update" class="hidden"><!-- XXX freeze in place w/ CSS? -->
+            <tr>
+                <th>
+                    <label for="acq-bu-item_count">[% l("Copies") %]</label>
+                </th>
+                <th>
+                    <label for="acq-bu-owning_lib">[% l("Owning Branch") %]</label>
+                </th>
+                <th>
+                    <label for="acq-bu-location">[% l("Copy Location") %]</label>
+                </th>
+                <th>
+                    <label for="acq-bu-collection_code">[% l("Collection Code") %]</label>
+                </th>
+                <th>
+                    <label for="acq-bu-fund">[% l("Fund") %]</label>
+                </th>
+                <th>
+                    <label for="acq-bu-circ_modifier">[% l("Circ Modifier") %]</label>
+                </th>
+                <th>
+                    <label for="acq-bu-distribution_formula">[% l("Distribution Formula") %]</label>
+                </th>
+            </tr>
+            <tr>
+                <td>
+                    <span id="acq-bu-item_count"></span>
+                </td>
+                <td>
+                    <span id="acq-bu-owning_lib"></span>
+                </td>
+                <td>
+                    <span id="acq-bu-location"></span>
+                </td>
+                <td>
+                    <span id="acq-bu-collection_code"></span>
+                </td>
+                <td>
+                    <span id="acq-bu-fund"></span>
+                </td>
+                <td>
+                    <span id="acq-bu-circ_modifier"></span> OR
+                </td>
+                <td>
+                    <span id="acq-bu-distribution_formula"></span>
+                    <span dojoType="dijit.form.Button" jsId="acqBatchUpdateApply">[% l("Apply to Selected") %]</span>
+                </td>
+            </tr>
+        </table>
+        <table id='acq-lit-table' class='oils-generic-table'>
+            <tbody><tr><td colspan='0' style='height:20px;'></td></tr></tbody>
             <tbody style='font-weight:bold;border:1px solid #aaa;'>
                 <tr>
                     <td><span><a id='acq-lit-select-toggle' href='javascript:void(0);'>&#x2713</a></span></td>
diff --git a/Open-ILS/web/css/skin/default/acq.css b/Open-ILS/web/css/skin/default/acq.css
index cfa600d..7da2a78 100644
--- a/Open-ILS/web/css/skin/default/acq.css
+++ b/Open-ILS/web/css/skin/default/acq.css
@@ -166,6 +166,10 @@ label[for="attr_search_type_scalar"] { vertical-align: top; }
 span[name="worksheet"] { padding: 0 6px; }
 #acq-lit-li-claim-dia-lid-list-init { margin-left: 8px; }
 
+#acq-batch-update { padding: 20px 0; }
+#acq-batch-update th { font-weight: bold; }
+#acq-batch-update td { white-space: nowrap; padding-right: 0.5em; }
+
 #acq-worksheet-contents thead th { font-weight: bold; background-color: #ccc; text-align: center; border-bottom: 1px #000 solid; border-right: 1px #000 solid; padding: 0 6px; }
 #acq-worksheet-contents tbody td { text-align: left; vertical-align: top; border: 1px #999 inset; padding: 0 2px; }
 
diff --git a/Open-ILS/web/js/dojo/openils/acq/nls/acq.js b/Open-ILS/web/js/dojo/openils/acq/nls/acq.js
index 1f15d16..eb6d7f9 100644
--- a/Open-ILS/web/js/dojo/openils/acq/nls/acq.js
+++ b/Open-ILS/web/js/dojo/openils/acq/nls/acq.js
@@ -69,8 +69,10 @@
     "INVOICE_ITEM_PO_DETAILS" : "<b>${0}</b><br/><a href='${1}/acq/po/view/${2}'>PO #${3} ${4}</a><br/>Total Estimated Cost: $${5}",
     "UNNAMED" : "Unnamed",
     "NO_FIND_INVOICE" : "Could not find that invoice.\nNote that the Invoice # field is case-sensitive.",
-    "NO_LI_TO_CLAIM" : "You have not selected any lineitems to claim.",
-    "NO_LID_TO_CLAIM" : "You have not selected any lineitem details to claim.",
+    "LI_BATCH_UPDATE": "Line item batch update",
+    "NO_LI_TO_UPDATE" : "You have not selected any line items to update.",
+    "NO_LI_TO_CLAIM" : "You have not selected any line items to claim.",
+    "NO_LID_TO_CLAIM" : "You have not selected any line item details to claim.",
     "CHANGE_CLAIM_POLICY" : "Change claim policy",
     "CANCELED" : "Canceled",
     "RECVD" : "Recv'd",
diff --git a/Open-ILS/web/js/ui/default/acq/common/li_table.js b/Open-ILS/web/js/ui/default/acq/common/li_table.js
index a541cf2..7a804da 100644
--- a/Open-ILS/web/js/ui/default/acq/common/li_table.js
+++ b/Open-ILS/web/js/ui/default/acq/common/li_table.js
@@ -144,6 +144,169 @@ function AcqLiTable() {
     dojo.byId('acq-lit-notes-back-button').onclick = function(){self.show('list')};
     dojo.byId('acq-lit-real-copies-back-button').onclick = function(){self.show('list')};
 
+    this.afwCopyFieldArgs = function(field, perms) {
+        return {
+                "fmField" : field,
+                "fmClass": 'acqlid',
+                "labelFormat": (field == 'fund') ? fundLabelFormat : null,
+                "searchFormat": (field == 'fund') ? fundSearchFormat : null,
+                "searchFilter": (field == 'fund') ? {"active": "t"} : null,
+                "orgLimitPerms": [perms],
+                "dijitArgs": {
+                    "required": false,
+                    "labelType": (field == "fund") ? "html" : null
+                },
+                "noCache": (field == "fund"),
+                "forceSync": true
+            };
+    };
+
+    /* This is the "new" batch updater that sits atop all lineitems. It does
+     * use this.afwCopyFieldArgs() to borrow a little common code  from the
+     * "old" batch updater atop the copy details view. */
+    this.initBatchUpdater = function(disabled_fields) {
+        openils.Util.show("acq-batch-update", "table");
+
+        if (!dojo.isArray(disabled_fields)) disabled_fields = [];
+
+        /* Note that this will directly contain dijits, not the AutoWidget
+         * wrapper object. */
+        this.batchUpdateWidgets = {};
+
+        this.batchUpdateWidgets.item_count = new dijit.form.TextBox(
+            {
+                "style": {"width": "3em"},
+                "disabled": Boolean(
+                    dojo.indexOf(disabled_fields, "item_count") != -1
+                )
+            },
+            "acq-bu-item_count"
+        );
+
+        (new openils.widget.AutoFieldWidget({
+            "fmClass": "acqdf",
+            "selfReference": true,
+            "dijitArgs": { "required": false },
+            "forceSync": true,
+            "parentNode": "acq-bu-distribution_formula"
+        })).build(
+            function(w) {
+                dojo.style(w.domNode, {"width": "12em"});
+                /* dijitArgs to AutoFieldWidget won't work for 'disabled' */
+                w.attr(
+                    "disabled",
+                    dojo.indexOf(disabled_fields, "distribution_formula") != -1
+                );
+                self.batchUpdateWidgets.distribution_formula = w;
+            }
+        );
+
+        dojo.forEach(
+            ["owning_lib","location","collection_code","circ_modifier","fund"],
+            function(field) {
+                var args = self.afwCopyFieldArgs(field,"CREATE_PURCHASE_ORDER");
+                args.parentNode = dojo.byId("acq-bu-" + field);
+
+                (new openils.widget.AutoFieldWidget(args)).build(
+                    function(w, aw) {
+                        if (field == "fund") {
+                            dojo.connect(
+                                w, "onChange", function(val) {
+                                    self._updateFundSelectorStyle(aw, val);
+                                }
+                            );
+                            if (w.store)
+                                self._ensureCSSFundClasses(w.store);
+                        }
+
+                        dojo.style(w.domNode, {"width": "10em"});
+                        w.attr(
+                            "disabled",
+                            dojo.indexOf(disabled_fields, field) != -1
+                        );
+                        self.batchUpdateWidgets[field] = w;
+                    }
+                );
+            }
+        );
+
+        acqBatchUpdateApply.onClick = function() {
+            var li_id_list = self.getSelected(false, null, true /* id list */);
+            if (!li_id_list.length) {
+                alert(localeStrings.NO_LI_TO_UPDATE);
+                return;
+            }
+
+            progressDialog.show(true);
+            progressDialog.attr("title", localeStrings.LI_BATCH_UPDATE);
+            progressDialog.update({"maximum": li_id_list.length,"progress": 0});
+
+            var count = 0;
+
+            var params = [ self.authtoken, {"lineitems": li_id_list},
+                        self.batchUpdateChanges(), self.batchUpdateFormula() ];
+            console.log("batch update params: " + dojo.toJson(params));
+
+            fieldmapper.standardRequest(
+                ["open-ils.acq", "open-ils.acq.lineitem.batch_update"], {
+                    "async": true,
+                    "params": params,
+                    "onresponse": function(r) {
+                        if ((r = openils.Util.readResponse(r))) { // assignment
+                            progressDialog.update({"progress": ++count});
+                        } else {
+                            progressDialog.hide();
+                            progressDialog.attr("title", "");
+                        }
+                    },
+                    "oncomplete": function() {
+                        /* XXX Is the last call to onresponse guaranteed to
+                         * finish before oncomplete is fired? */
+                        if (count != li_id_list.length) {
+                            console.error("lineitem batch update operation failed");
+                            progressDialog.hide();
+                            progressDialog.attr("title", "");
+                        } else {
+                            location.href = location.href;
+                        }
+                    }
+                }
+            );
+        };
+    };
+
+    this.batchUpdateChanges = function() {
+        var o = {};
+
+        dojo.forEach(
+            openils.Util.objectProperties(this.batchUpdateWidgets),
+            function(k) {
+                if (k == "distribution_formula") return; /* handled elsewhere */
+                if (self.batchUpdateWidgets[k].attr("disabled")) return;
+
+                /* It's important that a value of "" should mean that a field
+                 * doesn't get used in the arguments to the batch updater API,
+                 * but 0 should mean an actual 0. */
+                var value = self.batchUpdateWidgets[k].attr("value");
+                if (value !== "")
+                    o[k] = value;
+            }
+        );
+
+        return o;
+    };
+
+    this.batchUpdateFormula = function() {
+        if (this.batchUpdateWidgets.distribution_formula.attr("disabled")) {
+            return null;
+        } else {
+            return (
+                this.batchUpdateWidgets.distribution_formula.attr("value") ||
+                null
+            );
+        }
+    };
+
     this.reset = function(keep_selectors) {
         while(self.tbody.childNodes[0])
             self.tbody.removeChild(self.tbody.childNodes[0]);
@@ -175,7 +338,7 @@ function AcqLiTable() {
     };
 
     this.enableActionsDropdownOptions = function(mask) {
-        /* 'mask' is probably a minomer the way I'm using it, but it needs to
+        /* 'mask' is probably a misnomer the way I'm using it, but it needs to
          * be one of pl,po,ao,gs,vp, or fs. */
         dojo.query("option", "acq-lit-li-actions-selector").forEach(
             function(option) {
@@ -1924,21 +2087,10 @@ function AcqLiTable() {
                 if(self.copyBatchRowDrawn) {
                     self.copyBatchWidgets[field].attr('value', null);
                 } else {
-                    var widget = new openils.widget.AutoFieldWidget({
-                        fmField : field,
-                        fmClass : 'acqlid',
-                        labelFormat : (field == 'fund') ? fundLabelFormat : null,
-                        searchFormat : (field == 'fund') ? fundSearchFormat : null,
-                        searchFilter : (field == 'fund') ? {"active": "t"} : null,
-                        parentNode : dojo.query('[name='+field+']', row)[0],
-                        orgLimitPerms : ['CREATE_PICKLIST'],
-                        dijitArgs : {
-                            "required": false,
-                            "labelType": (field == "fund") ? "html" : null
-                        },
-                        noCache: (field == "fund"),
-                        forceSync : true
-                    });
+                    var args = self.afwCopyFieldArgs(field, "CREATE_PICKLIST");
+                    args.parentNode = dojo.query('[name='+field+']', row)[0];
+
+                    var widget = new openils.widget.AutoFieldWidget(args);
                     widget.build(
                         function(w, ww) {
                             if (field == "fund" && w.store)
diff --git a/Open-ILS/web/js/ui/default/acq/po/view_po.js b/Open-ILS/web/js/ui/default/acq/po/view_po.js
index 2a9b44c..0159b5b 100644
--- a/Open-ILS/web/js/ui/default/acq/po/view_po.js
+++ b/Open-ILS/web/js/ui/default/acq/po/view_po.js
@@ -318,6 +318,7 @@ function renderPo() {
     if(PO.order_date()) {
         openils.Util.show('acq-po-activated-on', 'inline');
         liTable.enableActionsDropdownOptions("ao"); /* activated */
+        liTable.initBatchUpdater(["item_count", "distribution_formula"]);
 
         dojo.byId('acq-po-activated-on').innerHTML = 
             dojo.string.substitute(
@@ -344,6 +345,7 @@ function renderPo() {
     } else {
         /* These things only make sense for not-ordered-yet POs */
 
+        liTable.initBatchUpdater();
         liTable.enableActionsDropdownOptions("po");
 
         openils.Util.show("acq-po-zero-activate-label", "table-cell");
diff --git a/docs/RELEASE_NOTES_NEXT/acq-interface-improvements.txt b/docs/RELEASE_NOTES_NEXT/acq-interface-improvements.txt
new file mode 100644
index 0000000..303941c
--- /dev/null
+++ b/docs/RELEASE_NOTES_NEXT/acq-interface-improvements.txt
@@ -0,0 +1,33 @@
+Acquisitions Purchase Order and other Interface Improvements
+============================================================
+
+Feature Summary
+---------------
+
+The following features, which primarily affect the user interface layer,
+improve Acquisitions work flows.
+
+  * Avoid double-activation of POs
+  * Disable invoice and cancel options for pending POs
+  * Disable zero-copy checkbox for activated POs
+  * Disable new charges for activated POs
+  * Replace "Shelving Location" with Copy Location
+
+  * Rearranging "actions" drop-down
+    ** More consitency in actions applying to selected lineitems specifically
+    ** Things moved from the per-lineitem dropdown to the main one when
+       sensible.
+    ** Add to PO dialog added
+    ** You can no longer add lineitems to a PO if they're already on one.
+    ** Actions in dropdown now enabled/disabled differently depending on
+       the interface where it appears (PO vs Selection List vs Acq Search etc.)
+
+  * Batch update for line items
+     ** Apply updates to all copies of all selected line items at once
+     ** Relies on a middle layer method that streams back information that
+        would suit a more asynchronous display in the future (rather than
+        simply reloading the page upon success, which it does now)
+     ** For failure cases, specific information about which line item cannot
+        be updated, and why, is available to the client, although taking
+        best advantage of this information for user-friendly display is left
+        to the future.
diff --git a/docs/RELEASE_NOTES_NEXT/acq_po_interface_improvements.txt b/docs/RELEASE_NOTES_NEXT/acq_po_interface_improvements.txt
deleted file mode 100644
index 1570948..0000000
--- a/docs/RELEASE_NOTES_NEXT/acq_po_interface_improvements.txt
+++ /dev/null
@@ -1,23 +0,0 @@
-Acquisitions Purchase Order Improvements
-========================================
-
-Feature Summary
----------------
-
-The following features, which primarily affect the user interface layer,
-improve Acquisitions work flows.
-
-  * Avoid double-activation of POs
-  * Disable invoice and cancel options for pending POs
-  * Disable zero-copy checkbox for activated POs
-  * Disable new charges for activated POs
-  * Replace "Shelving Location" with Copy Location
-
-  * Rearranging "actions" drop-down
-    ** More consitency in actions applying to selected lineitems specifically
-    ** Things moved from the per-lineitem dropdown to the main one when
-       sensible.
-    ** Add to PO dialog added
-    ** You can no longer add lineitems to a PO if they're already on one.
-    ** Actions in dropdown now enabled/disabled differently depending on
-       the interface where it appears (PO vs Selection List vs Acq Search etc.)

commit 8780429c3a92e7c89ed4cb37527444104558c641
Author: Lebbeous Fogle-Weekley <lebbeous at esilibrary.com>
Date:   Tue Feb 12 14:40:27 2013 -0500

    Acq: Line item batch update API method
    
    This new method gives you a server-side way to make batch updates to
    all the copies of a target set of lineitems.  Permissions are checked
    for each target object.  The method returns OpenILS::Event instances
    for all kinds of permission problems and other errors.  IDs of lineitems
    affected are streamed back to the client in the successful case.
    
    This also expands distribution formulae to contain more (optional)
    fields so that they can be used to make updates to copies on all the
    same fields that you can just specify individually.  IDL and interface
    changes to support the new fields are included.
    
    Signed-off-by: Lebbeous Fogle-Weekley <lebbeous at esilibrary.com>
    Signed-off-by: Bill Erickson <berick at esilibrary.com>

diff --git a/Open-ILS/examples/fm_IDL.xml b/Open-ILS/examples/fm_IDL.xml
index 4d8a299..4443128 100644
--- a/Open-ILS/examples/fm_IDL.xml
+++ b/Open-ILS/examples/fm_IDL.xml
@@ -8526,11 +8526,16 @@ SELECT  usr,
 			<field reporter:label="Item Count" name="item_count" reporter:datatype="int"/>
 			<field reporter:label="Owning Library" name="owning_lib" reporter:datatype="org_unit"/>
 			<field reporter:label="Location" name="location" reporter:datatype="link"/>
+			<field reporter:label="Fund" name="fund" reporter:datatype="link"/>
+			<field reporter:label="Circulation Modifier" name="circ_modifier" reporter:datatype="link"/>
+			<field reporter:label="Collection Code" name="collection_code" reporter:datatype="text"/>
 		</fields>
 		<links>
 			<link field="formula" reltype="has_a" key="id" map="" class="acqdf"/>
 			<link field="owning_lib" reltype="has_a" key="id" map="" class="aou"/>
 			<link field="location" reltype="has_a" key="id" map="" class="acpl"/>
+			<link field="fund" reltype="has_a" key="id" map="" class="acqf"/>
+			<link field="circ_modifier" reltype="has_a" key="code" map="" class="ccm"/>
 		</links>
 		<permacrud xmlns="http://open-ils.org/spec/opensrf/IDL/permacrud/v1">
 			<actions>
diff --git a/Open-ILS/src/extras/ils_events.xml b/Open-ILS/src/extras/ils_events.xml
index c37226b..3a4c650 100644
--- a/Open-ILS/src/extras/ils_events.xml
+++ b/Open-ILS/src/extras/ils_events.xml
@@ -652,7 +652,7 @@
 		<desc xml:lang='en-US'>The requested acq.funding_source_balance was not found</desc>
 	</event>
 	<event code='1858' textcode='ACQ_LINEITEM_NOT_FOUND'>
-		<desc xml:lang='en-US'>The requested acq.po_lineitem was not found</desc>
+		<desc xml:lang='en-US'>The requested acq.lineitem was not found</desc>
 	</event>
 	<event code='1859' textcode='ACQ_PURCHASE_ORDER_NOT_FOUND'>
 		<desc xml:lang='en-US'>The requested acq.purchase_order was not found</desc>
diff --git a/Open-ILS/src/perlmods/lib/OpenILS/Application/Acq/Lineitem.pm b/Open-ILS/src/perlmods/lib/OpenILS/Application/Acq/Lineitem.pm
index 9fe3ae6..35d4648 100644
--- a/Open-ILS/src/perlmods/lib/OpenILS/Application/Acq/Lineitem.pm
+++ b/Open-ILS/src/perlmods/lib/OpenILS/Application/Acq/Lineitem.pm
@@ -12,6 +12,7 @@ use OpenILS::Application::AppUtils;
 use OpenILS::Application::Acq::Financials;
 use OpenILS::Application::Cat::BibCommon;
 use OpenILS::Application::Cat::AssetCommon;
+use OpenILS::Application::Acq::Lineitem::BatchUpdate;
 my $U = 'OpenILS::Application::AppUtils';
 
 
diff --git a/Open-ILS/src/perlmods/lib/OpenILS/Application/Acq/Lineitem/BatchUpdate.pm b/Open-ILS/src/perlmods/lib/OpenILS/Application/Acq/Lineitem/BatchUpdate.pm
new file mode 100644
index 0000000..620ae06
--- /dev/null
+++ b/Open-ILS/src/perlmods/lib/OpenILS/Application/Acq/Lineitem/BatchUpdate.pm
@@ -0,0 +1,457 @@
+package OpenILS::Application::Acq::Lineitem::BatchUpdate;
+
+use strict;
+use warnings;
+
+use base qw/OpenILS::Application/;
+
+# All of the packages we might 'use' are already imported in
+# OpenILS::Application::Acq::Lineitem.  Only those that export symbols
+# need to be mentioned explicitly here.
+
+use List::Util qw/reduce/;
+use OpenSRF::Utils::Logger qw/:logger/;
+use OpenILS::Utils::CStoreEditor q/:funcs/;
+
+my $U = "OpenILS::Application::AppUtils";
+
+
+# lineitem_batch_update_perm_test(), helper for lineitem_batch_update_api()
+#
+# Tests permissions on targeted lineitems, purchase orders, and picklists.
+# Returns undef on success, event on perm failure.
+# Responsible for calling $e->die_event.
+# Also sanitizes values in $target.
+#
+sub lineitem_batch_update_perm_test {
+    my ($e, $target) = @_;
+
+    return $e->die_event(new OpenILS::Event("BAD_PARAMS", note => "target"))
+        unless ref $target eq "HASH";
+
+    my $perm_for = {
+        ordering_agency => "CREATE_PURCHASE_ORDER",
+        org_unit => "UPDATE_PICKLIST"
+    };
+
+    if (ref $target->{lineitems} eq "ARRAY") {
+        # Sanitization
+        $target->{lineitems} = [ map { int $_ } @{$target->{lineitems}} ];
+
+        return $e->die_event(
+            new OpenILS::Event(
+                "BAD_PARAMS", note => "target (lineitems list empty)"
+            )
+        ) unless @{$target->{lineitems}};
+
+        # Get all PO & picklist linkings from lineitems in question.
+        my $li_rows = $e->json_query({
+            select => {
+                jub => ["id"],
+                acqpo => ["ordering_agency"],
+                acqpl => ["org_unit"]
+            },
+            from => {
+                jub => {acqpl => {type => "left"}, acqpo => {type => "left"}}
+            },
+            where => {
+                "+jub" => {id => $target->{lineitems}}
+            }
+        }) or return $e->die_event;
+
+        # Fail loudly rather than giving user any surprises if they asked to
+        # update lineitems that don't exist.  This is an asymmetric difference
+        # calculation.
+        my %present = map { $_->{id} => 1 } @$li_rows;
+        my @missing = grep { not exists $present{$_} } @{$target->{lineitems}};
+        return $e->die_event(
+            new OpenILS::Event("ACQ_LINEITEM_NOT_FOUND", payload => \@missing)
+        ) if @missing;
+
+        # To avoid repetition of perm tests, track them here.
+        my $already_done = {
+            ordering_agency => {},
+            org_unit => {}
+        };
+
+        # Test all lineitems based on the context OU of all linked POs AND PLs.
+        foreach my $row (@$li_rows) {
+            foreach my $field (keys %$already_done) {
+                if ($row->{$field}) {
+                    if (not $already_done->{$row}{$field}) {
+                        my $perm = $perm_for->{$field};
+                        my $context = $row->{$field};
+
+                        if (not $e->allowed($perm, $context)) {
+                            my $evt = $e->die_event;
+
+                            # Take the PERM_FAILURE event and annotate it with
+                            # a list of the targeted lineitems that would fail
+                            # the same permission check (i.e. that have the
+                            # same context).
+                            $evt->{payload} = [
+                                map { $_->{id} } (
+                                    grep { $_->{$field} == $context } @$li_rows
+                                )
+                            ];
+                            return $evt;
+                        } else {
+                            $already_done->{$row}{$field} = 1;
+                        }
+                    }
+                }
+            }
+        }
+    } elsif ($target->{purchase_order}) {
+        $target->{purchase_order} = int($target->{purchase_order});
+
+        my $po = $e->retrieve_acq_purchase_order($target->{purchase_order}) or
+            return $e->die_event;
+
+        return $e->die_event unless
+            $e->allowed($perm_for->{ordering_agency}, $po->ordering_agency);
+    } elsif ($target->{picklist}) {
+        $target->{picklist} = int($target->{picklist});
+
+        my $pl = $e->retrieve_acq_picklist($target->{picklist}) or
+            return $e->die_event;
+
+        return $e->die_event unless
+            $e->allowed($perm_for->{org_unit}, $pl->org_unit);
+    } else {
+        return $e->die_event(
+            new OpenILS::Event("BAD_PARAMS", note => "target")
+        );
+    }
+
+    return; # perm check pass
+}
+
+
+# $changes->{item_count} wins over distribution formula if both are present.
+# It's also ok for neither to be present.
+sub pick_winning_item_count {
+    my ($changes, $dist_formula) = @_;
+
+    if (exists $changes->{item_count}) {
+        return $changes->{item_count};
+    } elsif ($dist_formula) {
+        return reduce { $a + $b->item_count } 0, @{$dist_formula->entries};
+    }
+
+    return;
+}
+
+
+# pick_winning_change() should be called in list context, so the caller can
+# distinguish between empty result (no change at all) and undef result (clear
+# field).
+sub pick_winning_change {
+    my ($changes, $dist_formula, $field, $position) = @_;
+
+    if (exists $changes->{$field}) {
+        # Remember: in $changes, not exists means no change, while undef
+        # means clear.
+
+        return $changes->{$field} if $position >= $changes->{position};
+    }
+
+    if ($dist_formula) {
+        my $hit;
+
+        my $count_over_entries = 0;
+        foreach my $entry (@{$dist_formula->entries}) {
+            $count_over_entries += $entry->item_count;
+
+            if ($count_over_entries > $position) {
+                # Abuse this virtual field on the distribution formula
+                # to let the caller know we actually used it.
+
+                $dist_formula->use_count(($dist_formula->use_count || 0) + 1);
+                $hit = $entry->$field;
+                last;
+            }
+        }
+
+        # The database doesn't give us a way to distinguish between "not exists"
+        # and undef like a hash does, so for dist formulas, undef (null) has
+        # to mean no change, and so if we come up with nothing defined, we
+        # don't return anything, not even the undef, since that would be
+        # misunderstood by the caller.
+        return $hit if defined $hit;
+    }
+
+    return; # return nothing, not even undef (in list context, anyway)
+}
+
+
+# adjust_lineitem_copy_counts() directly changes contents of @$lineitems
+sub adjust_lineitem_copy_counts {
+    my ($lineitems, $item_count) = @_;
+
+    # Count how many lineitem details we have per lineitem, and for
+    # each lineitem add or remove lineitems to match $item_count, as needed.
+
+    my %counts;
+
+    foreach my $jub (@$lineitems) {
+        $counts{$jub->id} = scalar @{$jub->lineitem_details};
+
+        if ($counts{$jub->id} > $item_count) {
+            # Take care of excess lineitem details.
+
+            for (my $i = $item_count; $i < $counts{$jub->id}; $i++) {
+                $jub->lineitem_details->[$i]->isdeleted(1);
+            }
+        } elsif ($counts{$jub->id} < $item_count) {
+            # Add missing lineitem details.
+
+            for (my $i = $counts{$jub->id}; $i < $item_count; $i++) {
+                my $lid = new Fieldmapper::acq::lineitem_detail;
+                $lid->isnew(1);
+                $lid->lineitem($jub->id);
+
+                push @{$jub->lineitem_details}, $lid;
+            }
+        }
+    }
+}
+
+
+# lineitem_batch_update_impl() should be handed everything pre-perm-checked
+# and ready-to-go. $e is in a transaction.
+sub lineitem_batch_update_impl {
+    my ($conn, $e, $dry_run, $target, $changes, $dist_formula) = @_;
+
+    # Keep client's attention.
+    $conn->status(new OpenSRF::DomainObject::oilsContinueStatus);
+
+    # First, retrieve existing lineitems with lineitem details.  We could do
+    # with the lineitem details only if not for having to catch lineitems
+    # with zero current lineitem details, so that we can augment those if
+    # requested by the user via $changes->{item_count}.
+
+    # The right ordering is important for adjusting lineitem detail counts.
+    my %order_by = (order_by => [
+        {class => "jub", field => "id"},
+        {class => "acqlid", field => "id"}
+    ]);
+
+    # XXX The following could be refactored only to retrieve one lineitem at a
+    # time, since the list of fleshed lineitem_details could conceivably be
+    # very long for each one. We'd then update each lineitem_detail on that
+    # lineitem before proceeding to the next.
+
+    my $lineitems;
+
+    if ($target->{lineitems}) {
+        $lineitems = $e->search_acq_lineitem(
+            [
+                {id => $target->{lineitems}},
+                {flesh => 1,
+                    flesh_fields => {"jub" => ["lineitem_details"]}, %order_by}
+            ], {substream => 1}
+        ) or return $e->die_event;
+    } else {
+        my $where;
+
+        if ($target->{purchase_order}) {
+            $where = {purchase_order => $target->{purchase_order}};
+        } else {
+            $where = {picklist => $target->{picklist}};
+        }
+
+        $lineitems = $e->search_acq_lineitem(
+            [
+                $where,
+                {flesh => 1,
+                    flesh_fields => {"jub" => ["lineitem_details"]}, %order_by}
+            ], {substream => 1}
+        ) or return $e->die_event;
+    }
+
+    $conn->status(new OpenSRF::DomainObject::oilsContinueStatus);
+    $logger->info(
+        "lineitem_batch_update_impl() working with " .
+        scalar(@$lineitems) . " lineitems"
+    );
+
+    my $item_count = pick_winning_item_count($changes, $dist_formula);
+    adjust_lineitem_copy_counts($lineitems, $item_count) if defined $item_count;
+
+    # Now, going through all our lineitem details, make the updates
+    # called for in $changes, other than the 'item_count' field (handled above).
+
+    my @fields = qw/owning_lib fund location collection_code circ_modifier/;
+    foreach my $jub (@$lineitems) {
+        # We use the counting style of loop below because we need to know our
+        # position for dist_formula application.
+
+        my $starting_use_count =
+            $dist_formula ? $dist_formula->use_count : undef;
+
+        for (my $i = 0; $i < scalar @{$jub->lineitem_details}; $i++) {
+            my $lid = $jub->lineitem_details->[$i];
+
+            # Handle copies needing a delete.
+            if ($lid->isdeleted) {
+                $e->delete_acq_lineitem_detail($lid) or return $e->die_event;
+                next;
+            }
+
+            # Handle existing and new copies.
+            foreach my $field (@fields) {
+                # Calling pick_winning_change() in list context gets us an
+                # empty list for "no change to make", (undef) for "clear the
+                # field", and ($value) for "set the field to $value".
+
+                my @change =
+                    pick_winning_change($changes, $dist_formula, $field, $i);
+
+                if (scalar @change) {
+                    my $change = pop @change;
+
+                    if (not defined $change) {
+                        my $meth = "clear_$field";
+                        $lid->$meth;
+                    } else {
+                        $lid->$field($change);
+                    }
+                }
+            }
+
+            my $method = ($lid->isnew ? "create" : "update") .
+                "_acq_lineitem_detail";
+
+            $e->$method($lid) or return $e->die_event;
+        }
+
+        if (defined $starting_use_count and
+            $dist_formula->use_count > $starting_use_count) {
+
+            # Record the application of the distribution formula.
+            my $dfa = new Fieldmapper::acq::distribution_formula_application;
+
+            $dfa->lineitem($jub->id);
+            $dfa->formula($dist_formula->id);
+            $dfa->creator($e->requestor->id);
+
+            $e->create_acq_distribution_formula_application($dfa) or
+                return $e->die_event;
+        }
+
+        $conn->respond($jub->id);
+    }
+
+    # Explicit bare return statements below avoid sending extra data to client.
+    if ($dry_run) {
+        $e->rollback;
+        return;
+    } else {
+        $e->commit or return $e->die_event;
+        return;
+    }
+}
+
+
+__PACKAGE__->register_method(
+    method => "lineitem_batch_update_api",
+    api_name => "open-ils.acq.lineitem.batch_update",
+    signature => {
+        desc => "Apply changes to the lineitem details realted to specified lineitems in batch",
+        params => [
+            {desc => "Authentication token", type => "string"},
+            {desc => "Target. Object key must be one of lineitems, purchase_order or picklist.  The value for 'lineitems' must be an array of IDs, and the values for either of the other two must be single IDs.", type => "object"},
+            {desc => "Changes (optional).  If these changes conflict with distribution formula, these changes win.", type => "object"},
+            {desc => "Distribution formula ID (optional). Note that a distribution formula's 'skip_count' field does nothing, but the 'position' and 'item_count' fields of distribution formula *entries* do what they ought to. ", type => "number"}
+        ],
+        return => {
+            desc => q/A stream of lineitem IDs affected upon success.  Events
+                on failure.  ANY events in the results, even after any number
+                of lineitem IDs, should be interpreted by the client to mean
+                that a rollback has happened and nothing has changed./,
+            type => "mixed"
+        }
+    }
+);
+
+__PACKAGE__->register_method(
+    method => "lineitem_batch_update_api",
+    api_name => "open-ils.acq.lineitem.batch_update.dry_run",
+    signature => {
+        desc => "Impotent version of open-ils.acq.lineitem.batch_update that always ends in a rollback",
+        params => "See open-ils.acq.lineitem.batch_update",
+        return => "See open-ils.acq.lineitem.batch_update"
+    }
+);
+
+sub lineitem_batch_update_api {
+    my ($self, $conn, $auth, $target, $changes, $dist_formula) = @_;
+
+    # Make sure that $changes->{item_count}, if it exists, is a natural number.
+    # Other things in $change are safe to treat somewhat more casually,
+    # except fund, which is handled later.
+    $changes ||= {};
+    if (exists $changes->{item_count}) {
+        $changes->{item_count} = int($changes->{item_count});
+        return new OpenILS::Event("BAD_PARAMS", note => "changes (item_count)")
+            unless $changes->{item_count} >= 0;
+    }
+
+    # We want to do our perm tests and everything within a transaction.
+    my $e = new_editor(authtoken => $auth, xact => 1);
+    return $e->die_event unless $e->checkauth;
+
+    # If any distribution formula ID is given, fetch distribution formula
+    # (with entries fleshed) early so we can get a quick permission check
+    # out of the way.
+    if ($dist_formula) {
+
+        # It's important that we NOT flesh use_count here, if that [ever]
+        # does anything.  We're going to abuse that field internally.
+
+        $dist_formula = $e->acq->retrieve_acq_distribution_formula([
+            int($dist_formula), {flesh=>1, flesh_fields=>["entries","fund"]}
+        ]) or return $e->die_event;
+
+        return $e->die_event unless
+            $e->allowed("ADMIN_ACQ_DISTRIB_FORMULA", $dist_formula->owner);
+
+        # If the distribution formula has a fund, there's an additional perm
+        # test to do before proceeding.
+        if ($dist_formula->fund) {
+            return $e->die_event unless $e->allowed(
+                ["ADMIN_FUND", "MANAGE_FUND"],
+                $dist_formula->fund->org, $dist_formula->fund
+            );
+        }
+
+        # The following sort is crucial later.
+        $dist_formula->entries([
+            sort { $a->position cmp $b->position } @{$dist_formula->entries}
+        ]);
+    }
+
+    # Next, test permissions on fund to set, if any, from $changes.
+    if ($changes->{fund}) {
+        my $fund = $e->retrieve_acq_fund($changes->{fund}) or
+            return $e->die_event;
+
+        return $e->die_event unless
+            $e->allowed(["ADMIN_FUND", "MANAGE_FUND"], $fund->org, $fund);
+    }
+
+    # Now test permissions on the targets.  lineitem_batch_update_perm_test()
+    # calls die_event() for us if needed.  Has side-effect of target
+    # sanitization.
+    my $evt = lineitem_batch_update_perm_test($e, $target);
+    return $evt if $U->event_code($evt);
+
+    # Finally do the actual work.
+    return lineitem_batch_update_impl(
+        $conn, $e, scalar($self->api_name =~ /dry_run/),
+        $target, $changes, $dist_formula
+    );
+}
+
+1;
diff --git a/Open-ILS/src/sql/Pg/200.schema.acq.sql b/Open-ILS/src/sql/Pg/200.schema.acq.sql
index 126c44e..1095513 100644
--- a/Open-ILS/src/sql/Pg/200.schema.acq.sql
+++ b/Open-ILS/src/sql/Pg/200.schema.acq.sql
@@ -631,6 +631,9 @@ CREATE TABLE acq.distribution_formula_entry (
 	owning_lib	INTEGER REFERENCES actor.org_unit(id)
 				DEFERRABLE INITIALLY DEFERRED,
 	location	INTEGER REFERENCES asset.copy_location(id),
+	fund		INTEGER REFERENCES acq.fund (id),
+	circ_modifier	TEXT REFERENCES config.circ_modifier (code),
+	collection_code TEXT,
 	CONSTRAINT acqdfe_lib_once_per_formula UNIQUE( formula, position ),
 	CONSTRAINT acqdfe_must_be_somewhere
 				CHECK( owning_lib IS NOT NULL OR location IS NOT NULL ) 
diff --git a/Open-ILS/src/sql/Pg/upgrade/XXXX.schema.acq.distribution_formula.expansion.sql b/Open-ILS/src/sql/Pg/upgrade/XXXX.schema.acq.distribution_formula.expansion.sql
new file mode 100644
index 0000000..391bcf8
--- /dev/null
+++ b/Open-ILS/src/sql/Pg/upgrade/XXXX.schema.acq.distribution_formula.expansion.sql
@@ -0,0 +1,10 @@
+BEGIN;
+
+--SELECT evergreen.upgrade_deps_block_check('XXXX', :eg_version);
+
+ALTER TABLE acq.distribution_formula_entry
+    ADD COLUMN fund INT REFERENCES acq.fund (id),
+    ADD COLUMN circ_modifier TEXT REFERENCES config.circ_modifier (code),
+    ADD COLUMN collection_code TEXT ;
+
+COMMIT;
diff --git a/Open-ILS/src/templates/conify/global/acq/distribution_formula.tt2 b/Open-ILS/src/templates/conify/global/acq/distribution_formula.tt2
index d80e29e..68f536e 100644
--- a/Open-ILS/src/templates/conify/global/acq/distribution_formula.tt2
+++ b/Open-ILS/src/templates/conify/global/acq/distribution_formula.tt2
@@ -50,6 +50,9 @@
                 <th></th>
                 <th>[% l('Owning Library') %]</th>
                 <th>[% l('Copy Location') %]</th>
+                <th>[% l('Fund') %]</th>
+                <th>[% l('Circ Modifier') %]</th>
+                <th>[% l('Collection Code') %]</th>
                 <th>[% l('Item Count') %]</th>
                 <th></th>
             </tr>
@@ -57,9 +60,12 @@
         <tbody id='formula-entry-tbody'>
             <tr id='formula-entry-tempate'>
                 <td><div name='delete' dojoType='dijit.form.Button' style='color:red;' scrollOnFocus='false'>X</div></td>
-                <td><div name='owning_lib'></td>
-                <td><div name='location'></td>
-                <td><div name='item_count'></td>
+                <td><div name='owning_lib'></div></td>
+                <td><div name='location'></div></td>
+                <td><div name='fund'></div></td>
+                <td><div name='circ_modifier'></div></td>
+                <td><div name='collection_code'></div></td>
+                <td><div name='item_count'></div></td>
                 <td>
                     <img src='[% ctx.media_prefix %]/images/dimple.png'/>
                     <img src='[% ctx.media_prefix %]/images/dimple.png'/>
diff --git a/Open-ILS/web/js/ui/default/conify/global/acq/distribution_formula.js b/Open-ILS/web/js/ui/default/conify/global/acq/distribution_formula.js
index 69e3932..a2d5eec 100644
--- a/Open-ILS/web/js/ui/default/conify/global/acq/distribution_formula.js
+++ b/Open-ILS/web/js/ui/default/conify/global/acq/distribution_formula.js
@@ -12,7 +12,8 @@ var formCache = {};
 var formula, entryTbody, entryTemplate, dndSource;
 var virtualId = -1;
 var pcrud;
-
+var _collection_code_textboxes = [];
+var _collection_code_kludge_active = false;
 
 function gridDataLoader() {
     fListGrid.resetStore();
@@ -145,7 +146,7 @@ function addEntry(entry) {
     };
 
     dojo.forEach(
-        ['owning_lib', 'location', 'item_count'],
+        ['owning_lib', 'location', 'fund', 'circ_modifier', 'collection_code', 'item_count'],
         function(field) {
             new openils.widget.AutoFieldWidget({
                 forceSync : true,
@@ -159,6 +160,10 @@ function addEntry(entry) {
                 dijitArgs : (field == 'item_count') ? {min:1, places:0} : null
             }).build(
                 function(w, ww) {
+                    if (field == "collection_code") {
+                        /* kludge for glitchy textbox */
+                        _collection_code_textboxes.push(w);
+                    }
                     dojo.connect(w, 'onChange', 
                         function(newVal) {
                             entry[field]( newVal );
@@ -169,6 +174,35 @@ function addEntry(entry) {
             );
         }
     );
+
+    /* For some reason (bug) the dndSource intercepts onMouseDown events
+     * that should hit dijit textboxes in our table thingy. Other dijits
+     * (buttons, filteringselects, etc) seem not to be affected.  This
+     * workaround deals with the only textboxes we have for now: the ones
+     * for the collection_code field. */
+    if (!_collection_code_kludge_active) {
+        _collection_code_kludge_active = true;
+        var original = dojo.hitch(dndSource, dndSource.onMouseDown);
+        dndSource.onMouseDown = function(e) {
+            var hits = _collection_code_textboxes.filter(
+                function(w) {
+                    var c = dojo.coords(w.domNode);
+                    if (e.clientX >= c.x && e.clientX < c.x + c.w) {
+                        if (e.clientY >= c.y && e.clientY < c.y + c.h) {
+                            return true;
+                        }
+                    }
+                    return false;
+                }
+            );
+
+            if (hits.length) {
+                hits[0].focus();
+            } else {
+                original(e);
+            }
+        };
+    }
 }
 
 function saveFormula() {

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

Summary of changes:
 Open-ILS/examples/fm_IDL.xml                       |    7 +-
 Open-ILS/src/extras/ils_events.xml                 |    2 +-
 .../lib/OpenILS/Application/Acq/Lineitem.pm        |    1 +
 .../Application/Acq/Lineitem/BatchUpdate.pm        |  465 ++++++++++++++++++++
 Open-ILS/src/sql/Pg/002.schema.config.sql          |    2 +-
 Open-ILS/src/sql/Pg/200.schema.acq.sql             |   20 +-
 Open-ILS/src/sql/Pg/950.data.seed-values.sql       |   20 +
 ....schema.acq.distribution_formula.expansion.sql} |  136 +-----
 ...781.data.acq.distribution_formula.expansion.sql |   25 +
 Open-ILS/src/templates/acq/common/li_table.tt2     |  172 +++++---
 .../conify/global/acq/distribution_formula.tt2     |   12 +-
 Open-ILS/web/css/skin/default/acq.css              |    4 +
 Open-ILS/web/js/dojo/openils/acq/nls/acq.js        |    6 +-
 Open-ILS/web/js/ui/default/acq/common/li_table.js  |  184 +++++++-
 Open-ILS/web/js/ui/default/acq/po/view_po.js       |    2 +
 .../conify/global/acq/distribution_formula.js      |   38 ++-
 .../acq-interface-improvements.txt                 |   33 ++
 .../acq_po_interface_improvements.txt              |   23 -
 18 files changed, 920 insertions(+), 232 deletions(-)
 create mode 100644 Open-ILS/src/perlmods/lib/OpenILS/Application/Acq/Lineitem/BatchUpdate.pm
 copy Open-ILS/src/sql/Pg/upgrade/{0730.schema.acq-function-dedup.sql => 0780.schema.acq.distribution_formula.expansion.sql} (58%)
 create mode 100644 Open-ILS/src/sql/Pg/upgrade/0781.data.acq.distribution_formula.expansion.sql
 create mode 100644 docs/RELEASE_NOTES_NEXT/acq-interface-improvements.txt
 delete mode 100644 docs/RELEASE_NOTES_NEXT/acq_po_interface_improvements.txt


hooks/post-receive
-- 
Evergreen ILS


More information about the open-ils-commits mailing list