diff --git a/lib/NGCP/Panel/Controller/Administrator.pm b/lib/NGCP/Panel/Controller/Administrator.pm index 4541d656a7..a9128551c0 100644 --- a/lib/NGCP/Panel/Controller/Administrator.pm +++ b/lib/NGCP/Panel/Controller/Administrator.pm @@ -95,7 +95,6 @@ sub create :Chained('list_admin') :PathPart('create') :Args(0) { try { $form->params->{reseller_id} = delete $form->params->{reseller}{id}; delete $form->params->{reseller}; - delete $form->params->{save}; delete $form->params->{id}; $c->model('DB')->resultset('admins')->create($form->params); $c->flash(messages => [{type => 'success', text => 'Administrator created.'}]); @@ -131,7 +130,7 @@ sub edit :Chained('base') :PathPart('edit') :Args(0) { my ($self, $c) = @_; my $posted = $c->request->method eq 'POST'; my $form; - if($c->user->auth_realm eq "admin") { + if($c->user->is_superuser) { $form = NGCP::Panel::Form::Administrator::Admin->new; $c->stash->{administrator}->{reseller}{id} = delete $c->stash->{administrator}->{reseller_id}; @@ -145,7 +144,11 @@ sub edit :Chained('base') :PathPart('edit') :Args(0) { params => $posted ? $c->request->params : $c->stash->{administrator}, action => $c->uri_for($c->stash->{administrator}->{id}, 'edit'), ); - # TODO: if pass is empty, don't update it + NGCP::Panel::Utils::Navigation::check_form_buttons( + c => $c, + form => $form, + fields => {}, + ); if ($posted && $form->validated) { try { my $form_values = $form->value; diff --git a/lib/NGCP/Panel/Controller/Billing.pm b/lib/NGCP/Panel/Controller/Billing.pm index 6e58e30a69..91f3166ecd 100644 --- a/lib/NGCP/Panel/Controller/Billing.pm +++ b/lib/NGCP/Panel/Controller/Billing.pm @@ -15,6 +15,7 @@ use NGCP::Panel::Form::BillingPeaktimeWeekdays; use NGCP::Panel::Form::BillingPeaktimeSpecial; use NGCP::Panel::Form::BillingFeeUpload; use NGCP::Panel::Utils::Navigation; +use NGCP::Panel::Utils::Datatables; my @WEEKDAYS = map { langinfo($_) } (DAY_2, DAY_3, DAY_4, DAY_5, DAY_6, DAY_7, DAY_1); #Monday Tuesday Wednesday Thursday Friday Saturday Sunday @@ -32,6 +33,11 @@ sub profile_list :Chained('/') :PathPart('billing') :CaptureArgs(0) { my $dispatch_to = '_profile_resultset_' . $c->user->auth_realm; my $profiles_rs = $self->$dispatch_to($c); $c->stash(profiles_rs => $profiles_rs); + $c->stash->{profile_dt_columns} = NGCP::Panel::Utils::Datatables::set_columns($c, [ + { name => "id", "search" => 1, "title" => "#" }, + { name => "name", "search" => 1, "title" => "Name" }, + { name => "reseller.name", "search" => 1, "title" => "Reseller" }, + ]); $c->stash(template => 'billing/list.tt'); } @@ -57,10 +63,7 @@ sub ajax :Chained('profile_list') :PathPart('ajax') :Args(0) { my ($self, $c) = @_; my $resultset = $c->stash->{profiles_rs}; - - $c->forward( "/ajax_process_resultset", [$resultset, - ["id", "name"], - ["id", "name"]]); + NGCP::Panel::Utils::Datatables::process($c, $resultset, $c->stash->{profile_dt_columns}); $c->detach( $c->view("JSON") ); } @@ -110,18 +113,36 @@ sub edit :Chained('base') :PathPart('edit') { sub create :Chained('profile_list') :PathPart('create') :Args(0) { my ($self, $c) = @_; + my $posted = ($c->request->method eq 'POST'), my $dispatch_to = 'NGCP::Panel::Form::BillingProfile_' . $c->user->auth_realm; my $form = $dispatch_to->new; $form->process( - posted => ($c->request->method eq 'POST'), + posted => $posted, params => $c->request->params, action => $c->uri_for('create'), - item => $c->stash->{profiles_rs}->new_result({}), ); - if($form->validated) { - $c->flash(messages => [{type => 'success', text => 'Billing profile successfully created!'}]); - $c->response->redirect($c->uri_for()); - return; + NGCP::Panel::Utils::Navigation::check_form_buttons( + c => $c, + form => $form, + fields => {}, + back_uri => $c->req->uri, + ); + if($posted && $form->validated) { + try { + if($c->user->is_superuser) { + $form->values->{reseller_id} = $form->values->{reseller}{id}; + } else { + $form->values->{reseller_id} = $c->user->reseller_id; + } + delete $form->values->{reseller}; + $c->model('DB')->resultset('billing_profiles')->create($form->values); + $c->flash(messages => [{type => 'success', text => 'Billing profile successfully created'}]); + } catch($e) { + $c->log->error("failed to create billing profile: $e"); + $c->flash(messages => [{type => 'error', text => 'Failed to create billing profile'}]); + NGCP::Panel::Utils::Navigation::back_or($c, $c->uri_for); + } + NGCP::Panel::Utils::Navigation::back_or($c, $c->uri_for); } $c->stash(close_target => $c->uri_for()); diff --git a/lib/NGCP/Panel/Controller/Contact.pm b/lib/NGCP/Panel/Controller/Contact.pm index 8c6937500a..1898265082 100644 --- a/lib/NGCP/Panel/Controller/Contact.pm +++ b/lib/NGCP/Panel/Controller/Contact.pm @@ -3,7 +3,8 @@ use Sipwise::Base; use namespace::sweep; BEGIN { extends 'Catalyst::Controller'; } -use NGCP::Panel::Form::Contact; +use NGCP::Panel::Form::Contact::Reseller; +use NGCP::Panel::Form::Contact::Admin; use NGCP::Panel::Utils::Navigation; sub auto :Does(ACL) :ACLDetachTo('/denied_page') :AllowedRole(admin) :AllowedRole(reseller) { @@ -16,35 +17,22 @@ sub auto :Does(ACL) :ACLDetachTo('/denied_page') :AllowedRole(admin) :AllowedRol sub list_contact :Chained('/') :PathPart('contact') :CaptureArgs(0) { my ($self, $c) = @_; - my $contacts; - if($c->user->auth_realm eq "reseller") { - $contacts = $c->model('DB')->resultset('contracts')->search({ - reseller_id => $c->user->reseller_id - })->search_related_rs('contact'); - } else { - $contacts = $c->model('DB')->resultset('contacts'); + my $contacts = $c->model('DB')->resultset('contacts'); + unless($c->user->is_superuser) { + $contacts = $contacts->search({ reseller_id => $c->user->reseller_id }); } - $c->stash(contacts => $contacts); + $c->stash(template => 'contact/list.tt'); $c->stash->{contact_dt_columns} = NGCP::Panel::Utils::Datatables::set_columns($c, [ { name => "id", search => 1, title => "#" }, + { name => "reseller.name", search => 1, title => "Reseller" }, { name => "firstname", search => 1, title => "First Name" }, { name => "lastname", search => 1, title => "Last Name" }, { name => "company", search => 1, title => "Company" }, { name => "email", search => 1, title => "Email" }, ]); - - # TODO: wtf? - if($c->session->{redirect_targets} && @{ $c->session->{redirect_targets} }) { - my $target = ${ $c->session->{redirect_targets} }[0]; - if('/'.$c->request->path eq $target->path) { - shift @{$c->session->{redirect_targets}}; - } else { - $c->stash(close_target => $target); - } - } } sub root :Chained('list_contact') :PathPart('') :Args(0) { @@ -54,35 +42,36 @@ sub root :Chained('list_contact') :PathPart('') :Args(0) { sub create :Chained('list_contact') :PathPart('create') :Args(0) { my ($self, $c) = @_; - my $form = NGCP::Panel::Form::Contact->new; + my $posted = ($c->request->method eq 'POST'); + my $form; + my $params = {}; + if($c->user->is_superuser) { + $form = NGCP::Panel::Form::Contact::Admin->new; + } else { + $form = NGCP::Panel::Form::Contact::Reseller->new; + $params->{reseller}{id} = $c->user->reseller_id; + } $form->process( - posted => ($c->request->method eq 'POST'), + posted => $posted, params => $c->request->params, - action => $c->uri_for('create'), + item => $params, + ); + NGCP::Panel::Utils::Navigation::check_form_buttons( + c => $c, + form => $form, + fields => {}, ); - if($form->validated) { + if($posted && $form->validated) { try { - delete $form->params->{submitid}; - delete $form->params->{save}; - my $contact = $c->stash->{contacts}->create($form->params); - if($c->stash->{close_target}) { - $c->session->{created_object} = { contact => { id => $contact->id } }; - $c->response->redirect($c->stash->{close_target}); - return; - } + my $contact = $c->stash->{contacts}->create($form->values); + $c->session->{created_object} = { contact => { id => $contact->id } }; $c->flash(messages => [{type => 'success', text => 'Contact successfully created'}]); - $c->response->redirect($c->uri_for_action('/contact/root')); - return; } catch($e) { $c->log->error("failed to create contact: $e"); - if($c->stash->{close_target}) { - $c->response->redirect($c->stash->{close_target}); - return; - } $c->flash(messages => [{type => 'error', text => 'Failed to create contact'}]); - $c->response->redirect($c->uri_for_action('/contact/root')); - return; + NGCP::Panel::Utils::Navigation::back_or($c, $c->uri_for_action('/contact/root')); } + NGCP::Panel::Utils::Navigation::back_or($c, $c->uri_for_action('/contact/root')); } $c->stash(create_flag => 1); @@ -94,11 +83,10 @@ sub base :Chained('list_contact') :PathPart('') :CaptureArgs(1) { unless($contact_id && $contact_id =~ /^\d+$/) { $c->flash(messages => [{type => 'error', text => 'Invalid contact id detected!'}]); - $c->response->redirect($c->uri_for()); - return; + NGCP::Panel::Utils::Navigation::back_or($c, $c->uri_for()); } - - $c->stash(contact => $c->stash->{contacts}->find($contact_id)); + my $res = $c->stash->{contacts}; + $c->stash(contact => $res->find($contact_id)); } sub edit :Chained('base') :PathPart('edit') :Args(0) { @@ -118,13 +106,11 @@ sub edit :Chained('base') :PathPart('edit') :Args(0) { delete $form->params->{save}; $c->stash->{contact}->update($form->params); $c->flash(messages => [{type => 'success', text => 'Contact successfully changed'}]); - $c->response->redirect($c->uri_for_action('/contact/root')); - return; + NGCP::Panel::Utils::Navigation::back_or($c, $c->uri_for_action('/contact/root')); } catch($e) { $c->log->error("failed to update contact: $e"); $c->flash(messages => [{type => 'error', text => 'Failed to update contact'}]); - $c->response->redirect($c->uri_for_action('/contact/root')); - return; + NGCP::Panel::Utils::Navigation::back_or($c, $c->uri_for_action('/contact/root')); } } @@ -137,33 +123,24 @@ sub edit :Chained('base') :PathPart('edit') :Args(0) { sub delete :Chained('base') :PathPart('delete') :Args(0) { my ($self, $c) = @_; - $c->stash->{contact}->delete; - $c->flash(messages => [{type => 'success', text => 'Contact successfully deleted'}]); - $c->response->redirect($c->uri_for()); + try { + $c->stash->{contact}->delete; + $c->flash(messages => [{type => 'success', text => 'Contact successfully deleted'}]); + } catch($e) { + $c->log->error("failed to delete contact: $e"); + $c->flash(messages => [{type => 'error', text => 'Failed to delete contact'}]); + } + NGCP::Panel::Utils::Navigation::back_or($c, $c->uri_for); } sub ajax :Chained('list_contact') :PathPart('ajax') :Args(0) { my ($self, $c) = @_; - #TODO: when user is not logged in, this gets forwarded to login page - - my $contacts = $c->model('DB')->resultset('contacts')->search_rs({}); NGCP::Panel::Utils::Datatables::process($c, $c->stash->{contacts}, $c->stash->{contact_dt_columns}); $c->detach( $c->view("JSON") ); } -=head1 AUTHOR - -Andreas Granig,,, - -=head1 LICENSE - -This library is free software. You can redistribute it and/or modify -it under the same terms as Perl itself. - -=cut - __PACKAGE__->meta->make_immutable; 1; diff --git a/lib/NGCP/Panel/Controller/Contract.pm b/lib/NGCP/Panel/Controller/Contract.pm index 15e170a502..dac78a15c1 100644 --- a/lib/NGCP/Panel/Controller/Contract.pm +++ b/lib/NGCP/Panel/Controller/Contract.pm @@ -2,6 +2,7 @@ package NGCP::Panel::Controller::Contract; use Sipwise::Base; use namespace::autoclean; BEGIN { extends 'Catalyst::Controller'; } +use Hash::Merge; use NGCP::Panel::Form::Contract; use NGCP::Panel::Utils::Navigation; use NGCP::Panel::Utils::Contract; @@ -15,8 +16,20 @@ sub auto :Does(ACL) :ACLDetachTo('/denied_page') :AllowedRole(admin) :AllowedRol sub contract_list :Chained('/') :PathPart('contract') :CaptureArgs(0) { my ($self, $c) = @_; - + + $c->stash->{contract_dt_columns} = NGCP::Panel::Utils::Datatables::set_columns($c, [ + { name => "id", search => 1, title => "#" }, + { name => "external_id", search => 1, title => "External #" }, + { name => "contact.reseller.name", search => 1, title => "Reseller" }, + { name => "contact.email", search => 1, title => "Contact Email" }, + { name => "billing_mappings.billing_profile.name", search => 1, title => "Billing Profile" }, + { name => "status", search => 1, title => "Status" }, + ]); + my $mapping_rs = $c->model('DB')->resultset('billing_mappings'); + + # TODO: also order by end_date desc (also in rate-o-mat etc?) + # leave it as is currently to preserve backwards-compatibility my $rs = $c->model('DB')->resultset('contracts') ->search({ 'billing_mappings.id' => { @@ -37,20 +50,24 @@ sub contract_list :Chained('/') :PathPart('contract') :CaptureArgs(0) { })->get_column('id')->as_query, }, },{ - 'join' => { - 'billing_mappings' => 'billing_profile', - }, + 'join' => 'billing_mappings', '+select' => [ - 'billing_mappings.billing_profile_id', - 'billing_profile.name', + 'billing_mappings.id', ], '+as' => [ - 'billing_profile_id', - 'billing_profile_name', + 'billing_mapping_id', ], }); + unless($c->user->is_superuser) { + $rs = $rs->search({ + 'contact.reseller_id' => $c->user->reseller_id, + }, { + join => 'contact', + }); + } $c->stash(contract_select_rs => $rs); + $c->stash(ajax_uri => $c->uri_for_action("/contract/ajax")); $c->stash(template => 'contract/list.tt'); } @@ -62,43 +79,52 @@ sub root :Chained('contract_list') :PathPart('') :Args(0) { sub create :Chained('contract_list') :PathPart('create') :Args(0) { my ($self, $c) = @_; - my $item = $c->model('DB')->resultset('billing_mappings')->new_result({}); - - my $params = delete $c->session->{created_object} || {}; + my $posted = ($c->request->method eq 'POST'); + my $params = {}; + Hash::Merge->new('RIGHT_PRECEDENT')->merge($params, delete $c->session->{created_object}); # TODO: where to store created contact and billing profile? - my $form = NGCP::Panel::Form::Contract->new; - if($form->process( - posted => ($c->request->method eq 'POST'), + my $form; + $form = NGCP::Panel::Form::Contract->new; + $form->process( + posted => $posted, params => $c->request->params, - action => $c->uri_for('create'), - item => $item, - )) { - # insert ok, populate contract_balance table - try { - NGCP::Panel::Utils::Contract::create_contract_balance( - c => $c, - profile => $item->billing_profile, - contract => $item->contract, - ); - $c->session->{created_object} = { contract => { id => $item->contract->id } }; - } catch($e) { - # TODO: roll back contract and billing_mappings creation and - # redirect to correct entry point - $c->log->error("Failed to create contract balance: $e"); - $c->flash(messages => [{type => 'error', text => 'Failed to create contract balance!'}]); - NGCP::Panel::Utils::Navigation::back_or($c, $c->uri_for_action('/contract/root')); - } - } + item => $params + ); NGCP::Panel::Utils::Navigation::check_form_buttons( - c => $c, form => $form, - fields => {'contract.contact.create' => $c->uri_for('/contact/create'), + c => $c, + form => $form, + fields => {'contact.create' => $c->uri_for('/contact/create'), 'billing_profile.create' => $c->uri_for('/billing/create')}, back_uri => $c->req->uri, ); - if($form->validated) { - $c->flash(messages => [{type => 'success', text => 'Contract successfully created!'}]); + if($posted && $form->validated) { + try { + my $schema = $c->model('DB'); + $schema->txn_do(sub { + $form->params->{contact_id} = $form->params->{contact}{id}; + delete $form->params->{contract}; + my $bprof_id = $form->params->{billing_profile}{id}; + delete $form->params->{billing_profile}; + my $contract = $schema->resultset('contracts')->create($form->params); + my $billing_profile = $schema->resultset('billing_profiles')->find($bprof_id); + $contract->billing_mappings->create({ + billing_profile_id => $bprof_id, + }); + + NGCP::Panel::Utils::Contract::create_contract_balance( + c => $c, + profile => $billing_profile, + contract => $contract, + ); + $c->flash(messages => [{type => 'success', text => 'Contract successfully created!'}]); + }); + } catch($e) { + $c->log->error("Failed to create contract: $e"); + $c->flash(messages => [{type => 'error', text => 'Failed to create contract'}]); + NGCP::Panel::Utils::Navigation::back_or($c, $c->uri_for_action('/contract/root')); + } NGCP::Panel::Utils::Navigation::back_or($c, $c->uri_for_action('/contract/root')); - } + } $c->stash(create_flag => 1); $c->stash(form => $form); @@ -112,15 +138,15 @@ sub base :Chained('contract_list') :PathPart('') :CaptureArgs(1) { NGCP::Panel::Utils::Navigation::back_or($c, $c->uri_for); } - my $res = $c->stash->{contract_select_rs} - ->search(undef, { + my $res = $c->stash->{contract_select_rs}; + $res = $res->search(undef, { '+select' => 'billing_mappings.id', '+as' => 'bmid', }) ->find($contract_id); - + unless(defined($res)) { - $c->flash(messages => [{type => 'error', text => 'Contract does not exist!'}]); + $c->flash(messages => [{type => 'error', text => 'Contract does not exist'}]); NGCP::Panel::Utils::Navigation::back_or($c, $c->uri_for); } @@ -134,22 +160,23 @@ sub edit :Chained('base') :PathPart('edit') :Args(0) { my $posted = ($c->request->method eq 'POST'); - my $contr = $c->stash->{contract_result}; - my $item = $contr->billing_mappings->find($contr->get_column('bmid')); - if ($posted && $item->billing_profile_id) { - if($item->billing_profile_id != $c->req->params->{'billing_profile.id'}) { - $item = $c->stash->{contract_result}->billing_mappings->new_result({}); - $item->start_date(time); - } - } else { + my $contract = $c->stash->{contract_result}; + my $billing_mapping = $contract->billing_mappings->find($contract->get_column('bmid')); + my $params = {}; + unless($posted) { + $params->{billing_profile}{id} = $billing_mapping->billing_profile->id; + $params->{contact}{id} = $contract->contact_id; + $params->{external_id} = $contract->external_id; + $params->{status} = $contract->status; } - + + # TODO: handle created contact/bilprof + my $form = NGCP::Panel::Form::Contract->new; $form->process( posted => $posted, params => $c->req->params, - item => $item, - action => $c->uri_for($c->stash->{contract}->{id}, 'edit'), + item => $params, ); NGCP::Panel::Utils::Navigation::check_form_buttons( c => $c, form => $form, @@ -158,7 +185,27 @@ sub edit :Chained('base') :PathPart('edit') :Args(0) { back_uri => $c->req->uri, ); if($posted && $form->validated) { - $c->flash(messages => [{type => 'success', text => 'Contract successfully changed!'}]); + try { + my $schema = $c->model('DB'); + $schema->txn_do(sub { + if($form->values->{billing_profile}{id} != $billing_mapping->billing_profile->id) { + say ">>>>>>>> billing profile changed, update mapping"; + $contract->billing_mappings->create({ + start_date => DateTime->now(), + billing_profile_id => $form->values->{billing_profile}{id}, + }); + } + delete $form->values->{billing_profile}; + $form->values->{contact_id} = $form->values->{contact}{id}; + delete $form->values->{contact}; + $contract->update($form->values); + }); + $c->flash(messages => [{type => 'success', text => 'Contract successfully changed!'}]); + } catch($e) { + $c->log->error("failed to update contract: $e"); + $c->flash(messages => [{type => 'error', text => 'Failed to update contract'}]); + NGCP::Panel::Utils::Navigation::back_or($c, $c->uri_for); + } NGCP::Panel::Utils::Navigation::back_or($c, $c->uri_for); } @@ -166,15 +213,28 @@ sub edit :Chained('base') :PathPart('edit') :Args(0) { $c->stash(edit_flag => 1); } +sub terminate :Chained('base') :PathPart('terminate') :Args(0) { + my ($self, $c) = @_; + + try { + $c->stash->{contract_result}->update({ status => 'terminated' }); + $c->flash(messages => [{type => 'success', text => 'Contract successfully terminated'}]); + } catch (DBIx::Class::Exception $e) { + $c->log->info("failed to terminate contract: $e"); + $c->flash(messages => [{type => 'error', text => 'Failed to terminate contract'}]); + }; + NGCP::Panel::Utils::Navigation::back_or($c, $c->uri_for); +} + sub delete :Chained('base') :PathPart('delete') :Args(0) { my ($self, $c) = @_; try { $c->stash->{contract_result}->delete; - $c->flash(messages => [{type => 'success', text => 'Contract successfully deleted!'}]); + $c->flash(messages => [{type => 'success', text => 'Contract successfully deleted'}]); } catch (DBIx::Class::Exception $e) { - $c->flash(messages => [{type => 'error', text => 'Delete failed.'}]); - $c->log->info("Delete failed: " . $e); + $c->log->info("failed to delete contract: $e"); + $c->flash(messages => [{type => 'error', text => 'Failed to delete contract'}]); }; NGCP::Panel::Utils::Navigation::back_or($c, $c->uri_for); } @@ -182,11 +242,12 @@ sub delete :Chained('base') :PathPart('delete') :Args(0) { sub ajax :Chained('contract_list') :PathPart('ajax') :Args(0) { my ($self, $c) = @_; - my $rs = $c->stash->{contract_select_rs}; + my $res = $c->stash->{contract_select_rs}; + NGCP::Panel::Utils::Datatables::process($c, $res, $c->stash->{contract_dt_columns}); - $c->forward( "/ajax_process_resultset", [$rs, - ["id", "contact_id", "billing_profile_name", "billing_profile_id", "status"], - ["billing_profile.name", "status"]]); +# $c->forward( "/ajax_process_resultset", [$rs, +# ["id", "contact_id", "billing_profile_name", "billing_profile_id", "status"], +# ["billing_profile.name", "status"]]); $c->detach( $c->view("JSON") ); } diff --git a/lib/NGCP/Panel/Controller/Reseller.pm b/lib/NGCP/Panel/Controller/Reseller.pm index e92b7d973a..25dbee877c 100644 --- a/lib/NGCP/Panel/Controller/Reseller.pm +++ b/lib/NGCP/Panel/Controller/Reseller.pm @@ -3,6 +3,7 @@ use Sipwise::Base; use namespace::sweep; BEGIN { extends 'Catalyst::Controller'; } use DateTime qw(); +use Hash::Merge; use HTTP::Status qw(HTTP_SEE_OTHER); use NGCP::Panel::Form::Reseller; use NGCP::Panel::Utils::Navigation; @@ -178,7 +179,6 @@ sub edit :Chained('base') :PathPart('edit') :Args(0) { my $params = { $c->stash->{reseller}->first->get_inflated_columns }; $params->{contract}{id} = delete $params->{contract_id}; if($c->session->{created_object}) { # got a contract id from next step - use Hash::Merge; $params = Hash::Merge->new('RIGHT_PRECEDENT')->merge($params, delete $c->session->{created_object}); } $form->process( diff --git a/lib/NGCP/Panel/Form/BillingProfile_admin.pm b/lib/NGCP/Panel/Form/BillingProfile_admin.pm index 5d1fc3a9a9..22c7d23b74 100644 --- a/lib/NGCP/Panel/Form/BillingProfile_admin.pm +++ b/lib/NGCP/Panel/Form/BillingProfile_admin.pm @@ -5,15 +5,16 @@ extends 'NGCP::Panel::Form::BillingProfile_reseller'; has_field 'reseller' => ( type => '+NGCP::Panel::Field::Reseller', + not_nullable => 1, ); has_block 'fields' => ( tag => 'div', class => [qw/modal-body/], - render_list => [qw/handle name interval_charge interval_free_time interval_free_cash + render_list => [qw/reseller handle name prepaid interval_charge interval_free_time interval_free_cash fraud_interval_limit fraud_interval_lock fraud_interval_notify fraud_daily_limit fraud_daily_lock fraud_daily_notify - currency vat_rate vat_included reseller id/], + currency vat_rate vat_included id/], ); diff --git a/lib/NGCP/Panel/Form/BillingProfile_reseller.pm b/lib/NGCP/Panel/Form/BillingProfile_reseller.pm index 6ac8062dde..31b1491064 100644 --- a/lib/NGCP/Panel/Form/BillingProfile_reseller.pm +++ b/lib/NGCP/Panel/Form/BillingProfile_reseller.pm @@ -1,7 +1,7 @@ package NGCP::Panel::Form::BillingProfile_reseller; use HTML::FormHandler::Moose; -extends 'HTML::FormHandler::Model::DBIC'; +extends 'HTML::FormHandler'; use Moose::Util::TypeConstraints; use HTML::FormHandler::Widget::Block::Bootstrap; @@ -34,12 +34,18 @@ has_field 'handle' => ( }, ); +has_field 'prepaid' => ( + type => 'Boolean', + default => 0, +); + has_field 'interval_charge' => ( type => 'Money', element_attr => { rel => ['tooltip'], title => ['base fee charged per billing interval, float, specifying Euro'] }, + default => '0', ); has_field 'interval_free_time' => ( @@ -48,6 +54,7 @@ has_field 'interval_free_time' => ( rel => ['tooltip'], title => ['included time per billing interval, integer, specifying seconds'] }, + default => '0', ); has_field 'interval_free_cash' => ( @@ -56,6 +63,7 @@ has_field 'interval_free_cash' => ( rel => ['tooltip'], title => ['included money per billing interval, float, specifying EUR, USD, etc.'] }, + default => '0', ); has_field 'fraud_interval_limit' => ( @@ -99,6 +107,8 @@ has_field 'fraud_daily_limit' => ( rel => ['tooltip'], title => ['fraud detection threshold, per day, float, specifying EUR, USD, etc.'] }, + required => 0, + default => undef, ); has_field 'fraud_daily_lock' => ( @@ -152,6 +162,7 @@ has_field 'vat_included' => ( rel => ['tooltip'], title => ['check if fees are inclusive VAT'] }, + default => 0, ); has_field 'save' => ( @@ -164,7 +175,7 @@ has_field 'save' => ( has_block 'fields' => ( tag => 'div', class => [qw/modal-body/], - render_list => [qw/handle name interval_charge interval_free_time interval_free_cash + render_list => [qw/handle name prepaid interval_charge interval_free_time interval_free_cash fraud_interval_limit fraud_interval_lock fraud_interval_notify fraud_daily_limit fraud_daily_lock fraud_daily_notify currency vat_rate vat_included id/], @@ -176,12 +187,5 @@ has_block 'actions' => ( render_list => [qw/save/], ); -before 'update_model' => sub { - my $self = shift; - foreach my $val(values $self->value) { - $val = '' unless defined($val); - } -}; - 1; # vim: set tabstop=4 expandtab: diff --git a/lib/NGCP/Panel/Form/Contact/Admin.pm b/lib/NGCP/Panel/Form/Contact/Admin.pm new file mode 100644 index 0000000000..afd765fc90 --- /dev/null +++ b/lib/NGCP/Panel/Form/Contact/Admin.pm @@ -0,0 +1,19 @@ +package NGCP::Panel::Form::Contact::Admin; + +use HTML::FormHandler::Moose; +extends 'NGCP::Panel::Form::Contact::Reseller'; +use Moose::Util::TypeConstraints; + +has_field 'reseller' => ( + type => '+NGCP::Panel::Field::Reseller', + not_nullable => 1, +); + +has_block 'fields' => ( + tag => 'div', + class => [qw/modal-body/], + render_list => [qw/reseller firstname lastname email company/], +); + +1; +# vim: set tabstop=4 expandtab: diff --git a/lib/NGCP/Panel/Form/Contact.pm b/lib/NGCP/Panel/Form/Contact/Reseller.pm similarity index 83% rename from lib/NGCP/Panel/Form/Contact.pm rename to lib/NGCP/Panel/Form/Contact/Reseller.pm index 5db1e0faf3..e91725bd51 100644 --- a/lib/NGCP/Panel/Form/Contact.pm +++ b/lib/NGCP/Panel/Form/Contact/Reseller.pm @@ -1,4 +1,4 @@ -package NGCP::Panel::Form::Contact; +package NGCP::Panel::Form::Contact::Reseller; use HTML::FormHandler::Moose; extends 'HTML::FormHandler'; @@ -14,15 +14,17 @@ sub build_form_element_class { [qw/form-horizontal/] } has_field 'firstname' => ( type => 'Text', label => 'First Name', - required => 1, ); has_field 'lastname' => ( type => 'Text', label => 'Last Name', - required => 1, ); +has_field 'company' => ( + type => 'Text', + label => 'Company', +); has_field 'email' => ( type => 'Email', @@ -39,7 +41,7 @@ has_field 'save' => ( has_block 'fields' => ( tag => 'div', class => [qw/modal-body/], - render_list => [qw/firstname lastname email/], + render_list => [qw/firstname lastname email company/], ); has_block 'actions' => ( diff --git a/lib/NGCP/Panel/Form/Contract.pm b/lib/NGCP/Panel/Form/Contract.pm index 9d531a059a..f9d1adfb57 100644 --- a/lib/NGCP/Panel/Form/Contract.pm +++ b/lib/NGCP/Panel/Form/Contract.pm @@ -1,7 +1,7 @@ package NGCP::Panel::Form::Contract; use HTML::FormHandler::Moose; -extends 'HTML::FormHandler::Model::DBIC'; +extends 'HTML::FormHandler'; use Moose::Util::TypeConstraints; use HTML::FormHandler::Widget::Block::Bootstrap; @@ -11,11 +11,7 @@ has_field 'submitid' => ( type => 'Hidden' ); sub build_render_list {[qw/submitid fields actions/]} sub build_form_element_class { [qw/form-horizontal/] } -has_field 'contract' => ( - type => 'Compound', -); - -has_field 'contract.contact' => ( +has_field 'contact' => ( type => '+NGCP::Panel::Field::Contact', label => 'Contact', not_nullable => 1, @@ -26,12 +22,17 @@ has_field 'billing_profile' => ( not_nullable => 1, ); - -has_field 'contract.status' => ( +has_field 'status' => ( type => '+NGCP::Panel::Field::ContractStatusSelect', not_nullable => 1, ); +has_field 'external_id' => ( + type => 'Text', + label => 'External #', + required => 0, +); + has_field 'save' => ( type => 'Submit', value => 'Save', @@ -42,7 +43,7 @@ has_field 'save' => ( has_block 'fields' => ( tag => 'div', class => [qw/modal-body/], - render_list => [qw/contract.contact billing_profile contract.status/], + render_list => [qw/contact billing_profile status external_id/], ); has_block 'actions' => ( diff --git a/lib/NGCP/Panel/Utils/Contract.pm b/lib/NGCP/Panel/Utils/Contract.pm index 63e918ed00..7b60946f64 100644 --- a/lib/NGCP/Panel/Utils/Contract.pm +++ b/lib/NGCP/Panel/Utils/Contract.pm @@ -37,14 +37,17 @@ sub create_contract_balance { } try { - $c->model('DB')->resultset('contract_balances')->create({ - contract_id => $contract->id, - cash_balance => $cash_balance, - cash_balance_interval => $cash_balance_interval, - free_time_balance => $free_time_balance, - free_time_balance_interval => $free_time_balance_interval, - start => $stime, - end => $etime, + my $schema = $c->model('DB'); + $schema->txn_do(sub { + $schema->resultset('contract_balances')->create({ + contract_id => $contract->id, + cash_balance => $cash_balance, + cash_balance_interval => $cash_balance_interval, + free_time_balance => $free_time_balance, + free_time_balance_interval => $free_time_balance_interval, + start => $stime, + end => $etime, + }); }); } catch($e) { $c->log->error("Creating contract balance failed: " . $e); diff --git a/lib/NGCP/Panel/Utils/Navigation.pm b/lib/NGCP/Panel/Utils/Navigation.pm index b69ba4bbc0..dfada47e87 100644 --- a/lib/NGCP/Panel/Utils/Navigation.pm +++ b/lib/NGCP/Panel/Utils/Navigation.pm @@ -36,10 +36,12 @@ sub check_form_buttons { my $posted = ($c->request->method eq 'POST'); delete $form->params->{save} if $posted; + delete $form->values->{save} if $posted; if($posted && $form->field('submitid')) { my $val = $form->value->{submitid}; delete $form->params->{submitid}; + delete $form->values->{submitid}; if(defined $val and exists($fields->{$val}) ) { my $target; if (defined $fields->{$val}) { @@ -55,7 +57,7 @@ sub check_form_buttons { $c->session->{redirect_targets} = [ $back_uri ]; } $c->response->redirect($target); - $c->detach(); + $c->detach; } } } @@ -64,7 +66,7 @@ sub back_or { my ($c, $alternative_target) = @_; my $target = $c->stash->{close_target} || $alternative_target || $c->req->uri; $c->response->redirect($target); - $c->detach(); + $c->detach; } 1; diff --git a/share/templates/billing/list.tt b/share/templates/billing/list.tt index f00136f79e..3c727b160f 100644 --- a/share/templates/billing/list.tt +++ b/share/templates/billing/list.tt @@ -1,25 +1,25 @@ [% META title = 'Billing Profiles' -%] [% helper.name = 'Billing Profiles'; - helper.show_create_button = 1; helper.messages = messages; - helper.column_titles = [ '#', 'Profile' ]; - helper.column_fields = [ 'id', 'name' ]; + helper.dt_columns = profile_dt_columns; helper.close_target = close_target; helper.create_flag = create_flag; helper.edit_flag = edit_flag; helper.form_object = form; helper.ajax_uri = c.uri_for( c.controller.action_for('ajax') ); - - helper.dt_buttons = [ - { name = 'Edit', uri = "/billing/'+full[\"id\"]+'/edit", class = 'btn-small btn-primary', icon = 'icon-edit' }, - { name = 'Fees', uri = "/billing/'+full[\"id\"]+'/fees", class = 'btn-small btn-tertiary', icon = 'icon-shopping-cart' }, - { name = 'Peaktimes', uri = "/billing/'+full[\"id\"]+'/peaktimes", class = 'btn-small btn-tertiary', icon = 'icon-time' }, - ]; - helper.top_buttons = [ - { name = 'Create Billing Profile', uri = c.uri_for('/billing/create'), icon = 'icon-star' }, - ]; + + UNLESS c.user.read_only; + helper.dt_buttons = [ + { name = 'Edit', uri = "/billing/'+full[\"id\"]+'/edit", class = 'btn-small btn-primary', icon = 'icon-edit' }, + { name = 'Fees', uri = "/billing/'+full[\"id\"]+'/fees", class = 'btn-small btn-tertiary', icon = 'icon-shopping-cart' }, + { name = 'Peaktimes', uri = "/billing/'+full[\"id\"]+'/peaktimes", class = 'btn-small btn-tertiary', icon = 'icon-time' }, + ]; + helper.top_buttons = [ + { name = 'Create Billing Profile', uri = c.uri_for('/billing/create'), icon = 'icon-star' }, + ]; + END; PROCESS 'helpers/datatables.tt'; -%] diff --git a/share/templates/contract/list.tt b/share/templates/contract/list.tt index 58f3f93ed3..350fb19345 100644 --- a/share/templates/contract/list.tt +++ b/share/templates/contract/list.tt @@ -1,11 +1,9 @@ [% META title = 'Contracts' -%] [% helper.name = 'Contract'; - helper.show_create_button = 1; helper.data = contracts; helper.messages = messages; - helper.column_titles = [ '#', 'Contact #', 'Billing Profile', 'Status' ]; - helper.column_fields = [ 'id', 'contact_id', 'billing_profile_name', 'status' ]; + helper.dt_columns = contract_dt_columns; helper.close_target = close_target; helper.create_flag = create_flag; @@ -13,13 +11,16 @@ helper.form_object = form; helper.ajax_uri = ajax_uri; - helper.dt_buttons = [ - { name = 'Edit', uri = "/contract/'+full[\"id\"]+'/edit", class = 'btn-small btn-primary', icon = 'icon-edit' }, - { name = 'Delete', uri = "/contract/'+full[\"id\"]+'/delete", class = 'btn-small btn-secondary', icon = 'icon-trash' }, - ]; - helper.top_buttons = [ - { name = 'Create Contract', uri = c.uri_for('/contract/create'), icon = 'icon-star' }, - ]; + UNLESS c.user.read_only; + helper.dt_buttons = [ + { name = 'Edit', uri = "/contract/'+full.id+'/edit", class = 'btn-small btn-primary', icon = 'icon-edit' }, + { name = 'Terminate', uri = "/contract/'+full.id+'/terminate", class = 'btn-small btn-primary', icon = 'icon-remove' }, + { name = 'Delete', uri = "/contract/'+full.id+'/delete", class = 'btn-small btn-secondary', icon = 'icon-trash' }, + ]; + helper.top_buttons = [ + { name = 'Create Contract', uri = c.uri_for('/contract/create'), icon = 'icon-star' }, + ]; + END; PROCESS 'helpers/datatables.tt'; -%]