feat(Logic.computable?): add computable? to know if a ineligibilite_rules set is computable
This commit is contained in:
parent
5de4ce889f
commit
5644692448
9 changed files with 141 additions and 0 deletions
|
@ -21,6 +21,10 @@ module ChampConditionalConcern
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def reset_visible # recompute after a dossier update
|
||||||
|
remove_instance_variable :@visible if instance_variable_defined? :@visible
|
||||||
|
end
|
||||||
|
|
||||||
private
|
private
|
||||||
|
|
||||||
def champs_for_condition
|
def champs_for_condition
|
||||||
|
|
|
@ -938,6 +938,10 @@ class Dossier < ApplicationRecord
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def ineligibilite_rules_computable?
|
||||||
|
revision.ineligibilite_rules_computable?(champs_for_revision(scope: :public))
|
||||||
|
end
|
||||||
|
|
||||||
def demander_un_avis!(avis)
|
def demander_un_avis!(avis)
|
||||||
log_dossier_operation(avis.claimant, :demander_un_avis, avis)
|
log_dossier_operation(avis.claimant, :demander_un_avis, avis)
|
||||||
end
|
end
|
||||||
|
|
|
@ -7,5 +7,12 @@ class Logic::And < Logic::NAryOperator
|
||||||
@operands.map { |operand| operand.compute(champs) }.all?
|
@operands.map { |operand| operand.compute(champs) }.all?
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def computable?(champs = [])
|
||||||
|
return true if sources.blank?
|
||||||
|
|
||||||
|
champs.filter { _1.stable_id.in?(sources) && _1.visible? }
|
||||||
|
.all? { _1.value.present? }
|
||||||
|
end
|
||||||
|
|
||||||
def to_s(type_de_champs) = "(#{@operands.map { |o| o.to_s(type_de_champs) }.join(' && ')})"
|
def to_s(type_de_champs) = "(#{@operands.map { |o| o.to_s(type_de_champs) }.join(' && ')})"
|
||||||
end
|
end
|
||||||
|
|
|
@ -42,6 +42,15 @@ class Logic::BinaryOperator < Logic::Term
|
||||||
l&.send(operation, r) || false
|
l&.send(operation, r) || false
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def computable?(champs = [])
|
||||||
|
return true if sources.blank?
|
||||||
|
|
||||||
|
visible_champs_sources = champs.filter { _1.stable_id.in?(sources) && _1.visible? }
|
||||||
|
|
||||||
|
return false if visible_champs_sources.size != sources.size
|
||||||
|
visible_champs_sources.all? { _1.value.present? }
|
||||||
|
end
|
||||||
|
|
||||||
def to_s(type_de_champs) = "(#{@left.to_s(type_de_champs)} #{operation} #{@right.to_s(type_de_champs)})"
|
def to_s(type_de_champs) = "(#{@left.to_s(type_de_champs)} #{operation} #{@right.to_s(type_de_champs)})"
|
||||||
|
|
||||||
def ==(other)
|
def ==(other)
|
||||||
|
|
|
@ -7,5 +7,15 @@ class Logic::Or < Logic::NAryOperator
|
||||||
@operands.map { |operand| operand.compute(champs) }.any?
|
@operands.map { |operand| operand.compute(champs) }.any?
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
|
def computable?(champs = [])
|
||||||
|
return true if sources.blank?
|
||||||
|
|
||||||
|
visible_champs_sources = champs.filter { _1.stable_id.in?(sources) && _1.visible? }
|
||||||
|
|
||||||
|
return false if visible_champs_sources.blank?
|
||||||
|
visible_champs_sources.all? { _1.value.present? } || compute(visible_champs_sources)
|
||||||
|
end
|
||||||
|
|
||||||
def to_s(type_de_champs = []) = "(#{@operands.map { |o| o.to_s(type_de_champs) }.join(' || ')})"
|
def to_s(type_de_champs = []) = "(#{@operands.map { |o| o.to_s(type_de_champs) }.join(' || ')})"
|
||||||
end
|
end
|
||||||
|
|
|
@ -269,6 +269,12 @@ class ProcedureRevision < ApplicationRecord
|
||||||
types_de_champ_for(scope: :public).filter(&:conditionable?)
|
types_de_champ_for(scope: :public).filter(&:conditionable?)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def ineligibilite_rules_computable?(champs)
|
||||||
|
ineligibilite_enabled && ineligibilite_rules&.computable?(champs)
|
||||||
|
ensure
|
||||||
|
champs.map(&:reset_visible) # otherwise @visible is cached, then dossier can be updated. champs are not updated
|
||||||
|
end
|
||||||
|
|
||||||
private
|
private
|
||||||
|
|
||||||
def compute_estimated_fill_duration
|
def compute_estimated_fill_duration
|
||||||
|
@ -483,6 +489,13 @@ class ProcedureRevision < ApplicationRecord
|
||||||
changes
|
changes
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def ineligibilite_rules_are_valid?
|
||||||
|
if ineligibilite_rules
|
||||||
|
ineligibilite_rules.errors(types_de_champ_for(scope: :public).to_a)
|
||||||
|
.each { errors.add(:ineligibilite_rules, :invalid) }
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
def replace_type_de_champ_by_clone(coordinate)
|
def replace_type_de_champ_by_clone(coordinate)
|
||||||
cloned_type_de_champ = coordinate.type_de_champ.deep_clone do |original, kopy|
|
cloned_type_de_champ = coordinate.type_de_champ.deep_clone do |original, kopy|
|
||||||
ClonePiecesJustificativesService.clone_attachments(original, kopy)
|
ClonePiecesJustificativesService.clone_attachments(original, kopy)
|
||||||
|
|
|
@ -6,6 +6,42 @@ describe Logic::And do
|
||||||
it { expect(and_from([true, true, false]).compute).to be false }
|
it { expect(and_from([true, true, false]).compute).to be false }
|
||||||
end
|
end
|
||||||
|
|
||||||
|
describe '#computable?' do
|
||||||
|
let(:champ_1) { create(:champ_integer_number, value: value_1) }
|
||||||
|
let(:champ_2) { create(:champ_integer_number, value: value_2) }
|
||||||
|
|
||||||
|
let(:logic) do
|
||||||
|
ds_and([
|
||||||
|
greater_than(champ_value(champ_1.stable_id), constant(1)),
|
||||||
|
less_than(champ_value(champ_2.stable_id), constant(10))
|
||||||
|
])
|
||||||
|
end
|
||||||
|
|
||||||
|
subject { logic.computable?([champ_1, champ_2]) }
|
||||||
|
|
||||||
|
context "when none of champs.value are filled, and logic can't be computed" do
|
||||||
|
let(:value_1) { nil }
|
||||||
|
let(:value_2) { nil }
|
||||||
|
it { is_expected.to be_falsey }
|
||||||
|
end
|
||||||
|
context "when one champs has a value (that compute to false) the other has not, and logic keeps waiting for the 2nd value" do
|
||||||
|
let(:value_1) { 1 }
|
||||||
|
let(:value_2) { nil }
|
||||||
|
it { is_expected.to be_falsey }
|
||||||
|
end
|
||||||
|
context 'when all champs.value are filled, and logic can be computed' do
|
||||||
|
let(:value_1) { 1 }
|
||||||
|
let(:value_2) { 10 }
|
||||||
|
it { is_expected.to be_truthy }
|
||||||
|
end
|
||||||
|
context 'when one champs is not visible and the other has a value, and logic can be computed' do
|
||||||
|
let(:value_1) { 1 }
|
||||||
|
let(:value_2) { nil }
|
||||||
|
before { expect(champ_2).to receive(:visible?).and_return(false) }
|
||||||
|
it { is_expected.to be_truthy }
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
describe '#to_s' do
|
describe '#to_s' do
|
||||||
it do
|
it do
|
||||||
expect(and_from([true, false, true]).to_s([])).to eq "(Oui && Non && Oui)"
|
expect(and_from([true, false, true]).to_s([])).to eq "(Oui && Non && Oui)"
|
||||||
|
|
|
@ -28,6 +28,19 @@ describe Logic::BinaryOperator do
|
||||||
it { expect(greater_than(constant(2), champ_value(champ.stable_id)).sources).to eq([champ.stable_id]) }
|
it { expect(greater_than(constant(2), champ_value(champ.stable_id)).sources).to eq([champ.stable_id]) }
|
||||||
it { expect(greater_than(champ_value(champ.stable_id), champ_value(champ2.stable_id)).sources).to eq([champ.stable_id, champ2.stable_id]) }
|
it { expect(greater_than(champ_value(champ.stable_id), champ_value(champ2.stable_id)).sources).to eq([champ.stable_id, champ2.stable_id]) }
|
||||||
end
|
end
|
||||||
|
|
||||||
|
describe '#computable?' do
|
||||||
|
let(:champ) { create(:champ_integer_number, value: nil) }
|
||||||
|
|
||||||
|
it 'computable?' do
|
||||||
|
expect(greater_than(champ_value(champ.stable_id), constant(1)).computable?([])).to be(false)
|
||||||
|
expect(greater_than(champ_value(champ.stable_id), constant(1)).computable?([champ])).to be(false)
|
||||||
|
allow(champ).to receive(:value).and_return(double(present?: true))
|
||||||
|
expect(greater_than(champ_value(champ.stable_id), constant(1)).computable?([champ])).to be(true)
|
||||||
|
allow(champ).to receive(:visible?).and_return(false)
|
||||||
|
expect(greater_than(champ_value(champ.stable_id), constant(1)).computable?([champ])).to be(false)
|
||||||
|
end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
describe Logic::GreaterThan do
|
describe Logic::GreaterThan do
|
||||||
|
@ -43,6 +56,8 @@ end
|
||||||
|
|
||||||
describe Logic::GreaterThanEq do
|
describe Logic::GreaterThanEq do
|
||||||
include Logic
|
include Logic
|
||||||
|
let(:champ) { create(:champ_integer_number, value: nil) }
|
||||||
|
|
||||||
it 'computes' do
|
it 'computes' do
|
||||||
expect(greater_than_eq(constant(0), constant(1)).compute).to be(false)
|
expect(greater_than_eq(constant(0), constant(1)).compute).to be(false)
|
||||||
expect(greater_than_eq(constant(1), constant(1)).compute).to be(true)
|
expect(greater_than_eq(constant(1), constant(1)).compute).to be(true)
|
||||||
|
|
|
@ -7,6 +7,49 @@ describe Logic::Or do
|
||||||
it { expect(or_from([false, false, false]).compute).to be false }
|
it { expect(or_from([false, false, false]).compute).to be false }
|
||||||
end
|
end
|
||||||
|
|
||||||
|
describe '#computable?' do
|
||||||
|
let(:champ_1) { create(:champ_integer_number, value: value_1) }
|
||||||
|
let(:champ_2) { create(:champ_integer_number, value: value_2) }
|
||||||
|
|
||||||
|
let(:logic) do
|
||||||
|
ds_or([
|
||||||
|
greater_than(champ_value(champ_1.stable_id), constant(1)),
|
||||||
|
less_than(champ_value(champ_2.stable_id), constant(10))
|
||||||
|
])
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'with all champs' do
|
||||||
|
subject { logic.computable?([champ_1, champ_2]) }
|
||||||
|
|
||||||
|
context "when none of champs.value are filled, or logic can't be computed" do
|
||||||
|
let(:value_1) { nil }
|
||||||
|
let(:value_2) { nil }
|
||||||
|
it { is_expected.to be_falsey }
|
||||||
|
end
|
||||||
|
context "when one champs has a value (that compute to false) the other has not, or logic keeps waiting for the 2nd value" do
|
||||||
|
let(:value_1) { 1 }
|
||||||
|
let(:value_2) { nil }
|
||||||
|
it { is_expected.to be_falsey }
|
||||||
|
end
|
||||||
|
context 'when all champs.value are filled, or logic can be computed' do
|
||||||
|
let(:value_1) { 1 }
|
||||||
|
let(:value_2) { 10 }
|
||||||
|
it { is_expected.to be_truthy }
|
||||||
|
end
|
||||||
|
context 'when one champs.value and his condition is true, or logic can be computed' do
|
||||||
|
let(:value_1) { 2 }
|
||||||
|
let(:value_2) { nil }
|
||||||
|
it { is_expected.to be_truthy }
|
||||||
|
end
|
||||||
|
context 'when one champs is not visible and the other has a value that fails, or logic can be computed' do
|
||||||
|
let(:value_1) { 1 }
|
||||||
|
let(:value_2) { nil }
|
||||||
|
before { expect(champ_2).to receive(:visible?).and_return(false) }
|
||||||
|
it { is_expected.to be_truthy }
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
describe '#to_s' do
|
describe '#to_s' do
|
||||||
it { expect(or_from([true, false, true]).to_s).to eq "(Oui || Non || Oui)" }
|
it { expect(or_from([true, false, true]).to_s).to eq "(Oui || Non || Oui)" }
|
||||||
end
|
end
|
||||||
|
|
Loading…
Reference in a new issue