First, `yarn install`.
Then use `yarn build_js` or `yarn watch_js` to regenerate the dist/main.js file
Signed-off-by: Jonathan Field <jonathan.field@ptfs-europe.com>
Signed-off-by: Martin Renvoize <martin.renvoize@ptfs-europe.com>
Signed-off-by: Kyle M Hall <kyle@bywatersolutions.com>
Signed-off-by: Tomas Cohen Arazi <tomascohen@theke.io>
=cut
sub periods {
- my ( $self ) = @_;
+ my ( $self, $periods ) = @_;
+
+ if ( $periods ) {
+ my $schema = $self->_result->result_source->schema;
+ $schema->txn_do(
+ sub {
+ $self->periods->delete;
+
+ for my $period (@$periods) {
+ $self->_result->add_to_erm_agreement_periods($period);
+ }
+ }
+ );
+ }
my $periods_rs = $self->_result->erm_agreement_periods;
return Koha::ERM::Agreement::Periods->_new_from_dbic($periods_rs);
=cut
sub user_roles {
- my ( $self ) = @_;
-
+ my ( $self, $user_roles ) = @_;
+
+ if ( $user_roles ) {
+ my $schema = $self->_result->result_source->schema;
+ $schema->txn_do(
+ sub {
+ $self->user_roles->delete;
+
+ for my $user_role (@$user_roles) {
+ $self->_result->add_to_erm_agreement_user_roles($user_role);
+ }
+ }
+ );
+ }
my $user_roles_rs = $self->_result->erm_agreement_user_roles;
return Koha::ERM::Agreement::UserRoles->_new_from_dbic($user_roles_rs);
}
use Koha::ERM::Agreements;
my $input = CGI->new;
-my $agreement_id = $input->param('agreement_id');
-my $op = $input->param('op') || 'list';
-my @messages;
my ( $template, $loggedinuser, $cookie ) = get_template_and_user(
{
}
);
-my $dbh = C4::Context->dbh;
-if ( $op eq 'add_form' ) {
- my $agreement;
- if ($agreement_id) {
- $agreement = Koha::ERM::Agreements->find($agreement_id);
- }
-
- $template->param( agreement => $agreement, );
-}
-elsif ( $op eq 'add_validate' ) {
- my $vendor_id = $input->param('vendor_id');
- my $name = $input->param('name');
- my $description = $input->param('description');
- my $status = $input->param('status');
- my $closure_reason = $input->param('closure_reason');
- my $is_perpetual = $input->param('is_perpetual');
- my $renewal_priority = $input->param('renewal_priority');
- my $license_info = $input->param('license_info');
-
- my $schema = Koha::Database->new->schema;
- $schema->txn_do(sub{
- my ( $stored, $agreement );
- if ($agreement_id) {
- $agreement = Koha::ERM::Agreements->find($agreement_id);
- $agreement->vendor_id($vendor_id);
- $agreement->name($name);
- $agreement->description($description);
- $agreement->status($status);
- $agreement->closure_reason($closure_reason);
- $agreement->is_perpetual($is_perpetual);
- $agreement->renewal_priority($renewal_priority);
- $agreement->license_info($license_info);
-
- eval { $agreement->store; };
- if ($@) {
- push @messages, { type => 'error', code => 'error_on_update' };
- }
- else {
- $stored = 1;
- push @messages, { type => 'message', code => 'success_on_update' };
- }
- }
- else {
- $agreement = Koha::ERM::Agreement->new(
- {
- vendor_id => $vendor_id,
- name => $name,
- description => $description,
- status => $status,
- closure_reason => $closure_reason,
- is_perpetual => $is_perpetual,
- renewal_priority => $renewal_priority,
- license_info => $license_info,
- }
- );
- eval { $agreement->store; };
- if ($@) {
- push @messages, { type => 'error', code => 'error_on_insert' };
- }
- else {
- $stored = 1;
- push @messages, { type => 'message', code => 'success_on_insert' };
- }
- }
-
- if ( $stored ) {
- if ( $agreement_id ) {
- $agreement->periods->delete;
- $agreement->user_roles->delete;
- }
- for my $unique_id ( $input->multi_param('period_unique_id') ) {
- my $started_on = $input->param( 'started_on_' . $unique_id );
- next unless $started_on;
- my $ended_on = $input->param( 'ended_on_' . $unique_id );
- my $cancellation_deadline = $input->param( 'cancellation_deadline_' . $unique_id );
- my $notes = $input->param( 'notes_' . $unique_id );
-
- $started_on = dt_from_string($started_on);
- $ended_on &&= dt_from_string($ended_on);
- $cancellation_deadline &&= dt_from_string($cancellation_deadline);
-
- Koha::ERM::Agreement::Period->new(
- {
- agreement_id => $agreement->agreement_id,
- started_on => $started_on,
- ended_on => $ended_on,
- cancellation_deadline => $cancellation_deadline,
- notes => $notes,
- }
- )->store;
- }
-
- for my $unique_id ( $input->multi_param('user_unique_id') ) {
- my $user_id = $input->param('user_id_' . $unique_id);
- next unless $user_id;
- my $role = $input->param('user_role_' . $unique_id);
- Koha::ERM::Agreement::UserRole->new(
- {
- agreement_id => $agreement->agreement_id,
- user_id => $user_id,
- role => $role,
- }
- )->store;
- }
-
- }
- });
- $op = 'list';
-}
-elsif ( $op eq 'delete_confirm' ) {
- my $agreement = Koha::ERM::Agreements->find($agreement_id);
- $template->param( agreement => $agreement, );
-}
-elsif ( $op eq 'delete_confirmed' ) {
- my $agreement = Koha::ERM::Agreements->find($agreement_id);
- my $deleted = eval { $agreement->delete; };
-
- if ( $@ or not $deleted ) {
- push @messages, { type => 'error', code => 'error_on_delete' };
- }
- else {
- push @messages, { type => 'message', code => 'success_on_delete' };
- }
- $op = 'list';
-}
-
-if ( $op eq 'list' ) {
- $template->param(
- agreements_count => Koha::ERM::Agreements->search->count );
-}
-
$template->param(
- vendors => Koha::Acquisition::Booksellers->search,
- agreement_id => $agreement_id,
- messages => \@messages,
- op => $op,
+ vendors => Koha::Acquisition::Booksellers->search,
);
output_html_with_http_headers $input, $cookie, $template->output;
<script>
flatpickr.l10ns.default.weekdays = flatpickr_weekdays;
flatpickr.l10ns.default.months = flatpickr_months;
- flatpickr.setDefaults({
+ let flatpickr_defaults = {
allowInput: true,
dateFormat: "Y-m-d",
altInput: true,
}
})
]
- });
+ };
+
+ flatpickr.setDefaults(flatpickr_defaults);
+
$(document).ready(function(){
$(".flatpickr").each(function(){
let options = {};
return m.format(get_time_pattern(timeformat)+(dateformat=='rfc3339'?':ss'+(!m.isUTC()?'Z':''):''))+(dateformat=='rfc3339' && m.isUTC()?'Z':'');
}
+ window.$date_to_rfc3339 = function(value, options) {
+ var dateformat = (options&&options.dateformat)||def_date_format;
+ let m = moment(value, get_date_pattern(dateformat));
+ return m.format("YYYY-MM-DD");
+ }
+
})();
</script>
<!-- / js-date-format.inc -->
}
function select_user(borrowernumber, data) {
var p = window.opener;
- [% IF callback %]
- p.[% callback | html %](borrowernumber, data);
- [% ELSE %]
- p.select_user(borrowernumber, data);
- [% END %]
+ if ( p.document.getElementById("selected_patron_id") ) {
+ p.document.getElementById("selected_patron_id").value = borrowernumber;
+ } else {
+ [% IF callback %]
+ p.[% callback | html %](borrowernumber, data);
+ [% ELSE %]
+ p.select_user(borrowernumber, data);
+ [% END %]
+ }
window.close();
}
</script>
<a href="/cgi-bin/koha/erm/erm-home.pl">Electronic resources management</a>
</li>
- [% IF op == 'add_form' %]
- <li>
- <a href="/cgi-bin/koha/erm/agreements.pl">Agreements</a>
- </li>
- <li>
- <a href="#" aria-current="page">
- [% IF agreement.agreement_id %]
- Modify
- [% ELSE %]
- New
- [% END %] Agreement
- </a>
- </li>
-
- [% ELSIF op == 'delete_confirm' %]
- <li>
- <a href="/cgi-bin/koha/erm/agreements.pl">Agreements</a>
- </li>
- <li>
- <a href="#" aria-current="page">
- Confirm deletion of agreement
- </a>
- </li>
-
- [% ELSE %]
- <li>
- <a href="#" aria-current="page">
- Agreements
- </a>
- </li>
- [% END %]
+ <li>
+ <a href="/cgi-bin/koha/erm/agreements.pl">Agreements</a>
+ </li>
</ol>
</nav>
<div class="col-sm-10 col-sm-push-2">
<main>
-[% FOR m IN messages %]
- <div class="dialog [% m.type | html %]">
- [% SWITCH m.code %]
- [% CASE 'error_on_update' %]
- An error occurred when updating this agreement. Perhaps it already exists.
- [% CASE 'error_on_insert' %]
- An error occurred when adding this agreement. The agreement id might already exist.
- [% CASE 'error_on_delete' %]
- An error occurred when deleting this agreement. Check the logs.
- [% CASE 'success_on_update' %]
- Agreement updated successfully.
- [% CASE 'success_on_insert' %]
- Agreement added successfully.
- [% CASE 'success_on_delete' %]
- Agreement deleted successfully.
- [% CASE 'already_exists' %]
- This agreement already exists.
- [% CASE %]
- [% m.code | html %]
- [% END %]
- </div>
-[% END %]
-
-[% IF op == 'add_form' %]
- [% IF agreement %]
- <h1>Modify a agreement</h1>
- [% ELSE %]
- <h1>New agreement</h1>
- [% END %]
-
- <form action="/cgi-bin/koha/erm/agreements.pl" name="Aform" method="post" class="validated">
- <input type="hidden" name="op" value="add_validate" />
- <input type="hidden" name="agreement_id" value="[% agreement.agreement_id | html %]" />
-
- <fieldset class="rows">
- <ol>
- [% IF agreement %]
- <li><span class="label">Agreement ID: </span>[% agreement.agreement_id | html %]</li>
- [% END %]
-
- <li>
- <label for="vendor_id">Vendor: </label>
- <select name="vendor_id">
- <option value=""></option>
- [% FOR v IN vendors %]
- [% IF v.id == agreement.vendor_id %]
- <option value="[% v.id %]" selected="selected">[% v.name %]</option>
- [% ELSE %]
- <option value="[% v.id %]">[% v.name %]</option>
- [% END %]
- [% END %]
- </select>
- </li>
- <li>
- <label for="name" class="required">Name: </label>
- <input type="text" name="name" id="name" size="80" value="[% agreement.name | html %]" required="required" class="required" /> <span class="required">Required</span>
- <li>
- <label for="description">Description: </label>
- <input type="text" name="description" id="description" size="80" value="[% agreement.description | html %]" />
- <li>
- <label for="status" class="required">Status: </label>
- <select name="status" required="required" required="required">
- <option value=""></option>
- [% PROCESS options_for_authorised_values authorised_values => AuthorisedValues.GetAuthValueDropbox( 'ERM_AGREEMENT_STATUS' ), selected_av => agreement.status %]
- </select>
- <span class="required">Required</span>
- </li>
- <li>
- <label for="closure_reason">Closure reason: </label>
- <select name="closure_reason">
- <option value=""></option>
- [% PROCESS options_for_authorised_values authorised_values => AuthorisedValues.GetAuthValueDropbox( 'ERM_AGREEMENT_CLOSURE_REASON' ), selected_av => agreement.closure_reason %]
- </select>
- </li>
- <li>
- <label for="is_perpetual">Is perpetual: </label>
- <label for="is_perpetual_yes"> Yes
- [% IF agreement.is_perpetual %]
- <input type="radio" id="is_perpetual_yes" name="is_perpetual" value="1" checked="checked">
- [% ELSE %]
- <input type="radio" id="is_perpetual_yes" name="is_perpetual" value="1">
- [% END %]
- </label>
- <label for="is_perpetual_no"> No
- [% IF agreement.is_perpetual %]
- <input type="radio" id="is_perpetual_no" name="is_perpetual" value="0">
- [% ELSE %]
- <input type="radio" id="is_perpetual_no" name="is_perpetual" value="0" checked="checked">
- [% END %]
- </label>
- </li>
- <li>
- <label for="renewal_priority">Renewal priority: </label>
- <select name="renewal_priority">
- <option value=""></option>
- [% PROCESS options_for_authorised_values authorised_values => AuthorisedValues.GetAuthValueDropbox( 'ERM_AGREEMENT_RENEWAL_PRIORITY' ), selected_av => agreement.renewal_priority %]
- </select>
- <li>
- <label for="license_info">License info: </label>
- <input type="text" name="license_info" id="license_info" size="80" value="[% agreement.license_info | html %]" />
- </li>
- </ol>
- </fieldset>
-
-[% BLOCK agreement_period %]
- <fieldset class="agreement_period">
- <legend>
- Agreement period <span class="period_count">[% id | html %]</span>
- <a href="#" class="remove_period"><i class="fa fa-trash"></i> Remove this period</a>
- </legend>
- <input type="hidden" name="period_unique_id" value="[% id | html %]" />
- <ol>
- <li>
- <label for="started_on" class="required">Start date: </label>
- <input type="text" id="started_on_[% id | html %]" class="started_on" name="started_on_[% id | html %]" value="[% p.started_on | $KohaDates %]" class="flatpickr" data-date_to="ended_on_[% id | html %]" />
- <span class="required">Required</span>
- <div class="hint">[% INCLUDE 'date-format.inc' %]</div>
- </li>
- <li>
- <label for="ended_on">End date: </label>
- <input type="text" id="ended_on_[% id | html %]" class="ended_on" name="ended_on_[% id | html %]" value="[% p.ended_on | $KohaDates %]" class="flatpickr" />
- <div class="hint">[% INCLUDE 'date-format.inc' %]</div>
- </li>
- <li>
- <label>Cancellation deadline: </label>
- <input type="text" class="cancellation_deadline" name="cancellation_deadline_[% id | html %]" value="[% p.cancellation_deadline | $KohaDates %]" class="flatpickr" />
- <div class="hint">[% INCLUDE 'date-format.inc' %]</div>
- </li>
- <li>
- <label>Notes: </label>
- <input type="text" class="notes" name="notes_[% id | html %]" value="[% p.notes | html %]" />
- </li>
- </ol>
- </fieldset>
-[% END %]
-
- <fieldset class="rows" id="agreement_periods">
- <legend>Periods</legend>
- [% IF agreement.periods.count %]
- [% FOR p IN agreement.periods %]
- [% PROCESS agreement_period period => p, id => loop.count %]
- [% END %]
- [% ELSE %]
- [% PROCESS agreement_period id => 1 %]
- [% END %]
- <button class="add_new_period" type="button" class="btn btn-primary"><i class="fa fa-plus" aria-hidden="true"></i> Add new period</button>
- </fieldset>
-
-[% BLOCK agreement_user %]
- <fieldset class="agreement_user">
- <legend>
- User <span class="user_count">[% id | html %]</span>
- <a href="#" class="remove_user"><i class="fa fa-trash"></i> Remove this user</a>
- </legend>
- <input type="hidden" name="user_unique_id" value="[% id | html %]" />
-
- <ol>
- <li>
- <label for="user" class="required">User: </label>
- <span class="user">
- [% IF u %]
- <a href="/cgi-bin/koha/members/moremember.pl?borrowernumber=[% u.user_id| uri %]">
- [% INCLUDE 'patron-title.inc' patron = u.patron %]
- </a>
- <input type="hidden" class="user_id" name="user_id_[% id | html %]" value="[% u.user_id %]" />
- [% END %]
- </span>
- (<a href="#" class="pick_user" class="btn btn-default">Select user</a>)
- </li>
-
- <li>
- <label>Role: </label>
- <select class="user_role" name="user_role_[% id | html %]">
- <option value=""></option>
- [% PROCESS options_for_authorised_values authorised_values => AuthorisedValues.GetAuthValueDropbox( 'ERM_AGREEMENT_USER_ROLES' ), selected_av => u.role %]
- </select>
- </li>
- </ol>
- </fieldset>
-[% END %]
-
- <fieldset class="rows">
- <legend>Users</legend>
- [% IF agreement.user_roles.count %]
- [% FOR u IN agreement.user_roles %]
- [% PROCESS agreement_user user => u, id => loop.count %]
- [% END %]
- [% ELSE %]
- [% PROCESS agreement_user, id => 1 %]
- [% END %]
-
- <button class="add_new_user_block" type="button" class="btn btn-primary"><i class="fa fa-plus" aria-hidden="true"></i> Add new user</button>
- </fieldset>
-
- <fieldset class="action">
- <input type="submit" value="Submit" />
- <a class="cancel" href="/cgi-bin/koha/erm/agreements.pl">Cancel</a>
- </fieldset>
- </form>
-[% END %]
-
-[% IF op == 'delete_confirm' %]
- <div class="dialog alert">
- <h3>Delete agreement "[% agreement.agreement_id | html %]?"</h3>
- <table>
- <tr><th>Agreement id</th>
- <td>[% agreement.agreement_id| html %]</td>
- </tr>
- <tr><th>Vendor</th>
- <td>[% agreement.vendor_id| html %]</td>
- </tr>
- <tr><th>Name</th>
- <td>[% agreement.name| html %]</td>
- </tr>
- <tr><th>Description</th>
- <td>[% agreement.description| html %]</td>
- </tr>
- <tr><th>Status</th>
- <td>[% agreement.status| html %]</td>
- </tr>
- <tr><th>Closure_reason</th>
- <td>[% agreement.closure_reason| html %]</td>
- </tr>
- <tr><th>Is perpetual</th>
- <td>[% agreement.is_perpetual| html %]</td>
- </tr>
- <tr><th>Renewal priority</th>
- <td>[% agreement.renewal_priority| html %]</td>
- </tr>
- <tr><th>License info</th>
- <td>[% agreement.license_info| html %]</td>
- </tr>
- </table>
- <form action="/cgi-bin/koha/erm/agreements.pl" method="post">
- <input type="hidden" name="op" value="delete_confirmed" />
- <input type="hidden" name="agreement_id" value="[% agreement.agreement_id | html %]" />
- <button type="submit" class="approve"><i class="fa fa-fw fa-check"></i> Yes, delete</button>
- </form>
- <form action="/cgi-bin/koha/erm/agreements.pl" method="get">
- <button type="submit" class="deny"><i class="fa fa-fw fa-remove"></i> No, do not delete</button>
- </form>
- </div>
-[% END %]
-
-[% IF op == 'list' %]
-
- <div id="toolbar" class="btn-toolbar">
- <a class="btn btn-default" id="newagreement" href="/cgi-bin/koha/erm/agreements.pl?op=add_form"><i class="fa fa-plus"></i> New agreement</a>
- </div>
-
- <h2>Agreements</h2>
- [% IF agreement_name_filter %]
- Searching: [% agreement_name_filter | html %]
- [% END %]
-
- [% IF agreements_count > 0 %]
- <div class="table_agreements_table_controls"></div>
- <table id="table_agreements">
- <thead>
- <tr>
- <th>ID</th>
- <th>Vendor</th>
- <th>Name</th>
- <th>Description</th>
- <th>Status</th>
- <th>Closure reason</th>
- <th>Is perpetual</th>
- <th>Renewal priority</th>
- <th data-class-name="actions noExport">Actions</th>
- </tr>
- </thead>
- </table>
- [% ELSE %]
- <div class="dialog message">
- There are no agreements defined. <a href="/cgi-bin/koha/erm/agreements.pl?op=add_form">Create a new agreement</a>.
- </div>
- [% END %]
-[% END %]
+ <div id="agreements"></div>
</main>
</div> <!-- /.col-sm-10.col-sm-push-2 -->
[% INCLUDE 'datatables.inc' %]
[% INCLUDE 'columns_settings.inc' %]
[% INCLUDE 'js-patron-format.inc' %]
+ [% INCLUDE 'js-date-format.inc' %]
+
<script>
const agreement_statuses = [% To.json(AuthorisedValues.Get('ERM_AGREEMENT_STATUS')) | $raw %];
- let agreement_statuses_map = agreement_statuses.reduce((map, e) => {
- map[e.authorised_value] = e;
- return map;
- }, {});
+
const agreement_closure_reasons = [% To.json(AuthorisedValues.Get('ERM_AGREEMENT_CLOSURE_REASON')) | $raw %];
- let agreement_closure_reasons_map = agreement_closure_reasons.reduce((map, e) => {
- map[e.authorised_value] = e;
- return map;
- }, {});
const agreement_renewal_priorities = [% To.json(AuthorisedValues.Get('ERM_AGREEMENT_RENEWAL_PRIORITY')) | $raw %];
- let agreement_renewal_priorities_map = agreement_renewal_priorities.reduce((map, e) => {
- map[e.authorised_value] = e;
- return map;
- }, {});
-
+ const agreement_user_roles = [% To.json(AuthorisedValues.Get('ERM_AGREEMENT_USER_ROLES')) | $raw %];
- let current_user_node;
var columns_settings = [% TablesSettings.GetColumns( 'erm', 'agreements', 'table_agreements', 'json' ) | $raw %];
- $(document).ready(function() {
- var agreements_table_url = '/api/v1/erm/agreements?';
+ var agreements_table_url = '/api/v1/erm/agreements?';
[% IF agreement_name_filter %]
var agreement_name_filter = {
};
agreements_table_url += 'q='+ encodeURIComponent(JSON.stringify(agreement_name_filter));
[% END %]
+ </script>
- var agreements_table = $("#table_agreements").kohaTable({
- "ajax": {
- "url": agreements_table_url
- },
- "order": [[ 1, "asc" ]],
- "columns": [
- {
- "data": "agreement_id",
- "searchable": true,
- "orderable": true
- },
- {
- "data": "vendor_id",
- "searchable": true,
- "orderable": true
- },
- {
- "data": "name",
- "searchable": true,
- "orderable": true
- },
- {
- "data": "description",
- "searchable": true,
- "orderable": true
- },
- {
- "data": "status",
- "searchable": true,
- "orderable": true,
- "render": function( data, type, row, meta ) {
- return escape_str(agreement_statuses_map[row.status].lib);
- }
- },
- {
- "data": "closure_reason",
- "searchable": true,
- "orderable": true,
- "render": function( data, type, row, meta ) {
- return row.closure_reason != undefined && row.closure_reason != "" ? escape_str(agreement_closure_reasons_map[row.closure_reason].lib) : "";
- }
- },
- {
- "data": "is_perpetual",
- "searchable": true,
- "orderable": true,
- "render": function( data, type, row, meta ) {
- return escape_str(row.is_perpetual ? _("Yes") : _("No"));
- }
- },
- {
- "data": "renewal_priority",
- "searchable": true,
- "orderable": true,
- "render": function( data, type, row, meta ) {
- return row.renewal_priority != undefined && row.renewal_priority != "" ? escape_str(agreement_renewal_priorities_map[row.renewal_priority].lib) : "";
- }
- },
- {
- "data": function( row, type, val, meta ) {
-
- var result = '<a class="btn btn-default btn-xs" role="button" href="/cgi-bin/koha/erm/agreements.pl?op=add_form&agreement_id='+ encodeURIComponent(row.agreement_id) +'"><i class="fa fa-pencil" aria-hidden="true"></i> '+_("Edit")+'</a>'+"\n";
- result += '<a class="btn btn-default btn-xs" role="button" href="/cgi-bin/koha/erm/agreements.pl?op=delete_confirm&agreement_id='+ encodeURIComponent(row.agreement_id) +'"><i class="fa fa-trash" aria-hidden="true"></i> '+_("Delete")+'</a>';
- return result;
-
- },
- "searchable": false,
- "orderable": false
- }
- ]
- }, columns_settings, 1);
-
- $(".add_new_period").on("click", function(e){
- e.preventDefault();
- let first_period_block = $("fieldset.agreement_period:first");
- if ( first_period_block.is(":visible") ) {
- let new_period_block = first_period_block.clone(1);
- new_period_block.find("input").val("");
- $(new_period_block).insertBefore(this);
- } else {
- first_period_block.show();
- }
- update_period_count();
- });
- $(".remove_period").on("click", function(e){
- e.preventDefault();
- let fieldset = $(this).parent().parent();
- if ( $("fieldset.agreement_period").length == 1 ) {
- clear_block(fieldset);
- fieldset.hide();
- } else {
- fieldset.remove();
- }
- update_period_count();
- });
-
- $(".add_new_user_block").on("click",function(e){
- e.preventDefault();
- let first_user_block = $("fieldset.agreement_user:first");
- if ( first_user_block.is(":visible") ) {
- let new_user_block = $("fieldset.agreement_user:first").clone(1);
- new_user_block.find("span.user").empty();
- clear_block(new_user_block);
- $(new_user_block).insertBefore(this);
- } else {
- first_user_block.show();
- }
-
- update_user_count();
- });
- $(".remove_user").on("click", function(e){
- e.preventDefault();
- let fieldset = $(this).parent().parent();
- if ( $("fieldset.agreement_user").length == 1 ) {
- fieldset.find("span.user").empty();
- clear_block(fieldset);
- fieldset.hide();
- } else {
- fieldset.remove();
- }
-
- update_user_count();
- });
-
- $(".pick_user").on("click", function(e){
- e.preventDefault();
- current_user_node = $(this).closest("fieldset");
- window.open("/cgi-bin/koha/members/search.pl?columns=cardnumber,name,category,branch,action&selection_type=select&filter=erm_users",
- 'PatronPopup',
- 'width=740,height=450,location=yes,toolbar=no,'
- + 'scrollbars=yes,resize=yes'
- );
- });
-
- update_period_count();
- update_user_count();
- });
-
- function clear_block(block){
- $(block).find('input').val("");
- $(block).find("select option:first-child").attr("selected", "selected");
- }
- function update_period_count(){
- $("fieldset.agreement_period").each(function(i, period){
- let id = i + 1;
- $(period).find(".period_count").text(id);
- $(period).find("input[name='period_unique_id']").val(id);
-
- let ended_on_input = $(period).find("input.ended_on");
- $(ended_on_input).attr("id", "ended_on_" + id);
- $(ended_on_input).attr("name", "ended_on_" + id);
- $(ended_on_input).flatpickr();
-
- let started_on_input = $(period).find("input.started_on");
- $(started_on_input).attr("name", "started_on_" + id);
- $(started_on_input).data("date_to", "ended_on_" + id);
- $(started_on_input).flatpickr();
-
- let cancellation_deadline_input = $(period).find("input.cancellation_deadline");
- $(cancellation_deadline_input).attr("name", "cancellation_deadline_" + id);
- $(cancellation_deadline_input).flatpickr();
-
- $(period).find(".notes").attr("name", "notes_" + id);
- $(period).attr('id', 'agreement_period_' + id);
- });
- }
-
- function update_user_count(){
- $("fieldset.agreement_user").each(function(i, user){
- let id = i + 1;
- let remove_user_link = $(this).find(".remove_user");
- $(user).find(".user_count").text(id);
- $(user).find("input[name='user_unique_id']").val(id);
-
- $(user).find(".user_id").attr("name", "user_id_" + id);
- $(user).find(".user_role").attr("name", "user_role_" + id);
- });
- }
-
- function select_user(borrowernumber, patron) {
- patron['patron_id'] = borrowernumber;
- let unique_id = $(current_user_node).find("input[name='user_unique_id']").val();
- let a = '<a href="/cgi-bin/koha/members/moremember.pl?borrowernumber='
- + borrowernumber + '">' + $patron_to_html(patron) + '</a> '
- + '<input type="hidden" class="user_id" name="user_id_' + unique_id + '" value="' + borrowernumber + '" />';
- $(current_user_node).find("span.user").html(a);
- }
-
+ [% Asset.js("js/vue/dist/main.js") %]
+ [% Asset.js("js/vue/dist/runtime.js") %]
- </script>
[% END %]
[% INCLUDE 'intranet-bottom.inc' %]
--- /dev/null
+<template>
+ <Toolbar v-if="op == 'list'" @switch-view="switchView" />
+ <b-alert v-if="message" variant="success" show>{{ message }}</b-alert>
+ <b-alert v-if="error" variant="warning" show>{{ error }}</b-alert>
+ <List
+ v-if="op == 'list'"
+ :vendors="vendors"
+ :av_statuses="statuses"
+ :av_closure_reasons="closure_reasons"
+ :av_renewal_priorities="renewal_priorities"
+ @set-current-agreement-id="setCurrentAgreementID"
+ @switch-view="switchView"
+ @set-error="setError"
+ />
+ <AddForm
+ v-if="op == 'add-form'"
+ :agreement_id="agreement_id"
+ :vendors="vendors"
+ :av_statuses="statuses"
+ :av_closure_reasons="closure_reasons"
+ :av_renewal_priorities="renewal_priorities"
+ :av_user_roles="user_roles"
+ @agreement-created="agreementCreated"
+ @agreement-updated="agreementUpdated"
+ @set-error="setError"
+ @switch-view="switchView"
+ />
+ <ConfirmDeleteForm
+ v-if="op == 'confirm-delete-form'"
+ :agreement_id="agreement_id"
+ @agreement-deleted="agreementDeleted"
+ @set-error="setError"
+ @switch-view="switchView"
+ />
+</template>
+
+<script>
+import Toolbar from "./components/ERM/AgreementsToolbar.vue"
+import List from "./components/ERM/AgreementsList.vue"
+import AddForm from "./components/ERM/AgreementsFormAdd.vue"
+import ConfirmDeleteForm from "./components/ERM/AgreementsFormConfirmDelete.vue"
+
+import { reactive, computed } from "vue"
+
+export default {
+ data() {
+ return {
+ agreement_id: null,
+ op: "list",
+ message: null,
+ error: null,
+ vendors: [],
+ statuses: agreement_statuses,
+ closure_reasons: agreement_closure_reasons,
+ renewal_priorities: agreement_renewal_priorities,
+ user_roles: agreement_user_roles,
+ }
+ },
+ beforeCreate() {
+ // FIXME it's not only called on setup, but setup() does not have 'this'.
+ const apiUrl = "/api/v1/acquisitions/vendors"
+
+ fetch(apiUrl)
+ .then((res) => res.json())
+ .then(
+ (result) => {
+ this.vendors = result
+ }).catch(
+ (error) => {
+ this.$emit('set-error', error)
+ }
+ )
+
+ },
+ methods: {
+ switchView(view) {
+ this.message = null
+ this.error = null
+ this.op = view
+ if (view == "list") this.agreement_id = null
+ },
+ agreementCreated() {
+ this.message = "Agreement created"
+ this.error = null
+ this.agreement_id = null
+ this.op = "list"
+ },
+ agreementUpdated() {
+ this.message = "Agreement updated"
+ this.error = null
+ this.agreement_id = null
+ this.op = "list"
+ },
+ agreementDeleted() {
+ this.message = "Agreement deleted"
+ this.error = null
+ this.agreement_id = null
+ this.op = "list"
+ },
+ setCurrentAgreementID(agreement_id) {
+ this.agreement_id = agreement_id
+ },
+ setError(error) {
+ this.message = null
+ this.error = "Something went wrong: " + error
+ },
+ },
+ components: {
+ Toolbar,
+ List,
+ AddForm,
+ ConfirmDeleteForm,
+ },
+ emits: ["set-error"],
+};
+</script>
--- /dev/null
+<template>
+ <fieldset class="rows" id="agreement_periods">
+ <legend>Periods</legend>
+ <fieldset
+ class="rows"
+ v-for="(period, counter) in periods"
+ v-bind:key="counter"
+ >
+ <legend>
+ Agreement period {{ counter + 1 }}
+ <a href="#" @click.prevent="deletePeriod(counter)"
+ ><i class="fa fa-trash"></i> Remove this period</a
+ >
+ </legend>
+ <ol>
+ <li>
+ <label :for="`started_on_${counter}`" class="required"
+ >Start date:
+ </label>
+ <flat-pickr
+ v-model="period.started_on"
+ required
+ :config="fp_config"
+ :data-date_to="`ended_on_${counter}`"
+ />
+ <span class="required">Required</span>
+ </li>
+ <li>
+ <label :for="`ended_on_${counter}`">End date: </label>
+ <flat-pickr
+ :id="`ended_on_${counter}`"
+ v-model="period.ended_on"
+ :config="fp_config"
+ />
+ </li>
+ <li>
+ <label :for="`cancellation_deadline_${counter}`"
+ >Cancellation deadline:
+ </label>
+ <flat-pickr
+ :id="`cancellation_deadline_${counter}`"
+ v-model="period.cancellation_deadline"
+ :config="fp_config"
+ />
+ </li>
+ <li>
+ <label :for="`notes_${counter}`">Notes: </label>
+ <input
+ type="text"
+ class="notes"
+ :name="`notes_${counter}`"
+ v-model="period.notes"
+ />
+ </li>
+ </ol>
+ </fieldset>
+ <button @click="addPeriod" type="button" class="btn btn-primary">
+ <i class="fa fa-plus" aria-hidden="true"></i> Add new period
+ </button>
+ </fieldset>
+</template>
+
+<script>
+import flatPickr from 'vue-flatpickr-component'
+export default {
+ name: 'AgreementPeriods',
+ data() {
+ return { fp_config: flatpickr_defaults, dates_fixed: 0 }
+ },
+ props: {
+ periods: Array
+ },
+ beforeUpdate() {
+ if (!this.dates_fixed) {
+ this.periods.forEach(p => {
+ p.started_on = $date(p.started_on)
+ })
+ this.dates_fixed = 1
+ }
+ },
+ methods: {
+ addPeriod() {
+ this.periods.push({
+ started_on: null,
+ ended_on: null,
+ cancellation_deadline: null,
+ notes: null,
+ })
+ },
+ deletePeriod(counter) {
+ this.periods.splice(counter, 1)
+ }
+ },
+ components: {
+ flatPickr
+ }
+}
+</script>
--- /dev/null
+<template>
+ <fieldset class="rows" id="agreement_user_roles">
+ <legend>Users</legend>
+ <fieldset
+ class="rows"
+ v-for="(user_role, counter) in user_roles"
+ v-bind:key="counter"
+ >
+ <legend>
+ Agreement user {{ counter + 1 }}
+ <a href="#" @click.prevent="deleteUser(counter)"
+ ><i class="fa fa-trash"></i> Remove this user</a
+ >
+ </legend>
+ <ol>
+ <li>
+ <label :for="`user_id_${counter}`">User: </label>
+ <span class="user">
+ {{ user_role.patron_str }}
+ </span>
+ (<a
+ href="#"
+ @click="selectUser(counter)"
+ class="btn btn-default"
+ >Select user</a
+ >)
+ </li>
+ <li>
+ <label :for="`user_role_${counter}`">Role: </label>
+ <b-form-select v-model="user_role.role" required>
+ <b-form-select-option value=""></b-form-select-option>
+ <b-form-select-option
+ v-for="r in av_user_roles"
+ :key="r.authorised_values"
+ :value="r.authorised_value"
+ :selected="
+ r.authorised_value == user_role.role
+ ? true
+ : false
+ "
+ >{{ r.lib }}</b-form-select-option
+ >
+ </b-form-select>
+ <span class="required">Required</span>
+ </li>
+ </ol>
+ </fieldset>
+ <input
+ type="hidden"
+ name="selected_patron_id"
+ id="selected_patron_id"
+ />
+ <button @click="addUser" type="button" class="btn btn-primary">
+ <i class="fa fa-plus" aria-hidden="true"></i> Add new user
+ </button>
+ </fieldset>
+</template>
+
+<script>
+export default {
+ name: 'AgreementUserRoles',
+ props: {
+ av_user_roles: Array,
+ user_roles: Array,
+ },
+ beforeUpdate() {
+ this.user_roles.forEach(u => {
+ u.patron_str = $patron_to_html(u.patron)
+ })
+ },
+ methods: {
+ addUser() {
+ this.user_roles.push({
+ user_id: null,
+ role: null,
+ patron_str: '',
+ })
+ },
+ deleteUser(counter) {
+ this.user_roles.splice(counter, 1)
+ },
+ selectUser(counter) {
+ let select_user_window = window.open("/cgi-bin/koha/members/search.pl?columns=cardnumber,name,category,branch,action&selection_type=select&filter=erm_users",
+ 'PatronPopup',
+ 'width=740,height=450,location=yes,toolbar=no,'
+ + 'scrollbars=yes,resize=yes'
+ )
+ // This is a bit dirty, the "select user" window should be rewritten and be a Vue component
+ // but that's not for now...
+ select_user_window.addEventListener('beforeunload', this.newUserSelected, false)
+ select_user_window.counter = counter
+ },
+ newUserSelected(e) {
+ let c = e.currentTarget.counter
+ let selected_patron_id = document.getElementById("selected_patron_id").value
+ fetch('/api/v1/patrons/' + selected_patron_id)
+ .then(res => res.json())
+ .then(
+ (result) => {
+ this.user_roles[c].patron = result
+ this.user_roles[c].patron_str = $patron_to_html(result)
+ this.user_roles[c].user_id = result.patron_id
+ }).catch(
+ (error) => {
+ this.$emit('set-error', error)
+ }
+ )
+
+ }
+ },
+}
+</script>
--- /dev/null
+<template>
+ <button variant="default" size="sm">Delete</button>
+</template>
+
+<script>
+export default {
+ name: "AgreementsButtonDelete"
+}
+</script>
--- /dev/null
+<template>
+ <button variant="default" size="sm">Edit</button>
+</template>
+
+<script>
+export default {
+ name: "AgreementsButtonEdit",
+}
+</script>
--- /dev/null
+<template>
+ <h2 v-if="agreement.agreement_id">Edit agreement</h2>
+ <h2 v-else>New agreement</h2>
+ <div>
+ <b-form @submit="onSubmit">
+ <b-form-group
+ id="agreement_name"
+ label="Agreement name:"
+ label-for="agreement_name"
+ label-cols="4"
+ label-cols-lg="2"
+ >
+ <b-form-input
+ id="agreement_name"
+ v-model="agreement.name"
+ placeholder="Agreement name"
+ required
+ ></b-form-input>
+ <span class="required">Required</span>
+ </b-form-group>
+ <b-form-group
+ id="agreement_vendor_id"
+ label="Vendor:"
+ label-for="agreement_vendor_id"
+ label-cols="4"
+ label-cols-lg="2"
+ >
+ <b-form-select v-model="agreement.vendor_id">
+ <b-form-select-option value=""></b-form-select-option>
+ <b-form-select-option
+ v-for="vendor in vendors"
+ :key="vendor.vendor_id"
+ :value="vendor.id"
+ :selected="
+ vendor.id == agreement.vendor_id ? true : false
+ "
+ >{{ vendor.name }}</b-form-select-option
+ >
+ </b-form-select>
+ </b-form-group>
+ <b-form-group
+ id="agreement_description"
+ label="Description"
+ label-for="agreement_description"
+ label-cols="4"
+ label-cols-lg="2"
+ >
+ <b-form-input
+ id="agreement_description"
+ v-model="agreement.description"
+ placeholder="Description"
+ required
+ ></b-form-input>
+ <span class="required">Required</span>
+ </b-form-group>
+ <b-form-group
+ id="agreement_status"
+ label="Status:"
+ label-for="agreement_status"
+ label-cols="4"
+ label-cols-lg="2"
+ >
+ <b-form-select
+ id="agreement_status"
+ v-model="agreement.status"
+ @change="onStatusChange($event)"
+ required
+ >
+ <b-form-select-option value=""></b-form-select-option>
+ <b-form-select-option
+ v-for="status in av_statuses"
+ :key="status.authorised_values"
+ :value="status.authorised_value"
+ :selected="
+ status.authorised_value == agreement.status
+ ? true
+ : false
+ "
+ >{{ status.lib }}</b-form-select-option
+ >
+ </b-form-select>
+ <span class="required">Required</span>
+ </b-form-group>
+ <b-form-group
+ id="agreement_closure_reason"
+ label="Closure reason:"
+ label-for="agreement_closure_reason"
+ label-cols="4"
+ label-cols-lg="2"
+ >
+ <b-form-select
+ id="agreement_closure_reason"
+ v-model="agreement.closure_reason"
+ :disabled="agreement.status == 'closed' ? true : false"
+ >
+ <b-form-select-option value=""></b-form-select-option>
+ <b-form-select-option
+ v-for="r in av_closure_reasons"
+ :key="r.authorised_values"
+ :value="r.authorised_value"
+ :selected="
+ r.authorised_value == agreement.closure_reason
+ ? true
+ : false
+ "
+ >{{ r.lib }}</b-form-select-option
+ >
+ </b-form-select>
+ </b-form-group>
+ <b-form-group
+ label="Is perpetual:"
+ label-for="agreement_is_perpetual"
+ label-cols="4"
+ label-cols-lg="2"
+ >
+ <b-form-radio-group
+ id="agreement_is_perpetual"
+ label="Is perpetual:"
+ label-for="agreement_is_perpetual"
+ label-cols="4"
+ label-cols-lg="2"
+ v-model="agreement.is_perpetual"
+ :options="is_perpetual_options"
+ >
+ </b-form-radio-group>
+ </b-form-group>
+ <b-form-group
+ id="agreement_renewal_priority"
+ label="Renewal priority:"
+ label-for="agreement_renewal_priority"
+ label-cols="4"
+ label-cols-lg="2"
+ >
+ <b-form-select v-model="agreement.renewal_priority">
+ <b-form-select-option value=""></b-form-select-option>
+ <b-form-select-option
+ v-for="p in av_renewal_priorities"
+ :key="p.authorised_values"
+ :value="p.authorised_value"
+ :selected="
+ p.authorised_value == agreement.renewal_priority
+ ? true
+ : false
+ "
+ >{{ p.lib }}</b-form-select-option
+ >
+ </b-form-select>
+ </b-form-group>
+ <b-form-group
+ id="agreement_license_info"
+ label="License info:"
+ label-for="agreement_license_info"
+ label-cols="4"
+ label-cols-lg="2"
+ >
+ <b-form-input
+ id="agreement_license_info"
+ v-model="agreement.license_info"
+ placeholder="License info"
+ ></b-form-input>
+ </b-form-group>
+
+ <AgreementPeriods :periods="agreement.periods" />
+ <AgreementUserRoles
+ :user_roles="agreement.user_roles"
+ :av_user_roles="av_user_roles"
+ />
+
+ <b-button type="submit" variant="primary">Submit</b-button>
+ <a href="#" @click="$emit('switch-view', 'list')">Cancel</a>
+ </b-form>
+ </div>
+</template>
+
+<script>
+import AgreementPeriods from './AgreementPeriods.vue'
+import AgreementUserRoles from './AgreementUserRoles.vue'
+
+export default {
+ data() {
+ return {
+ is_perpetual_options: [{ text: "Yes", value: true }, { text: "No", value: false }],
+ agreement: {
+ agreement_id: null,
+ name: '',
+ vendor_id: null,
+ description: '',
+ status: '',
+ closure_reason: '',
+ is_perpetual: false,
+ renewal_priority: '',
+ license_info: '',
+ periods: [],
+ user_roles: [],
+ }
+ }
+ },
+ created() {
+ if (!this.agreement_id) return
+ const apiUrl = '/api/v1/erm/agreements/' + this.agreement_id
+
+ fetch(apiUrl, {
+ headers: {
+ 'x-koha-embed': 'periods,user_roles,user_roles.patron'
+ }
+ })
+ .then(res => res.json())
+ .then(
+ (result) => {
+ this.agreement = result
+ }
+ )
+ },
+ methods: {
+ onSubmit() {
+
+ //let agreement= Object.assign( {} ,this.agreement); // copy
+ let agreement = JSON.parse(JSON.stringify(this.agreement)) // copy
+ let apiUrl = '/api/v1/erm/agreements'
+
+ const myHeaders = new Headers()
+ myHeaders.append('Content-Type', 'application/json')
+
+ let method = 'POST'
+ if (agreement.agreement_id) {
+ method = 'PUT'
+ apiUrl += '/' + agreement.agreement_id
+ }
+ delete agreement.agreement_id
+
+ agreement.periods.forEach(p => {
+ p.started_on = $date_to_rfc3339(p.started_on)
+ p.ended_on = p.ended_on ? $date_to_rfc3339(p.ended_on) : null
+ p.cancellation_deadline = p.cancellation_deadline ? $date_to_rfc3339(p.cancellation_deadline) : null
+ })
+
+ agreement.periods = agreement.periods.map(({ agreement_id, agreement_period_id, ...keepAttrs }) => keepAttrs)
+
+ agreement.user_roles = agreement.user_roles.map(({ patron, patron_str, ...keepAttrs }) => keepAttrs)
+
+ const options = {
+ method: method,
+ body: JSON.stringify(agreement),
+ myHeaders
+ }
+
+ fetch(apiUrl, options)
+ .then(response => {
+ if (response.status == 200) {
+ this.$emit('agreement-updated')
+ } else if (response.status == 201) {
+ this.$emit('agreement-created')
+ } else {
+ this.$emit('set-error', response.message || response.statusText)
+ }
+ }).catch(
+ (error) => {
+ this.$emit('set-error', error)
+ }
+ )
+ },
+ onStatusChange(status) {
+ if (status == 'closed') {
+ this.agreement.closure_reason = ''
+ }
+ }
+ },
+ emits: ['agreement-created', 'agreement-updated', 'set-error', 'switch-view'],
+ props: {
+ agreement_id: Number,
+ vendors: Array,
+ av_statuses: Array,
+ av_closure_reasons: Array,
+ av_renewal_priorities: Array,
+ av_user_roles: Array,
+ },
+ components: {
+ AgreementPeriods,
+ AgreementUserRoles
+ },
+ name: "AgreementsFormAdd",
+}
+</script>
--- /dev/null
+<template>
+ <h2>Delete agreement</h2>
+ <div>
+ <b-form @submit="onSubmit">
+ <b-form-group
+ id="agreement_name"
+ label="Agreement name:"
+ label-for="agreement_name"
+ label-cols="4"
+ label-cols-lg="2"
+ >
+ {{ agreement.name }}
+ </b-form-group>
+ <b-form-group
+ id="agreement_vendor"
+ label="Vendor:"
+ label-for="agreement_vendor"
+ label-cols="4"
+ label-cols-lg="2"
+ >
+ {{ agreement.vendor_id }}
+ </b-form-group>
+ <b-form-group
+ id="agreement_description"
+ label="Description:"
+ label-for="agreement_description"
+ label-cols="4"
+ label-cols-lg="2"
+ >
+ {{ agreement.description }}
+ </b-form-group>
+ <b-button type="submit" variant="primary">Submit</b-button>
+ <a href="#" @click="$emit('switch-view', 'list')">Cancel</a>
+ </b-form>
+ </div>
+</template>
+
+<script>
+
+export default {
+ data() {
+ return {
+ agreement: {},
+ }
+ },
+ created() {
+ const apiUrl = '/api/v1/erm/agreements/' + this.agreement_id
+
+ fetch(apiUrl)
+ .then(res => res.json())
+ .then(
+ (result) => {
+ this.agreement = result
+ },
+ ).catch(
+ (error) => {
+ this.$emit('set-error', error)
+ }
+ )
+ },
+ methods: {
+ onSubmit() {
+
+ let apiUrl = '/api/v1/erm/agreements/' + this.agreement_id
+
+ const myHeaders = new Headers()
+ myHeaders.append('Content-Type', 'application/json')
+
+ const options = {
+ method: 'DELETE',
+ myHeaders
+ }
+
+ fetch(apiUrl, options)
+ .then(
+ (response) => {
+ if (response.status == 204) {
+ this.$emit('agreement-deleted')
+ } else {
+ this.$emit('set-error', response.message || response.statusText)
+ }
+ }
+ ).catch(
+ (error) => {
+ this.$emit('set-error', error)
+ }
+ )
+ }
+ },
+ emits: ['agreement-deleted', 'set-error', 'switch-view'],
+ props: {
+ agreement_id: Number
+ },
+ name: "AgreementsFormConfirmDelete",
+}
+</script>
--- /dev/null
+<template>
+ <div>
+ <table v-if="agreements.length" id="my_table"></table>
+ <div v-else-if="this.initialized" class="dialog message">
+ There are no agreements defined.
+ </div>
+ <div v-else>Loading...</div>
+ </div>
+</template>
+
+<script>
+import AgreementsButtonEdit from "./AgreementsButtonEdit.vue"
+import AgreementsButtonDelete from "./AgreementsButtonDelete.vue"
+import { createVNode, defineComponent, render, resolveComponent } from 'vue'
+export default {
+ created() {
+ const apiUrl = '/api/v1/erm/agreements'
+
+ fetch(apiUrl)
+ .then(res => res.json())
+ .then(
+ (result) => {
+ this.agreements = result
+ this.initialized = true
+ },
+ ).catch(
+ (error) => {
+ this.$emit('set-error', error)
+ }
+ )
+ },
+ updated() {
+ let edit_agreement = this.edit_agreement
+ let delete_agreement = this.delete_agreement
+ let vendors_map = this.vendors.reduce((map, e) => {
+ map[e.id] = e
+ return map
+ }, {})
+ let statuses_map = this.av_statuses.reduce((map, e) => {
+ map[e.authorised_value] = e
+ return map
+ }, {})
+ let closure_reasons_map = this.av_closure_reasons.reduce((map, e) => {
+ map[e.authorised_value] = e
+ return map
+ }, {})
+ let renewal_priorities_map = this.av_renewal_priorities.reduce((map, e) => {
+ map[e.authorised_value] = e
+ return map
+ }, {})
+
+ $('#my_table').kohaTable({
+ "ajax": {
+ "url": agreements_table_url,
+ },
+ "order": [[1, "asc"]],
+ "columnDefs": [{
+ "targets": [0, 1, 2, 3, 4],
+ "render": function (data, type, row, meta) {
+ if (type == 'display') {
+ return escape_str(data)
+ }
+ return data
+ }
+ }],
+ "columns": [
+ {
+ "title": __("Agrement ID"),
+ "data": "agreement_id",
+ "searchable": true,
+ "orderable": true
+ },
+ {
+ "title": __("Vendor"),
+ "data": "vendor_id",
+ "searchable": true,
+ "orderable": true,
+ "render": function (data, type, row, meta) {
+ return row.vendor_id != undefined ? escape_str(vendors_map[row.vendor_id].name) : ""
+ }
+ },
+ {
+ "title": __("Name"),
+ "data": "name",
+ "searchable": true,
+ "orderable": true
+ },
+ {
+ "title": __("description"),
+ "data": "description",
+ "searchable": true,
+ "orderable": true
+ },
+ {
+ "title": __("Status"),
+ "data": "status",
+ "searchable": true,
+ "orderable": true,
+ "render": function (data, type, row, meta) {
+ return escape_str(statuses_map[row.status].lib)
+ }
+ },
+ {
+ "title": __("Closure reason"),
+ "data": "closure_reason",
+ "searchable": true,
+ "orderable": true,
+ "render": function (data, type, row, meta) {
+ return row.closure_reason != undefined && row.closure_reason != "" ? escape_str(closure_reasons_map[row.closure_reason].lib) : ""
+ }
+ },
+ {
+ "title": __("Is perpetual"),
+ "data": "is_perpetual",
+ "searchable": true,
+ "orderable": true,
+ "render": function (data, type, row, meta) {
+ return escape_str(row.is_perpetual ? _("Yes") : _("No"))
+ }
+ },
+ {
+ "title": __("Renewal priority"),
+ "data": "renewal_priority",
+ "searchable": true,
+ "orderable": true,
+ "render": function (data, type, row, meta) {
+ return row.renewal_priority != undefined && row.renewal_priority != "" ? escape_str(renewal_priorities_map[row.renewal_priority].lib) : ""
+ }
+ },
+ {
+ "title": __("Actions"),
+ "data": function (row, type, val, meta) {
+ return '<div class="actions" data-agreement_id="' + row.agreement_id + '"></div>'
+ },
+ "searchable": false,
+ "orderable": false
+ }
+ ],
+ drawCallback: function (settings) {
+ $.each($(this).find(".actions"), function (index, e) {
+ let agreement_id = $(e).data('agreement_id')
+ let editButton = createVNode(AgreementsButtonEdit, {
+ onClick: () => {
+ edit_agreement(agreement_id)
+ }
+ })
+ let deleteButton = createVNode(AgreementsButtonDelete, {
+ onClick: () => {
+ delete_agreement(agreement_id)
+ }
+ })
+ let n = createVNode('span', {}, [editButton, deleteButton])
+ render(n, e)
+ })
+ },
+ preDrawCallback: function(settings){
+ var table_id = settings.nTable.id
+ $("#"+table_id).find("thead th").eq(1).attr('data-filter', 'vendors');
+ }
+
+ }, columns_settings, 1)
+ },
+ beforeUnmount() {
+ $('#my_table')
+ .DataTable()
+ .destroy(true)
+ },
+ data: function () {
+ return {
+ agreements: [],
+ initialized: false,
+ }
+ },
+ methods: {
+ edit_agreement: function (agreement_id) {
+ this.$emit('set-current-agreement-id', agreement_id)
+ this.$emit('switch-view', 'add-form')
+ },
+ delete_agreement: function (agreement_id) {
+ this.$emit('set-current-agreement-id', agreement_id)
+ this.$emit('switch-view', 'confirm-delete-form')
+ },
+ },
+ props: {
+ vendors: Array,
+ av_statuses: Array,
+ av_closure_reasons: Array,
+ av_renewal_priorities: Array,
+ },
+ name: "AgreementsList",
+}
+</script>
--- /dev/null
+<template>
+ <b-button
+ @click="$emit('switch-view', 'add-form')"
+ id="new_agreement"
+ variant="default"
+ ><font-awesome-icon icon="plus" /> New agreement</b-button
+ >
+</template>
+
+<script>
+export default {
+ name: "AgreementsToolbar",
+ emits: ['switch-view'],
+}
+</script>
--- /dev/null
+import {createApp} from 'vue'
+import BootstrapVue3 from 'bootstrap-vue-3'
+
+//import 'bootstrap/dist/css/bootstrap.css'
+import 'bootstrap-vue-3/dist/bootstrap-vue-3.css'
+
+import {library} from "@fortawesome/fontawesome-svg-core"
+import {faPlus, faPencil, faTrash} from "@fortawesome/free-solid-svg-icons"
+import {FontAwesomeIcon} from "@fortawesome/vue-fontawesome"
+
+library.add(faPlus, faPencil, faTrash)
+
+import App from './Agreements.vue'
+
+createApp(App)
+ .component("font-awesome-icon", FontAwesomeIcon)
+ .use(BootstrapVue3)
+ .mount('#agreements')
"test": "test"
},
"dependencies": {
- "bootstrap": "^4.5.2",
+ "@fortawesome/fontawesome-svg-core": "^6.1.0",
+ "@fortawesome/free-solid-svg-icons": "^6.0.0",
+ "@fortawesome/vue-fontawesome": "^3.0.0-5",
+ "@popperjs/core": "^2.11.2",
+ "babel-core": "^7.0.0-beta.3",
+ "bootstrap": "^5.1.3",
+ "bootstrap-vue-3": "^0.1.7",
+ "css-loader": "^6.6.0",
"gulp": "^4.0.2",
"gulp-autoprefixer": "^4.0.0",
"gulp-concat-po": "^1.0.0",
"js-yaml": "^3.13.1",
"lodash": "^4.17.12",
"merge-stream": "^2.0.0",
- "minimist": "^1.2.5"
+ "minimist": "^1.2.5",
+ "style-loader": "^3.3.1",
+ "vue": "^3.2.31",
+ "vue-flatpickr-component": "^9"
},
"scripts": {
"build": "node_modules/.bin/gulp build",
+ "build_js": "webpack --mode production",
+ "watch_js": "webpack --mode development --watch",
"css": "node_modules/.bin/gulp css",
"watch": "node_modules/.bin/gulp watch"
},
"postcss": "^8.4.14",
"stylelint-config-standard-scss": "^5.0.0",
"stylelint-order": "^5.0.0",
- "stylelint": "^14.9.1"
+ "stylelint": "^14.9.1",
+ "@babel/core": "^7.17.5",
+ "@babel/preset-env": "^7.16.11",
+ "@vue/compiler-sfc": "^3.2.31",
+ "babel-loader": "^8.2.3",
+ "babelify": "^10.0.0",
+ "browserify": "^17.0.0",
+ "clean-webpack-plugin": "^4.0.0",
+ "gulp-tap": "^1.0.1",
+ "html-webpack-plugin": "^5.5.0",
+ "ts-loader": "^9.2.7",
+ "typescript": "^4.6.2",
+ "vinyl-source-stream": "^2.0.0",
+ "vue-loader": "^17.0.0",
+ "watchify": "^4.0.0",
+ "webpack": "^5.69.1",
+ "webpack-cli": "^4.9.2",
+ "webpack-dev-server": "^4.7.4"
}
}
--- /dev/null
+{
+ "compilerOptions": {
+ }
+}
--- /dev/null
+const { VueLoaderPlugin } = require("vue-loader");
+const autoprefixer = require("autoprefixer");
+const path = require("path");
+
+module.exports = {
+ entry: {
+ main: "./koha-tmpl/intranet-tmpl/prog/js/vue/main-erm.ts",
+ },
+ output: {
+ filename: "[name].js",
+ path: path.resolve(__dirname, "koha-tmpl/intranet-tmpl/prog/js/vue/dist/"),
+ chunkFilename: "[name].js",
+ },
+ module: {
+ rules: [
+ {
+ test: /\.vue$/,
+ loader: "vue-loader",
+ },
+ {
+ test: /\.ts$/,
+ loader: 'ts-loader',
+ options: {
+ appendTsSuffixTo: [/\.vue$/]
+ }
+ },
+ {
+ test: /\.css$/,
+ use: ['style-loader', 'css-loader']
+ }
+ ],
+ },
+ plugins: [
+ new VueLoaderPlugin(),
+ ],
+};