Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Added Price to Catalog Items. #5719

Merged
merged 9 commits into from
Jul 4, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@ ManageIQ.angular.app.controller('catalogItemFormController', ['$scope', '$timeou
location: 'playbook',
catalog_id: '',
zone_id: '',
currency_id: '',
price: '',
key: '',
key_value: '',
provisioning_repository_id: '',
Expand Down Expand Up @@ -58,7 +60,6 @@ ManageIQ.angular.app.controller('catalogItemFormController', ['$scope', '$timeou
vm.afterGet = false;
vm.inventory_mode = 'localhost';
vm.all_catalogs = allCatalogsNames;
vm.zones = [];

ManageIQ.angular.scope = $scope;

Expand All @@ -77,13 +78,16 @@ ManageIQ.angular.app.controller('catalogItemFormController', ['$scope', '$timeou
vm.catalogItemModel.display = catalogItemData.display;
vm.catalogItemModel.catalog_id = catalogItemData.service_template_catalog_id === undefined ? '' : catalogItemData.service_template_catalog_id;
vm.catalogItemModel.zone_id = catalogItemData.zone_id === undefined ? '' : catalogItemData.zone_id;
vm.catalogItemModel.currency_id = catalogItemData.currency_id === undefined ? '' : catalogItemData.currency_id;
vm.catalogItemModel.price = catalogItemData.price;
vm.catalogItemModel.provisioning_dialog_id = catalogItemData.config_info.provision.dialog_id;
playbookReusableCodeMixin.formOptions(vm);
playbookReusableCodeMixin.formCloudCredentials(vm, catalogItemData.config_info.provision.cloud_credential_id, catalogItemData.config_info.retirement.cloud_credential_id);
getConfigInfo(catalogItemData.config_info);
vm.modelCopy = angular.copy(vm.catalogItemModel);
});
}
vm.priceRequired();
};

listenToRx(function(data) {
Expand Down Expand Up @@ -249,6 +253,7 @@ ManageIQ.angular.app.controller('catalogItemFormController', ['$scope', '$timeou
display: configData.display,
service_template_catalog_id: configData.catalog_id,
zone_id: configData.zone_id,
currency_id: configData.currency_id,
prov_type: 'generic_ansible_playbook',
type: 'ServiceTemplateAnsiblePlaybook',
additional_tenant_ids: configData.additional_tenant_ids,
Expand All @@ -264,6 +269,12 @@ ManageIQ.angular.app.controller('catalogItemFormController', ['$scope', '$timeou
},
},
};

if (typeof vm.catalogItemModel.currency_id !== 'undefined' && vm.catalogItemModel.currency_id !== '') {
catalog_item.price = configData.price
} else {
catalog_item.price = '';
}
if (vm.catalogItemModel.provisioning_execution_ttl !== undefined) {
catalog_item.config_info.provision.execution_ttl = configData.provisioning_execution_ttl;
}
Expand Down Expand Up @@ -441,6 +452,11 @@ ManageIQ.angular.app.controller('catalogItemFormController', ['$scope', '$timeou
vm.catalogItemModel[prefix + '_dialog_name'] = '';
};

vm.priceRequired = function() {
return (typeof vm.catalogItemModel.currency_id !== 'undefined' && vm.catalogItemModel.currency_id !== ''
&& (typeof vm.catalogItemModel.price === 'undefined' || vm.catalogItemModel.price === ''))
};

vm.fieldsRequired = function(prefix) {
return prefix === 'provisioning';
};
Expand All @@ -451,12 +467,18 @@ ManageIQ.angular.app.controller('catalogItemFormController', ['$scope', '$timeou
};

// watch for all the drop downs on screen
'catalog provisioning_playbook retirement_playbook provisioning_machine_credential retirement_machine_credential provisioning_vault_credential retirement_vault_credential provisioning_network_credential retirement_network_credential provisioning_cloud_credential retirement_cloud_credential provisioning_dialog zone'.split(' ').forEach(idWatch);
'catalog currency provisioning_playbook retirement_playbook provisioning_machine_credential retirement_machine_credential provisioning_vault_credential retirement_vault_credential provisioning_network_credential retirement_network_credential provisioning_cloud_credential retirement_cloud_credential provisioning_dialog zone'.split(' ').forEach(idWatch);

function idWatch(name) {
var fieldName = 'vm._' + name;
$scope.$watch(fieldName, function(value) {
vm.catalogItemModel[name + '_id'] = value ? value.id : '';
if (name == 'currency' && !value) {
vm.catalogItemModel.currency_name = '';
} else if (name == 'currency' && value && typeof value !== 'undefined') {
vm.catalogItemModel.currency_name = _.find(vm.currencies, {id: value.id}).code;
himdel marked this conversation as resolved.
Show resolved Hide resolved
vm.priceRequired();
}
playbookReusableCodeMixin.checkFormPristine(vm.catalogItemModel, vm.modelCopy, $scope.angularForm);
});
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -170,6 +170,16 @@ function playbookReusableCodeMixin(API, $q, miqService) {
.catch(miqService.handleFailure)
);

allApiPromises.push(API.get('/api/currencies/?expand=resources&attributes=id,full_name,symbol,code&sort_by=full_name&sort_order=ascending')
.then(function(data) {
vm.currencies = data.resources;
vm._currency = _.find(vm.currencies, {id: vm[vm.model].currency_id});
if (vm._currency)
vm[vm.model].currency_name = vm._currency.code;
})
.catch(miqService.handleFailure)
);

// list of machine credentials
getCredentialsForType('machine', '/api/authentications?collection_class=ManageIQ::Providers::EmbeddedAnsible::AutomationManager::MachineCredential&expand=resources&attributes=id,name', vm);

Expand Down
34 changes: 33 additions & 1 deletion app/controllers/catalog_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -186,6 +186,7 @@ def atomic_form_field_changed
page << javascript_for_miq_button_visibility(changed)
session[:changed] = changed
end
page.replace_html("price_span", @edit[:new][:code_currency])
page << set_spinner_off
end
end
Expand Down Expand Up @@ -306,6 +307,7 @@ def st_edit
add_flash(_("Resource must be selected"), :error)
end
add_flash(_("Provisioning Entry Point is required"), :error) if @edit[:new][:fqname].blank?
validate_price
dialog_catalog_check

if @flash_array
Expand Down Expand Up @@ -842,7 +844,7 @@ def atomic_req_submit
end

add_flash(_("Provisioning Entry Point is required"), :error) if @edit[:new][:fqname].blank?

validate_price
# Check for a Dialog if Display in Catalog is selected
dialog_catalog_check

Expand Down Expand Up @@ -898,6 +900,8 @@ def atomic_req_submit
st.add_resource(request) if need_prov_dialogs?(@edit[:new][:st_prov_type])
end
end
st.currency = @edit[:new][:currency] ? ChargebackRateDetailCurrency.find_by(:id => @edit[:new][:currency].to_i) : nil
st.price = st.currency ? @edit[:new][:price] : nil if @edit[:new][:price]

if st.save
set_resource_action(st) unless st.kind_of?(ServiceTemplateContainerTemplate)
Expand Down Expand Up @@ -1061,6 +1065,8 @@ def common_st_record_vars(st)
st.generic_subtype = @edit[:new][:generic_subtype] if @edit[:new][:st_prov_type] == 'generic'
st.zone_id = @edit[:new][:zone_id]
st.additional_tenants = Tenant.where(:id => @edit[:new][:tenant_ids]) # Selected Additional Tenants in the tree
st.currency = @edit[:new][:currency] ? ChargebackRateDetailCurrency.find_by(:id => @edit[:new][:currency].to_i) : nil
st.price = st.currency ? @edit[:new][:price] : nil if @edit[:new][:price]
end

def st_set_record_vars(st)
Expand Down Expand Up @@ -1116,6 +1122,10 @@ def set_form_vars
fetch_zones
@edit[:new][:zone_id] = @record.zone_id

@edit[:new][:currency] = @record.currency ? @record.currency.id : nil
@edit[:new][:code_currency] = @record.currency ? code_currency_label(@record.currency.id) : _("Price / Month")
@edit[:new][:price] = @record.price

# initialize fqnames
@edit[:new][:fqname] = @edit[:new][:reconfigure_fqname] = @edit[:new][:retire_fqname] = ""
@record.resource_actions.each do |ra|
Expand Down Expand Up @@ -1258,10 +1268,21 @@ def get_form_vars
@tenants_tree = build_tenants_tree # Build the tree with available tenants
@available_catalogs = available_catalogs.sort # Get available catalogs with tenants and ancestors
@additional_tenants = @edit[:new][:tenant_ids].map(&:to_s) # Get ids of selected Additional Tenants in the Tenants tree

if params[:currency]
@edit[:new][:currency] = params[:currency].blank? ? nil : params[:currency].to_i
@edit[:new][:code_currency] = @edit[:new][:currency] ? code_currency_label(params[:currency]) : _('Price / Month')
end
@edit[:new][:price] = params[:price] if params[:price]

get_form_vars_orchestration if @edit[:new][:st_prov_type] == 'generic_orchestration'
fetch_form_vars_ansible_or_ct if %w[generic_ansible_tower generic_container_template].include?(@edit[:new][:st_prov_type])
end

def code_currency_label(currency)
_('Price / Month (in %{currency})') % {:currency => ChargebackRateDetailCurrency.find(currency).code}
end

def checked_tenants
new_id = params[:id].split('-').pop.to_i if params[:id].starts_with?('tn')
tenant_ids = @edit[:new][:tenant_ids]
Expand Down Expand Up @@ -1991,6 +2012,17 @@ def dialog_catalog_check
add_flash(_("Dialog has to be set if Display in Catalog is chosen"), :error)
end

def validate_price
if @edit[:new][:currency] && @edit[:new][:price].blank?
add_flash(_("Price / Month is required"), :error)
end
add_flash(_("Price must be a numeric value"), :error) if @edit[:new][:price].present? && !float_value?(@edit[:new][:price])
end

def float_value?(value)
value.to_s =~ /(^(\d+)(\.)?(\d+)?)|(^(\d+)?(\.)(\d+))/
end

def x_edit_tags_reset(db)
@tagging = session[:tag_db] = db
checked_ids = find_checked_items.empty? ? [params[:id]] : find_checked_items
Expand Down
27 changes: 27 additions & 0 deletions app/views/catalog/_form_basic_info.html.haml
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,33 @@
:class => "selectpicker")
:javascript
miqSelectPickerEvent('zone_id', '#{url}')
/Add a new selector for the currencies
.form-group
%label.col-md-2.control-label
= _('Select currency')
.col-md-4
%p.form-control-static
- currency = Array(ChargebackRateDetailCurrency.currencies_for_select)
= select_tag("currency",
options_for_select([[_("<Choose>"), nil]] + currency, @edit[:new][:currency]),
"data-live-search" => "true",
"class" => "selectpicker")
:javascript
miqInitSelectPicker();
miqSelectPickerEvent("currency", "#{url}");

.form-group
%label.col-md-2.control-label
%span#price_span
= @edit[:new][:code_currency]
.col-md-8{:style => "padding: 0px;"}
.col-md-4
= text_field_tag("price",
@edit[:new][:price].to_s,
:maxlength => 40,
:class => "form-control",
"data-miq_observe" => {:interval => '.5', :url => url}.to_json)

- if @edit[:new][:st_prov_type] == "generic"
.form-group
%label.col-md-2.control-label
Expand Down
6 changes: 6 additions & 0 deletions app/views/catalog/_sandt_tree_show.html.haml
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,12 @@
= _('Dialog')
.col-md-9
= h(@sb[:dialog_label])
- if @record.currency && @record.price
.form-group
%label.col-md-3.control-label
= _('Price / Month (in %{currency})') % {:currency => @record.currency.code}
.col-md-9
= @record.price
- if @record.prov_type
.form-group
%label.col-md-3.control-label
Expand Down
29 changes: 29 additions & 0 deletions app/views/catalog/_st_angular_form.html.haml
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,35 @@
'miq-select' => true}
%option{"value" => ""} &lt;Choose&gt;

.form-group
%label.col-md-2.control-label{"for" => "currency_id"}
= _('Select currency')
.col-md-8
%select{"ng-model" => "vm._currency",
"name" => "currency_id",
'ng-options' => 'currency as currency.symbol + " [" + currency.full_name + "]" for currency in vm.currencies',
"data-live-search" => "true",
'miq-select' => true}
%option{"value" => ""} &lt;Choose&gt;

.form-group{"ng-class" => "{'has-error': vm.priceRequired()}"}
%label.col-md-2.control-label{"for" => "price"}
= _("Price / Month (in {{vm.catalogItemModel.currency_name}})")
.col-md-8
%input.form-control{"type" => "text",
"id" => "price",
"name" => "price",
"ng-model" => "vm.catalogItemModel.price",
"ng-change" => "vm.priceRequired()",
"ng-required" => "vm.priceRequired()",
"ng-pattern" => "/(^([0-9]+)(\.)?([0-9]+)?)|(^([0-9]+)?(\.)([0-9]+))/",
"maxlength" => 60,
"checkchange" => ""}
%span.help-block{"ng-show" => "vm.priceRequired()"}
= _("Required")
%span.help-block{"ng-show" => "angularForm.price.$error.pattern"}
= _("Must be a numeric value")

= render :partial => "layouts/angular/multi_tab_ansible_form_options",
:locals => {:record => @record, :ng_model => "vm.catalogItemModel"}
= render :partial => "layouts/angular/x_edit_buttons_angular"
Expand Down
8 changes: 7 additions & 1 deletion app/views/catalog/_svccat_tree_show.html.haml
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,13 @@
.col-md-8
%p.form-control-static
= @sb[:dialog_label]

- if @record.currency && @record.price
.form-group
%label.col-md-2.control-label
= _('Price / Month (in %{currency})') % {:currency => @record.currency.code}
.col-md-8
%p.form-control-static
= @record.price
.form-group
.col-md-1{:align => "center"}
#buttons
Expand Down
59 changes: 59 additions & 0 deletions spec/controllers/catalog_controller_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -260,6 +260,65 @@
end
end

describe "#st_edit" do
let(:edit) do
{:new => {:name => "New Name",
:description => "New Description",
:selected_resources => [st.id],
:rsc_groups => [[{:name => "Some name"}]],
:fqname => 'ns1/cls1/inst1',
:currency => nil,
:price => nil,
:tenant_ids => []},
:key => "st_edit__new",
:rec_id => st.id}
end
let(:st) { FactoryBot.create(:service_template) }
let(:symbol) { '฿' }
let(:currency) { FactoryBot.create(:chargeback_rate_detail_currency, :symbol => symbol) }

before do
allow(controller).to receive(:replace_right_cell)
allow(controller).to receive(:session).and_return(:edit => edit)
controller.instance_variable_set(:@edit, edit)
allow(controller).to receive(:build_tenants_tree)
end

it "currency is set but price is not set" do
controller.params = {:currency => currency.id, :price => '', :button => 'add'}
expect(controller).to receive(:render)
controller.send(:st_edit)
expect(assigns(:flash_array).first[:message]).to include('Price / Month is required')
end

it "currency and price both are not set" do
controller.params = {:button => 'add'}
controller.send(:st_edit)
expect(assigns(:flash_array).first[:message]).to include('Catalog Bundle "New Name" was added')
end

it "currency and price both are set, but price is non numeric value" do
controller.params = {:currency => currency.id, :price => 'aaa', :button => 'add'}
expect(controller).to receive(:render)
controller.send(:st_edit)
expect(assigns(:flash_array).first[:message]).to include('Price must be a numeric value')
end

it "currency and price both are set, price is numeric value" do
controller.params = {:currency => currency.id, :price => '100.0', :button => 'add'}
controller.send(:st_edit)
expect(assigns(:flash_array).first[:message]).to include('Catalog Bundle "New Name" was added')
end

it "currency and price both are set, user tries to unset currency" do
edit[:new][:currency] = currency.id
edit[:new][:price] = 100.0
controller.params = {:currency => '', :button => 'add'}
controller.send(:st_edit)
expect(assigns(:flash_array).first[:message]).to include('Catalog Bundle "New Name" was added')
end
end

describe "#st_upload_image" do
before do
ApplicationController.handle_exceptions = true
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,8 @@ describe('catalogItemFormController', function() {
prov_type: 'generic_ansible_playbook',
type: 'ServiceTemplateAnsiblePlaybook',
additional_tenant_ids: additionalTenantIds,
currency_id: '',
price: '',
config_info: {
provision: {
dialog_id: '10000000000031',
Expand Down