Commit 9af64aa7 authored by Katrin Fischer's avatar Katrin Fischer Committed by Kyle M Hall

Bug 5260 - Add option to send an order by e-mail to the acquisition module

With this patch it will be possible to send order information
to the vendor by e-mail. For now this feature can be triggered
manually with a button before closing the basket.
The order e-mail is based on the acquisition claim feature, but
uses a new notice template.

Test plan:

1) Vendors
A new checkbox "Contact when ordering?" was added to the vendor
page.
- Add a vendor and/or edit an existing vendor
- Verify the new option is saved correctly
- Verify the new option displays on the vendor summary page
  after saving

2) Notices
The feature works with a new notice template: ACQORDER
It works with the same formatting/fields etc. as the acq claim
notice.
- Add a new notice template ACQORDER in module
  'Claim/order aquisition'
- Make sure to use fields from the various offered tables
  in your notice
- Verify it is saved correctly

3) Basket
- Turn on LetterLog system preference
- Create multiple order lines
- Click the 'Send order' button in the toolbar
- Verify error or success message
- Verify you received the e-mail
- Verify there is a new entry with about the sent
  notice in your action_logs table

4) Regression testing...
- Verify order claims still work
- Verify serial claims still work
- Verify new serial issue notices still work
...
(I can provide additional test plans if needed)
Signed-off-by: Martin Renvoize's avatarMartin Renvoize <martin.renvoize@ptfs-europe.com>
Signed-off-by: joubu's avatarJonathan Druart <jonathan.druart@biblibre.com>
Signed-off-by: default avatarKyle M Hall <kyle@bywatersolutions.com>
parent 0bc8f1fd
......@@ -63,6 +63,10 @@ Contact's e-mail address.
Notes about contact.
=item orderacquisition
Whether the contact should receive acquisitions orders.
=item claimacquisition
Whether the contact should receive acquisitions claims.
......@@ -92,7 +96,7 @@ use C4::Context;
use base qw(Class::Accessor);
__PACKAGE__->mk_accessors(qw(id name position phone altphone fax email notes claimacquisition claimissues acqprimary serialsprimary bookseller));
__PACKAGE__->mk_accessors(qw(id name position phone altphone fax email notes orderacquisition claimacquisition claimissues acqprimary serialsprimary bookseller));
=head1 METHODS
......@@ -168,14 +172,15 @@ sub save {
$self->phone, $self->altphone,
$self->fax, $self->email,
$self->notes, $self->acqprimary ? 1 : 0,
$self->serialsprimary ? 1 : 0, $self->claimacquisition ? 1 : 0,
$self->serialsprimary ? 1 : 0,
$self->orderacquisition ? 1 : 0, $self->claimacquisition ? 1 : 0,
$self->claimissues ? 1 : 0, $self->bookseller
);
if ($self->id) {
$query = 'UPDATE aqcontacts SET name = ?, position = ?, phone = ?, altphone = ?, fax = ?, email = ?, notes = ?, acqprimary = ?, serialsprimary = ?, claimacquisition = ?, claimissues = ?, booksellerid = ? WHERE id = ?;';
$query = 'UPDATE aqcontacts SET name = ?, position = ?, phone = ?, altphone = ?, fax = ?, email = ?, notes = ?, acqprimary = ?, serialsprimary = ?, orderacquisition = ?, claimacquisition = ?, claimissues = ?, booksellerid = ? WHERE id = ?;';
push @params, $self->id;
} else {
$query = 'INSERT INTO aqcontacts (name, position, phone, altphone, fax, email, notes, acqprimary, serialsprimary, claimacquisition, claimissues, booksellerid) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?);';
$query = 'INSERT INTO aqcontacts (name, position, phone, altphone, fax, email, notes, acqprimary, serialsprimary, orderacquisition, claimacquisition, claimissues, booksellerid) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?);';
}
my $dbh = C4::Context->dbh;
my $sth = $dbh->prepare($query);
......
......@@ -17,8 +17,7 @@ package C4::Letters;
# You should have received a copy of the GNU General Public License
# along with Koha; if not, see <http://www.gnu.org/licenses>.
use strict;
use warnings;
use Modern::Perl;
use MIME::Lite;
use Mail::Sendmail;
......@@ -364,12 +363,20 @@ sub findrelatedto {
=head2 SendAlerts
parameters :
- $type : the type of alert
- $externalid : the id of the "object" to query
- $letter_code : the letter to send.
my $err = &SendAlerts($type, $externalid, $letter_code);
send an alert to all borrowers having put an alert on a given subject.
Parameters:
- $type : the type of alert
- $externalid : the id of the "object" to query
- $letter_code : the notice template to use
C<&SendAlerts> sends an email notice directly to a patron or a vendor.
Currently it supports ($type):
- claim serial issues (claimissues)
- claim acquisition orders (claimacquisition)
- send acquisition orders to the vendor (orderacquisition)
- notify patrons about newly received serial issues (issue)
- notify patrons when their account is created (members)
Returns undef or { error => 'message } on failure.
Returns true on success.
......@@ -449,20 +456,36 @@ sub SendAlerts {
}
}
}
elsif ( $type eq 'claimacquisition' or $type eq 'claimissues' ) {
elsif ( $type eq 'claimacquisition' or $type eq 'claimissues' or $type eq 'orderacquisition' ) {
# prepare the letter...
# search the biblionumber
my $strsth = $type eq 'claimacquisition'
? qq{
my $strsth;
my $sthorders;
my $dataorders;
my $action;
if ( $type eq 'claimacquisition') {
$strsth = qq{
SELECT aqorders.*,aqbasket.*,biblio.*,biblioitems.*
FROM aqorders
LEFT JOIN aqbasket ON aqbasket.basketno=aqorders.basketno
LEFT JOIN biblio ON aqorders.biblionumber=biblio.biblionumber
LEFT JOIN biblioitems ON aqorders.biblionumber=biblioitems.biblionumber
WHERE aqorders.ordernumber IN (
};
if (!@$externalid){
carp "No order selected";
return { error => "no_order_selected" };
}
: qq{
$strsth .= join( ",", @$externalid ) . ")";
$action = "ACQUISITION CLAIM";
$sthorders = $dbh->prepare($strsth);
$sthorders->execute;
$dataorders = $sthorders->fetchall_arrayref( {} );
}
if ($type eq 'claimissues') {
$strsth = qq{
SELECT serial.*,subscription.*, biblio.*, aqbooksellers.*,
aqbooksellers.id AS booksellerid
FROM serial
......@@ -472,21 +495,46 @@ sub SendAlerts {
WHERE serial.serialid IN (
};
if (!@$externalid){
carp "No Order selected";
return { error => "no_order_selected" };
if (!@$externalid){
carp "No Order selected";
return { error => "no_order_selected" };
}
$strsth .= join( ",", @$externalid ) . ")";
$action = "CLAIM ISSUE";
$sthorders = $dbh->prepare($strsth);
$sthorders->execute;
$dataorders = $sthorders->fetchall_arrayref( {} );
}
$strsth .= join( ",", @$externalid ) . ")";
my $sthorders = $dbh->prepare($strsth);
$sthorders->execute;
my $dataorders = $sthorders->fetchall_arrayref( {} );
if ( $type eq 'orderacquisition') {
$strsth = qq{
SELECT aqorders.*,aqbasket.*,biblio.*,biblioitems.*
FROM aqorders
LEFT JOIN aqbasket ON aqbasket.basketno=aqorders.basketno
LEFT JOIN biblio ON aqorders.biblionumber=biblio.biblionumber
LEFT JOIN biblioitems ON aqorders.biblionumber=biblioitems.biblionumber
WHERE aqbasket.basketno = ?
AND orderstatus IN ('new','ordered')
};
if (!$externalid){
carp "No basketnumber given";
return { error => "no_basketno" };
}
$action = "ACQUISITION ORDER";
$sthorders = $dbh->prepare($strsth);
$sthorders->execute($externalid);
$dataorders = $sthorders->fetchall_arrayref( {} );
}
my $sthbookseller =
$dbh->prepare("select * from aqbooksellers where id=?");
$sthbookseller->execute( $dataorders->[0]->{booksellerid} );
my $databookseller = $sthbookseller->fetchrow_hashref;
my $addressee = $type eq 'claimacquisition' ? 'acqprimary' : 'serialsprimary';
my $addressee = $type eq 'claimacquisition' || $type eq 'orderacquisition' ? 'acqprimary' : 'serialsprimary';
my $sthcontact =
$dbh->prepare("SELECT * FROM aqcontacts WHERE booksellerid=? AND $type=1 ORDER BY $addressee DESC");
$sthcontact->execute( $dataorders->[0]->{booksellerid} );
......@@ -537,12 +585,14 @@ sub SendAlerts {
: 'text/plain; charset="utf-8"',
);
$mail{'Reply-to'} = C4::Context->preference('ReplytoDefault')
if C4::Context->preference('ReplytoDefault');
$mail{'Sender'} = C4::Context->preference('ReturnpathDefault')
if C4::Context->preference('ReturnpathDefault');
$mail{'Bcc'} = $userenv->{emailaddress}
if C4::Context->preference("ClaimsBccCopy");
if ($type eq 'claimacquisition' || $type eq 'claimissues' ) {
$mail{'Reply-to'} = C4::Context->preference('ReplytoDefault')
if C4::Context->preference('ReplytoDefault');
$mail{'Sender'} = C4::Context->preference('ReturnpathDefault')
if C4::Context->preference('ReturnpathDefault');
$mail{'Bcc'} = $userenv->{emailaddress}
if C4::Context->preference("ClaimsBccCopy");
}
unless ( sendmail(%mail) ) {
carp $Mail::Sendmail::error;
......@@ -551,7 +601,7 @@ sub SendAlerts {
logaction(
"ACQUISITION",
$type eq 'claimissues' ? "CLAIM ISSUE" : "ACQUISITION CLAIM",
$action,
undef,
"To="
. join( ',', @email )
......
......@@ -20,8 +20,7 @@
# You should have received a copy of the GNU General Public License
# along with Koha; if not, see <http://www.gnu.org/licenses>.
use strict;
use warnings;
use Modern::Perl;
use C4::Auth;
use C4::Koha;
use C4::Output;
......@@ -35,6 +34,7 @@ use C4::Members qw/GetMember/; #needed for permissions checking for changing ba
use C4::Items;
use C4::Suggestions;
use Koha::Libraries;
use C4::Letters qw/SendAlerts/;
use Date::Calc qw/Add_Delta_Days/;
use Koha::Database;
use Koha::EDI qw( create_edi_order get_edifact_ean );
......@@ -116,6 +116,10 @@ if (!defined $op) {
my $confirm_pref= C4::Context->preference("BasketConfirmations") || '1';
$template->param( skip_confirm_reopen => 1) if $confirm_pref eq '2';
$template->param( email_ok => 1 ) if defined $query->param('email_ok');
$template->param( email_error => $query->param('email_error') ) if defined $query->param('email_error');
if ( $op eq 'delete_confirm' ) {
my $basketno = $query->param('basketno');
my $delbiblio = $query->param('delbiblio');
......@@ -165,6 +169,25 @@ if ( $op eq 'delete_confirm' ) {
);
print GetBasketAsCSV($query->param('basketno'), $query);
exit;
} elsif ($op eq 'email') {
my $redirect_url = '/cgi-bin/koha/acqui/basket.pl?basketno='.$basket->{'basketno'};
my $err;
eval {
$err = SendAlerts( 'orderacquisition', $query->param('basketno'), 'ACQORDER' );
};
if ( $@ ) {
$redirect_url .= '&email_error='.$@;
} elsif ( ref $err and exists $err->{error} and $err->{error} eq "no_email" ) {
$redirect_url .= '&email_error=no_email';
} elsif ( ref $err and exists $err->{error} and $err->{error} eq "no_basketno" ) {
$redirect_url .= '&email_error=no_basketno';
} else {
$redirect_url .= '&email_ok=1';
}
print $query->redirect($redirect_url)
} elsif ($op eq 'close') {
my $confirm = $query->param('confirm') || $confirm_pref eq '2';
if ($confirm) {
......
......@@ -102,10 +102,10 @@ if ( $delay and not $delay =~ /^\d{1,3}$/ ) {
}
if ($op and $op eq "send_alert"){
my @ordernums = $input->multi_param("ordernumber");# FIXME: Fallback values?
my @ordernums = $input->multi_param("ordernumber");
my $err;
eval {
$err = SendAlerts( 'claimacquisition', \@ordernums, $input->param("letter_code") ); # FIXME: Fallback value?
$err = SendAlerts( 'claimacquisition', \@ordernums, $input->param("letter_code") );
if ( not ref $err or not exists $err->{error} ) {
AddClaim ( $_ ) for @ordernums;
}
......
......@@ -97,14 +97,14 @@ $data{'active'}=$input->param('status');
my @contacts;
my %contact_info;
foreach (qw(id name position phone altphone fax email notes claimacquisition claimissues acqprimary serialsprimary)) {
foreach (qw(id name position phone altphone fax email notes orderacquisition claimacquisition claimissues acqprimary serialsprimary)) {
$contact_info{$_} = [ $input->param('contact_' . $_) ];
}
for my $cnt (0..scalar(@{$contact_info{'id'}})) {
my %contact;
my $real_contact;
foreach (qw(id name position phone altphone fax email notes claimacquisition claimissues acqprimary serialsprimary)) {
foreach (qw(id name position phone altphone fax email notes orderacquisition claimacquisition claimissues acqprimary serialsprimary)) {
$contact{$_} = $contact_info{$_}->[$cnt];
$real_contact = 1 if $contact{$_};
}
......
ALTER TABLE `aqcontacts` ADD `orderacquisition` BOOLEAN NOT NULL DEFAULT 0 AFTER `notes`;
......@@ -2914,6 +2914,7 @@ CREATE TABLE aqcontacts (
fax varchar(100) default NULL, -- contact's fax number
email varchar(100) default NULL, -- contact's email address
notes mediumtext, -- notes related to the contact
orderacquisition BOOLEAN NOT NULL DEFAULT 0, -- should this contact receive acquisition orders
claimacquisition BOOLEAN NOT NULL DEFAULT 0, -- should this contact receive acquisitions claims
claimissues BOOLEAN NOT NULL DEFAULT 0, -- should this contact receive serial claims
acqprimary BOOLEAN NOT NULL DEFAULT 0, -- is this the primary contact for acquisitions messages
......
......@@ -201,6 +201,9 @@
[% IF ediaccount %]
<div class="btn-group"><a href="/cgi-bin/koha/acqui/edi_ean.pl?op=ediorder&amp;basketno=[% basketno %]&amp;booksellerid=[% booksellerid %]" class="btn btn-small" id="ediorderbutton"><i class="fa fa-download"></i> Create EDIFACT order</a></div>
[% END %]
[% IF ( active && books_loop ) %]
<div class="btn-group"><a href="[% script_name %]?op=email&amp;basketno=[% basketno %]" class="btn btn-small" id="emailvendorbutton"><i class="fa fa-envelope"></i> E-mail order</a></div>
[% END %]
</div>
<!-- Modal for confirm deletion box-->
<div class="modal hide" id="deleteBasketModal" tabindex="-1" role="dialog" aria-labelledby="delbasketModalLabel" aria-hidden="true">
......@@ -291,6 +294,21 @@
<META HTTP-EQUIV=Refresh CONTENT="0; url=booksellers.pl">
[% END %]
[% ELSE %]
[% IF email_error %]
<div class="dialog alert">
[% IF ( email_error == "no_email" ) %]
This vendor has no contact selected for sending orders to or is missing an e-mail address.
[% ELSIF ( email_error == "no_basketno" ) %]
No basket given.
[% ELSE %]
ERROR! - [% email_error %]
[% END %]
</div>
[% END %]
[% IF ( email_ok ) %]
<div class="dialog message">Order e-mail was sent to the vendor.</div>
[% END %]
<h1>[% UNLESS ( basketno ) %]New [% END %]Basket [% basketname|html %] ([% basketno %]) for <a href="supplier.pl?booksellerid=[% booksellerid %]">[% name|html %]</a></h1>
[% IF ( basketno ) %]
<div id="acqui_basket_summary" class="yui-g">
......@@ -433,7 +451,7 @@
<th>No.</th>
<th class="anti-the">Order</th>
<th class="gste">RRP tax exc.</th>
<th class="gste">ecost tax exc.</th>
<th class="gste">Ecost tax exc.</th>
<th class="gsti">RRP tax inc.</th>
<th class="gsti">ecost tax inc.</th>
<th>Qty.</th>
......
......@@ -30,6 +30,13 @@
<input type="checkbox" id="contact_serialsprimary[% contact.id %]" class="contact_serialsprimary"></input>
[% END %]
<input type="hidden" class="contact_serialsprimary_hidden" name="contact_serialsprimary" value="[% contact.serialsprimary %]"></input>
<li><label for="contact_orderacquisition[% contact.id %]">Contact when ordering?</label>
[% IF contact.orderacquisition %]
<input type="checkbox" id="contact_orderacquisition[% contact.id %]" class="contact_orderacquisition" checked="checked"></input>
[% ELSE %]
<input type="checkbox" id="contact_orderacquisition[% contact.id %]" class="contact_orderacquisition"></input>
[% END %]
<input type="hidden" class="contact_orderacquisition_hidden" name="contact_orderacquisition" value="[% contact.orderacquisition %]"></input>
<li><label for="contact_claimacquisition[% contact.id %]">Contact about late orders?</label>
[% IF contact.claimacquisition %]
<input type="checkbox" id="contact_claimacquisition[% contact.id %]" class="contact_claimacquisition" checked="checked"></input>
......@@ -67,6 +74,9 @@
[% IF ( contact.serialsprimary ) %]
<p><span class="label">Primary serials contact</span></p>
[% END %]
[% IF ( contact.orderacquisition ) %]
<p><span class="label">Receives orders</span></p>
[% END %]
[% IF ( contact.claimacquisition ) %]
<p><span class="label">Receives claims for late orders</span></p>
[% END %]
......@@ -101,7 +111,7 @@ function add_contact() {
});
$(new_contact).insertBefore(this);
if ($('.supplier-contact').length === 2) { // First contact
$.each(['.contact_acqprimary', '.contact_serialsprimary', '.contact_claimacquisition', '.contact_claimissues'], function (idx, checkbox) {
$.each(['.contact_acqprimary', '.contact_serialsprimary', '.contact_orderacquisition', '.contact_claimacquisition', '.contact_claimissues'], function (idx, checkbox) {
$(checkbox, new_contact).click();
});
}
......@@ -142,6 +152,9 @@ function delete_contact(ev) {
}
$(this).next('.contact_serialsprimary_hidden').val($(this).is(':checked') ? '1' : '0');
});
$('body').on('click', '.contact_orderacquisition', null, function () {
$(this).next('.contact_orderacquisition_hidden').val($(this).is(':checked') ? '1' : '0');
});
$('body').on('click', '.contact_claimacquisition', null, function () {
$(this).next('.contact_claimacquisition_hidden').val($(this).is(':checked') ? '1' : '0');
});
......
......@@ -319,6 +319,11 @@ $(document).ready(function() {
[% ELSE %]
<option value="circulation">Circulation</option>
[% END %]
[% IF ( module == "orderacquisition" ) %]
<option value="orderacquisition" selected="selected">Order acquisition</option>
[% ELSE %]
<option value="orderacquisition">Order acquisition</option>
[% END %]
[% IF ( module == "claimacquisition" ) %]
<option value="claimacquisition" selected="selected">Claim acquisition</option>
[% ELSE %]
......
......@@ -198,8 +198,8 @@ sub add_form {
elsif ( $module eq 'acquisition' ) {
push @{$field_selection}, add_fields('aqbooksellers', 'aqorders', 'biblio', 'items');
}
elsif ($module eq 'claimacquisition') {
push @{$field_selection}, add_fields('aqbooksellers', 'aqorders', 'biblio', 'biblioitems');
elsif ($module eq 'claimacquisition' || $module eq 'orderacquisition') {
push @{$field_selection}, add_fields('aqbooksellers', 'aqbasket', 'aqorders', 'biblio', 'biblioitems');
}
elsif ($module eq 'claimissues') {
push @{$field_selection}, add_fields('aqbooksellers', 'serial', 'subscription');
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment