* Using lineitem estimated_unit_price to store the price instead of the lineitem...
authorerickson <erickson@dcc99617-32d9-48b4-a31d-7c20da2025e4>
Tue, 9 Mar 2010 20:24:14 +0000 (20:24 +0000)
committererickson <erickson@dcc99617-32d9-48b4-a31d-7c20da2025e4>
Tue, 9 Mar 2010 20:24:14 +0000 (20:24 +0000)
* If necessary, perform the currency conversion exactly once, when the order is activated.  Otherewise, assume the price is in the currency of the vendor.
* Create fund debits during PO activation instead of PO creation time.
* Cleared out a pile of deprecated code
* TODO: update JEDI template to pull price from the estimated_price_field

git-svn-id: svn://svn.open-ils.org/ILS/trunk@15769 dcc99617-32d9-48b4-a31d-7c20da2025e4

Open-ILS/src/perlmods/OpenILS/Application/Acq/Financials.pm
Open-ILS/src/perlmods/OpenILS/Application/Acq/Order.pm
Open-ILS/src/perlmods/OpenILS/WWW/Vandelay.pm
Open-ILS/web/js/ui/default/acq/common/li_table.js
Open-ILS/web/templates/default/acq/picklist/upload.tt2

index 9901e69..447ee4a 100644 (file)
@@ -595,25 +595,6 @@ sub retrieve_all_currency_type {
     $conn->respond($_) for @{$e->retrieve_all_acq_currency_type()};
 }
 
-sub currency_conversion_impl {
-    my($src_currency, $dest_currency, $amount) = @_;
-    my $result = new_editor()->json_query({
-        select => {
-            acqct => [{
-                params => [$dest_currency, $amount],
-                transform => 'acq.exchange_ratio',
-                column => 'code',
-                alias => 'value'
-            }]
-        },
-        where => {code => $src_currency},
-        from => 'acqct'
-    });
-
-    return $result->[0]->{value};
-}
-
-
 __PACKAGE__->register_method(
        method => 'create_lineitem_assets',
        api_name        => 'open-ils.acq.lineitem.assets.create',
@@ -736,137 +717,6 @@ sub create_purchase_order_impl {
 }
 
 
-# returns (price, type), where type=1 is local, type=2 is provider, type=3 is marc
-sub get_li_price {
-    my $li = shift;
-    my $attrs = $li->attributes;
-    my ($marc_estimated, $local_estimated, $local_actual, $prov_estimated, $prov_actual);
-
-    for my $attr (@$attrs) {
-        if($attr->attr_name eq 'estimated_price') {
-            $local_estimated = $attr->attr_value 
-                if $attr->attr_type eq 'lineitem_local_attr_definition';
-            $prov_estimated = $attr->attr_value 
-                if $attr->attr_type eq 'lineitem_prov_attr_definition';
-            $marc_estimated = $attr->attr_value
-                if $attr->attr_type eq 'lineitem_marc_attr_definition';
-
-        } elsif($attr->attr_name eq 'actual_price') {
-            $local_actual = $attr->attr_value     
-                if $attr->attr_type eq 'lineitem_local_attr_definition';
-            $prov_actual = $attr->attr_value 
-                if $attr->attr_type eq 'lineitem_prov_attr_definition';
-        }
-    }
-
-    return ($local_actual, 1) if $local_actual;
-    return ($prov_actual, 2) if $prov_actual;
-    return ($local_estimated, 1) if $local_estimated;
-    return ($prov_estimated, 2) if $prov_estimated;
-    return ($marc_estimated, 3);
-}
-
-
-__PACKAGE__->register_method(
-       method => 'create_purchase_order_debits',
-       api_name        => 'open-ils.acq.purchase_order.debits.create',
-       signature => {
-        desc => 'Creates debits associated with a PO',
-        params => [
-            {desc => 'Authentication token', type => 'string'},
-            {desc => 'purchase_order whose debits to create', type => 'number'},
-            {desc => 'arguments hash.  Options include: encumbrance=bool', type => 'object'},
-        ],
-        return => {desc => 'The total amount of all created debits, Event on error'}
-    }
-);
-
-sub create_purchase_order_debits {
-    my($self, $conn, $auth, $po_id, $args) = @_;
-    my $e = new_editor(xact=>1, authtoken=>$auth);
-    return $e->die_event unless $e->checkauth;
-    
-    my $po = $e->retrieve_acq_purchase_order($po_id) or return $e->die_event;
-
-    my $li_ids = $e->search_acq_lineitem(
-        {purchase_order => $po_id},
-        {idlist => 1}
-    );
-
-    for my $li_id (@$li_ids) {
-        my $li = $e->retrieve_acq_lineitem([
-            $li_id,
-            {   flesh => 1,
-                flesh_fields => {jub => ['attributes']},
-            }
-        ]);
-
-        my ($total, $evt) = create_li_debit_impl($e, $li);
-        return $evt if $evt;
-    }
-    $e->commit;
-    return 1;
-}
-
-sub create_li_debit_impl {
-    my($e, $li, $args) = @_;
-    $args ||= {};
-
-    my ($price, $ptype) = get_li_price($li);
-
-    unless($price) {
-        $e->rollback;
-        return (undef, OpenILS::Event->new('ACQ_LINEITEM_NO_PRICE', payload => $li->id));
-    }
-
-    unless($li->provider) {
-        $e->rollback;
-        return (undef, OpenILS::Event->new('ACQ_LINEITEM_NO_PROVIDER', payload => $li->id));
-    }
-
-    my $lid_ids = $e->search_acq_lineitem_detail(
-        {lineitem => $li->id}, 
-        {idlist=>1}
-    );
-
-    my $total = 0;
-    for my $lid_id (@$lid_ids) {
-
-        my $lid = $e->retrieve_acq_lineitem_detail([
-            $lid_id,
-            {   flesh => 1, 
-                flesh_fields => {acqlid => ['fund']}
-            }
-        ]);
-
-        my $debit = Fieldmapper::acq::fund_debit->new;
-        $debit->fund($lid->fund->id);
-        $debit->origin_amount($price);
-
-        if($ptype == 2) { # price from vendor
-            $debit->origin_currency_type($li->provider->currency_type);
-            $debit->amount(currency_conversion_impl(
-                $li->provider->currency_type, $lid->fund->currency_type, $price));
-        } else {
-            $debit->origin_currency_type($lid->fund->currency_type);
-            $debit->amount($price);
-        }
-
-        $debit->encumbrance($args->{encumbrance});
-        $debit->debit_type('purchase');
-        $e->create_acq_fund_debit($debit) or return (undef, $e->die_event);
-
-        # point the lineitem detail at the fund debit object
-        $lid->fund_debit($debit->id);
-        $lid->fund($lid->fund->id);
-        $e->update_acq_lineitem_detail($lid) or return (undef, $e->die_event);
-        $total += $debit->amount;
-    }
-
-    return ($total);
-}
-
-
 __PACKAGE__->register_method(
        method => 'retrieve_all_user_purchase_order',
        api_name        => 'open-ils.acq.purchase_order.user.all.retrieve',
@@ -1006,6 +856,8 @@ sub po_perm_failure {
 sub build_price_summary {
     my ($e, $po_id) = @_;
 
+    # TODO: Add summary value for estimated amount (pre-encumber)
+
     # fetch the fund debits for this purchase order
     my $debits = $e->json_query({
         "select" => {"acqfdeb" => [qw/encumbrance amount/]},
index c62214e..bddfa09 100644 (file)
@@ -207,9 +207,38 @@ sub create_lineitem {
     $li->$_($args{$_}) for keys %args;
     $li->clear_id;
     $mgr->add_li;
-    return $mgr->editor->create_acq_lineitem($li);
+    $mgr->editor->create_acq_lineitem($li) or return 0;
+    
+    unless($li->estimated_unit_price) {
+        # extract the price from the MARC data
+        my $price = get_li_price_from_attrs($li) or return $li;
+        $li->estimated_unit_price($price);
+        return update_lineitem($mgr, $li);
+    }
+
+    return $li;
+}
+
+sub get_li_price_from_attr {
+    my($e, $li) = @_;
+    my $attrs = $li->attributes || $e->search_acq_lineitem_attr({lineitem => $li->id});
+
+    for my $attr_type (qw/    
+            lineitem_local_attr_definition 
+            lineitem_prov_attr_definition 
+            lineitem_marc_attr_definition/) {
+
+        my ($attr) = grep {
+            $_->attr_name eq 'estimated_price' and 
+            $_->attr_type eq $attr_type } @$attrs;
+
+        return $attr->attr_value if $attr;
+    }
+
+    return undef;
 }
 
+
 sub update_lineitem {
     my($mgr, $li) = @_;
     $li->edit_time('now');
@@ -501,11 +530,6 @@ sub receive_lineitem_detail {
     $copy->editor($e->requestor->id);
     $e->update_asset_copy($copy) or return 0;
 
-    if($lid->fund_debit) {
-        $lid->fund_debit->encumbrance('f');
-        $e->update_acq_fund_debit($lid->fund_debit) or return 0;
-    }
-
     $mgr->add_lid;
 
     return 1 if $skip_complete_check;
@@ -541,11 +565,6 @@ sub rollback_receive_lineitem_detail {
     $copy->editor($e->requestor->id);
     $e->update_asset_copy($copy) or return 0;
 
-    if($lid->fund_debit) {
-        $lid->fund_debit->encumbrance('t');
-        $e->update_acq_fund_debit($lid->fund_debit) or return 0;
-    }
-
     $mgr->add_lid;
     return $lid;
 }
@@ -583,45 +602,13 @@ sub set_lineitem_attr {
     }
 }
 
-sub get_li_price {
-    my $li = shift;
-    my $attrs = $li->attributes;
-    my ($marc_estimated, $local_estimated, $local_actual, $prov_estimated, $prov_actual);
-
-    for my $attr (@$attrs) {
-        if($attr->attr_name eq 'estimated_price') {
-            $local_estimated = $attr->attr_value 
-                if $attr->attr_type eq 'lineitem_local_attr_definition';
-            $prov_estimated = $attr->attr_value 
-                if $attr->attr_type eq 'lineitem_prov_attr_definition';
-            $marc_estimated = $attr->attr_value
-                if $attr->attr_type eq 'lineitem_marc_attr_definition';
-
-        } elsif($attr->attr_name eq 'actual_price') {
-            $local_actual = $attr->attr_value     
-                if $attr->attr_type eq 'lineitem_local_attr_definition';
-            $prov_actual = $attr->attr_value 
-                if $attr->attr_type eq 'lineitem_prov_attr_definition';
-        }
-    }
-
-    return ($local_actual, 1) if $local_actual;
-    return ($prov_actual, 2) if $prov_actual;
-    return ($local_estimated, 1) if $local_estimated;
-    return ($prov_estimated, 2) if $prov_estimated;
-    return ($marc_estimated, 3);
-}
-
-
 # ----------------------------------------------------------------------------
 # Lineitem Debits
 # ----------------------------------------------------------------------------
 sub create_lineitem_debits {
-    my($mgr, $li, $price, $ptype) = @_; 
+    my($mgr, $li) = @_; 
 
-    ($price, $ptype) = get_li_price($li) unless $price;
-
-    unless($price) {
+    unless($li->estimated_unit_price) {
         $mgr->editor->event(OpenILS::Event->new('ACQ_LINEITEM_NO_PRICE', payload => $li->id));
         $mgr->editor->rollback;
         return 0;
@@ -647,7 +634,7 @@ sub create_lineitem_debits {
             }
         ]);
 
-        create_lineitem_detail_debit($mgr, $li, $lid, $price, $ptype) or return 0;
+        create_lineitem_detail_debit($mgr, $li, $lid) or return 0;
     }
 
     return 1;
@@ -656,9 +643,8 @@ sub create_lineitem_debits {
 
 # flesh li->provider
 # flesh lid->fund
-# ptype 1=local, 2=provider, 3=marc
 sub create_lineitem_detail_debit {
-    my($mgr, $li, $lid, $price, $ptype) = @_;
+    my($mgr, $li, $lid) = @_;
 
     my $li_id = ref($li) ? $li->id : $li;
 
@@ -680,19 +666,27 @@ sub create_lineitem_detail_debit {
         ]);
     }
 
-    my $ctype = $lid->fund->currency_type;
-    my $amount = $price;
+    my $amount = $li->estimated_unit_price;
+    if($li->provider->currency_type ne $lid->fund->currency_type) {
+
+        # At Fund debit creation time, translate into the currency of the fund
+        # TODO: org setting to disable automatic currency conversion at debit create time?
 
-    if($ptype == 2) { # price from vendor
-        $ctype = $li->provider->currency_type;
-        $amount = currency_conversion($mgr, $ctype, $lid->fund->currency_type, $price);
+        $amount = $mgr->editor->json_query({
+            from => [
+                'acq.exchange_ratio', 
+                $li->provider->currency_type, # source currency
+                $lid->fund->currency_type, # destination currency
+                $li->estimated_unit_price # source amount
+            ]
+        })->[0]->{value};
     }
 
     my $debit = create_fund_debit(
         $mgr, 
         fund => $lid->fund->id,
-        origin_amount => $price,
-        origin_currency_type => $ctype,
+        origin_amount => $li->estimated_unit_price,
+        origin_currency_type => $li->provider->currency_type,
         amount => $amount
     ) or return 0;
 
@@ -740,13 +734,6 @@ sub create_fund_debit {
     return $mgr->editor->create_acq_fund_debit($debit);
 }
 
-sub currency_conversion {
-    my($mgr, $src_currency, $dest_currency, $amount) = @_;
-    my $result = $mgr->editor->json_query(
-        {from => ['acq.exchange_ratio', $src_currency, $dest_currency, $amount]});
-    return $result->[0]->{'acq.exchange_ratio'};
-}
-
 
 # ----------------------------------------------------------------------------
 # Picklist
@@ -1115,6 +1102,7 @@ sub upload_records {
     my $provider = $data->{provider};
     my $picklist = $data->{picklist};
     my $create_po = $data->{create_po};
+    my $activate_po = $data->{activate_po};
     my $ordering_agency = $data->{ordering_agency};
     my $create_assets = $data->{create_assets};
     my $po;
@@ -1196,7 +1184,7 @@ sub upload_records {
         $args{picklist} = $picklist->id if $picklist;
         if($po) {
             $args{purchase_order} = $po->id;
-            $args{state} = 'on-order';
+            $args{state} = 'order-pending';
         }
 
         my $li = create_lineitem($mgr, %args) or return $mgr->editor->die_event;
@@ -1210,6 +1198,9 @@ sub upload_records {
         $mgr->respond;
        }
 
+    my $die_event = activate_purchase_order_impl($mgr, $po->id) if $po;;
+    return $die_event if $die_event;
+
        $e->commit;
     unlink($filename);
     $cache->delete_cache('vandelay_import_spool_' . $key);
@@ -1259,21 +1250,8 @@ sub import_lineitem_details {
         $idx++;
     }
 
-    # set the price attr so we'll know the source of the price
-    set_lineitem_attr(
-        $mgr, 
-        attr_name => 'estimated_price',
-        attr_type => 'lineitem_local_attr_definition',
-        attr_value => $price,
-        lineitem => $li->id
-    ) or return 0;
-
-    # if we're creating a purchase order, create the debits
-    if($li->purchase_order) {
-        create_lineitem_debits($mgr, $li, $price, 2) or return 0;
-        $mgr->respond;
-    }
-
+    $li->estimated_unit_price($price);
+    update_lineitem($mgr, $li) or return 0;
     return 1;
 }
 
@@ -1473,8 +1451,6 @@ sub create_purchase_order_api {
             $li->state('pending-order');
             update_lineitem($mgr, $li) or return $e->die_event;
             $mgr->respond;
-
-            create_lineitem_debits($mgr, $li) or return $e->die_event;
         }
     }
 
@@ -1838,24 +1814,29 @@ __PACKAGE__->register_method(
 );
 
 sub set_lineitem_price_api {
-    my($self, $conn, $auth, $li_id, $price, $currency) = @_;
+    my($self, $conn, $auth, $li_id, $price) = @_;
 
     my $e = new_editor(xact=>1, authtoken=>$auth);
     return $e->die_event unless $e->checkauth;
     my $mgr = OpenILS::Application::Acq::BatchManager->new(editor => $e, conn => $conn);
 
-    # XXX perms
+    my $li = $e->retrieve_acq_lineitem([
+        $li_id,
+        {   flesh => 1,
+            flesh_fields => {jub => ['purchase_order', 'picklist']}
+        }
+    ]) or return $e->die_event;
 
-    my $li = $e->retrieve_acq_lineitem($li_id) or return $e->die_event;
+    if($li->purchase_order) {
+        return $e->die_event unless 
+            $e->allowed('CREATE_PURCHASE_ORDER', $li->purchase_order->ordering_agency);
+    } else {
+        return $e->die_event unless 
+            $e->allowed('CREATE_PICKLIST', $li->picklist->org_unit);
+    }
 
-    # update the local attr for estimated price
-    set_lineitem_attr(
-        $mgr, 
-        attr_name => 'estimated_price',
-        attr_type => 'lineitem_local_attr_definition',
-        attr_value => $price,
-        lineitem => $li_id
-    ) or return $e->die_event;
+    $li->estimated_unit_price($price);
+    update_lineitem($mgr, $li) or return $e->die_event;
 
     my $lid_ids = $e->search_acq_lineitem_detail(
         {lineitem => $li_id, fund_debit => {'!=' => undef}}, 
@@ -1869,18 +1850,7 @@ sub set_lineitem_price_api {
             flesh => 1, flesh_fields => {acqlid => ['fund', 'fund_debit']}}
         ]);
 
-        # onless otherwise specified, assume currency of new price is same as currency type of the fund
-        $currency ||= $lid->fund->currency_type;
-        my $amount = $price;
-
-        if($lid->fund->currency_type ne $currency) {
-            $amount = currency_conversion($mgr, $currency, $lid->fund->currency_type, $price);
-        }
-        
-        $lid->fund_debit->origin_currency_type($currency);
-        $lid->fund_debit->origin_amount($price);
-        $lid->fund_debit->amount($amount);
-
+        $lid->fund_debit->amount($price);
         $e->update_acq_fund_debit($lid->fund_debit) or return $e->die_event;
         $mgr->add_lid;
         $mgr->respond;
@@ -2044,6 +2014,7 @@ sub activate_purchase_order {
 
     while( my $li = $e->search_acq_lineitem($query)->[0] ) {
         $li->state('on-order');
+        create_lineitem_debits($mgr, $li) or return $e->die_event;
         update_lineitem($mgr, $li) or return $e->die_event;
         $mgr->post_process( sub { create_lineitem_status_events($mgr, $li->id, 'aur.ordered'); });
         $mgr->respond;
index 8333ed0..314b2e3 100644 (file)
@@ -69,6 +69,7 @@ sub spool_marc {
     my $provider = $cgi->param('provider') || '';
     my $picklist = $cgi->param('picklist') || '';
     my $create_po = $cgi->param('create_po') || '';
+    my $activate_po = $cgi->param('activate_po') || '';
     my $ordering_agency = $cgi->param('ordering_agency') || '';
     my $create_assets = $cgi->param('create_assets') || '';
 
index 6d28780..e9b3a45 100644 (file)
@@ -254,10 +254,10 @@ function AcqLiTable() {
 
         // lineitem state
         nodeByName('li_state', row).innerHTML = li.state(); // TODO i18n state labels
+        
         // lineitem price
         var priceInput = dojo.query('[name=price]', row)[0];
-        var priceData = liWrapper.getPrice();
-        priceInput.value = (priceData) ? priceData.price : '';
+        priceInput.value = li.estimated_unit_price() || '';
         priceInput.onchange = function() { self.updateLiPrice(priceInput, li) };
 
         // show either "mark received" or "unreceive" as appropriate
@@ -505,11 +505,7 @@ function AcqLiTable() {
     this.updateLiPrice = function(input, li) {
 
         var price = input.value;
-        var liWrapper = new openils.acq.Lineitem({lineitem:li});
-        var oldPrice = liWrapper.getPrice() || null;
-
-        if(oldPrice) oldPrice = oldPrice.price;
-        if(price == oldPrice) return;
+        if(Number(price) == Number(li.estimated_unit_price())) return;
 
         fieldmapper.standardRequest(
             ['open-ils.acq', 'open-ils.acq.lineitem.price.set'],
index d4b39e0..4045499 100644 (file)
                 </td>
             </tr>
             <tr>
+                <td>Activate Purchase Order</td>
+                <td>
+                    <input dojoType='dijit.form.CheckBox' name='activate_po'></input>
+                </td>
+            </tr>
+            <tr>
                 <!-- XXX CHECK IMPORT PERMS TO ENABLE -->
                 <td>Load Bibs and Items into the ILS</td>
                 <td>