diff --git a/app/models/contract.rb b/app/models/contract.rb index c111536..537e3f3 100644 --- a/app/models/contract.rb +++ b/app/models/contract.rb @@ -33,6 +33,8 @@ class Contract < ActiveRecord::Base attr_accessible :client_point_of_contact attr_accessible :details + named_scope :by_name, {:order => "#{Contract.table_name}.name ASC"} + [:status, :contract_type, :fixed_spent, :fixed_budget, :markup_spent, :markup_budget, diff --git a/config/locales/en.yml b/config/locales/en.yml index 69cb56c..c4dd024 100644 --- a/config/locales/en.yml +++ b/config/locales/en.yml @@ -59,3 +59,4 @@ en: enumeration_payment_term: "Payment Terms" field_deliverable_title: "Deliverable" field_contract_name: "Contract" + field_contract: "Contract" diff --git a/lib/redmine_contracts/patches/query_patch.rb b/lib/redmine_contracts/patches/query_patch.rb index 70e9a71..d5f4a91 100644 --- a/lib/redmine_contracts/patches/query_patch.rb +++ b/lib/redmine_contracts/patches/query_patch.rb @@ -9,6 +9,9 @@ module RedmineContracts unloadable alias_method_chain :available_filters, :deliverable + alias_method_chain :available_filters, :contract + + alias_method_chain :sql_for_field, :contract end end @@ -34,6 +37,52 @@ module RedmineContracts end end + + # TODO: Should have an API on the Redmine core for this + def available_filters_with_contract + @available_filters = available_filters_without_contract + + if project + contract_filters = { + "contract_id" => { + :type => :list_optional, + :order => 16, + :values => project.contracts.by_name.collect { |d| [d.name, d.id.to_s] } + } + } + return @available_filters.merge(contract_filters) + else + return @available_filters + end + + end + + def sql_for_field_with_contract(field, operator, value, db_table, db_field, is_custom_filter=false) + if field != "contract_id" + return sql_for_field_without_contract(field, operator, value, db_table, db_field, is_custom_filter) + else + # Contracts > Deliverables > Issue + case operator + when "=" + contracts = value.collect{|val| "'#{connection.quote_string(val)}'"}.join(",") + inner_select = "(SELECT id from deliverables where deliverables.contract_id IN (#{contracts}))" + sql = "#{Issue.table_name}.deliverable_id IN (#{inner_select})" + when "!" + contracts = value.collect{|val| "'#{connection.quote_string(val)}'"}.join(",") + inner_select = "(SELECT id from deliverables where deliverables.contract_id IN (#{contracts}))" + sql = "(#{Issue.table_name}.deliverable_id IS NULL OR #{Issue.table_name}.deliverable_id NOT IN (#{inner_select}))" + when "!*" + # If it doesn't have a deliverable, it can't have a contract + sql = "#{Issue.table_name}.deliverable_id IS NULL" + when "*" + # If it has a deliverable, it must have a contract + sql = "#{Issue.table_name}.deliverable_id IS NOT NULL" + end + + return sql + end + end + end end end diff --git a/test/unit/lib/redmine_contracts/patches/query_patch_test.rb b/test/unit/lib/redmine_contracts/patches/query_patch_test.rb index 011e76e..84e91d5 100644 --- a/test/unit/lib/redmine_contracts/patches/query_patch_test.rb +++ b/test/unit/lib/redmine_contracts/patches/query_patch_test.rb @@ -27,7 +27,57 @@ class RedmineContracts::Patches::QueryTest < ActionController::TestCase ["Two", @deliverable2.id.to_s] ], deliverable_filter[:values] end + + should "add a contract_id filter" do + filters = @query.available_filters + + assert filters.keys.include?("contract_id") + + contract_filter = filters["contract_id"] + assert_equal :list_optional, contract_filter[:type] + assert_equal [["A Contract", @contract.id.to_s]], contract_filter[:values] + end end + + # TODO: Dragons in this test + context "#sql_for_field_with_contract" do + context "for contract_id fields" do + setup do + @query = Query.new + end + + context "with the equal operator" do + should "return the SQL snippet for checking for deliverables on the specific contracts" do + sql = @query.send(:sql_for_field, 'contract_id', '=', ['1','2'], '', '') + assert_equal "issues.deliverable_id IN ((SELECT id from deliverables where deliverables.contract_id IN ('1','2')))", sql + end + end + + context "with is not operator" do + should "return the SQL snippet for checking for null deliverables or deliverables no on the specific contracts" do + sql = @query.send(:sql_for_field, 'contract_id', '!', ['1','2'], '', '') + assert_equal "(issues.deliverable_id IS NULL OR issues.deliverable_id NOT IN ((SELECT id from deliverables where deliverables.contract_id IN ('1','2'))))", sql + end + end + + context "with none operator" do + should "return the SQL snippet for checking for null deliverables" do + sql = @query.send(:sql_for_field, 'contract_id', '!*', '', '', '') + assert_equal "issues.deliverable_id IS NULL", sql + end + end + + context "with all operator" do + should "return the SQL snippet for checking for not null deliverables" do + sql = @query.send(:sql_for_field, 'contract_id', '*', '', '', '') + assert_equal "issues.deliverable_id IS NOT NULL", sql + end + end + + + end + end + end end