Bug 18639: Add replacementprice field to acquisitions workflow

To test:
 0 - Apply patches and updatedatabase
 1 - Add an order to a basket
 2 - You should note new 'Retail price field'
 3 - You should have a separate 'Replacement price' field
 4 - Enter values and ensure they are saved as expected
 5 - In the basket you should see the replacement price
 6 - Modify order and ensure value is loaded and saved correctly
 7 - Add and cancle an order and esure replacement price shows/saves
 8 - Close basket
 9 - Receive an order
10 - You should be able to edit replacement price
11 - 'retail price' field is not editable
12 - Check associated item, replacement price in item should be updated
13 - Cancel receipt, check item. receive again with new replacement
price, check item
14 - Price should be correctly updated
15 - Finish receipt, value should show in table
16 - Test with receive from file

Signed-off-by: Martin Renvoize <martin.renvoize@ptfs-europe.com>

Signed-off-by: Nick Clemens <nick@bywatersolutions.com>
This commit is contained in:
Nick Clemens 2017-12-29 16:16:23 +00:00
parent 26976dfba9
commit a3e8e12364
10 changed files with 137 additions and 92 deletions

View File

@ -1507,6 +1507,10 @@ sub ModReceiveOrder {
orderstatus = 'complete'
|;
$query .= q|
, replacementprice = ?
| if defined $order->{replacementprice};
$query .= q|
, unitprice = ?, unitprice_tax_included = ?, unitprice_tax_excluded = ?
| if defined $order->{unitprice};
@ -1528,6 +1532,10 @@ sub ModReceiveOrder {
my $sth = $dbh->prepare( $query );
my @params = ( $quantrec, $datereceived, $invoice->{invoiceid}, ( $budget_id ? $budget_id : $order->{budget_id} ) );
if ( defined $order->{replacementprice} ) {
push @params, $order->{replacementprice};
}
if ( defined $order->{unitprice} ) {
push @params, $order->{unitprice}, $order->{unitprice_tax_included}, $order->{unitprice_tax_excluded};
}

View File

@ -262,6 +262,7 @@ if ($op eq ""){
);
my $price = $infos->{price};
my $replacementprice = $infos->{replacementprice};
if ($price){
# in France, the cents separator is the , but sometimes, ppl use a .
# in this case, the price will be x100 when unformatted ! Replace the . by a , to get a proper price calculation
@ -283,6 +284,7 @@ if ($op eq ""){
} else {
$orderinfo{listprice} = 0;
}
$orderinfo{replacementprice} = $replacementprice || 0;
# remove uncertainprice flag if we have found a price in the MARC record
$orderinfo{uncertainprice} = 0 if $orderinfo{listprice};
@ -511,8 +513,9 @@ sub import_biblios_list {
my ( $marcblob, $encoding ) = GetImportRecordMarc( $biblio->{'import_record_id'} );
my $marcrecord = MARC::Record->new_from_usmarc($marcblob) || die "couldn't translate marc information";
my $infos = get_infos_syspref('MarcFieldsToOrder', $marcrecord, ['price', 'quantity', 'budget_code', 'discount', 'sort1', 'sort2']);
my $infos = get_infos_syspref('MarcFieldsToOrder', $marcrecord, ['price', 'quantity', 'budget_code', 'discount', 'sort1', 'sort2','replacementprice']);
my $price = $infos->{price};
my $replacementprice = $infos->{replacementprice};
my $quantity = $infos->{quantity};
my $budget_code = $infos->{budget_code};
my $discount = $infos->{discount};
@ -573,7 +576,7 @@ sub import_biblios_list {
'quantity' => $item_quantity,
'budget_id' => $item_budget_id || $budget_id,
'itemprice' => $item_price || $price,
'replacementprice' => $item_replacement_price,
'replacementprice' => $item_replacement_price || $replacementprice,
'itemcallnumber' => $item_callnumber,
);
$all_items_quantity++;
@ -590,6 +593,7 @@ sub import_biblios_list {
if ($alliteminfos == -1 || scalar(@$alliteminfos) == 0) {
$cellrecord{price} = $price || '';
$cellrecord{replacementprice} = $replacementprice || '';
$cellrecord{quantity} = $quantity || '';
$cellrecord{budget_id} = $budget_id || '';
$cellrecord{discount} = $discount || '';

View File

@ -48,6 +48,7 @@ my $origquantityrec = $input->param('origquantityrec');
my $quantityrec = $input->param('quantityrec');
my $quantity = $input->param('quantity');
my $unitprice = $input->param('unitprice');
my $replacementprice = $input->param('replacementprice');
my $datereceived = $input->param('datereceived'),
my $invoiceid = $input->param('invoiceid');
my $invoice = GetInvoice($invoiceid);
@ -59,6 +60,8 @@ my $order = GetOrder($ordernumber);
my $new_ordernumber = $ordernumber;
$unitprice = Koha::Number::Price->new( $unitprice )->unformat();
$replacementprice = Koha::Number::Price->new( $replacementprice )->unformat();
warn "Replacement $replacementprice";
my $basket = Koha::Acquisition::Orders->find( $ordernumber )->basket;
#need old receivedate if we update the order, parcel.pl only shows the right parcel this way FIXME
@ -85,6 +88,7 @@ if ($quantityrec > $origquantityrec ) {
$order->{order_internalnote} = $input->param("order_internalnote");
$order->{tax_rate_on_receiving} = $input->param("tax_rate");
$order->{replacementprice} = $replacementprice;
$order->{unitprice} = $unitprice;
$order = C4::Acquisition::populate_order_with_prices(
@ -156,7 +160,7 @@ ModItem(
dateaccessioned => $datereceived,
datelastseen => $datereceived,
price => $unitprice,
replacementprice => $order->{rrp},
replacementprice => $replacementprice,
replacementpricedate => $datereceived,
},
$biblionumber,

View File

@ -371,6 +371,7 @@ if ( defined $from_subscriptionid ) {
$data->{tax_rate} = $lastOrderReceived->{tax_rate_on_ordering};
$data->{discount} = $lastOrderReceived->{discount};
$data->{rrp} = $lastOrderReceived->{rrp};
$data->{replacementprice} = $lastOrderReceived->{replacementprice};
$data->{ecost} = $lastOrderReceived->{ecost};
$data->{quantity} = $lastOrderReceived->{quantity};
$data->{unitprice} = $lastOrderReceived->{unitprice};
@ -454,6 +455,7 @@ $template->param(
quantity => $quantity,
quantityrec => $quantity,
rrp => $data->{'rrp'},
replacementprice => $data->{'replacementprice'},
gst_values => \@gst_values,
tax_rate => $data->{tax_rate_on_ordering} ? $data->{tax_rate_on_ordering}+0.0 : $bookseller->tax_rate ? $bookseller->tax_rate+0.0 : 0,
listprice => sprintf( "%.2f", $data->{listprice} || $data->{price} || $listprice),

View File

@ -213,6 +213,7 @@ $template->param(
quantityreceivedplus1 => $order->{'quantityreceived'} + 1,
quantityreceived => $order->{'quantityreceived'},
rrp => $rrp,
replacementprice => $order->{'replacementprice'},
ecost => $ecost,
unitprice => $unitprice,
tax_rate => $tax_rate,

View File

@ -358,6 +358,7 @@
<th class="tax_excluded">ecost tax exc.</th>
<th class="tax_included">RRP tax inc.</th>
<th class="tax_included">ecost tax inc.</th>
<th class="replacementprice">Replacement price</th>
<th>Qty.</th>
<th class="tax_excluded">Total tax exc. ([% currency | html %])</th>
<th class="tax_included">Total tax inc. ([% currency | html %])</th>
@ -382,6 +383,7 @@
<th class="tax_excluded">&nbsp;</th>
<th class="tax_included">&nbsp;</th>
<th class="tax_included">&nbsp;</th>
<th class="replacementprice">&nbsp;</th>
<th>[% foot_loo.quantity | html %]</th>
<th class="tax_excluded">[% foot_loo.total_tax_excluded | $Price | html %]</th>
<th class="tax_included">[% foot_loo.total_tax_included | $Price | html %]</th>
@ -404,6 +406,7 @@
<th class="tax_excluded">&nbsp;</th>
<th class="tax_included">&nbsp;</th>
<th class="tax_included">&nbsp;</th>
<th class="replacementprice">&nbsp;</th>
<th>[% total_quantity | html %]</th>
<th class="tax_excluded">[% total_tax_excluded | $Price | html %]</th>
<th class="tax_included">[% total_tax_included | $Price | html %]</th>
@ -479,6 +482,7 @@
<td class="number tax_excluded [% IF books_loo.ecost_tax_excluded.search(zero_regex) %]error[% END %]">[% books_loo.ecost_tax_excluded | $Price | html %]</td>
<td class="number tax_included [% IF books_loo.rrp_tax_included.search(zero_regex) %]error[% END %]">[% books_loo.rrp_tax_included | $Price | html %]</td>
<td class="number tax_included [% IF books_loo.ecost_tax_included.search(zero_regex) %]error[% END %]">[% books_loo.ecost_tax_included | $Price | html %]</td>
<td class="number replacementprice [% IF books_loo.replacementprice.search(zero_regex) %]error[% END %]">[% books_loo.replacementprice | $Price | html %]</td>
<td class="number [% IF books_loo.quantity.search(zero_regex) %]error[% END %]">[% books_loo.quantity | html %]</td>
<td class="number tax_excluded [% IF books_loo.total_tax_excluded.search(zero_regex) %]error[% END %]">[% books_loo.total_tax_excluded | $Price | html %]</td>
<td class="number tax_included [% IF books_loo.total_tax_included.search(zero_regex) %]error[% END %]">[% books_loo.total_tax_included | $Price | html %]</td>
@ -541,6 +545,7 @@
<th class="tax_excluded">ecost tax exc.</th>
<th class="tax_included">RRP tax inc.</th>
<th class="tax_included">ecost tax inc.</th>
<th class="replacementprice">Replacement price</th>
<th>Qty.</th>
<th class="tax_excluded">Total tax exc. ([% currency | html %])</th>
<th class="tax_included">Total tax inc. ([% currency | html %])</th>
@ -593,6 +598,7 @@
<td class="number tax_excluded">[% order.ecost_tax_excluded | $Price | html %]</td>
<td class="number tax_included">[% order.rrp_tax_included | $Price | html %]</td>
<td class="number tax_included">[% order.ecost_tax_included | $Price | html %]</td>
<td class="number replacementprice">[% order.replacementprice | $Price | html %]</td>
<td class="number">[% order.quantity | html %]</td>
<td class="number tax_excluded">[% order.total_tax_excluded | $Price | html %]</td>
<td class="number tax_included">[% order.total_tax_included | $Price | html %]</td>

View File

@ -244,6 +244,7 @@
<th>Library</th>
<th class="tax_excluded">Actual cost tax exc.</th>
<th class="tax_included">Actual cost tax inc.</th>
<th class="replacementprice">Replacement price</th>
<th>Qty.</th>
<th class="tax_excluded">Total tax exc. ([% currency.symbol | html %])</th>
<th class="tax_included">Total tax inc. ([% currency.symbol | html %])</th>
@ -274,6 +275,7 @@
<td><p>[% order.branchcode | html %]</p></td>
<td class="number tax_excluded">[% order.unitprice_tax_excluded | $Price | html %]</td>
<td class="number tax_included">[% order.unitprice_tax_included | $Price | html %]</td>
<td class="number replacementprice">[% order.replacementprice | $Price | html %]</td>
<td class="number">[% order.quantity | html %]</td>
<td class="number tax_excluded">[% order.total_tax_excluded | $Price | html %]</td>
<td class="number tax_included">[% order.total_tax_included | $Price | html %]</td>
@ -289,6 +291,7 @@
<th colspan="2">Total (GST [% tf.tax_rate * 100 | html %] %)</th>
<th class="tax_excluded"></th>
<th class="tax_included"></th>
<th class="replacementprice"/>
<th>[% tf.quantity | html %]</th>
<th class="tax_excluded">[% tf.total_tax_excluded | $Price | html %]</th>
<th class="tax_included">[% tf.total_tax_included | $Price | html %]</th>
@ -301,6 +304,7 @@
<th colspan="2">Total ([% currency.symbol | html %])</th>
<th class="tax_excluded"></th>
<th class="tax_included"></th>
<th class="replacementprice"/>
<th>[% total_quantity | html %]</th>
<th class="tax_excluded">[% total_tax_excluded | $Price | html %]</th>
<th class="tax_included">[% total_tax_included | $Price | html %]</th>
@ -312,6 +316,7 @@
<th colspan="2">Total + Adjustments + Shipment cost ([% currency.symbol | html %])</th>
<th class="tax_excluded"></th>
<th class="tax_included"></th>
<th class="replacementprice"/>
<th>[% total_quantity | html %]</th>
<th class="tax_excluded">[% total_tax_excluded_shipment + total_adj | $Price | html %]</th>
<th class="tax_included">[% total_tax_included_shipment | $Price | html %]</th>

View File

@ -433,13 +433,17 @@
</li>
<li>
[% IF ( close ) %]
<span class="label">Replacement cost: </span>
<span class="label">Retail price: </span>
<input type="hidden" name="rrp" id="rrp" value="[% rrp | html %]" />[% rrp | html %] (adjusted for [% cur_active | html %], [% IF (listincgst == 1) %]tax inc.[% ELSE %]tax exc.[% END %])
[% ELSE %]
<label for="rrp">Replacement cost: </label>
<label for="rrp">Retail price: </label>
<input type="text" size="20" name="rrp" id="rrp" value="[% rrp | html %]" /> (adjusted for [% cur_active | html %], [% IF (listincgst == 1) %]tax inc.[% ELSE %]tax exc.[% END %])
[% END %]
</li>
<li>
<label for="replacementprice">Replacement cost: </label>
<input type="text" size="20" name="replacementprice" id="replacementprice" value="[% replacementprice | html %]" />
</li>
<li>
<label for="ecost">Budgeted cost: </label>
<input type="text" size="20" name="ecost" id="ecost" value="[% ecost | html %]" readonly="readonly" /> [% IF (listincgst == 1) %](tax inc.)[% ELSE %](tax exc.)[% END %]

View File

@ -239,7 +239,11 @@
<input type="hidden" name="tax_rate" value="0" />
[% END %]
<li><label for="rrp">Replacement cost: </label>[% rrp | $Price | html %]</li>
<li><label for="rrp">Retail price: </label>[% rrp | $Price | html %]</li>
<li>
<label for="replacementprice">Replacement price:</label>
<input type="text" size="20" name="replacementprice" id="replacementprice" value="[% replacementprice | $Price | html %]" />
</li>
<li><label for="ecost">Budgeted cost: </label>[% ecost | $Price | html %]</li>
<li>
<label for="unitprice">Actual cost:</label>

View File

@ -104,6 +104,7 @@
<th>Order line search</th>
<th>Summary search</th>
<th>&nbsp;</th>
<th>Replacement price search</th>
<th>Quantity search</th>
<th>Unit cost search</th>
<th>Order cost search</th>
@ -117,6 +118,7 @@
<th>Order line</th>
<th>Summary</th>
<th>More</th>
<th>Replacement price</th>
<th>Quantity</th>
<th>Unit cost</th>
<th>Order cost</th>
@ -169,6 +171,7 @@
<a href="/cgi-bin/koha/catalogue/showmarc.pl?id=[% loop_order.biblionumber | html %]" class="previewData">MARC</a><br>
<a href="/cgi-bin/koha/catalogue/showmarc.pl?viewas=card&amp;id=[% loop_order.biblionumber | html %]" class="previewData">Card</a>
</td>
<td>[% loop_order.replacementprice | $Price | html %]</td>
<td>[% loop_order.quantity | html %]</td>
<td>[% loop_order.ecost | $Price | html %]</td>
<td>[% loop_order.total | $Price | html %]</td>
@ -229,6 +232,7 @@
<th title="Item holds / Total holds">Holds</th>
<th>Summary</th>
<th>More</th>
<th>Replacement price</th>
<th>Quantity</th>
<th>Fund</th>
<th>Est cost</th>
@ -320,6 +324,7 @@
<a href="/cgi-bin/koha/catalogue/showmarc.pl?id=[% order.biblionumber | html %]" class="previewData">MARC</a><br>
<a href="/cgi-bin/koha/catalogue/showmarc.pl?viewas=card&amp;id=[% order.biblionumber | html %]" class="previewData">Card</a>
</td>
<td>[% order.replacementprice | $Price | html %]</td>
<td>[% order.quantityreceived | html %]</td>
<td>[% order.budget.budget_name | html %]</td>
<td>[% order.ecost | $Price | html %]</td>
@ -445,90 +450,92 @@
var sticky_filters = [% sticky_filters | html %];
$(document).ready(function(){
if ( $("#pendingt").length ) {
var pendingt = $("#pendingt").dataTable($.extend(true, {}, dataTablesDefaults, {
"bStateSave": true,
"iCookieDuration": 60*60*24*1000, // 1000 days
"iDisplayLength": 10,
"aLengthMenu": [[5, 10, 20, 50, 100, -1], [5, 10, 20, 50, 100, _("All")]],
"aoColumnDefs": [
{ "aTargets": [ 4, 9, 10 ], "bSortable": false, "bSearchable": false },
],
"aoColumns": [
{ "sType": "html" },
{ "sType": "html" },
{ "sType": "num-html" },
{ "sType": "anti-the" },
null,
null,
null,
null,
null,
null,
null,
],
'bAutoWidth': false,
"sPaginationType": "four_button"
})
).columnFilter({
sPlaceHolder: "head:after",
aoColumns: [
{ type: "text" },
{ type: "text" },
{ type: "text" },
{ type: "text" },
null,
{ type: "text" },
{ type: "text" },
{ type: "text" },
{ type: "text" },
null,
null
]
});
}
if ( $("#pendingt").length ) {
var pendingt = $("#pendingt").dataTable($.extend(true, {}, dataTablesDefaults, {
"bStateSave": true,
"iCookieDuration": 60*60*24*1000, // 1000 days
"iDisplayLength": 10,
"aLengthMenu": [[5, 10, 20, 50, 100, -1], [5, 10, 20, 50, 100, _("All")]],
"aoColumnDefs": [
{ "aTargets": [ 4, 9, 10 ], "bSortable": false, "bSearchable": false },
],
"aoColumns": [
{ "sType": "html" },
{ "sType": "html" },
{ "sType": "num-html" },
{ "sType": "anti-the" },
null,
null,
null,
null,
null,
null,
null,
null,
],
'bAutoWidth': false,
"sPaginationType": "four_button"
} )
).columnFilter({
sPlaceHolder: "head:after",
aoColumns: [
{ type: "text" },
{ type: "text" },
{ type: "text" },
{ type: "text" },
null,
{ type: "text" },
{ type: "text" },
{ type: "text" },
{ type: "text" },
{ type: "text" },
null,
null
]
});
}
if ( $("#receivedt").length ) {
var receivedt = $("#receivedt").dataTable($.extend(true, {}, dataTablesDefaults, {
"bStateSave": true,
"iCookieDuration": 60*60*24*1000, // 1000 days
"iDisplayLength": 10,
"aLengthMenu": [[5, 10, 20, 50, 100, -1], [5, 10, 20, 50, 100, _("All")]],
"aoColumnDefs": [
{ "aTargets": [ 5, -1 ], "bSortable": false, "bSearchable": false },
],
"aoColumns": [
{ "sType": "html" },
{ "sType": "html" },
{ "sType": "html" },
{ "sType": "num-html" },
{ "sType": "anti-the" },
null,
null,
null,
null,
null,
null,
null
],
"sPaginationType": "four_button"
}));
}
if ( $("#receivedt").length ) {
var receivedt = $("#receivedt").dataTable($.extend(true, {}, dataTablesDefaults, {
"bStateSave": true,
"iCookieDuration": 60*60*24*1000, // 1000 days
"iDisplayLength": 10,
"aLengthMenu": [[5, 10, 20, 50, 100, -1], [5, 10, 20, 50, 100, _("All")]],
"aoColumnDefs": [
{ "aTargets": [ 5, -1 ], "bSortable": false, "bSearchable": false },
],
"aoColumns": [
{ "sType": "html" },
{ "sType": "html" },
{ "sType": "html" },
{ "sType": "num-html" },
{ "sType": "anti-the" },
null,
null,
null,
null,
null,
null,
null
],
"sPaginationType": "four_button"
}));
}
// Keep filters from finishreceive.pl to parcel.pl
// Keep filters from finishreceive.pl to parcel.pl
$.cookie("filter_parcel_summary", $("#summaryfilter").val());
$.cookie("filter_parcel_basketname", $("#basketfilter").val());
$.cookie("filter_parcel_orderno", $("#orderfilter").val());
$.cookie("filter_parcel_basketgroupname", $("#basketgroupnamefilter").val());
$.cookie("filter_parcel_ean", $("#eanfilter").val());
$("#filterform").on('submit', function(){
$.cookie("filter_parcel_summary", $("#summaryfilter").val());
$.cookie("filter_parcel_basketname", $("#basketfilter").val());
$.cookie("filter_parcel_orderno", $("#orderfilter").val());
$.cookie("filter_parcel_basketgroupname", $("#basketgroupnamefilter").val());
$.cookie("filter_parcel_ean", $("#eanfilter").val());
$("#filterform").on('submit', function(){
$.cookie("filter_parcel_summary", $("#summaryfilter").val());
$.cookie("filter_parcel_basketname", $("#basketfilter").val());
$.cookie("filter_parcel_orderno", $("#orderfilter").val());
$.cookie("filter_parcel_basketgroupname", $("#basketgroupnamefilter").val());
$.cookie("filter_parcel_ean", $("#eanfilter").val());
});
});
$(".previewData").on("click", function(e){
e.preventDefault();
@ -545,21 +552,21 @@
});
// Case-insensitive version of jquery's contains function
jQuery.extend(jQuery.expr[':'], {
icontains : "jQuery(a).text().toUpperCase().indexOf(m[3].toUpperCase())>=0"
});
// Case-insensitive version of jquery's contains function
jQuery.extend(jQuery.expr[':'], {
icontains : "jQuery(a).text().toUpperCase().indexOf(m[3].toUpperCase())>=0"
});
// Contains exactly function
jQuery.extend(jQuery.expr[':'], {
containsExactly: "$(a).text() == m[3]"
});
jQuery.extend(jQuery.expr[':'], {
containsExactly: "$(a).text() == m[3]"
});
function transfer_order_popup(ordernumber) {
function transfer_order_popup(ordernumber) {
var url = "/cgi-bin/koha/acqui/transferorder.pl?"
+ "ordernumber=" + ordernumber
window.open(url, 'TransferOrder');
}
}
</script>
[% END %]