1
0
Fork 0

Add reference OrgUnit#resource

This commit is contained in:
Alex Kotov 2019-10-21 12:15:08 +05:00
parent 0c49c40330
commit 68193ec846
Signed by: kotovalexarian
GPG Key ID: 553C0EBBEB5D5F08
6 changed files with 220 additions and 2 deletions

View File

@ -14,6 +14,10 @@ class OrgUnit < ApplicationRecord
inverse_of: :children_units,
optional: true
belongs_to :resource,
polymorphic: true,
optional: true
has_many :children_units,
class_name: 'OrgUnit',
inverse_of: :parent_unit,
@ -37,6 +41,12 @@ class OrgUnit < ApplicationRecord
message: :required,
}
validates :resource,
presence: {
if: ->(record) { record.kind&.resource_type },
message: :required,
}
validate :parent_matches_kind
#############

View File

@ -0,0 +1,75 @@
# frozen_string_literal: true
class AddResourceToOrgUnits < ActiveRecord::Migration[6.0]
include Partynest::Migration
def change
reversible do |dir|
dir.up do
execute 'ALTER SEQUENCE org_units_id_seq RESTART WITH 1000'
end
end
add_reference :org_units, :resource, polymorphic: true, null: true
add_func_validate_org_unit_resource
add_trigger :org_units,
:add_func_validate_org_unit_resource,
'BEFORE INSERT OR UPDATE',
'add_func_validate_org_unit_resource()'
end
def add_func_validate_org_unit_resource
add_func :add_func_validate_org_unit_resource, <<~SQL
() RETURNS trigger LANGUAGE plpgsql AS
$$
DECLARE
org_unit_kind record;
BEGIN
IF NEW.kind_id IS NULL THEN
IF NEW.resource_type IS NOT NULL THEN
RAISE EXCEPTION 'resource type is invalid (expected NULL)';
END IF;
IF NEW.resource_id IS NOT NULL THEN
RAISE EXCEPTION 'resource ID is invalid (expected NULL)';
END IF;
RETURN NEW;
END IF;
SELECT * FROM org_unit_kinds INTO org_unit_kind WHERE id = NEW.kind_id;
IF org_unit_kind IS NULL THEN
RAISE EXCEPTION 'can not find type';
END IF;
IF org_unit_kind.resource_type IS NULL THEN
IF NEW.resource_type IS NOT NULL THEN
RAISE EXCEPTION 'resource type is invalid (expected NULL)';
END IF;
IF NEW.resource_id IS NOT NULL THEN
RAISE EXCEPTION 'resource ID is invalid (expected NULL)';
END IF;
ELSE
IF NEW.resource_type IS NULL THEN
RAISE EXCEPTION 'resource type is invalid (expected NOT NULL)';
END IF;
IF NEW.resource_type != org_unit_kind.resource_type THEN
RAISE EXCEPTION 'resource type is invalid';
END IF;
IF NEW.resource_id IS NULL THEN
RAISE EXCEPTION 'resource ID is invalid (expected NULL)';
END IF;
END IF;
RETURN NEW;
END;
$$;
SQL
end
end

View File

@ -48,6 +48,61 @@ CREATE TYPE public.sex AS ENUM (
);
--
-- Name: add_func_validate_org_unit_resource(); Type: FUNCTION; Schema: public; Owner: -
--
CREATE FUNCTION public.add_func_validate_org_unit_resource() RETURNS trigger
LANGUAGE plpgsql
AS $$
DECLARE
org_unit_kind record;
BEGIN
IF NEW.kind_id IS NULL THEN
IF NEW.resource_type IS NOT NULL THEN
RAISE EXCEPTION 'resource type is invalid (expected NULL)';
END IF;
IF NEW.resource_id IS NOT NULL THEN
RAISE EXCEPTION 'resource ID is invalid (expected NULL)';
END IF;
RETURN NEW;
END IF;
SELECT * FROM org_unit_kinds INTO org_unit_kind WHERE id = NEW.kind_id;
IF org_unit_kind IS NULL THEN
RAISE EXCEPTION 'can not find type';
END IF;
IF org_unit_kind.resource_type IS NULL THEN
IF NEW.resource_type IS NOT NULL THEN
RAISE EXCEPTION 'resource type is invalid (expected NULL)';
END IF;
IF NEW.resource_id IS NOT NULL THEN
RAISE EXCEPTION 'resource ID is invalid (expected NULL)';
END IF;
ELSE
IF NEW.resource_type IS NULL THEN
RAISE EXCEPTION 'resource type is invalid (expected NOT NULL)';
END IF;
IF NEW.resource_type != org_unit_kind.resource_type THEN
RAISE EXCEPTION 'resource type is invalid';
END IF;
IF NEW.resource_id IS NULL THEN
RAISE EXCEPTION 'resource ID is invalid (expected NULL)';
END IF;
END IF;
RETURN NEW;
END;
$$;
--
-- Name: ensure_contact_list_id_matches_related_person(); Type: FUNCTION; Schema: public; Owner: -
--
@ -732,6 +787,8 @@ CREATE TABLE public.org_units (
kind_id bigint NOT NULL,
parent_unit_id bigint,
level integer NOT NULL,
resource_type character varying,
resource_id bigint,
CONSTRAINT level CHECK ((level >= 0)),
CONSTRAINT name CHECK (public.is_good_small_text((name)::text)),
CONSTRAINT parent_unit CHECK ((parent_unit_id <> id)),
@ -1528,6 +1585,13 @@ CREATE UNIQUE INDEX index_org_units_on_name ON public.org_units USING btree (nam
CREATE INDEX index_org_units_on_parent_unit_id ON public.org_units USING btree (parent_unit_id);
--
-- Name: index_org_units_on_resource_type_and_resource_id; Type: INDEX; Schema: public; Owner: -
--
CREATE INDEX index_org_units_on_resource_type_and_resource_id ON public.org_units USING btree (resource_type, resource_id);
--
-- Name: index_org_units_on_short_name; Type: INDEX; Schema: public; Owner: -
--
@ -1682,6 +1746,13 @@ CREATE UNIQUE INDEX index_users_on_reset_password_token ON public.users USING bt
CREATE UNIQUE INDEX index_users_on_unlock_token ON public.users USING btree (unlock_token);
--
-- Name: org_units add_func_validate_org_unit_resource; Type: TRIGGER; Schema: public; Owner: -
--
CREATE TRIGGER add_func_validate_org_unit_resource BEFORE INSERT OR UPDATE ON public.org_units FOR EACH ROW EXECUTE PROCEDURE public.add_func_validate_org_unit_resource();
--
-- Name: accounts ensure_contact_list_id_matches_related_person; Type: TRIGGER; Schema: public; Owner: -
--
@ -1905,6 +1976,7 @@ INSERT INTO "schema_migrations" (version) VALUES
('20191001022049'),
('20191002002101'),
('20191002170727'),
('20191021060000');
('20191021060000'),
('20191021061920');

View File

@ -2,6 +2,14 @@
FactoryBot.define do
factory :federal_subject do
initialize_with do
FederalSubject.find_or_initialize_by(
number: number,
english_name: english_name,
native_name: native_name,
)
end
number { rand 1..2**31 - 1 }
english_name do
@ -16,4 +24,20 @@ FactoryBot.define do
timezone { "#{[nil, :-].sample}#{rand(0..11).to_s.rjust(2, '0')}:00:00" }
end
factory :moscow_federal_subject, parent: :federal_subject do
number { 77 }
english_name { 'Moscow' }
native_name { 'Москва' }
centre { 'Москва' }
timezone { '03:00:00' }
end
factory :perm_federal_subject, parent: :federal_subject do
number { 27 }
english_name { 'Perm Krai' }
native_name { 'Пермский край' }
centre { 'Пермь' }
timezone { '05:00:00' }
end
end

View File

@ -35,6 +35,7 @@ FactoryBot.define do
association :kind, factory: :reg_dept_org_unit_kind
association :parent_unit, factory: :lpr_org_unit
association :resource, factory: :moscow_federal_subject
end
factory :perm_reg_dept_org_unit, parent: :lpr_org_unit do
@ -46,6 +47,7 @@ FactoryBot.define do
association :kind, factory: :reg_dept_org_unit_kind
association :parent_unit, factory: :lpr_org_unit
association :resource, factory: :perm_federal_subject
end
factory :fed_management_org_unit, parent: :lpr_org_unit do

View File

@ -35,7 +35,7 @@ RSpec.describe OrgUnit do
end
end
context 'when organizational unit type does not require parent' do
context 'when organizational unit type requires parent' do
subject { create :some_children_org_unit }
it do
@ -46,6 +46,41 @@ RSpec.describe OrgUnit do
end
end
describe '#resource' do
it { is_expected.to belong_to(:resource).optional }
context 'when organizational unit type does not require resource' do
subject { create :some_children_org_unit }
it do
is_expected.not_to \
validate_presence_of(:resource)
.with_message(:required)
end
end
context 'when organizational unit type requires resource' do
subject do
create :some_children_org_unit,
kind: org_unit_kind,
resource: resource
end
let :org_unit_kind do
create :some_children_org_unit_kind,
resource_type: resource.class.name
end
let(:resource) { create :federal_subject }
it do
is_expected.to \
validate_presence_of(:resource)
.with_message(:required)
end
end
end
describe '#children_units' do
it do
is_expected.to \