mirror of
https://github.com/internetee/registry.git
synced 2025-07-28 05:26:17 +02:00
Merge branch 'master' into 2334-remove-que
This commit is contained in:
commit
a6a3f72032
240 changed files with 5827 additions and 1432 deletions
4
.github/workflows/ruby.yml
vendored
4
.github/workflows/ruby.yml
vendored
|
@ -6,7 +6,7 @@ jobs:
|
||||||
test:
|
test:
|
||||||
services:
|
services:
|
||||||
postgres:
|
postgres:
|
||||||
image: postgres:12
|
image: postgres:14
|
||||||
ports: ["5432:5432"]
|
ports: ["5432:5432"]
|
||||||
env:
|
env:
|
||||||
POSTGRES_PASSWORD: password
|
POSTGRES_PASSWORD: password
|
||||||
|
@ -79,7 +79,7 @@ jobs:
|
||||||
- name: Save coverage
|
- name: Save coverage
|
||||||
run: ./cc-test-reporter format-coverage --output coverage/codeclimate.${{ matrix.ruby }}.json
|
run: ./cc-test-reporter format-coverage --output coverage/codeclimate.${{ matrix.ruby }}.json
|
||||||
|
|
||||||
- uses: actions/upload-artifact@v3.0.0
|
- uses: actions/upload-artifact@v3.1.0
|
||||||
with:
|
with:
|
||||||
name: coverage-${{ matrix.ruby }}
|
name: coverage-${{ matrix.ruby }}
|
||||||
path: coverage/codeclimate.${{ matrix.ruby }}.json
|
path: coverage/codeclimate.${{ matrix.ruby }}.json
|
||||||
|
|
3
.gitignore
vendored
3
.gitignore
vendored
|
@ -5,12 +5,13 @@
|
||||||
/coverage/
|
/coverage/
|
||||||
/.bundle
|
/.bundle
|
||||||
/vendor/bundle
|
/vendor/bundle
|
||||||
|
/vendor/gems
|
||||||
/config/database.yml
|
/config/database.yml
|
||||||
/config/application.yml
|
/config/application.yml
|
||||||
/config/environments/development.rb
|
/config/environments/development.rb
|
||||||
/config/deploy.rb
|
/config/deploy.rb
|
||||||
/config/master.key
|
/config/master.key
|
||||||
/.idea
|
/.idea
|
||||||
|
/config/master.key
|
||||||
# Do not commit one. Instead, download the latest from https://github.com/internetee/style-guide.
|
# Do not commit one. Instead, download the latest from https://github.com/internetee/style-guide.
|
||||||
.rubocop.yml
|
.rubocop.yml
|
||||||
|
|
86
CHANGELOG.md
86
CHANGELOG.md
|
@ -1,3 +1,89 @@
|
||||||
|
08.09.2022
|
||||||
|
* Fixed template error for multi-year registered domains in force delete process [#2435](https://github.com/internetee/registry/issues/2435)
|
||||||
|
|
||||||
|
02.09.2022
|
||||||
|
* Update invoice status on payment order payments [#2427](https://github.com/internetee/registry/pull/2427)
|
||||||
|
|
||||||
|
01.09.2022
|
||||||
|
* Monthly invoice payment status fix [#2428](https://github.com/internetee/registry/issues/2428)
|
||||||
|
|
||||||
|
31.08.2022
|
||||||
|
* new fully automated process for registrar monthly invoices [#2424](https://github.com/internetee/registry/pull/2424)
|
||||||
|
|
||||||
|
25.08.2022
|
||||||
|
* Contact creation fix to not require postal addresses in Registrar portal [#2421](https://github.com/internetee/registry/pull/2421)
|
||||||
|
|
||||||
|
23.08.2022
|
||||||
|
* REPP update to fix search by registrant in Registrar portal [#2425](https://github.com/internetee/registry/pull/2425)
|
||||||
|
|
||||||
|
21.07.2022
|
||||||
|
* Removed deprecated statuses_before_force_delete field [#2363](https://github.com/internetee/registry/issues/2363)
|
||||||
|
|
||||||
|
15.07.2022
|
||||||
|
* REPP api update for new registrar portal [#2387](https://github.com/internetee/registry/pull/2387)
|
||||||
|
|
||||||
|
4.07.2022
|
||||||
|
* Update apipie-rails to 0.8.0 [#2383](https://github.com/internetee/registry/pull/2383)
|
||||||
|
* Bump jmespath to 1.6.1 [#2388](https://github.com/internetee/registry/pull/2388)
|
||||||
|
|
||||||
|
1.07.2022
|
||||||
|
* Update pg to 1.4.1 [#2394](https://github.com/internetee/registry/pull/2394)
|
||||||
|
* Update rack to 2.2.4 [#2398](https://github.com/internetee/registry/pull/2398)
|
||||||
|
|
||||||
|
21.06.2022
|
||||||
|
* Update pg to 1.4.0 [#2392](https://github.com/internetee/registry/pull/2392)
|
||||||
|
|
||||||
|
02.06.2022
|
||||||
|
* fix for force delete check query [#2380](https://github.com/internetee/registry/pull/2380)
|
||||||
|
* Integration with the billing service [#2266](https://github.com/internetee/registry/pull/2266)
|
||||||
|
|
||||||
|
25.05.2022
|
||||||
|
* Fixed looping validation issue [#2377](https://github.com/internetee/registry/pull/2377)
|
||||||
|
* ForceDelete query fix [#2380](https://github.com/internetee/registry/pull/2380)
|
||||||
|
|
||||||
|
19.05.2022
|
||||||
|
* Process to remove expired validation event records [#2236](https://github.com/internetee/registry/issues/2236)
|
||||||
|
|
||||||
|
17.05.2022
|
||||||
|
* removed unnecessary contact validation on contact create [#2376](https://github.com/internetee/registry/pull/2376)
|
||||||
|
* Refactored email validation job [#2369](https://github.com/internetee/registry/pull/2369)
|
||||||
|
* Job for deprecated validation events removal [#2374](https://github.com/internetee/registry/issues/2374)
|
||||||
|
|
||||||
|
09.05.2022
|
||||||
|
* test for auction view [#2373](https://github.com/internetee/registry/pull/2373)
|
||||||
|
|
||||||
|
06.05.2022
|
||||||
|
* refactored out the contact_code_cache from domain_contacts model [#2370](https://github.com/internetee/registry/issues/2370)
|
||||||
|
|
||||||
|
28.04.2022
|
||||||
|
* Fixed ns and dnssec validation error messages [#2296](https://github.com/internetee/registry/issues/2296)
|
||||||
|
* Added status notes to REPP domain info output [#2331](https://github.com/internetee/registry/issues/2331)
|
||||||
|
* Added auction list view to admin for improved ahandling of upcoming enlgish auction feature [#2341](https://github.com/internetee/registry/pull/2341)
|
||||||
|
|
||||||
|
27.04.2022
|
||||||
|
* Refactored email validation - reducing dns requests [#2364](https://github.com/internetee/registry/issues/2364)
|
||||||
|
|
||||||
|
21.04.2022
|
||||||
|
* Delay renovate Ruby version updates for 60 days [#2361](https://github.com/internetee/registry/issues/2361)
|
||||||
|
|
||||||
|
20.04.2022
|
||||||
|
* Contacts with disclosed attributes can now be updated [#2340](https://github.com/internetee/registry/issues/2340)
|
||||||
|
* Legacy code fix [#2360](https://github.com/internetee/registry/pull/2360)
|
||||||
|
|
||||||
|
19.04.2022
|
||||||
|
* Rolled back ruby version to 3.0.3 [#2358](https://github.com/internetee/registry/pull/2358)
|
||||||
|
|
||||||
|
18.04.2022
|
||||||
|
* Fixed error 2005 epp syntax issue [#2338](https://github.com/internetee/registry/issues/2338)
|
||||||
|
* Fixed poll issue with email validations [#2343](https://github.com/internetee/registry/issues/2343)
|
||||||
|
* Removed registrant portal code from registry project [#2350](https://github.com/internetee/registry/issues/2350)
|
||||||
|
|
||||||
|
14.04.2022
|
||||||
|
* Removed legacy email verification code [#2349](https://github.com/internetee/registry/issues/2349)
|
||||||
|
|
||||||
|
06.04.2022
|
||||||
|
* Contact email validation on domain update [#2213](https://github.com/internetee/registry/issues/2213)
|
||||||
|
|
||||||
05.04.2022
|
05.04.2022
|
||||||
* Automatic contact name update poll messages are now grouped together into one change poll message [#2307](https://github.com/internetee/registry/issues/2307)
|
* Automatic contact name update poll messages are now grouped together into one change poll message [#2307](https://github.com/internetee/registry/issues/2307)
|
||||||
* Status notes are now added to status elements of epp xml [#2211](https://github.com/internetee/registry/issues/2211)
|
* Status notes are now added to status elements of epp xml [#2211](https://github.com/internetee/registry/issues/2211)
|
||||||
|
|
|
@ -3,6 +3,7 @@ FROM internetee/ruby:3.0-buster
|
||||||
RUN mkdir -p /opt/webapps/app/tmp/pids
|
RUN mkdir -p /opt/webapps/app/tmp/pids
|
||||||
WORKDIR /opt/webapps/app
|
WORKDIR /opt/webapps/app
|
||||||
COPY Gemfile Gemfile.lock ./
|
COPY Gemfile Gemfile.lock ./
|
||||||
|
# ADD vendor/gems/omniauth-tara ./vendor/gems/omniauth-tara
|
||||||
RUN gem install bundler && bundle install --jobs 20 --retry 5
|
RUN gem install bundler && bundle install --jobs 20 --retry 5
|
||||||
|
|
||||||
EXPOSE 3000
|
EXPOSE 3000
|
||||||
|
|
15
Gemfile
15
Gemfile
|
@ -2,7 +2,7 @@ source 'https://rubygems.org'
|
||||||
|
|
||||||
# core
|
# core
|
||||||
gem 'active_interaction', '~> 4.0'
|
gem 'active_interaction', '~> 4.0'
|
||||||
gem 'apipie-rails', '~> 0.5.19'
|
gem 'apipie-rails', '~> 0.6.0'
|
||||||
gem 'bootsnap', '>= 1.1.0', require: false
|
gem 'bootsnap', '>= 1.1.0', require: false
|
||||||
gem 'iso8601', '0.13.0' # for dates and times
|
gem 'iso8601', '0.13.0' # for dates and times
|
||||||
gem 'mimemagic', '0.4.3'
|
gem 'mimemagic', '0.4.3'
|
||||||
|
@ -17,11 +17,11 @@ gem 'figaro', '~> 1.2'
|
||||||
|
|
||||||
# model related
|
# model related
|
||||||
gem 'paper_trail', '~> 12.1'
|
gem 'paper_trail', '~> 12.1'
|
||||||
gem 'pg', '1.3.5'
|
gem 'pg', '1.4.3'
|
||||||
# 1.8 is for Rails < 5.0
|
# 1.8 is for Rails < 5.0
|
||||||
gem 'ransack', '~> 2.6.0'
|
gem 'ransack', '~> 2.6.0'
|
||||||
gem 'truemail', '~> 2.4' # validates email by regexp, mail server existence and address existence
|
gem 'truemail', '~> 2.4' # validates email by regexp, mail server existence and address existence
|
||||||
gem 'validates_email_format_of', '1.6.3' # validates email against RFC 2822 and RFC 3696
|
gem 'validates_email_format_of', '1.7.2' # validates email against RFC 2822 and RFC 3696
|
||||||
|
|
||||||
# 0.7.3 is the latest for Rails 4.2, however, it is absent on Rubygems server
|
# 0.7.3 is the latest for Rails 4.2, however, it is absent on Rubygems server
|
||||||
# https://github.com/huacnlee/rails-settings-cached/issues/165
|
# https://github.com/huacnlee/rails-settings-cached/issues/165
|
||||||
|
@ -57,10 +57,9 @@ gem 'digidoc_client',
|
||||||
ref: '1645e83a5a548addce383f75703b0275c5310c32'
|
ref: '1645e83a5a548addce383f75703b0275c5310c32'
|
||||||
|
|
||||||
# TARA
|
# TARA
|
||||||
gem 'omniauth'
|
|
||||||
gem 'omniauth-rails_csrf_protection'
|
gem 'omniauth-rails_csrf_protection'
|
||||||
gem 'omniauth-tara', github: 'internetee/omniauth-tara'
|
gem 'omniauth-tara', github: 'internetee/omniauth-tara'
|
||||||
|
# gem 'omniauth-tara', path: 'vendor/gems/omniauth-tara'
|
||||||
|
|
||||||
gem 'airbrake'
|
gem 'airbrake'
|
||||||
gem 'epp', github: 'internetee/epp', branch: :master
|
gem 'epp', github: 'internetee/epp', branch: :master
|
||||||
|
@ -73,11 +72,12 @@ gem 'company_register', github: 'internetee/company_register',
|
||||||
branch: 'master'
|
branch: 'master'
|
||||||
gem 'domain_name'
|
gem 'domain_name'
|
||||||
gem 'e_invoice', github: 'internetee/e_invoice', branch: :master
|
gem 'e_invoice', github: 'internetee/e_invoice', branch: :master
|
||||||
gem 'haml', '~> 5.2'
|
gem 'haml', '~> 6.0'
|
||||||
gem 'lhv', github: 'internetee/lhv', branch: 'master'
|
gem 'lhv', github: 'internetee/lhv', branch: 'master'
|
||||||
gem 'rexml'
|
gem 'rexml'
|
||||||
gem 'wkhtmltopdf-binary', '~> 0.12.5.1'
|
gem 'wkhtmltopdf-binary', '~> 0.12.5.1'
|
||||||
|
|
||||||
|
|
||||||
gem 'directo', github: 'internetee/directo', branch: 'master'
|
gem 'directo', github: 'internetee/directo', branch: 'master'
|
||||||
|
|
||||||
group :development, :test do
|
group :development, :test do
|
||||||
|
@ -101,3 +101,6 @@ gem 'pghero'
|
||||||
gem 'pg_query', '>= 0.9.0'
|
gem 'pg_query', '>= 0.9.0'
|
||||||
gem 'newrelic_rpm'
|
gem 'newrelic_rpm'
|
||||||
gem 'newrelic-infinite_tracing'
|
gem 'newrelic-infinite_tracing'
|
||||||
|
|
||||||
|
# token
|
||||||
|
gem 'jwt'
|
||||||
|
|
63
Gemfile.lock
63
Gemfile.lock
|
@ -18,10 +18,10 @@ GIT
|
||||||
|
|
||||||
GIT
|
GIT
|
||||||
remote: https://github.com/internetee/e_invoice.git
|
remote: https://github.com/internetee/e_invoice.git
|
||||||
revision: 312cac173935f434e449d1714f3497bfee9f8995
|
revision: 9f850465697a2448a31ebddb83c1be5a5a9be3d2
|
||||||
branch: master
|
branch: master
|
||||||
specs:
|
specs:
|
||||||
e_invoice (0.1.0)
|
e_invoice (0.1.3)
|
||||||
builder (~> 3.2)
|
builder (~> 3.2)
|
||||||
nokogiri
|
nokogiri
|
||||||
savon
|
savon
|
||||||
|
@ -149,8 +149,9 @@ GEM
|
||||||
akami (1.3.1)
|
akami (1.3.1)
|
||||||
gyoku (>= 0.4.0)
|
gyoku (>= 0.4.0)
|
||||||
nokogiri
|
nokogiri
|
||||||
apipie-rails (0.5.19)
|
apipie-rails (0.6.0)
|
||||||
rails (>= 4.1)
|
actionpack (>= 4.1)
|
||||||
|
activesupport (>= 4.1)
|
||||||
attr_required (1.0.1)
|
attr_required (1.0.1)
|
||||||
autoprefixer-rails (10.2.4.0)
|
autoprefixer-rails (10.2.4.0)
|
||||||
execjs
|
execjs
|
||||||
|
@ -240,8 +241,9 @@ GEM
|
||||||
googleapis-common-protos-types (~> 1.0)
|
googleapis-common-protos-types (~> 1.0)
|
||||||
gyoku (1.3.1)
|
gyoku (1.3.1)
|
||||||
builder (>= 2.1.2)
|
builder (>= 2.1.2)
|
||||||
haml (5.2.2)
|
haml (6.0.0)
|
||||||
temple (>= 0.8.0)
|
temple (>= 0.8.2)
|
||||||
|
thor
|
||||||
tilt
|
tilt
|
||||||
hashdiff (1.0.1)
|
hashdiff (1.0.1)
|
||||||
hashie (4.1.0)
|
hashie (4.1.0)
|
||||||
|
@ -253,12 +255,12 @@ GEM
|
||||||
httpi (2.4.5)
|
httpi (2.4.5)
|
||||||
rack
|
rack
|
||||||
socksify
|
socksify
|
||||||
i18n (1.10.0)
|
i18n (1.12.0)
|
||||||
concurrent-ruby (~> 1.0)
|
concurrent-ruby (~> 1.0)
|
||||||
i18n_data (0.13.0)
|
i18n_data (0.13.0)
|
||||||
isikukood (0.1.2)
|
isikukood (0.1.2)
|
||||||
iso8601 (0.13.0)
|
iso8601 (0.13.0)
|
||||||
jmespath (1.4.0)
|
jmespath (1.6.1)
|
||||||
jquery-rails (4.4.0)
|
jquery-rails (4.4.0)
|
||||||
rails-dom-testing (>= 1, < 3)
|
rails-dom-testing (>= 1, < 3)
|
||||||
railties (>= 4.2.0)
|
railties (>= 4.2.0)
|
||||||
|
@ -270,6 +272,7 @@ GEM
|
||||||
activesupport (>= 4.2)
|
activesupport (>= 4.2)
|
||||||
aes_key_wrap
|
aes_key_wrap
|
||||||
bindata
|
bindata
|
||||||
|
jwt (2.3.0)
|
||||||
kaminari (1.2.1)
|
kaminari (1.2.1)
|
||||||
activesupport (>= 4.1.0)
|
activesupport (>= 4.1.0)
|
||||||
kaminari-actionview (= 1.2.1)
|
kaminari-actionview (= 1.2.1)
|
||||||
|
@ -284,7 +287,7 @@ GEM
|
||||||
kaminari-core (1.2.1)
|
kaminari-core (1.2.1)
|
||||||
libxml-ruby (3.2.1)
|
libxml-ruby (3.2.1)
|
||||||
logger (1.4.3)
|
logger (1.4.3)
|
||||||
loofah (2.16.0)
|
loofah (2.18.0)
|
||||||
crass (~> 1.0.2)
|
crass (~> 1.0.2)
|
||||||
nokogiri (>= 1.5.9)
|
nokogiri (>= 1.5.9)
|
||||||
mail (2.7.1)
|
mail (2.7.1)
|
||||||
|
@ -316,10 +319,10 @@ GEM
|
||||||
newrelic_rpm (= 8.1.0)
|
newrelic_rpm (= 8.1.0)
|
||||||
newrelic_rpm (8.1.0)
|
newrelic_rpm (8.1.0)
|
||||||
nio4r (2.5.8)
|
nio4r (2.5.8)
|
||||||
nokogiri (1.13.3)
|
nokogiri (1.13.6)
|
||||||
mini_portile2 (~> 2.8.0)
|
mini_portile2 (~> 2.8.0)
|
||||||
racc (~> 1.4)
|
racc (~> 1.4)
|
||||||
nokogiri (1.13.3-x86_64-linux)
|
nokogiri (1.13.6-x86_64-linux)
|
||||||
racc (~> 1.4)
|
racc (~> 1.4)
|
||||||
nori (2.6.0)
|
nori (2.6.0)
|
||||||
omniauth (1.9.1)
|
omniauth (1.9.1)
|
||||||
|
@ -328,7 +331,7 @@ GEM
|
||||||
omniauth-rails_csrf_protection (0.1.2)
|
omniauth-rails_csrf_protection (0.1.2)
|
||||||
actionpack (>= 4.2)
|
actionpack (>= 4.2)
|
||||||
omniauth (>= 1.3.1)
|
omniauth (>= 1.3.1)
|
||||||
openid_connect (1.2.0)
|
openid_connect (1.3.0)
|
||||||
activemodel
|
activemodel
|
||||||
attr_required (>= 1.0.0)
|
attr_required (>= 1.0.0)
|
||||||
json-jwt (>= 1.5.0)
|
json-jwt (>= 1.5.0)
|
||||||
|
@ -343,7 +346,7 @@ GEM
|
||||||
activerecord (>= 5.2)
|
activerecord (>= 5.2)
|
||||||
request_store (~> 1.1)
|
request_store (~> 1.1)
|
||||||
pdfkit (0.8.5)
|
pdfkit (0.8.5)
|
||||||
pg (1.3.5)
|
pg (1.4.3)
|
||||||
pg_query (2.1.2)
|
pg_query (2.1.2)
|
||||||
google-protobuf (>= 3.17.1)
|
google-protobuf (>= 3.17.1)
|
||||||
pghero (2.8.1)
|
pghero (2.8.1)
|
||||||
|
@ -355,13 +358,15 @@ GEM
|
||||||
puma (5.6.4)
|
puma (5.6.4)
|
||||||
nio4r (~> 2.0)
|
nio4r (~> 2.0)
|
||||||
racc (1.6.0)
|
racc (1.6.0)
|
||||||
rack (2.2.3)
|
rack (2.2.4)
|
||||||
rack-oauth2 (1.16.0)
|
rack-oauth2 (1.16.0)
|
||||||
activesupport
|
activesupport
|
||||||
attr_required
|
attr_required
|
||||||
httpclient
|
httpclient
|
||||||
json-jwt (>= 1.11.0)
|
json-jwt (>= 1.11.0)
|
||||||
rack (>= 2.1.0)
|
rack (>= 2.1.0)
|
||||||
|
rack-protection (2.2.0)
|
||||||
|
rack
|
||||||
rack-test (1.1.0)
|
rack-test (1.1.0)
|
||||||
rack (>= 1.0, < 3)
|
rack (>= 1.0, < 3)
|
||||||
rails (6.1.4.1)
|
rails (6.1.4.1)
|
||||||
|
@ -382,7 +387,7 @@ GEM
|
||||||
rails-dom-testing (2.0.3)
|
rails-dom-testing (2.0.3)
|
||||||
activesupport (>= 4.2.0)
|
activesupport (>= 4.2.0)
|
||||||
nokogiri (>= 1.6)
|
nokogiri (>= 1.6)
|
||||||
rails-html-sanitizer (1.4.2)
|
rails-html-sanitizer (1.4.3)
|
||||||
loofah (~> 2.3)
|
loofah (~> 2.3)
|
||||||
railties (6.1.4.1)
|
railties (6.1.4.1)
|
||||||
actionpack (= 6.1.4.1)
|
actionpack (= 6.1.4.1)
|
||||||
|
@ -409,6 +414,7 @@ GEM
|
||||||
mime-types (>= 1.16, < 4.0)
|
mime-types (>= 1.16, < 4.0)
|
||||||
netrc (~> 0.8)
|
netrc (~> 0.8)
|
||||||
rexml (3.2.5)
|
rexml (3.2.5)
|
||||||
|
ruby2_keywords (0.0.5)
|
||||||
rubyzip (2.3.2)
|
rubyzip (2.3.2)
|
||||||
sass-rails (6.0.0)
|
sass-rails (6.0.0)
|
||||||
sassc-rails (~> 2.1, >= 2.1.1)
|
sassc-rails (~> 2.1, >= 2.1.1)
|
||||||
|
@ -444,6 +450,11 @@ GEM
|
||||||
simplecov-html (0.10.2)
|
simplecov-html (0.10.2)
|
||||||
simpleidn (0.2.1)
|
simpleidn (0.2.1)
|
||||||
unf (~> 0.1.4)
|
unf (~> 0.1.4)
|
||||||
|
sinatra (2.2.0)
|
||||||
|
mustermann (~> 1.0)
|
||||||
|
rack (~> 2.2)
|
||||||
|
rack-protection (= 2.2.0)
|
||||||
|
tilt (~> 2.0)
|
||||||
sixarm_ruby_unaccent (1.2.0)
|
sixarm_ruby_unaccent (1.2.0)
|
||||||
socksify (1.7.1)
|
socksify (1.7.1)
|
||||||
sprockets (4.0.2)
|
sprockets (4.0.2)
|
||||||
|
@ -454,13 +465,13 @@ GEM
|
||||||
activesupport (>= 4.0)
|
activesupport (>= 4.0)
|
||||||
sprockets (>= 3.0.0)
|
sprockets (>= 3.0.0)
|
||||||
spy (1.0.1)
|
spy (1.0.1)
|
||||||
swd (1.2.0)
|
swd (1.3.0)
|
||||||
activesupport (>= 3)
|
activesupport (>= 3)
|
||||||
attr_required (>= 0.0.5)
|
attr_required (>= 0.0.5)
|
||||||
httpclient (>= 2.4)
|
httpclient (>= 2.4)
|
||||||
temple (0.8.2)
|
temple (0.8.2)
|
||||||
thor (1.2.1)
|
thor (1.2.1)
|
||||||
tilt (2.0.10)
|
tilt (2.0.11)
|
||||||
truemail (2.4.9)
|
truemail (2.4.9)
|
||||||
simpleidn (~> 0.2.1)
|
simpleidn (~> 0.2.1)
|
||||||
tzinfo (2.0.4)
|
tzinfo (2.0.4)
|
||||||
|
@ -473,10 +484,10 @@ GEM
|
||||||
validate_email (0.1.6)
|
validate_email (0.1.6)
|
||||||
activemodel (>= 3.0)
|
activemodel (>= 3.0)
|
||||||
mail (>= 2.2.5)
|
mail (>= 2.2.5)
|
||||||
validate_url (1.0.13)
|
validate_url (1.0.15)
|
||||||
activemodel (>= 3.0.0)
|
activemodel (>= 3.0.0)
|
||||||
public_suffix
|
public_suffix
|
||||||
validates_email_format_of (1.6.3)
|
validates_email_format_of (1.7.2)
|
||||||
i18n
|
i18n
|
||||||
warden (1.2.9)
|
warden (1.2.9)
|
||||||
rack (>= 2.0.9)
|
rack (>= 2.0.9)
|
||||||
|
@ -488,7 +499,7 @@ GEM
|
||||||
nokogiri (~> 1.6)
|
nokogiri (~> 1.6)
|
||||||
rubyzip (>= 1.3.0)
|
rubyzip (>= 1.3.0)
|
||||||
selenium-webdriver (>= 3.0, < 4.0)
|
selenium-webdriver (>= 3.0, < 4.0)
|
||||||
webfinger (1.1.0)
|
webfinger (1.2.0)
|
||||||
activesupport
|
activesupport
|
||||||
httpclient (>= 2.4)
|
httpclient (>= 2.4)
|
||||||
webmock (3.14.0)
|
webmock (3.14.0)
|
||||||
|
@ -512,7 +523,7 @@ PLATFORMS
|
||||||
DEPENDENCIES
|
DEPENDENCIES
|
||||||
active_interaction (~> 4.0)
|
active_interaction (~> 4.0)
|
||||||
airbrake
|
airbrake
|
||||||
apipie-rails (~> 0.5.19)
|
apipie-rails (~> 0.6.0)
|
||||||
aws-sdk-sesv2 (~> 1.19)
|
aws-sdk-sesv2 (~> 1.19)
|
||||||
bootsnap (>= 1.1.0)
|
bootsnap (>= 1.1.0)
|
||||||
bootstrap-sass (~> 3.4)
|
bootstrap-sass (~> 3.4)
|
||||||
|
@ -533,11 +544,12 @@ DEPENDENCIES
|
||||||
epp!
|
epp!
|
||||||
epp-xml (= 1.2.0)!
|
epp-xml (= 1.2.0)!
|
||||||
figaro (~> 1.2)
|
figaro (~> 1.2)
|
||||||
haml (~> 5.2)
|
haml (~> 6.0)
|
||||||
isikukood
|
isikukood
|
||||||
iso8601 (= 0.13.0)
|
iso8601 (= 0.13.0)
|
||||||
jquery-rails
|
jquery-rails
|
||||||
jquery-ui-rails (= 6.0.1)
|
jquery-ui-rails (= 6.0.1)
|
||||||
|
jwt
|
||||||
kaminari
|
kaminari
|
||||||
lhv!
|
lhv!
|
||||||
mime-types-data
|
mime-types-data
|
||||||
|
@ -547,12 +559,11 @@ DEPENDENCIES
|
||||||
newrelic-infinite_tracing
|
newrelic-infinite_tracing
|
||||||
newrelic_rpm
|
newrelic_rpm
|
||||||
nokogiri (~> 1.13.0)
|
nokogiri (~> 1.13.0)
|
||||||
omniauth
|
|
||||||
omniauth-rails_csrf_protection
|
omniauth-rails_csrf_protection
|
||||||
omniauth-tara!
|
omniauth-tara!
|
||||||
paper_trail (~> 12.1)
|
paper_trail (~> 12.1)
|
||||||
pdfkit
|
pdfkit
|
||||||
pg (= 1.3.5)
|
pg (= 1.4.3)
|
||||||
pg_query (>= 0.9.0)
|
pg_query (>= 0.9.0)
|
||||||
pghero
|
pghero
|
||||||
pry (= 0.14.1)
|
pry (= 0.14.1)
|
||||||
|
@ -570,11 +581,11 @@ DEPENDENCIES
|
||||||
spy
|
spy
|
||||||
truemail (~> 2.4)
|
truemail (~> 2.4)
|
||||||
uglifier
|
uglifier
|
||||||
validates_email_format_of (= 1.6.3)
|
validates_email_format_of (= 1.7.2)
|
||||||
webdrivers
|
webdrivers
|
||||||
webmock
|
webmock
|
||||||
whenever (= 1.0.0)
|
whenever (= 1.0.0)
|
||||||
wkhtmltopdf-binary (~> 0.12.5.1)
|
wkhtmltopdf-binary (~> 0.12.5.1)
|
||||||
|
|
||||||
BUNDLED WITH
|
BUNDLED WITH
|
||||||
2.3.10
|
2.3.21
|
||||||
|
|
BIN
app/assets/images/everypay.png
Normal file
BIN
app/assets/images/everypay.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 15 KiB |
|
@ -1,11 +0,0 @@
|
||||||
//= require 'registrant/registrant-bootstrap'
|
|
||||||
//= require 'jquery-ui/datepicker'
|
|
||||||
//= require 'select2'
|
|
||||||
//= require 'select2-bootstrap'
|
|
||||||
@import shared/fonts
|
|
||||||
@import shared/general
|
|
||||||
@import forms
|
|
||||||
@import typeaheadjs
|
|
||||||
@import selectize
|
|
||||||
@import selectize.bootstrap3
|
|
||||||
@import registrant/registrant
|
|
|
@ -1,19 +0,0 @@
|
||||||
$brand-primary: #7EA82F
|
|
||||||
$navbar-default-bg: #7EA82F
|
|
||||||
$navbar-default-brand-color: #fff
|
|
||||||
$navbar-default-link-color: #fff
|
|
||||||
$border-radius-base: 2px
|
|
||||||
$body-bg: #F8F8F8
|
|
||||||
$container-large-desktop: 1040px
|
|
||||||
$font-family-sans-serif: 'EtelkaLightProRegular', Arial, Helvetica, sans-serif
|
|
||||||
$font-family-serif: 'EtelkaLightProBold', Georgia, "Times New Roman", Times, serif
|
|
||||||
$font-size-h1: 26px
|
|
||||||
$navbar-default-link-active-color: #333
|
|
||||||
|
|
||||||
@import 'bootstrap-sprockets'
|
|
||||||
@import 'bootstrap'
|
|
||||||
@import 'shared/general-bootstrap'
|
|
||||||
|
|
||||||
// Support rails error element
|
|
||||||
.field_with_errors
|
|
||||||
@extend .has-error
|
|
|
@ -1,44 +0,0 @@
|
||||||
html
|
|
||||||
position: relative
|
|
||||||
min-height: 100%
|
|
||||||
overflow-y: scroll
|
|
||||||
|
|
||||||
body
|
|
||||||
padding-bottom: 130px
|
|
||||||
|
|
||||||
body > .container
|
|
||||||
height: 100%
|
|
||||||
background: #fff
|
|
||||||
padding: 60px 30px 30px 30px
|
|
||||||
|
|
||||||
h1, h2, h3, h4
|
|
||||||
margin-bottom: 0px !important
|
|
||||||
|
|
||||||
// Commented out, default 20px is needed on forms
|
|
||||||
// hr
|
|
||||||
// margin-top: 10px !important
|
|
||||||
// margin-bottom: 10px !important
|
|
||||||
|
|
||||||
.navbar li
|
|
||||||
font-weight: bold
|
|
||||||
|
|
||||||
.footer
|
|
||||||
position: absolute
|
|
||||||
bottom: 0
|
|
||||||
width: 100%
|
|
||||||
height: 130px
|
|
||||||
background: image_url('bg.jpg')
|
|
||||||
color: white !important
|
|
||||||
background-size: 100%
|
|
||||||
|
|
||||||
.confirmation
|
|
||||||
padding: 40px 0 20px 0
|
|
||||||
.column-keys
|
|
||||||
text-align: right
|
|
||||||
width: 49%
|
|
||||||
float: left
|
|
||||||
.column-values
|
|
||||||
float: right
|
|
||||||
font-weight: bold
|
|
||||||
text-align: left
|
|
||||||
width: 49%
|
|
142
app/controllers/admin/auctions_controller.rb
Normal file
142
app/controllers/admin/auctions_controller.rb
Normal file
|
@ -0,0 +1,142 @@
|
||||||
|
module Admin
|
||||||
|
class AuctionsController < BaseController
|
||||||
|
load_and_authorize_resource
|
||||||
|
|
||||||
|
def index
|
||||||
|
params[:q] ||= {}
|
||||||
|
|
||||||
|
@auctions = Auction.with_domain_name(params[:domain_matches])
|
||||||
|
.with_status(params[:statuses_contains])
|
||||||
|
.with_start_created_at_date(params[:created_at_start])
|
||||||
|
.with_end_created_at_date(params[:created_at_end])
|
||||||
|
.order(created_at: :desc)
|
||||||
|
|
||||||
|
@auction = Auction.new
|
||||||
|
|
||||||
|
normalize_search_parameters do
|
||||||
|
@q = @auctions.ransack(PartialSearchFormatter.format(params[:q]))
|
||||||
|
@auctions = @q.result.page(params[:page])
|
||||||
|
end
|
||||||
|
|
||||||
|
@auctions = @auctions.per(params[:results_per_page_auction]) if params[:results_per_page_auction].to_i.positive?
|
||||||
|
|
||||||
|
domains = ReservedDomain.all.order(:name)
|
||||||
|
q = domains.ransack(PartialSearchFormatter.format(params[:q]))
|
||||||
|
@domains = q.result.page(params[:page])
|
||||||
|
@domains = @domains.per(params[:results_per_page]) if params[:results_per_page].to_i.positive?
|
||||||
|
|
||||||
|
render_by_format('admin/auctions/index', 'auctions')
|
||||||
|
end
|
||||||
|
|
||||||
|
def create
|
||||||
|
auction = Auction.new(domain: params[:domain], status: Auction.statuses[:started], platform: 'manual')
|
||||||
|
|
||||||
|
if domain_exists_in_blocked_disputed_and_registered?(params[:domain])
|
||||||
|
flash[:alert] = "Adding #{params[:domain]} failed - domain registered or regsitration is blocked"
|
||||||
|
redirect_to admin_auctions_path and return
|
||||||
|
end
|
||||||
|
|
||||||
|
result = check_availability(params[:domain])[0]
|
||||||
|
if result[:avail].zero?
|
||||||
|
flash[:alert] = "Cannot generate domain. Reason: #{result[:reason]}"
|
||||||
|
redirect_to admin_auctions_path and return
|
||||||
|
end
|
||||||
|
|
||||||
|
if auction.save
|
||||||
|
reserved_domain = auction.domain if remove_from_reserved(auction)
|
||||||
|
flash[:notice] = "Auction #{params[:domain]} created.
|
||||||
|
#{reserved_domain.present? ? 'These domain will be removed from reserved list: ' + reserved_domain : ' '}"
|
||||||
|
else
|
||||||
|
flash[:alert] = 'Something goes wrong'
|
||||||
|
end
|
||||||
|
|
||||||
|
redirect_to admin_auctions_path
|
||||||
|
end
|
||||||
|
|
||||||
|
def upload_spreadsheet
|
||||||
|
if params[:q].nil?
|
||||||
|
flash[:alert] = 'No file upload! Look at the left of upload button!'
|
||||||
|
redirect_to admin_auctions_path and return
|
||||||
|
end
|
||||||
|
|
||||||
|
filename = params[:q][:file]
|
||||||
|
table = CSV.parse(File.read(filename), headers: true)
|
||||||
|
|
||||||
|
failed_names = []
|
||||||
|
reserved_domains = []
|
||||||
|
|
||||||
|
if validate_table(table)
|
||||||
|
table.each do |row|
|
||||||
|
record = row.to_h
|
||||||
|
|
||||||
|
if domain_exists_in_blocked_disputed_and_registered?(record['name'])
|
||||||
|
failed_names << record['name']
|
||||||
|
|
||||||
|
next
|
||||||
|
end
|
||||||
|
|
||||||
|
result = check_availability(record['name'])[0]
|
||||||
|
if result[:avail].zero?
|
||||||
|
failed_names << record['name']
|
||||||
|
|
||||||
|
next
|
||||||
|
end
|
||||||
|
|
||||||
|
auction = Auction.new(domain: record['name'], status: Auction.statuses[:started], platform: 'manual')
|
||||||
|
flag = remove_from_reserved(auction) if auction.save!
|
||||||
|
reserved_domains << auction.domain if flag
|
||||||
|
end
|
||||||
|
|
||||||
|
message_template = "Domains added!
|
||||||
|
#{reserved_domains.present? ?
|
||||||
|
'These domains will be removed from reserved list: ' + reserved_domains.join(' ') + '! '
|
||||||
|
: '! '}
|
||||||
|
#{failed_names.present? ? 'These domains were ignored: ' + failed_names.join(' ') : '!'}"
|
||||||
|
|
||||||
|
flash[:notice] = message_template
|
||||||
|
else
|
||||||
|
flash[:alert] = "Invalid CSV format. Should be column with 'name' where is the list of name of domains!"
|
||||||
|
end
|
||||||
|
|
||||||
|
redirect_to admin_auctions_path
|
||||||
|
end
|
||||||
|
|
||||||
|
private
|
||||||
|
|
||||||
|
def check_availability(domain_name)
|
||||||
|
Epp::Domain.check_availability(domain_name)
|
||||||
|
end
|
||||||
|
|
||||||
|
def domain_exists_in_blocked_disputed_and_registered?(domain_name)
|
||||||
|
Domain.exists?(name: domain_name) ||
|
||||||
|
BlockedDomain.exists?(name: domain_name) ||
|
||||||
|
Dispute.exists?(domain_name: domain_name) ||
|
||||||
|
Auction.exists?(domain: domain_name)
|
||||||
|
end
|
||||||
|
|
||||||
|
def validate_table(table)
|
||||||
|
first_row = table.headers
|
||||||
|
first_row.include? 'name'
|
||||||
|
end
|
||||||
|
|
||||||
|
def remove_from_reserved(auction)
|
||||||
|
domain = ReservedDomain.find_by(name: auction.domain)
|
||||||
|
|
||||||
|
domain.destroy if domain.present?
|
||||||
|
end
|
||||||
|
|
||||||
|
def normalize_search_parameters
|
||||||
|
ca_cache = params[:q][:valid_to_lteq]
|
||||||
|
begin
|
||||||
|
end_time = params[:q][:valid_to_lteq].try(:to_date)
|
||||||
|
params[:q][:valid_to_lteq] = end_time.try(:end_of_day)
|
||||||
|
rescue
|
||||||
|
logger.warn('Invalid date')
|
||||||
|
end
|
||||||
|
|
||||||
|
yield
|
||||||
|
|
||||||
|
params[:q][:valid_to_lteq] = ca_cache
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
|
@ -32,7 +32,6 @@ module Admin
|
||||||
contacts = contacts.where("ident_country_code is null or ident_country_code=''")
|
contacts = contacts.where("ident_country_code is null or ident_country_code=''")
|
||||||
end
|
end
|
||||||
|
|
||||||
contacts = contacts.email_verification_failed if params[:email_verification_failed].eql?('1')
|
|
||||||
contacts
|
contacts
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
@ -13,6 +13,7 @@ module Admin
|
||||||
|
|
||||||
if @invoice&.persisted?
|
if @invoice&.persisted?
|
||||||
flash[:notice] = t(:record_created)
|
flash[:notice] = t(:record_created)
|
||||||
|
# send_invoice_data_to_billing_system
|
||||||
redirect_to [:admin, @invoice]
|
redirect_to [:admin, @invoice]
|
||||||
else
|
else
|
||||||
flash.now[:alert] = t(:failed_to_create_record)
|
flash.now[:alert] = t(:failed_to_create_record)
|
||||||
|
@ -48,6 +49,8 @@ module Admin
|
||||||
|
|
||||||
def cancel
|
def cancel
|
||||||
@invoice.cancel
|
@invoice.cancel
|
||||||
|
EisBilling::SendInvoiceStatus.send_info(invoice_number: @invoice.number, status: 'cancelled')
|
||||||
|
|
||||||
redirect_to [:admin, @invoice], notice: t('.cancelled')
|
redirect_to [:admin, @invoice], notice: t('.cancelled')
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -78,18 +81,24 @@ module Admin
|
||||||
payment_order.update(notes: 'Cancelled')
|
payment_order.update(notes: 'Cancelled')
|
||||||
end
|
end
|
||||||
|
|
||||||
|
# rubocop:disable Metrics/MethodLength
|
||||||
def filter_by_status
|
def filter_by_status
|
||||||
case params[:status]
|
case params[:status]
|
||||||
when 'Paid'
|
when 'Paid'
|
||||||
Invoice.includes(:account_activity, :buyer).where.not(account_activity: { id: nil })
|
Invoice.includes(:account_activity, :buyer).where.not(account_activity: { id: nil })
|
||||||
when 'Unpaid'
|
when 'Unpaid'
|
||||||
Invoice.includes(:account_activity, :buyer).where(account_activity: { id: nil })
|
Invoice.includes(:account_activity, :buyer).where(account_activity: { id: nil },
|
||||||
|
cancelled_at: nil,
|
||||||
|
monthly_invoice: false)
|
||||||
when 'Cancelled'
|
when 'Cancelled'
|
||||||
Invoice.includes(:account_activity, :buyer).where.not(cancelled_at: nil)
|
Invoice.includes(:account_activity, :buyer).where.not(cancelled_at: nil)
|
||||||
|
when 'Monthly'
|
||||||
|
Invoice.where(monthly_invoice: true, cancelled_at: nil)
|
||||||
else
|
else
|
||||||
Invoice.includes(:account_activity, :buyer)
|
Invoice.includes(:account_activity, :buyer)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
# rubocop:enable Metrics/MethodLength
|
||||||
|
|
||||||
def filter_by_receipt_date(invoices)
|
def filter_by_receipt_date(invoices)
|
||||||
date_from_param = params[:q][:receipt_date_gteq] if params[:q][:receipt_date_gteq].present?
|
date_from_param = params[:q][:receipt_date_gteq] if params[:q][:receipt_date_gteq].present?
|
||||||
|
|
|
@ -51,8 +51,26 @@ module Admin
|
||||||
redirect_to admin_reserved_domains_path
|
redirect_to admin_reserved_domains_path
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def release_to_auction
|
||||||
|
redirect_to admin_reserved_domains_path and return if params[:reserved_elements].nil?
|
||||||
|
|
||||||
|
reserved_domains_ids = params[:reserved_elements][:domain_ids]
|
||||||
|
reserved_domains = ReservedDomain.where(id: reserved_domains_ids)
|
||||||
|
|
||||||
|
reserved_domains.each do |domain|
|
||||||
|
Auction.create!(domain: domain.name, status: Auction.statuses[:started], platform: 'manual')
|
||||||
|
domain.destroy!
|
||||||
|
end
|
||||||
|
|
||||||
|
redirect_to admin_auctions_path
|
||||||
|
end
|
||||||
|
|
||||||
private
|
private
|
||||||
|
|
||||||
|
def reserved_checked_elements
|
||||||
|
# params.require(:reserved_elements).permit(:name, :password)
|
||||||
|
end
|
||||||
|
|
||||||
def reserved_domain_params
|
def reserved_domain_params
|
||||||
params.require(:reserved_domain).permit(:name, :password)
|
params.require(:reserved_domain).permit(:name, :password)
|
||||||
end
|
end
|
||||||
|
|
|
@ -44,7 +44,7 @@ module Api
|
||||||
private
|
private
|
||||||
|
|
||||||
def serializable_hash(auction)
|
def serializable_hash(auction)
|
||||||
{ id: auction.uuid, domain: auction.domain, status: auction.status }
|
{ id: auction.uuid, domain: auction.domain, status: auction.status, platform: auction.platform }
|
||||||
end
|
end
|
||||||
|
|
||||||
def serializable_hash_for_update_action(auction)
|
def serializable_hash_for_update_action(auction)
|
||||||
|
|
52
app/controllers/eis_billing/base_controller.rb
Normal file
52
app/controllers/eis_billing/base_controller.rb
Normal file
|
@ -0,0 +1,52 @@
|
||||||
|
module EisBilling
|
||||||
|
class BaseController < ApplicationController
|
||||||
|
protect_from_forgery with: :null_session
|
||||||
|
skip_authorization_check # Temporary solution
|
||||||
|
# skip_before_action :verify_authenticity_token # Temporary solution
|
||||||
|
before_action :authorized
|
||||||
|
|
||||||
|
INITIATOR = 'billing'.freeze
|
||||||
|
|
||||||
|
def encode_token(payload)
|
||||||
|
JWT.encode(payload, ENV['secret_word'])
|
||||||
|
end
|
||||||
|
|
||||||
|
def auth_header
|
||||||
|
# { Authorization: 'Bearer <token>' }
|
||||||
|
request.headers['Authorization']
|
||||||
|
end
|
||||||
|
|
||||||
|
def decoded_token
|
||||||
|
return unless auth_header
|
||||||
|
|
||||||
|
token = auth_header.split(' ')[1]
|
||||||
|
begin
|
||||||
|
JWT.decode(token, billing_secret_key, true, algorithm: 'HS256')
|
||||||
|
rescue JWT::DecodeError
|
||||||
|
nil
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def accessable_service
|
||||||
|
return decoded_token[0]['initiator'] == INITIATOR if decoded_token
|
||||||
|
|
||||||
|
false
|
||||||
|
end
|
||||||
|
|
||||||
|
def logged_in?
|
||||||
|
!!accessable_service
|
||||||
|
end
|
||||||
|
|
||||||
|
def authorized
|
||||||
|
render json: { message: 'Access denied' }, status: :unauthorized unless logged_in?
|
||||||
|
end
|
||||||
|
|
||||||
|
def billing_secret_key
|
||||||
|
ENV['billing_secret']
|
||||||
|
end
|
||||||
|
|
||||||
|
def logger
|
||||||
|
Rails.logger
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
36
app/controllers/eis_billing/directo_response_controller.rb
Normal file
36
app/controllers/eis_billing/directo_response_controller.rb
Normal file
|
@ -0,0 +1,36 @@
|
||||||
|
class EisBilling::DirectoResponseController < EisBilling::BaseController
|
||||||
|
def update
|
||||||
|
response = params[:response]
|
||||||
|
xml_data = params[:xml_data]
|
||||||
|
@month = params.fetch(:month, false)
|
||||||
|
|
||||||
|
process_directo_response(xml_data, response)
|
||||||
|
render status: :ok, json: { messege: 'Should return new directo number' }
|
||||||
|
end
|
||||||
|
|
||||||
|
private
|
||||||
|
|
||||||
|
def process_directo_response(xml, req)
|
||||||
|
Rails.logger.info "[Directo] - Responded with body: #{xml}"
|
||||||
|
Nokogiri::XML(req).css('Result').each do |res|
|
||||||
|
if @month
|
||||||
|
mark_invoice_as_sent(res: res, req: req)
|
||||||
|
else
|
||||||
|
inv = Invoice.find_by(number: res.attributes['docid'].value.to_i)
|
||||||
|
|
||||||
|
mark_invoice_as_sent(invoice: inv, res: res, req: req)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def mark_invoice_as_sent(invoice: nil, res:, req:)
|
||||||
|
directo_record = Directo.new(response: res.as_json.to_h,
|
||||||
|
request: req, invoice_number: res.attributes['docid'].value.to_i)
|
||||||
|
if invoice
|
||||||
|
directo_record.item = invoice
|
||||||
|
invoice.update(in_directo: true)
|
||||||
|
end
|
||||||
|
|
||||||
|
directo_record.save!
|
||||||
|
end
|
||||||
|
end
|
15
app/controllers/eis_billing/e_invoice_response_controller.rb
Normal file
15
app/controllers/eis_billing/e_invoice_response_controller.rb
Normal file
|
@ -0,0 +1,15 @@
|
||||||
|
class EisBilling::EInvoiceResponseController < EisBilling::BaseController
|
||||||
|
def update
|
||||||
|
invoice_number = params[:invoice_number]
|
||||||
|
|
||||||
|
mark_e_invoice_sent_at(invoice_number)
|
||||||
|
render status: :ok, json: { message: 'Response received' }
|
||||||
|
end
|
||||||
|
|
||||||
|
private
|
||||||
|
|
||||||
|
def mark_e_invoice_sent_at(invoice_number)
|
||||||
|
invoice = Invoice.find_by(number: invoice_number)
|
||||||
|
invoice.update(e_invoice_sent_at: Time.zone.now)
|
||||||
|
end
|
||||||
|
end
|
|
@ -0,0 +1,54 @@
|
||||||
|
module EisBilling
|
||||||
|
class LhvConnectTransactionsController < EisBilling::BaseController
|
||||||
|
def create
|
||||||
|
if params['_json'].nil? || params['_json'].empty?
|
||||||
|
render json: { message: 'MISSING PARAMS' }, status: :unprocessable_entity
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
|
bank_statement = BankStatement.create(bank_code: Setting.registry_bank_code,
|
||||||
|
iban: Setting.registry_iban)
|
||||||
|
|
||||||
|
params['_json'].each do |incoming_transaction|
|
||||||
|
process_transactions(incoming_transaction, bank_statement)
|
||||||
|
end
|
||||||
|
|
||||||
|
render status: :ok, json: { message: 'RECEIVED', params: params }
|
||||||
|
end
|
||||||
|
|
||||||
|
private
|
||||||
|
|
||||||
|
def process_transactions(incoming_transaction, bank_statement)
|
||||||
|
logger.info 'Got incoming transactions'
|
||||||
|
logger.info incoming_transaction
|
||||||
|
|
||||||
|
ActiveRecord::Base.transaction do
|
||||||
|
transaction = bank_statement.bank_transactions
|
||||||
|
.create!(transaction_attributes(incoming_transaction))
|
||||||
|
|
||||||
|
next if transaction.registrar.blank?
|
||||||
|
|
||||||
|
create_invoice_if_missing(transaction) unless transaction.non_canceled?
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def create_invoice_if_missing(transaction)
|
||||||
|
Invoice.create_from_transaction!(transaction) unless transaction.autobindable?
|
||||||
|
invoice = transaction.autobind_invoice
|
||||||
|
return unless invoice.paid?
|
||||||
|
|
||||||
|
EisBilling::SendInvoiceStatus.send_info(invoice_number: invoice.number,
|
||||||
|
status: 'paid')
|
||||||
|
end
|
||||||
|
|
||||||
|
def transaction_attributes(incoming_transaction)
|
||||||
|
{
|
||||||
|
sum: incoming_transaction['amount'],
|
||||||
|
currency: incoming_transaction['currency'],
|
||||||
|
paid_at: incoming_transaction['date'],
|
||||||
|
reference_no: incoming_transaction['payment_reference_number'],
|
||||||
|
description: incoming_transaction['payment_description'],
|
||||||
|
}
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
57
app/controllers/eis_billing/payment_status_controller.rb
Normal file
57
app/controllers/eis_billing/payment_status_controller.rb
Normal file
|
@ -0,0 +1,57 @@
|
||||||
|
module EisBilling
|
||||||
|
class PaymentStatusController < EisBilling::BaseController
|
||||||
|
TYPE = 'PaymentOrders::EveryPay'.freeze
|
||||||
|
|
||||||
|
def update
|
||||||
|
payment_status = define_payment_status(params[:payment_state])
|
||||||
|
invoice = Invoice.find_by(number: params[:order_reference])
|
||||||
|
|
||||||
|
return if invoice.paid?
|
||||||
|
|
||||||
|
bank = create_bank_transfer(invoice: invoice, sum: params[:standing_amount], paid_at: params[:transaction_time])
|
||||||
|
create_payment_order(invoice: invoice, everypay_response: params, payment_status: payment_status)
|
||||||
|
|
||||||
|
registrar = invoice.buyer
|
||||||
|
bank.create_activity(registrar, invoice)
|
||||||
|
|
||||||
|
respond_to do |format|
|
||||||
|
format.json do
|
||||||
|
render status: :ok, content_type: 'application/json', layout: false, json: { message: 'ok' }
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
private
|
||||||
|
|
||||||
|
def define_payment_status(status)
|
||||||
|
return :paid if PaymentOrders::EveryPay::SUCCESSFUL_PAYMENT.include? status
|
||||||
|
|
||||||
|
:failed
|
||||||
|
end
|
||||||
|
|
||||||
|
def create_payment_order(invoice:, everypay_response:, payment_status:)
|
||||||
|
payment = PaymentOrder.new
|
||||||
|
payment.type = TYPE
|
||||||
|
payment.invoice = invoice
|
||||||
|
payment.response = everypay_response
|
||||||
|
payment.status = payment_status
|
||||||
|
payment.save
|
||||||
|
|
||||||
|
payment
|
||||||
|
end
|
||||||
|
|
||||||
|
def create_bank_transfer(invoice:, sum:, paid_at:)
|
||||||
|
bank = BankTransaction.new
|
||||||
|
bank.description = invoice.order
|
||||||
|
bank.reference_no = invoice.reference_no
|
||||||
|
bank.currency = invoice.currency
|
||||||
|
bank.iban = invoice.seller_iban
|
||||||
|
bank.sum = sum
|
||||||
|
bank.paid_at = paid_at
|
||||||
|
bank.buyer_name = invoice.buyer_name
|
||||||
|
bank.save
|
||||||
|
|
||||||
|
bank
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
|
@ -168,7 +168,7 @@ module Epp
|
||||||
|
|
||||||
epp_errors.add(:epp_errors,
|
epp_errors.add(:epp_errors,
|
||||||
code: '2003',
|
code: '2003',
|
||||||
message: I18n.t('errors.messages.required_parameter_missing',
|
msg: I18n.t('errors.messages.required_parameter_missing',
|
||||||
key: "#{full_selector} [#{attr}]"))
|
key: "#{full_selector} [#{attr}]"))
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
@ -1,37 +0,0 @@
|
||||||
class RegistrantController < ApplicationController
|
|
||||||
before_action :authenticate_registrant_user!
|
|
||||||
before_action :set_paper_trail_whodunnit
|
|
||||||
layout 'registrant/application'
|
|
||||||
|
|
||||||
include Registrant::ApplicationHelper
|
|
||||||
|
|
||||||
helper_method :head_title_sufix
|
|
||||||
|
|
||||||
def head_title_sufix
|
|
||||||
t(:registrant_head_title_sufix)
|
|
||||||
end
|
|
||||||
|
|
||||||
private
|
|
||||||
|
|
||||||
def current_ability
|
|
||||||
@current_ability ||= Ability.new(current_registrant_user, request.remote_ip)
|
|
||||||
end
|
|
||||||
|
|
||||||
def user_for_paper_trail
|
|
||||||
current_registrant_user.present? ? current_registrant_user.id_role_username : 'anonymous'
|
|
||||||
end
|
|
||||||
|
|
||||||
def current_user_contacts
|
|
||||||
current_registrant_user.contacts
|
|
||||||
rescue CompanyRegister::NotAvailableError
|
|
||||||
flash.now[:notice] = t('registrant.company_register_unavailable')
|
|
||||||
current_registrant_user.direct_contacts
|
|
||||||
end
|
|
||||||
|
|
||||||
def current_user_domains
|
|
||||||
current_registrant_user.domains
|
|
||||||
rescue CompanyRegister::NotAvailableError
|
|
||||||
flash.now[:notice] = t('registrant.company_register_unavailable')
|
|
||||||
current_registrant_user.direct_domains
|
|
||||||
end
|
|
||||||
end
|
|
|
@ -36,14 +36,12 @@ class Registrar
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
@domains = @domains.per(params[:results_per_page]) if params[:results_per_page].to_i.positive?
|
|
||||||
|
|
||||||
respond_to do |format|
|
respond_to do |format|
|
||||||
format.html
|
format.html
|
||||||
format.csv do
|
format.csv do
|
||||||
domain_presenters = []
|
domain_presenters = []
|
||||||
|
|
||||||
@domains.find_each do |domain|
|
@q.result.find_each do |domain|
|
||||||
domain_presenters << ::DomainPresenter.new(domain: domain, view: view_context)
|
domain_presenters << ::DomainPresenter.new(domain: domain, view: view_context)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -88,14 +86,16 @@ class Registrar
|
||||||
@domain_params[:period] = Depp::Domain.default_period
|
@domain_params[:period] = Depp::Domain.default_period
|
||||||
end
|
end
|
||||||
|
|
||||||
|
# rubocop:disable Metrics/CognitiveComplexity
|
||||||
def create
|
def create
|
||||||
authorize! :create, Depp::Domain
|
authorize! :create, Depp::Domain
|
||||||
@domain_params = domain_params.to_h
|
@domain_params = domain_params.to_h
|
||||||
@data = @domain.create(@domain_params)
|
@data = @domain.create(@domain_params)
|
||||||
|
|
||||||
if response_ok?
|
if @data && response_ok?
|
||||||
redirect_to info_registrar_domains_url(domain_name: @domain_params[:name])
|
redirect_to info_registrar_domains_url(domain_name: @domain_params[:name])
|
||||||
else
|
else
|
||||||
|
flash[:alert] = t('.email_error_message') unless @emails_check_result
|
||||||
render 'new'
|
render 'new'
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
@ -113,13 +113,15 @@ class Registrar
|
||||||
@data = @domain.update(@domain_params)
|
@data = @domain.update(@domain_params)
|
||||||
@dispute = Dispute.active.find_by(domain_name: @domain_params[:name])
|
@dispute = Dispute.active.find_by(domain_name: @domain_params[:name])
|
||||||
|
|
||||||
if response_ok?
|
if @data && response_ok?
|
||||||
redirect_to info_registrar_domains_url(domain_name: @domain_params[:name])
|
redirect_to info_registrar_domains_url(domain_name: @domain_params[:name])
|
||||||
else
|
else
|
||||||
|
flash[:alert] = t('.email_error_message') unless @emails_check_result
|
||||||
params[:domain_name] = @domain_params[:name]
|
params[:domain_name] = @domain_params[:name]
|
||||||
render 'new'
|
render 'new'
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
# rubocop:enable Metrics/CognitiveComplexity
|
||||||
|
|
||||||
def delete
|
def delete
|
||||||
authorize! :delete, Depp::Domain
|
authorize! :delete, Depp::Domain
|
||||||
|
|
|
@ -17,6 +17,8 @@ class Registrar
|
||||||
|
|
||||||
def cancel
|
def cancel
|
||||||
@invoice.cancel
|
@invoice.cancel
|
||||||
|
EisBilling::SendInvoiceStatus.send_info(invoice_number: @invoice.number, status: 'cancelled')
|
||||||
|
|
||||||
redirect_to [:registrar, @invoice], notice: t('.cancelled')
|
redirect_to [:registrar, @invoice], notice: t('.cancelled')
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
@ -1,32 +1,164 @@
|
||||||
module Repp
|
module Repp
|
||||||
module V1
|
module V1
|
||||||
class AccountsController < BaseController
|
class AccountsController < BaseController # rubocop:disable Metrics/ClassLength
|
||||||
api :GET, '/repp/v1/accounts/balance'
|
load_and_authorize_resource
|
||||||
|
|
||||||
|
api :get, '/repp/v1/accounts'
|
||||||
|
desc 'Get all activities'
|
||||||
|
def index
|
||||||
|
records = current_user.registrar.cash_account.activities
|
||||||
|
|
||||||
|
q = records.ransack(PartialSearchFormatter.format(search_params))
|
||||||
|
q.sorts = 'created_at desc' if q.sorts.empty?
|
||||||
|
activities = q.result(distinct: true)
|
||||||
|
|
||||||
|
limited_activities = activities.limit(limit).offset(offset)
|
||||||
|
.includes(:invoice)
|
||||||
|
|
||||||
|
render_success(data: { activities: serialized_activities(limited_activities),
|
||||||
|
count: activities.count,
|
||||||
|
types_for_select: AccountActivity.types_for_select })
|
||||||
|
end
|
||||||
|
|
||||||
|
api :get, '/repp/v1/accounts/details'
|
||||||
|
desc 'Get current registrar account details'
|
||||||
|
def details
|
||||||
|
registrar = current_user.registrar
|
||||||
|
type = registrar.settings['balance_auto_reload']&.dig('type')
|
||||||
|
resp = { account: { billing_email: registrar.billing_email,
|
||||||
|
iban: registrar.iban,
|
||||||
|
iban_max_length: Iban.max_length,
|
||||||
|
linked_users: serialized_users(current_user.linked_users),
|
||||||
|
balance_auto_reload: type,
|
||||||
|
min_deposit: Setting.minimum_deposit } }
|
||||||
|
render_success(data: resp)
|
||||||
|
end
|
||||||
|
|
||||||
|
api :put, '/repp/v1/accounts'
|
||||||
|
desc 'Update current registrar account details'
|
||||||
|
def update
|
||||||
|
registrar = current_user.registrar
|
||||||
|
unless registrar.update(account_params)
|
||||||
|
handle_non_epp_errors(registrar)
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
|
render_success(data: { account: account_params },
|
||||||
|
message: I18n.t('registrar.account.update.saved'))
|
||||||
|
end
|
||||||
|
|
||||||
|
api :post, '/repp/v1/accounts/update_auto_reload_balance'
|
||||||
|
desc 'Enable current registrar balance auto reload'
|
||||||
|
def update_auto_reload_balance
|
||||||
|
type = BalanceAutoReloadTypes::Threshold.new(type_params)
|
||||||
|
unless type.valid?
|
||||||
|
handle_non_epp_errors(type)
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
|
settings = { balance_auto_reload: { type: type.as_json } }
|
||||||
|
current_user.registrar.update!(settings: settings)
|
||||||
|
render_success(data: { settings: settings },
|
||||||
|
message: I18n.t('registrar.settings.balance_auto_reload.update.saved'))
|
||||||
|
end
|
||||||
|
|
||||||
|
api :get, '/repp/v1/accounts/disable_auto_reload_balance'
|
||||||
|
desc 'Disable current registrar balance auto reload'
|
||||||
|
def disable_auto_reload_balance
|
||||||
|
registrar = current_user.registrar
|
||||||
|
registrar.settings.delete('balance_auto_reload')
|
||||||
|
registrar.save!
|
||||||
|
|
||||||
|
render_success(data: { settings: registrar.settings },
|
||||||
|
message: I18n.t('registrar.settings.balance_auto_reload.destroy.disabled'))
|
||||||
|
end
|
||||||
|
|
||||||
|
api :put, '/repp/v1/accounts/switch_user'
|
||||||
|
desc 'Switch user to another api user'
|
||||||
|
def switch_user
|
||||||
|
new_user = ApiUser.find(account_params[:new_user_id])
|
||||||
|
unless current_user.linked_with?(new_user)
|
||||||
|
handle_non_epp_errors(new_user, 'Cannot switch to unlinked user')
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
|
@current_user = new_user
|
||||||
|
data = auth_values_to_data(registrar: current_user.registrar)
|
||||||
|
message = I18n.t('registrar.current_user.switch.switched', new_user: new_user)
|
||||||
|
token = Base64.urlsafe_encode64("#{new_user.username}:#{new_user.plain_text_password}")
|
||||||
|
render_success(data: { token: token, registrar: data }, message: message)
|
||||||
|
end
|
||||||
|
|
||||||
|
api :get, '/repp/v1/accounts/balance'
|
||||||
desc "Get account's balance"
|
desc "Get account's balance"
|
||||||
def balance
|
def balance
|
||||||
resp = { balance: current_user.registrar.cash_account.balance,
|
resp = { balance: current_user.registrar.cash_account.balance,
|
||||||
currency: current_user.registrar.cash_account.currency }
|
currency: current_user.registrar.cash_account.currency }
|
||||||
resp[:transactions] = activities if params[:detailed] == 'true'
|
if params[:detailed] == 'true'
|
||||||
|
activities = current_user.registrar.cash_account.activities.order(created_at: :desc)
|
||||||
|
activities = activities.where('created_at >= ?', params[:from]) if params[:from]
|
||||||
|
activities = activities.where('created_at <= ?', params[:until]) if params[:until]
|
||||||
|
resp[:transactions] = serialized_activities(activities)
|
||||||
|
end
|
||||||
render_success(data: resp)
|
render_success(data: resp)
|
||||||
end
|
end
|
||||||
|
|
||||||
def activities
|
private
|
||||||
|
|
||||||
|
def account_params
|
||||||
|
params.require(:account).permit(:billing_email, :iban, :new_user_id)
|
||||||
|
end
|
||||||
|
|
||||||
|
def index_params
|
||||||
|
params.permit(:id, :limit, :offset, :q,
|
||||||
|
:page, :per_page,
|
||||||
|
q: [:description_matches, :created_at_gteq,
|
||||||
|
:created_at_lteq, :s, { s: [] }, { activity_type_in: [] }])
|
||||||
|
end
|
||||||
|
|
||||||
|
def type_params
|
||||||
|
permitted_params = params.require(:type).permit(:amount, :threshold)
|
||||||
|
normalize_params(permitted_params)
|
||||||
|
end
|
||||||
|
|
||||||
|
def normalize_params(params)
|
||||||
|
params[:amount] = params[:amount].to_f
|
||||||
|
params[:threshold] = params[:threshold].to_f
|
||||||
|
params
|
||||||
|
end
|
||||||
|
|
||||||
|
def search_params
|
||||||
|
index_params.fetch(:q, {}) || {}
|
||||||
|
end
|
||||||
|
|
||||||
|
def limit
|
||||||
|
index_params[:limit]
|
||||||
|
end
|
||||||
|
|
||||||
|
def offset
|
||||||
|
index_params[:offset] || 0
|
||||||
|
end
|
||||||
|
|
||||||
|
def serialized_users(users)
|
||||||
arr = []
|
arr = []
|
||||||
registrar_activities.each do |a|
|
users.each do |u|
|
||||||
arr << { created_at: a.created_at, description: a.description,
|
arr << { id: u.id, username: u.username,
|
||||||
type: a.activity_type == 'add_credit' ? 'credit' : 'debit',
|
role: u.roles.first, registrar_name: u.registrar.name }
|
||||||
sum: a.sum, balance: a.new_balance }
|
|
||||||
end
|
end
|
||||||
|
|
||||||
arr
|
arr
|
||||||
end
|
end
|
||||||
|
|
||||||
def registrar_activities
|
def serialized_activities(activities)
|
||||||
activities = current_user.registrar.cash_account.activities.order(created_at: :desc)
|
arr = []
|
||||||
activities = activities.where('created_at >= ?', params[:from]) if params[:from]
|
activities.each do |a|
|
||||||
activities = activities.where('created_at <= ?', params[:until]) if params[:until]
|
arr << { created_at: a.created_at, description: a.description,
|
||||||
|
type: a.activity_type == 'add_credit' ? 'credit' : 'debit',
|
||||||
|
sum: a.sum, balance: a.new_balance, currency: a.currency,
|
||||||
|
updator: a.updator_str }
|
||||||
|
end
|
||||||
|
|
||||||
activities
|
arr
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -1,12 +1,13 @@
|
||||||
module Repp
|
module Repp
|
||||||
module V1
|
module V1
|
||||||
class BaseController < ActionController::API # rubocop:disable Metrics/ClassLength
|
class BaseController < ActionController::API # rubocop:disable Metrics/ClassLength
|
||||||
|
attr_reader :current_user
|
||||||
|
|
||||||
around_action :log_request
|
around_action :log_request
|
||||||
before_action :authenticate_user
|
before_action :authenticate_user
|
||||||
before_action :validate_webclient_ca
|
before_action :validate_webclient_ca
|
||||||
|
before_action :validate_client_certs
|
||||||
before_action :check_ip_restriction
|
before_action :check_ip_restriction
|
||||||
attr_reader :current_user
|
|
||||||
|
|
||||||
before_action :set_paper_trail_whodunnit
|
before_action :set_paper_trail_whodunnit
|
||||||
|
|
||||||
private
|
private
|
||||||
|
@ -22,6 +23,10 @@ module Repp
|
||||||
rescue Apipie::ParamInvalid => e
|
rescue Apipie::ParamInvalid => e
|
||||||
@response = { code: 2005, message: e.message.gsub(/\n/, '. ') }
|
@response = { code: 2005, message: e.message.gsub(/\n/, '. ') }
|
||||||
render(json: @response, status: :bad_request)
|
render(json: @response, status: :bad_request)
|
||||||
|
rescue CanCan::AccessDenied => e
|
||||||
|
@response = { code: 2201, message: 'Authorization error' }
|
||||||
|
logger.error e.to_s
|
||||||
|
render(json: @response, status: :unauthorized)
|
||||||
ensure
|
ensure
|
||||||
create_repp_log
|
create_repp_log
|
||||||
end
|
end
|
||||||
|
@ -65,7 +70,6 @@ module Repp
|
||||||
|
|
||||||
def handle_errors(obj = nil)
|
def handle_errors(obj = nil)
|
||||||
@epp_errors ||= ActiveModel::Errors.new(self)
|
@epp_errors ||= ActiveModel::Errors.new(self)
|
||||||
|
|
||||||
if obj
|
if obj
|
||||||
obj.construct_epp_errors
|
obj.construct_epp_errors
|
||||||
obj.errors.each { |error| @epp_errors.import error }
|
obj.errors.each { |error| @epp_errors.import error }
|
||||||
|
@ -85,6 +89,12 @@ module Repp
|
||||||
render(json: @response, status: status)
|
render(json: @response, status: status)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def handle_non_epp_errors(obj, message = nil)
|
||||||
|
@response = { message: message || obj.errors.full_messages.join(', '),
|
||||||
|
data: {} }
|
||||||
|
render(json: @response, status: :bad_request)
|
||||||
|
end
|
||||||
|
|
||||||
def basic_token
|
def basic_token
|
||||||
pattern = /^Basic /
|
pattern = /^Basic /
|
||||||
header = request.headers['Authorization']
|
header = request.headers['Authorization']
|
||||||
|
@ -95,12 +105,14 @@ module Repp
|
||||||
def authenticate_user
|
def authenticate_user
|
||||||
username, password = Base64.urlsafe_decode64(basic_token).split(':')
|
username, password = Base64.urlsafe_decode64(basic_token).split(':')
|
||||||
@current_user ||= ApiUser.find_by(username: username, plain_text_password: password)
|
@current_user ||= ApiUser.find_by(username: username, plain_text_password: password)
|
||||||
|
user_active = @current_user.active?
|
||||||
|
|
||||||
return if @current_user
|
return if @current_user && user_active
|
||||||
|
|
||||||
raise(ArgumentError)
|
raise(ArgumentError)
|
||||||
rescue NoMethodError, ArgumentError
|
rescue NoMethodError, ArgumentError
|
||||||
@response = { code: 2202, message: 'Invalid authorization information' }
|
@response = { code: 2202, message: 'Invalid authorization information',
|
||||||
|
data: { username: username, password: password, active: user_active } }
|
||||||
render(json: @response, status: :unauthorized)
|
render(json: @response, status: :unauthorized)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -114,7 +126,7 @@ module Repp
|
||||||
end
|
end
|
||||||
|
|
||||||
def webclient_request?
|
def webclient_request?
|
||||||
return if Rails.env.test?
|
return false if Rails.env.test? || Rails.env.development?
|
||||||
|
|
||||||
ENV['webclient_ips'].split(',').map(&:strip).include?(request.ip)
|
ENV['webclient_ips'].split(',').map(&:strip).include?(request.ip)
|
||||||
end
|
end
|
||||||
|
@ -123,6 +135,7 @@ module Repp
|
||||||
return unless webclient_request?
|
return unless webclient_request?
|
||||||
|
|
||||||
request_name = request.env['HTTP_SSL_CLIENT_S_DN_CN']
|
request_name = request.env['HTTP_SSL_CLIENT_S_DN_CN']
|
||||||
|
|
||||||
webclient_cn = ENV['webclient_cert_common_name'] || 'webclient'
|
webclient_cn = ENV['webclient_cert_common_name'] || 'webclient'
|
||||||
return if request_name == webclient_cn
|
return if request_name == webclient_cn
|
||||||
|
|
||||||
|
@ -132,9 +145,28 @@ module Repp
|
||||||
render(json: @response, status: :unauthorized)
|
render(json: @response, status: :unauthorized)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def validate_client_certs
|
||||||
|
return if Rails.env.development? || Rails.env.test?
|
||||||
|
return if webclient_request?
|
||||||
|
return if @current_user.pki_ok?(request.env['HTTP_SSL_CLIENT_CERT'],
|
||||||
|
request.env['HTTP_SSL_CLIENT_S_DN_CN'])
|
||||||
|
|
||||||
|
@response = { code: 2202, message: 'Invalid certificate' }
|
||||||
|
render(json: @response, status: :unauthorized)
|
||||||
|
end
|
||||||
|
|
||||||
def logger
|
def logger
|
||||||
Rails.logger
|
Rails.logger
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def auth_values_to_data(registrar:)
|
||||||
|
data = current_user.as_json(only: %i[id username roles])
|
||||||
|
data[:registrar_name] = registrar.name
|
||||||
|
data[:legaldoc_mandatory] = registrar.legaldoc_mandatory?
|
||||||
|
data[:address_processing] = Contact.address_processing?
|
||||||
|
data[:abilities] = Ability.new(current_user).permissions
|
||||||
|
data
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -3,30 +3,67 @@ module Repp
|
||||||
module V1
|
module V1
|
||||||
class ContactsController < BaseController # rubocop:disable Metrics/ClassLength
|
class ContactsController < BaseController # rubocop:disable Metrics/ClassLength
|
||||||
before_action :find_contact, only: %i[show update destroy]
|
before_action :find_contact, only: %i[show update destroy]
|
||||||
|
skip_around_action :log_request, only: :search
|
||||||
|
|
||||||
api :get, '/repp/v1/contacts'
|
api :get, '/repp/v1/contacts'
|
||||||
desc 'Get all existing contacts'
|
desc 'Get all existing contacts'
|
||||||
def index
|
def index
|
||||||
record_count = current_user.registrar.contacts.count
|
authorize! :check, Epp::Contact
|
||||||
contacts = showable_contacts(params[:details], params[:limit] || 200,
|
records = current_user.registrar.contacts
|
||||||
params[:offset] || 0)
|
|
||||||
@response = { contacts: contacts, total_number_of_records: record_count }
|
q = records.ransack(PartialSearchFormatter.format(search_params))
|
||||||
render(json: @response, status: :ok)
|
q.sorts = 'created_at desc' if q.sorts.empty?
|
||||||
|
contacts = q.result(distinct: true)
|
||||||
|
|
||||||
|
limited_contacts = contacts.limit(limit).offset(offset)
|
||||||
|
.includes(:domain_contacts, :registrant_domains, :registrar)
|
||||||
|
|
||||||
|
render_success(data: { contacts: serialized_contacts(limited_contacts),
|
||||||
|
count: contacts.count, statuses: Contact::STATUSES,
|
||||||
|
ident_types: Contact::Ident.types })
|
||||||
end
|
end
|
||||||
|
|
||||||
|
# rubocop:disable Metrics/MethodLength
|
||||||
|
api :get, '/repp/v1/contacts/search(/:id)'
|
||||||
|
desc 'Search all existing contacts by optional id or query param'
|
||||||
|
def search
|
||||||
|
scope = current_user.registrar.contacts
|
||||||
|
if params[:query]
|
||||||
|
escaped_str = ActiveRecord::Base.connection.quote_string params[:query]
|
||||||
|
scope = scope.where("name ilike '%#{escaped_str}%' OR code ilike '%#{escaped_str}%'
|
||||||
|
OR ident ilike '%#{escaped_str}%'")
|
||||||
|
elsif params[:id]
|
||||||
|
scope = scope.where(code: params[:id])
|
||||||
|
end
|
||||||
|
|
||||||
|
render_success(data: scope.limit(10)
|
||||||
|
.map do |c|
|
||||||
|
{ value: c.code,
|
||||||
|
label: "#{c.code} #{c.name}",
|
||||||
|
selected: scope.size == 1 }
|
||||||
|
end)
|
||||||
|
end
|
||||||
|
# rubocop:enable Metrics/MethodLength
|
||||||
|
|
||||||
api :get, '/repp/v1/contacts/:contact_code'
|
api :get, '/repp/v1/contacts/:contact_code'
|
||||||
desc 'Get a specific contact'
|
desc 'Get a specific contact'
|
||||||
def show
|
def show
|
||||||
serializer = ::Serializers::Repp::Contact.new(@contact,
|
authorize! :check, Epp::Contact
|
||||||
show_address: Contact.address_processing?)
|
|
||||||
render_success(data: serializer.to_json)
|
simple = params[:simple] == 'true' || false
|
||||||
|
serializer = Serializers::Repp::Contact.new(@contact,
|
||||||
|
show_address: Contact.address_processing?,
|
||||||
|
domain_params: domain_filter_params,
|
||||||
|
simplify: simple)
|
||||||
|
|
||||||
|
render_success(data: { contact: serializer.to_json })
|
||||||
end
|
end
|
||||||
|
|
||||||
api :get, '/repp/v1/contacts/check/:contact_code'
|
api :get, '/repp/v1/contacts/check/:contact_code'
|
||||||
desc 'Check contact code availability'
|
desc 'Check contact code availability'
|
||||||
def check
|
def check
|
||||||
contact = Epp::Contact.find_by(code: params[:id])
|
contact = Epp::Contact.find_by(code: params[:id])
|
||||||
data = { contact: { id: params[:id], available: contact.nil? } }
|
data = { contact: { code: params[:id], available: contact.nil? } }
|
||||||
|
|
||||||
render_success(data: data)
|
render_success(data: data)
|
||||||
end
|
end
|
||||||
|
@ -35,7 +72,7 @@ module Repp
|
||||||
desc 'Create a new contact'
|
desc 'Create a new contact'
|
||||||
def create
|
def create
|
||||||
@contact = Epp::Contact.new(contact_params_with_address, current_user.registrar, epp: false)
|
@contact = Epp::Contact.new(contact_params_with_address, current_user.registrar, epp: false)
|
||||||
action = Actions::ContactCreate.new(@contact, params[:legal_document],
|
action = Actions::ContactCreate.new(@contact, contact_params[:legal_document],
|
||||||
contact_ident_params)
|
contact_ident_params)
|
||||||
|
|
||||||
unless action.call
|
unless action.call
|
||||||
|
@ -50,7 +87,7 @@ module Repp
|
||||||
desc 'Update existing contact'
|
desc 'Update existing contact'
|
||||||
def update
|
def update
|
||||||
action = Actions::ContactUpdate.new(@contact, contact_params_with_address(required: false),
|
action = Actions::ContactUpdate.new(@contact, contact_params_with_address(required: false),
|
||||||
params[:legal_document],
|
contact_params[:legal_document],
|
||||||
contact_ident_params(required: false), current_user)
|
contact_ident_params(required: false), current_user)
|
||||||
|
|
||||||
unless action.call
|
unless action.call
|
||||||
|
@ -73,29 +110,71 @@ module Repp
|
||||||
render_success
|
render_success
|
||||||
end
|
end
|
||||||
|
|
||||||
def contact_addr_present?
|
private
|
||||||
return false unless contact_addr_params.key?(:addr)
|
|
||||||
|
|
||||||
contact_addr_params[:addr].keys.any?
|
def index_params
|
||||||
|
params.permit(:id, :limit, :offset, :details, :q, :simple,
|
||||||
|
:page, :per_page, :domain_filter,
|
||||||
|
domain_filter: [],
|
||||||
|
q: %i[s name_matches code_eq ident_matches ident_type_eq
|
||||||
|
email_matches country_code_eq types_contains_array
|
||||||
|
updated_at_gteq created_at_gteq created_at_lteq
|
||||||
|
statuses_contains_array] + [s: []])
|
||||||
|
end
|
||||||
|
|
||||||
|
def search_params
|
||||||
|
index_params.fetch(:q, {}) || {}
|
||||||
|
end
|
||||||
|
|
||||||
|
def domain_filter_params
|
||||||
|
filter_params = index_params.slice(:id, :page, :per_page, :domain_filter).to_h
|
||||||
|
filter_params.merge!({ sort: hashify(index_params[:q].fetch(:s)) }) if index_params[:q]
|
||||||
|
filter_params
|
||||||
|
end
|
||||||
|
|
||||||
|
def hashify(sort)
|
||||||
|
return unless sort
|
||||||
|
|
||||||
|
sort_hash = {}
|
||||||
|
if sort.is_a?(Array)
|
||||||
|
sort.each do |s|
|
||||||
|
sort_hash.merge!(Hash[*s.split(' ')])
|
||||||
|
end
|
||||||
|
else
|
||||||
|
sort_hash.merge!(Hash[*sort.split(' ')])
|
||||||
|
end
|
||||||
|
sort_hash
|
||||||
|
end
|
||||||
|
|
||||||
|
def limit
|
||||||
|
index_params[:limit]
|
||||||
|
end
|
||||||
|
|
||||||
|
def offset
|
||||||
|
index_params[:offset] || 0
|
||||||
|
end
|
||||||
|
|
||||||
|
def serialized_contacts(contacts)
|
||||||
|
return contacts.map(&:code) unless index_params[:details] == 'true'
|
||||||
|
|
||||||
|
address_processing = Contact.address_processing?
|
||||||
|
contacts.map do |c|
|
||||||
|
Serializers::Repp::Contact.new(c, show_address: address_processing).to_json
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def contact_addr_present?
|
||||||
|
return false unless contact_addr_params
|
||||||
|
|
||||||
|
contact_addr_params.keys.any?
|
||||||
end
|
end
|
||||||
|
|
||||||
def create_update_success_body
|
def create_update_success_body
|
||||||
{ code: opt_addr? ? 1100 : nil, data: { contact: { id: @contact.code } },
|
{ code: opt_addr? ? 1100 : nil,
|
||||||
|
data: { contact: { code: @contact.code } },
|
||||||
message: opt_addr? ? I18n.t('epp.contacts.completed_without_address') : nil }
|
message: opt_addr? ? I18n.t('epp.contacts.completed_without_address') : nil }
|
||||||
end
|
end
|
||||||
|
|
||||||
def showable_contacts(details, limit, offset)
|
|
||||||
contacts = current_user.registrar.contacts.limit(limit).offset(offset)
|
|
||||||
|
|
||||||
return contacts.pluck(:code) unless details
|
|
||||||
|
|
||||||
contacts.map do |contact|
|
|
||||||
serializer = ::Serializers::Repp::Contact.new(contact,
|
|
||||||
show_address: Contact.address_processing?)
|
|
||||||
serializer.to_json
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
def opt_addr?
|
def opt_addr?
|
||||||
!Contact.address_processing? && contact_addr_present?
|
!Contact.address_processing? && contact_addr_present?
|
||||||
end
|
end
|
||||||
|
@ -106,36 +185,36 @@ module Repp
|
||||||
end
|
end
|
||||||
|
|
||||||
def contact_params_with_address(required: true)
|
def contact_params_with_address(required: true)
|
||||||
return contact_create_params(required: required) unless contact_addr_params.key?(:addr)
|
return contact_create_params(required: required) unless contact_addr_present?
|
||||||
|
|
||||||
addr = {}
|
contact_create_params(required: required).merge(contact_addr_params)
|
||||||
contact_addr_params[:addr].each_key { |k| addr[k] = contact_addr_params[:addr][k] }
|
|
||||||
contact_create_params(required: required).merge(addr)
|
|
||||||
end
|
end
|
||||||
|
|
||||||
def contact_create_params(required: true)
|
def contact_create_params(required: true)
|
||||||
params.require(:contact).require(%i[name email phone]) if required
|
create_params = %i[name email phone]
|
||||||
params.require(:contact).permit(:name, :email, :phone, :id)
|
contact_params.require(create_params) if required
|
||||||
|
contact_params.slice(:id, *create_params)
|
||||||
end
|
end
|
||||||
|
|
||||||
def contact_ident_params(required: true)
|
def contact_ident_params(required: true)
|
||||||
if required
|
ident_params = %i[ident ident_type ident_country_code]
|
||||||
params.require(:contact).require(:ident).require(%i[ident ident_type ident_country_code])
|
contact_params.require(:ident).require(ident_params) if required
|
||||||
params.require(:contact).require(:ident).permit(:ident, :ident_type, :ident_country_code)
|
contact_params[:ident].to_h
|
||||||
else
|
|
||||||
params.permit(contact: { ident: %i[ident ident_type ident_country_code] })
|
|
||||||
end
|
|
||||||
|
|
||||||
params[:contact][:ident]
|
|
||||||
end
|
end
|
||||||
|
|
||||||
def contact_addr_params
|
def contact_addr_params
|
||||||
if Contact.address_processing?
|
return contact_params[:addr] unless Contact.address_processing?
|
||||||
params.require(:contact).require(:addr).require(%i[country_code city street zip])
|
|
||||||
params.require(:contact).require(:addr).permit(:country_code, :city, :street, :zip)
|
addr_params = %i[country_code city street zip]
|
||||||
else
|
contact_params.require(:addr).require(addr_params)
|
||||||
params.require(:contact).permit(addr: %i[country_code city street zip])
|
contact_params[:addr]
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def contact_params
|
||||||
|
params.require(:contact).permit(:id, :name, :email, :phone, :legal_document,
|
||||||
|
legal_document: %i[body type],
|
||||||
|
ident: [%i[ident ident_type ident_country_code]],
|
||||||
|
addr: [%i[country_code city street zip state]])
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -7,7 +7,7 @@ module Repp
|
||||||
|
|
||||||
unless @new_contact.identical_to?(@current_contact)
|
unless @new_contact.identical_to?(@current_contact)
|
||||||
@epp_errors.add(:epp_errors,
|
@epp_errors.add(:epp_errors,
|
||||||
msg: 'Admin contacts must be identical',
|
msg: 'New and current admin contacts ident data must be identical',
|
||||||
code: '2304')
|
code: '2304')
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
@ -2,19 +2,16 @@ module Repp
|
||||||
module V1
|
module V1
|
||||||
module Domains
|
module Domains
|
||||||
class BaseContactsController < BaseController
|
class BaseContactsController < BaseController
|
||||||
before_action :set_current_contact, only: [:update]
|
before_action :set_contacts, only: [:update]
|
||||||
before_action :set_new_contact, only: [:update]
|
|
||||||
|
|
||||||
def set_current_contact
|
def set_contacts
|
||||||
@current_contact = current_user.registrar.contacts
|
contacts = current_user.registrar.contacts
|
||||||
.find_by!(code: contact_params[:current_contact_id])
|
@current_contact = contacts.find_by!(code: contact_params[:current_contact_id])
|
||||||
end
|
@new_contact = contacts.find_by!(code: contact_params[:new_contact_id])
|
||||||
|
|
||||||
def set_new_contact
|
|
||||||
@new_contact = current_user.registrar.contacts.find_by!(code: params[:new_contact_id])
|
|
||||||
end
|
end
|
||||||
|
|
||||||
def update
|
def update
|
||||||
|
authorize! :manage, :repp
|
||||||
@epp_errors ||= ActiveModel::Errors.new(self)
|
@epp_errors ||= ActiveModel::Errors.new(self)
|
||||||
return unless @new_contact.invalid?
|
return unless @new_contact.invalid?
|
||||||
|
|
||||||
|
@ -26,8 +23,11 @@ module Repp
|
||||||
private
|
private
|
||||||
|
|
||||||
def contact_params
|
def contact_params
|
||||||
params.require(%i[current_contact_id new_contact_id])
|
param_list = %i[current_contact_id new_contact_id]
|
||||||
params.permit(:current_contact_id, :new_contact_id)
|
params.require(param_list)
|
||||||
|
params.permit(:current_contact_id, :new_contact_id,
|
||||||
|
contact: {},
|
||||||
|
admin_contact: [param_list])
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -14,8 +14,8 @@ module Repp
|
||||||
api :GET, '/repp/v1/domains/:domain_name/contacts'
|
api :GET, '/repp/v1/domains/:domain_name/contacts'
|
||||||
desc "View domain's admin and tech contacts"
|
desc "View domain's admin and tech contacts"
|
||||||
def index
|
def index
|
||||||
admin_contacts = @domain.admin_domain_contacts.pluck(:contact_code_cache)
|
admin_contacts = @domain.admin_domain_contacts.map(&:contact).pluck(:code)
|
||||||
tech_contacts = @domain.tech_domain_contacts.pluck(:contact_code_cache)
|
tech_contacts = @domain.tech_domain_contacts.map(&:contact).pluck(:code)
|
||||||
|
|
||||||
data = { admin_contacts: admin_contacts, tech_contacts: tech_contacts }
|
data = { admin_contacts: admin_contacts, tech_contacts: tech_contacts }
|
||||||
render_success(data: data)
|
render_success(data: data)
|
||||||
|
@ -38,7 +38,6 @@ module Repp
|
||||||
def cta(action = 'add')
|
def cta(action = 'add')
|
||||||
params[:contacts].each { |c| c[:action] = action }
|
params[:contacts].each { |c| c[:action] = action }
|
||||||
action = Actions::DomainUpdate.new(@domain, contact_create_params, false)
|
action = Actions::DomainUpdate.new(@domain, contact_create_params, false)
|
||||||
|
|
||||||
# rubocop:disable Style/AndOr
|
# rubocop:disable Style/AndOr
|
||||||
handle_errors(@domain) and return unless action.call
|
handle_errors(@domain) and return unless action.call
|
||||||
# rubocop:enable Style/AndOr
|
# rubocop:enable Style/AndOr
|
||||||
|
|
|
@ -8,14 +8,14 @@ module Repp
|
||||||
|
|
||||||
api :POST, 'repp/v1/domains/:domain_name/renew'
|
api :POST, 'repp/v1/domains/:domain_name/renew'
|
||||||
desc 'Renew domain'
|
desc 'Renew domain'
|
||||||
param :renew, Hash, required: true, desc: 'Renew parameters' do
|
param :renews, Hash, required: true, desc: 'Renew parameters' do
|
||||||
param :period, Integer, required: true, desc: 'Renew period. Month (m) or year (y)'
|
param :period, Integer, required: true, desc: 'Renew period. Month (m) or year (y)'
|
||||||
param :period_unit, String, required: true, desc: 'For how many months or years to renew'
|
param :period_unit, String, required: true, desc: 'For how many months or years to renew'
|
||||||
param :exp_date, String, required: true, desc: 'Current expiry date for domain'
|
param :exp_date, String, required: true, desc: 'Current expiry date for domain'
|
||||||
end
|
end
|
||||||
def create
|
def create
|
||||||
authorize!(:renew, @domain)
|
authorize!(:renew, @domain)
|
||||||
action = Actions::DomainRenew.new(@domain, renew_params[:renew], current_user.registrar)
|
action = Actions::DomainRenew.new(@domain, renew_params[:renews], current_user.registrar)
|
||||||
|
|
||||||
unless action.call
|
unless action.call
|
||||||
handle_errors(@domain)
|
handle_errors(@domain)
|
||||||
|
@ -26,10 +26,11 @@ module Repp
|
||||||
end
|
end
|
||||||
|
|
||||||
def bulk_renew
|
def bulk_renew
|
||||||
|
authorize! :manage, :repp
|
||||||
renew = run_bulk_renew_task(@domains, bulk_renew_params[:renew_period])
|
renew = run_bulk_renew_task(@domains, bulk_renew_params[:renew_period])
|
||||||
return render_success(data: { updated_domains: @domains.map(&:name) }) if renew.valid?
|
return render_success(data: { updated_domains: @domains.map(&:name) }) if renew.valid?
|
||||||
|
|
||||||
msg = renew.errors.keys.map { |k, _v| renew.errors[k] }.join(', ')
|
msg = renew.errors.attribute_names.map { |k, _v| renew.errors[k] }.join(', ')
|
||||||
@epp_errors.add(:epp_errors, msg: msg, code: '2002')
|
@epp_errors.add(:epp_errors, msg: msg, code: '2002')
|
||||||
handle_errors
|
handle_errors
|
||||||
end
|
end
|
||||||
|
@ -37,7 +38,7 @@ module Repp
|
||||||
private
|
private
|
||||||
|
|
||||||
def renew_params
|
def renew_params
|
||||||
params.permit(:domain_id, renew: %i[period period_unit exp_date])
|
params.permit(:domain_id, renews: %i[period period_unit exp_date])
|
||||||
end
|
end
|
||||||
|
|
||||||
def validate_renew_period
|
def validate_renew_period
|
||||||
|
@ -50,13 +51,11 @@ module Repp
|
||||||
|
|
||||||
def select_renewable_domains
|
def select_renewable_domains
|
||||||
@epp_errors ||= ActiveModel::Errors.new(self)
|
@epp_errors ||= ActiveModel::Errors.new(self)
|
||||||
|
|
||||||
if bulk_renew_params[:domains].instance_of?(Array)
|
|
||||||
@domains = bulk_renew_domains
|
@domains = bulk_renew_domains
|
||||||
else
|
if @domains.empty?
|
||||||
@epp_errors.add(:epp_errors, msg: 'Domains attribute must be an array', code: '2005')
|
@epp_errors.add(:epp_errors, msg: 'Domains cannot be empty',
|
||||||
|
code: '2005')
|
||||||
end
|
end
|
||||||
|
|
||||||
return handle_errors if @epp_errors.any?
|
return handle_errors if @epp_errors.any?
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -75,6 +74,7 @@ module Repp
|
||||||
def bulk_renew_domains
|
def bulk_renew_domains
|
||||||
@epp_errors ||= ActiveModel::Errors.new(self)
|
@epp_errors ||= ActiveModel::Errors.new(self)
|
||||||
domains = []
|
domains = []
|
||||||
|
if bulk_renew_params[:domains].instance_of?(Array)
|
||||||
bulk_renew_params[:domains].each do |idn|
|
bulk_renew_params[:domains].each do |idn|
|
||||||
domain = Epp::Domain.find_by(name: idn)
|
domain = Epp::Domain.find_by(name: idn)
|
||||||
domains << domain if domain
|
domains << domain if domain
|
||||||
|
@ -84,6 +84,9 @@ module Repp
|
||||||
msg: "Object does not exist: #{idn}",
|
msg: "Object does not exist: #{idn}",
|
||||||
code: '2304')
|
code: '2304')
|
||||||
end
|
end
|
||||||
|
else
|
||||||
|
@epp_errors.add(:epp_errors, msg: 'Domains attribute must be an array', code: '2005')
|
||||||
|
end
|
||||||
|
|
||||||
domains
|
domains
|
||||||
end
|
end
|
||||||
|
|
|
@ -7,7 +7,6 @@ module Repp
|
||||||
|
|
||||||
api :DELETE, '/repp/v1/domains/:domain_name/statuses/:status'
|
api :DELETE, '/repp/v1/domains/:domain_name/statuses/:status'
|
||||||
param :domain_name, String, desc: 'Domain name'
|
param :domain_name, String, desc: 'Domain name'
|
||||||
param :status, String, desc: 'Status to be removed'
|
|
||||||
desc 'Remove status from specific domain'
|
desc 'Remove status from specific domain'
|
||||||
def destroy
|
def destroy
|
||||||
return editing_failed unless domain_with_status?(params[:id])
|
return editing_failed unless domain_with_status?(params[:id])
|
||||||
|
@ -22,7 +21,6 @@ module Repp
|
||||||
|
|
||||||
api :PUT, '/repp/v1/domains/:domain_name/statuses/:status'
|
api :PUT, '/repp/v1/domains/:domain_name/statuses/:status'
|
||||||
param :domain_name, String, desc: 'Domain name'
|
param :domain_name, String, desc: 'Domain name'
|
||||||
param :status, String, desc: 'Status to be added'
|
|
||||||
desc 'Add status to specific domain'
|
desc 'Add status to specific domain'
|
||||||
def update
|
def update
|
||||||
return editing_failed if domain_with_status?(params[:id])
|
return editing_failed if domain_with_status?(params[:id])
|
||||||
|
|
|
@ -3,6 +3,7 @@ module Repp
|
||||||
module V1
|
module V1
|
||||||
class DomainsController < BaseController # rubocop:disable Metrics/ClassLength
|
class DomainsController < BaseController # rubocop:disable Metrics/ClassLength
|
||||||
before_action :set_authorized_domain, only: %i[transfer_info destroy]
|
before_action :set_authorized_domain, only: %i[transfer_info destroy]
|
||||||
|
before_action :find_password, only: %i[update destroy]
|
||||||
before_action :validate_registrar_authorization, only: %i[transfer_info destroy]
|
before_action :validate_registrar_authorization, only: %i[transfer_info destroy]
|
||||||
before_action :forward_registrar_id, only: %i[create update destroy]
|
before_action :forward_registrar_id, only: %i[create update destroy]
|
||||||
before_action :set_domain, only: %i[update]
|
before_action :set_domain, only: %i[update]
|
||||||
|
@ -10,20 +11,31 @@ module Repp
|
||||||
api :GET, '/repp/v1/domains'
|
api :GET, '/repp/v1/domains'
|
||||||
desc 'Get all existing domains'
|
desc 'Get all existing domains'
|
||||||
def index
|
def index
|
||||||
records = current_user.registrar.domains
|
authorize! :info, Epp::Domain
|
||||||
domains = records.limit(limit).offset(offset)
|
records = current_user.registrar.domains.includes(:registrar, :registrant)
|
||||||
|
q = records.ransack(PartialSearchFormatter.format(search_params))
|
||||||
|
q.sorts = ['valid_to asc', 'created_at desc'] if q.sorts.empty?
|
||||||
|
# use distinct: false here due to ransack bug:
|
||||||
|
# https://github.com/activerecord-hackery/ransack/issues/429
|
||||||
|
domains = q.result(distinct: false)
|
||||||
|
|
||||||
render_success(data: { domains: serialized_domains(domains),
|
limited_domains = domains.limit(limit).offset(offset)
|
||||||
total_number_of_records: records.count })
|
|
||||||
|
render_success(data: { new_domain: records.any? ? serialized_domains([records.last]) : [],
|
||||||
|
domains: serialized_domains(limited_domains.to_a.uniq),
|
||||||
|
count: domains.count,
|
||||||
|
statuses: DomainStatus::STATUSES })
|
||||||
end
|
end
|
||||||
|
|
||||||
api :GET, '/repp/v1/domains/:domain_name'
|
api :GET, '/repp/v1/domains/:domain_name'
|
||||||
desc 'Get a specific domain'
|
desc 'Get a specific domain'
|
||||||
def show
|
def show
|
||||||
@domain = Epp::Domain.find_by!(name: params[:id])
|
@domain = Epp::Domain.find_by(name: params[:id])
|
||||||
|
authorize! :info, @domain
|
||||||
|
|
||||||
sponsor = @domain.registrar == current_user.registrar
|
sponsor = @domain.registrar == current_user.registrar
|
||||||
render_success(data: { domain: Serializers::Repp::Domain.new(@domain,
|
serializer = Serializers::Repp::Domain.new(@domain, sponsored: sponsor)
|
||||||
sponsored: sponsor).to_json })
|
render_success(data: { domain: serializer.to_json })
|
||||||
end
|
end
|
||||||
|
|
||||||
api :POST, '/repp/v1/domains'
|
api :POST, '/repp/v1/domains'
|
||||||
|
@ -33,7 +45,7 @@ module Repp
|
||||||
param :registrant, String, required: true, desc: 'Registrant contact code'
|
param :registrant, String, required: true, desc: 'Registrant contact code'
|
||||||
param :reserved_pw, String, required: false, desc: 'Reserved password for domain'
|
param :reserved_pw, String, required: false, desc: 'Reserved password for domain'
|
||||||
param :transfer_code, String, required: false, desc: 'Desired transfer code for domain'
|
param :transfer_code, String, required: false, desc: 'Desired transfer code for domain'
|
||||||
# param :period, String, required: true, desc: 'Registration period in months or years'
|
param :period, Integer, required: true, desc: 'Registration period in months or years'
|
||||||
param :period_unit, String, required: true, desc: 'Period type (month m) or (year y)'
|
param :period_unit, String, required: true, desc: 'Period type (month m) or (year y)'
|
||||||
param :nameservers_attributes, Array, required: false, desc: 'Domain nameservers' do
|
param :nameservers_attributes, Array, required: false, desc: 'Domain nameservers' do
|
||||||
param :hostname, String, required: true, desc: 'Nameserver hostname'
|
param :hostname, String, required: true, desc: 'Nameserver hostname'
|
||||||
|
@ -56,15 +68,18 @@ module Repp
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
def create
|
def create
|
||||||
authorize!(:create, Epp::Domain)
|
authorize! :create, Epp::Domain
|
||||||
@domain = Epp::Domain.new
|
@domain = Epp::Domain.new
|
||||||
action = Actions::DomainCreate.new(@domain, domain_create_params)
|
|
||||||
|
action = Actions::DomainCreate.new(@domain, domain_params)
|
||||||
|
|
||||||
# rubocop:disable Style/AndOr
|
# rubocop:disable Style/AndOr
|
||||||
handle_errors(@domain) and return unless action.call
|
handle_errors(@domain) and return unless action.call
|
||||||
# rubocop:enable Style/AndOr
|
# rubocop:enable Style/AndOr
|
||||||
|
|
||||||
render_success(data: { domain: { name: @domain.name, transfer_code: @domain.transfer_code } })
|
render_success(data: { domain: { name: @domain.name,
|
||||||
|
transfer_code: @domain.transfer_code,
|
||||||
|
id: @domain.reload.uuid } })
|
||||||
end
|
end
|
||||||
|
|
||||||
api :PUT, '/repp/v1/domains/:domain_name'
|
api :PUT, '/repp/v1/domains/:domain_name'
|
||||||
|
@ -73,14 +88,14 @@ module Repp
|
||||||
param :domain, Hash, required: true, desc: 'Changes of domain object' do
|
param :domain, Hash, required: true, desc: 'Changes of domain object' do
|
||||||
param :registrant, Hash, required: false, desc: 'New registrant object' do
|
param :registrant, Hash, required: false, desc: 'New registrant object' do
|
||||||
param :code, String, required: true, desc: 'New registrant contact code'
|
param :code, String, required: true, desc: 'New registrant contact code'
|
||||||
param :verified, [true, false], required: false,
|
param :verified, [true, false, 'true', 'false'], required: false,
|
||||||
desc: 'Registrant change is already verified'
|
desc: 'Registrant change is already verified'
|
||||||
end
|
end
|
||||||
param :transfer_code, String, required: false, desc: 'New authorization code'
|
param :transfer_code, String, required: false, desc: 'New authorization code'
|
||||||
end
|
end
|
||||||
def update
|
def update
|
||||||
action = Actions::DomainUpdate.new(@domain, params[:domain], false)
|
authorize!(:update, @domain, @password)
|
||||||
|
action = Actions::DomainUpdate.new(@domain, update_params, false)
|
||||||
unless action.call
|
unless action.call
|
||||||
handle_errors(@domain)
|
handle_errors(@domain)
|
||||||
return
|
return
|
||||||
|
@ -108,23 +123,28 @@ module Repp
|
||||||
api :POST, '/repp/v1/domains/transfer'
|
api :POST, '/repp/v1/domains/transfer'
|
||||||
desc 'Transfer multiple domains'
|
desc 'Transfer multiple domains'
|
||||||
def transfer
|
def transfer
|
||||||
|
authorize! :transfer, Epp::Domain
|
||||||
@errors ||= []
|
@errors ||= []
|
||||||
@successful = []
|
@successful = []
|
||||||
|
|
||||||
transfer_params[:domain_transfers].each do |transfer|
|
transfer_params[:domain_transfers].each do |transfer|
|
||||||
initiate_transfer(transfer)
|
initiate_transfer(transfer)
|
||||||
end
|
end
|
||||||
|
|
||||||
render_success(data: { success: @successful, failed: @errors })
|
render_success(data: { success: @successful, failed: @errors })
|
||||||
end
|
end
|
||||||
|
|
||||||
api :DELETE, '/repp/v1/domains/:domain_name'
|
api :DELETE, '/repp/v1/domains/:domain_name'
|
||||||
desc 'Delete specific domain'
|
desc 'Delete specific domain'
|
||||||
|
param :id, String, desc: 'Domain name in IDN / Puny format'
|
||||||
|
param :domain, Hash, required: true, desc: 'Changes of domain object' do
|
||||||
param :delete, Hash, required: true, desc: 'Object holding verified key' do
|
param :delete, Hash, required: true, desc: 'Object holding verified key' do
|
||||||
param :verified, [true, false], required: true,
|
param :verified, [true, false, 'true', 'false'], required: true,
|
||||||
desc: 'Whether to ask registrant verification or not'
|
desc: 'Whether to ask registrant verification or not'
|
||||||
end
|
end
|
||||||
|
end
|
||||||
def destroy
|
def destroy
|
||||||
action = Actions::DomainDelete.new(@domain, params, current_user.registrar)
|
authorize!(:delete, @domain, @password)
|
||||||
|
action = Actions::DomainDelete.new(@domain, domain_params, current_user.registrar)
|
||||||
|
|
||||||
# rubocop:disable Style/AndOr
|
# rubocop:disable Style/AndOr
|
||||||
handle_errors(@domain) and return unless action.call
|
handle_errors(@domain) and return unless action.call
|
||||||
|
@ -138,7 +158,8 @@ module Repp
|
||||||
def serialized_domains(domains)
|
def serialized_domains(domains)
|
||||||
return domains.pluck(:name) unless index_params[:details] == 'true'
|
return domains.pluck(:name) unless index_params[:details] == 'true'
|
||||||
|
|
||||||
domains.map { |d| Serializers::Repp::Domain.new(d).to_json }
|
simple = index_params[:simple] == 'true' || false
|
||||||
|
domains.map { |d| Serializers::Repp::Domain.new(d, simplify: simple).to_json }
|
||||||
end
|
end
|
||||||
|
|
||||||
def initiate_transfer(transfer)
|
def initiate_transfer(transfer)
|
||||||
|
@ -155,18 +176,13 @@ module Repp
|
||||||
end
|
end
|
||||||
|
|
||||||
def transfer_params
|
def transfer_params
|
||||||
params.require(:data).require(:domain_transfers).each do |t|
|
params.require(:data).require(:domain_transfers)
|
||||||
t.require(:domain_name)
|
params.require(:data).permit(domain_transfers: [%i[domain_name transfer_code]])
|
||||||
t.permit(:domain_name)
|
|
||||||
t.require(:transfer_code)
|
|
||||||
t.permit(:transfer_code)
|
|
||||||
end
|
|
||||||
params.require(:data).permit(domain_transfers: %i[domain_name transfer_code])
|
|
||||||
end
|
end
|
||||||
|
|
||||||
def transfer_info_params
|
def transfer_info_params
|
||||||
params.require(:id)
|
params.require(:id)
|
||||||
params.permit(:id)
|
params.permit(:id, :legal_document, delete: [:verified])
|
||||||
end
|
end
|
||||||
|
|
||||||
def forward_registrar_id
|
def forward_registrar_id
|
||||||
|
@ -177,6 +193,7 @@ module Repp
|
||||||
|
|
||||||
def set_domain
|
def set_domain
|
||||||
registrar = current_user.registrar
|
registrar = current_user.registrar
|
||||||
|
|
||||||
@domain = Epp::Domain.find_by(registrar: registrar, name: params[:id])
|
@domain = Epp::Domain.find_by(registrar: registrar, name: params[:id])
|
||||||
@domain ||= Epp::Domain.find_by!(registrar: registrar, name_puny: params[:id])
|
@domain ||= Epp::Domain.find_by!(registrar: registrar, name_puny: params[:id])
|
||||||
|
|
||||||
|
@ -185,6 +202,10 @@ module Repp
|
||||||
raise ActiveRecord::RecordNotFound
|
raise ActiveRecord::RecordNotFound
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def find_password
|
||||||
|
@password = domain_params[:transfer_code]
|
||||||
|
end
|
||||||
|
|
||||||
def set_authorized_domain
|
def set_authorized_domain
|
||||||
@epp_errors ||= ActiveModel::Errors.new(self)
|
@epp_errors ||= ActiveModel::Errors.new(self)
|
||||||
@domain = domain_from_url_hash
|
@domain = domain_from_url_hash
|
||||||
|
@ -201,14 +222,14 @@ module Repp
|
||||||
end
|
end
|
||||||
|
|
||||||
def domain_from_url_hash
|
def domain_from_url_hash
|
||||||
entry = transfer_info_params[:id]
|
entry = params[:id]
|
||||||
return Epp::Domain.find(entry) if entry.match?(/\A[0-9]+\z/)
|
return Epp::Domain.find(entry) if entry.match?(/\A[0-9]+\z/)
|
||||||
|
|
||||||
Epp::Domain.find_by!('name = ? OR name_puny = ?', entry, entry)
|
Epp::Domain.find_by!('name = ? OR name_puny = ?', entry, entry)
|
||||||
end
|
end
|
||||||
|
|
||||||
def limit
|
def limit
|
||||||
index_params[:limit] || 200
|
index_params[:limit]
|
||||||
end
|
end
|
||||||
|
|
||||||
def offset
|
def offset
|
||||||
|
@ -216,15 +237,47 @@ module Repp
|
||||||
end
|
end
|
||||||
|
|
||||||
def index_params
|
def index_params
|
||||||
params.permit(:limit, :offset, :details)
|
params.permit(:limit, :offset, :details, :simple, :q,
|
||||||
|
q: %i[s name_matches registrant_code_eq contacts_ident_eq
|
||||||
|
nameservers_hostname_eq valid_to_gteq valid_to_lteq
|
||||||
|
statuses_contains_array] + [s: []])
|
||||||
end
|
end
|
||||||
|
|
||||||
def domain_create_params
|
def search_params
|
||||||
params.require(:domain).permit(:name, :registrant, :period, :period_unit, :registrar,
|
index_params.fetch(:q, {}) || {}
|
||||||
:transfer_code, :reserved_pw,
|
end
|
||||||
dnskeys_attributes: [%i[flags alg protocol public_key]],
|
|
||||||
|
def update_params
|
||||||
|
dup_params = domain_params.to_h.dup
|
||||||
|
return dup_params unless dup_params[:contacts]
|
||||||
|
|
||||||
|
modify_contact_params(dup_params)
|
||||||
|
end
|
||||||
|
|
||||||
|
def modify_contact_params(params)
|
||||||
|
new_contact_params = params[:contacts].map { |c| c.to_h.symbolize_keys }
|
||||||
|
old_contact_params = @domain.domain_contacts.includes(:contact).map do |c|
|
||||||
|
{ code: c.contact.code, type: c.name.downcase }
|
||||||
|
end
|
||||||
|
params[:contacts] = (new_contact_params - old_contact_params).map do |c|
|
||||||
|
c.merge(action: 'add')
|
||||||
|
end
|
||||||
|
params[:contacts].concat((old_contact_params - new_contact_params)
|
||||||
|
.map { |c| c.merge(action: 'rem') })
|
||||||
|
params
|
||||||
|
end
|
||||||
|
|
||||||
|
def domain_params
|
||||||
|
params.require(:domain).permit(:name, :period, :period_unit, :registrar, :transfer_code,
|
||||||
|
:reserved_pw, :legal_document, :registrant,
|
||||||
|
legal_document: %i[body type], registrant: [%i[code verified]],
|
||||||
|
dns_keys: [%i[id flags alg protocol public_key action]],
|
||||||
|
nameservers: [[:id, :hostname, :action, { ipv4: [], ipv6: [] }]],
|
||||||
|
contacts: [%i[code type action]],
|
||||||
nameservers_attributes: [[:hostname, { ipv4: [], ipv6: [] }]],
|
nameservers_attributes: [[:hostname, { ipv4: [], ipv6: [] }]],
|
||||||
admin_contacts: [], tech_contacts: [])
|
admin_contacts: [], tech_contacts: [],
|
||||||
|
dnskeys_attributes: [%i[flags alg protocol public_key]],
|
||||||
|
delete: [:verified])
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
128
app/controllers/repp/v1/invoices_controller.rb
Normal file
128
app/controllers/repp/v1/invoices_controller.rb
Normal file
|
@ -0,0 +1,128 @@
|
||||||
|
require 'serializers/repp/invoice'
|
||||||
|
module Repp
|
||||||
|
module V1
|
||||||
|
class InvoicesController < BaseController # rubocop:disable Metrics/ClassLength
|
||||||
|
load_and_authorize_resource
|
||||||
|
|
||||||
|
# rubocop:disable Metrics/MethodLength
|
||||||
|
api :get, '/repp/v1/invoices'
|
||||||
|
desc 'Get all invoices'
|
||||||
|
def index
|
||||||
|
records = current_user.registrar.invoices
|
||||||
|
q = records.ransack(PartialSearchFormatter.format(search_params))
|
||||||
|
q.sorts = 'created_at desc' if q.sorts.empty?
|
||||||
|
invoices = q.result(distinct: true)
|
||||||
|
|
||||||
|
limited_invoices = invoices.limit(limit).offset(offset)
|
||||||
|
.includes(:items, :account_activity, :buyer)
|
||||||
|
|
||||||
|
render_success(data: { invoices: serialized_invoices(limited_invoices),
|
||||||
|
count: invoices.count })
|
||||||
|
end
|
||||||
|
# rubocop:enable Metrics/MethodLength
|
||||||
|
|
||||||
|
api :get, '/repp/v1/invoices/:id'
|
||||||
|
desc 'Get a specific invoice'
|
||||||
|
def show
|
||||||
|
serializer = Serializers::Repp::Invoice.new(@invoice)
|
||||||
|
render_success(data: { invoice: serializer.to_json })
|
||||||
|
end
|
||||||
|
|
||||||
|
api :get, '/repp/v1/invoices/:id/download'
|
||||||
|
desc 'Download a specific invoice as pdf file'
|
||||||
|
def download
|
||||||
|
filename = "Invoice-#{@invoice.number}.pdf"
|
||||||
|
@response = { code: 1000, message: 'Command completed successfully',
|
||||||
|
data: filename }
|
||||||
|
send_data @invoice.as_pdf, filename: filename
|
||||||
|
end
|
||||||
|
|
||||||
|
api :post, '/repp/v1/invoices/:id/send_to_recipient'
|
||||||
|
desc 'Send invoice pdf to recipient'
|
||||||
|
param :invoice, Hash, required: true, desc: 'Invoice data for sending to recipient' do
|
||||||
|
param :id, String, required: true, desc: 'Invoice id'
|
||||||
|
param :recipient, String, required: true, desc: 'Invoice receipient email'
|
||||||
|
end
|
||||||
|
def send_to_recipient
|
||||||
|
recipient = invoice_params[:recipient]
|
||||||
|
if recipient.blank?
|
||||||
|
handle_non_epp_errors(@invoice, 'Invoice recipient cannot be empty')
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
|
InvoiceMailer.invoice_email(invoice: @invoice, recipient: recipient)
|
||||||
|
.deliver_now
|
||||||
|
serializer = Serializers::Repp::Invoice.new(@invoice, simplify: true)
|
||||||
|
render_success(data: { invoice: serializer.to_json
|
||||||
|
.merge!(recipient: recipient) })
|
||||||
|
end
|
||||||
|
|
||||||
|
api :put, '/repp/v1/invoices/:id/cancel'
|
||||||
|
desc 'Cancel a specific invoice'
|
||||||
|
def cancel
|
||||||
|
action = Actions::InvoiceCancel.new(@invoice)
|
||||||
|
if action.call
|
||||||
|
EisBilling::SendInvoiceStatus.send_info(invoice_number: @invoice.number,
|
||||||
|
status: 'cancelled')
|
||||||
|
else
|
||||||
|
handle_non_epp_errors(@invoice)
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
|
serializer = Serializers::Repp::Invoice.new(@invoice, simplify: true)
|
||||||
|
render_success(data: { invoice: serializer.to_json })
|
||||||
|
end
|
||||||
|
|
||||||
|
api :post, '/repp/v1/invoices/add_credit'
|
||||||
|
desc 'Generate add credit invoice'
|
||||||
|
def add_credit
|
||||||
|
deposit = Deposit.new(invoice_params.merge(registrar: current_user.registrar))
|
||||||
|
invoice = deposit.issue_prepayment_invoice
|
||||||
|
if invoice
|
||||||
|
serializer = Serializers::Repp::Invoice.new(invoice, simplify: true)
|
||||||
|
render_success(data: { invoice: serializer.to_json })
|
||||||
|
else
|
||||||
|
handle_non_epp_errors(deposit)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
private
|
||||||
|
|
||||||
|
def index_params
|
||||||
|
params.permit(:id, :limit, :offset, :details, :q, :simple,
|
||||||
|
:page, :per_page,
|
||||||
|
q: %i[number_str_matches due_date_gteq due_date_lteq
|
||||||
|
account_activity_created_at_gteq
|
||||||
|
account_activity_created_at_lteq
|
||||||
|
account_activity_id_not_null
|
||||||
|
account_activity_id_null cancelled_at_null
|
||||||
|
cancelled_at_not_null number_gteq number_lteq
|
||||||
|
monthly_invoice_true monthly_invoice_false
|
||||||
|
total_gteq total_lteq s] + [s: []])
|
||||||
|
end
|
||||||
|
|
||||||
|
def search_params
|
||||||
|
index_params.fetch(:q, {}) || {}
|
||||||
|
end
|
||||||
|
|
||||||
|
def invoice_params
|
||||||
|
params.require(:invoice).permit(:id, :recipient, :amount, :description)
|
||||||
|
end
|
||||||
|
|
||||||
|
def limit
|
||||||
|
index_params[:limit] || 200
|
||||||
|
end
|
||||||
|
|
||||||
|
def offset
|
||||||
|
index_params[:offset] || 0
|
||||||
|
end
|
||||||
|
|
||||||
|
def serialized_invoices(invoices)
|
||||||
|
return invoices.map(&:number) unless index_params[:details] == 'true'
|
||||||
|
|
||||||
|
simple = index_params[:simple] == 'true' || false
|
||||||
|
invoices.map { |i| Serializers::Repp::Invoice.new(i, simplify: simple).to_json }
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
35
app/controllers/repp/v1/registrar/auth_controller.rb
Normal file
35
app/controllers/repp/v1/registrar/auth_controller.rb
Normal file
|
@ -0,0 +1,35 @@
|
||||||
|
module Repp
|
||||||
|
module V1
|
||||||
|
module Registrar
|
||||||
|
class AuthController < BaseController
|
||||||
|
skip_before_action :authenticate_user, only: :tara_callback
|
||||||
|
skip_before_action :check_ip_restriction, only: :tara_callback
|
||||||
|
skip_before_action :validate_client_certs, only: :tara_callback
|
||||||
|
|
||||||
|
api :GET, 'repp/v1/registrar/auth'
|
||||||
|
desc 'check user auth info and return data'
|
||||||
|
def index
|
||||||
|
registrar = current_user.registrar
|
||||||
|
render_success(data: auth_values_to_data(registrar: registrar))
|
||||||
|
end
|
||||||
|
|
||||||
|
api :POST, 'repp/v1/registrar/auth/tara_callback'
|
||||||
|
desc 'check tara callback omniauth user info and return token'
|
||||||
|
def tara_callback
|
||||||
|
user = ApiUser.from_omniauth(auth_params)
|
||||||
|
response = { code: 401, message: I18n.t(:no_such_user), data: {} }
|
||||||
|
render(json: response, status: :unauthorized) and return unless user && user&.active
|
||||||
|
|
||||||
|
token = Base64.urlsafe_encode64("#{user.username}:#{user.plain_text_password}")
|
||||||
|
render_success(data: { token: token, username: user.username })
|
||||||
|
end
|
||||||
|
|
||||||
|
private
|
||||||
|
|
||||||
|
def auth_params
|
||||||
|
params.require(:auth).permit(:uid, :new_user_id)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
|
@ -19,15 +19,17 @@ module Repp
|
||||||
end
|
end
|
||||||
|
|
||||||
def update # rubocop:disable Metrics/MethodLength
|
def update # rubocop:disable Metrics/MethodLength
|
||||||
|
authorize! :manage, :repp
|
||||||
affected, errored = if hostname.present?
|
affected, errored = if hostname.present?
|
||||||
current_user.registrar.replace_nameservers(hostname,
|
current_user.registrar
|
||||||
hostname_params[:data][:attributes],
|
.replace_nameservers(hostname,
|
||||||
|
hostname_params[:attributes],
|
||||||
domains: domains_from_params)
|
domains: domains_from_params)
|
||||||
else
|
else
|
||||||
current_user.registrar.add_nameservers(hostname_params[:data][:attributes],
|
current_user.registrar
|
||||||
|
.add_nameservers(hostname_params[:attributes],
|
||||||
domains: domains_from_params)
|
domains: domains_from_params)
|
||||||
end
|
end
|
||||||
|
|
||||||
render_success(data: data_format_for_success(affected, errored))
|
render_success(data: data_format_for_success(affected, errored))
|
||||||
rescue ActiveRecord::RecordInvalid => e
|
rescue ActiveRecord::RecordInvalid => e
|
||||||
handle_errors(e.record)
|
handle_errors(e.record)
|
||||||
|
@ -36,34 +38,33 @@ module Repp
|
||||||
private
|
private
|
||||||
|
|
||||||
def domains_from_params
|
def domains_from_params
|
||||||
return [] unless params[:data][:domains]
|
return [] unless hostname_params[:domains]
|
||||||
|
|
||||||
params[:data][:domains].map(&:downcase)
|
hostname_params[:domains].map(&:downcase)
|
||||||
end
|
end
|
||||||
|
|
||||||
def data_format_for_success(affected_domains, errored_domains)
|
def data_format_for_success(affected_domains, errored_domains)
|
||||||
{
|
{
|
||||||
type: 'nameserver',
|
type: 'nameserver',
|
||||||
id: params[:data][:attributes][:hostname],
|
id: hostname_params[:attributes][:hostname],
|
||||||
attributes: params[:data][:attributes],
|
attributes: hostname_params[:attributes],
|
||||||
affected_domains: affected_domains,
|
affected_domains: affected_domains || [],
|
||||||
skipped_domains: errored_domains,
|
skipped_domains: errored_domains || [],
|
||||||
}
|
}
|
||||||
end
|
end
|
||||||
|
|
||||||
def hostname_params
|
def hostname_params
|
||||||
params.require(:data).require(%i[type])
|
params.require(:data).permit(:type, :id,
|
||||||
params.require(:data).require(:attributes).require([:hostname])
|
:domains, nameserver: [], domains: [],
|
||||||
|
attributes: [:hostname, { ipv4: [], ipv6: [] }])
|
||||||
params.permit(data: [
|
.tap do |data|
|
||||||
:type, :id,
|
data.require(:type)
|
||||||
{ domains: [],
|
data.require(:attributes).require([:hostname])
|
||||||
attributes: [:hostname, { ipv4: [], ipv6: [] }] }
|
end
|
||||||
])
|
|
||||||
end
|
end
|
||||||
|
|
||||||
def hostname
|
def hostname
|
||||||
hostname_params[:data][:id] || nil
|
hostname_params[:id] || nil
|
||||||
end
|
end
|
||||||
|
|
||||||
def verify_nameserver_existance
|
def verify_nameserver_existance
|
||||||
|
|
|
@ -2,7 +2,7 @@ module Repp
|
||||||
module V1
|
module V1
|
||||||
module Registrar
|
module Registrar
|
||||||
class NotificationsController < BaseController
|
class NotificationsController < BaseController
|
||||||
before_action :set_notification, only: [:update]
|
before_action :set_notification, only: %i[update show]
|
||||||
|
|
||||||
api :GET, '/repp/v1/registrar/notifications'
|
api :GET, '/repp/v1/registrar/notifications'
|
||||||
desc 'Get the latest unread poll message'
|
desc 'Get the latest unread poll message'
|
||||||
|
@ -39,7 +39,6 @@ module Repp
|
||||||
api :GET, '/repp/v1/registrar/notifications/:notification_id'
|
api :GET, '/repp/v1/registrar/notifications/:notification_id'
|
||||||
desc 'Get a specific poll message'
|
desc 'Get a specific poll message'
|
||||||
def show
|
def show
|
||||||
@notification = current_user.registrar.notifications.find(params[:id])
|
|
||||||
data = @notification.as_json(only: %i[id text attached_obj_id attached_obj_type read])
|
data = @notification.as_json(only: %i[id text attached_obj_id attached_obj_type read])
|
||||||
|
|
||||||
render_success(data: data)
|
render_success(data: data)
|
||||||
|
@ -51,6 +50,7 @@ module Repp
|
||||||
param :read, [true, 'true'], required: true, desc: 'Set as true to mark as read'
|
param :read, [true, 'true'], required: true, desc: 'Set as true to mark as read'
|
||||||
end
|
end
|
||||||
def update
|
def update
|
||||||
|
authorize! :manage, :poll
|
||||||
# rubocop:disable Style/AndOr
|
# rubocop:disable Style/AndOr
|
||||||
handle_errors(@notification) and return unless @notification.mark_as_read
|
handle_errors(@notification) and return unless @notification.mark_as_read
|
||||||
# rubocop:enable Style/AndOr
|
# rubocop:enable Style/AndOr
|
||||||
|
|
114
app/controllers/repp/v1/registrar/summary_controller.rb
Normal file
114
app/controllers/repp/v1/registrar/summary_controller.rb
Normal file
|
@ -0,0 +1,114 @@
|
||||||
|
module Repp
|
||||||
|
module V1
|
||||||
|
module Registrar
|
||||||
|
class SummaryController < BaseController
|
||||||
|
api :GET, 'repp/v1/registrar/summary'
|
||||||
|
desc 'check user summary info and return data'
|
||||||
|
|
||||||
|
def index
|
||||||
|
user = current_user
|
||||||
|
registrar = user.registrar
|
||||||
|
if can?(:manage, :poll)
|
||||||
|
user_notifications = user.unread_notifications
|
||||||
|
notification = user_notifications.order('created_at DESC').take
|
||||||
|
end
|
||||||
|
render_success(data: serialize_data(registrar: registrar,
|
||||||
|
notification: notification,
|
||||||
|
notifications_count: user_notifications&.count,
|
||||||
|
object: notification_object(notification)))
|
||||||
|
end
|
||||||
|
|
||||||
|
def serialized_domain_transfer(object)
|
||||||
|
{
|
||||||
|
name: object.domain_name, trStatus: object.status,
|
||||||
|
reID: object.new_registrar.code,
|
||||||
|
reDate: object.transfer_requested_at.try(:iso8601),
|
||||||
|
acID: object.old_registrar.code,
|
||||||
|
acDate: object.transferred_at.try(:iso8601) || object.wait_until.try(:iso8601),
|
||||||
|
exDate: object.domain_valid_to.iso8601
|
||||||
|
}
|
||||||
|
end
|
||||||
|
|
||||||
|
def serialized_contact_update_action(object)
|
||||||
|
{
|
||||||
|
contacts: object.to_non_available_contact_codes,
|
||||||
|
operation: object.operation,
|
||||||
|
opDate: object.created_at.utc.xmlschema,
|
||||||
|
svTrid: object.id,
|
||||||
|
who: object.user.username,
|
||||||
|
reason: 'Auto-update according to official data',
|
||||||
|
}
|
||||||
|
end
|
||||||
|
|
||||||
|
private
|
||||||
|
|
||||||
|
# rubocop:disable Style/RescueStandardError
|
||||||
|
def notification_object(notification)
|
||||||
|
return unless notification&.attached_obj_type || notification&.attached_obj_id
|
||||||
|
|
||||||
|
object_by_type(notification.attached_obj_type).find(notification.attached_obj_id)
|
||||||
|
rescue => e
|
||||||
|
# the data model might be inconsistent; or ...
|
||||||
|
# this could happen if the registrar does not dequeue messages,
|
||||||
|
# and then the domain was deleted
|
||||||
|
# SELECT messages.id, domains.name, messages.body FROM messages LEFT OUTER
|
||||||
|
# JOIN domains ON attached_obj_id::INTEGER = domains.id
|
||||||
|
# WHERE attached_obj_type = 'Epp::Domain' AND name IS NULL;
|
||||||
|
message = 'orphan message, domain deleted, registrar should dequeue: '
|
||||||
|
Rails.logger.error message + e.to_s
|
||||||
|
end
|
||||||
|
# rubocop:enable Style/RescueStandardError
|
||||||
|
|
||||||
|
def object_by_type(object_type)
|
||||||
|
Object.const_get(object_type)
|
||||||
|
rescue NameError
|
||||||
|
Object.const_get("Version::#{object_type}")
|
||||||
|
end
|
||||||
|
|
||||||
|
# rubocop:disable Metrics/MethodLength
|
||||||
|
def serialize_data(registrar:, notification:, notifications_count:, object: nil)
|
||||||
|
data = current_user.as_json(only: %i[id username])
|
||||||
|
data[:registrar_name] = registrar.name
|
||||||
|
data[:registrar_reg_no] = registrar.reg_no
|
||||||
|
data[:balance] = { amount: registrar.cash_account&.balance,
|
||||||
|
currency: registrar.cash_account&.currency }
|
||||||
|
data[:last_login_date] = last_login_date
|
||||||
|
data[:domains] = registrar.domains.count
|
||||||
|
data[:contacts] = registrar.contacts.count
|
||||||
|
data[:phone] = registrar.phone
|
||||||
|
data[:email] = registrar.email
|
||||||
|
data[:billing_email] = registrar.billing_email
|
||||||
|
data[:billing_address] = registrar.address
|
||||||
|
data[:notification] = serialized_notification(notification, object)
|
||||||
|
data[:notifications_count] = notifications_count
|
||||||
|
data
|
||||||
|
end
|
||||||
|
# rubocop:enable Metrics/MethodLength
|
||||||
|
|
||||||
|
def last_login_date
|
||||||
|
q = ApiLog::ReppLog.ransack({ request_path_eq: '/repp/v1/registrar/auth',
|
||||||
|
response_code_eq: '200',
|
||||||
|
api_user_name_cont: current_user.username,
|
||||||
|
request_method_eq: 'GET' })
|
||||||
|
q.sorts = 'id desc'
|
||||||
|
q.result.offset(1).first&.created_at
|
||||||
|
end
|
||||||
|
|
||||||
|
def serialized_notification(notification, object)
|
||||||
|
return unless notification
|
||||||
|
|
||||||
|
notification.created_at = notification.created_at.utc.xmlschema
|
||||||
|
obj_data = serialized_object(object, notification.attached_obj_type)
|
||||||
|
notification.as_json(only: %i[id text created_at attached_obj_id attached_obj_type])
|
||||||
|
.merge({ attached_obj_data: obj_data })
|
||||||
|
end
|
||||||
|
|
||||||
|
def serialized_object(object, obj_type)
|
||||||
|
return unless object
|
||||||
|
|
||||||
|
try("serialized_#{obj_type.underscore}", object)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
100
app/controllers/repp/v1/stats_controller.rb
Normal file
100
app/controllers/repp/v1/stats_controller.rb
Normal file
|
@ -0,0 +1,100 @@
|
||||||
|
module Repp
|
||||||
|
module V1
|
||||||
|
class StatsController < BaseController
|
||||||
|
api :get, '/repp/v1/stats/market_share_distribution'
|
||||||
|
desc 'Get market share and distribution of registrars'
|
||||||
|
param :q, Hash, required: true, desc: 'Period parameters for data' do
|
||||||
|
param :end_date, String, required: true, desc: 'Period end date'
|
||||||
|
end
|
||||||
|
def market_share_distribution
|
||||||
|
registrars = ::Registrar.where(test_registrar: false).joins(:domains)
|
||||||
|
.where(from_condition).where(to_condition)
|
||||||
|
grouped = registrars.group(:name).count
|
||||||
|
|
||||||
|
result = grouped.map do |key, value|
|
||||||
|
hash = { name: key.strip, y: value }
|
||||||
|
hash.merge!({ sliced: true, selected: true }) if current_user.registrar.name == key
|
||||||
|
hash
|
||||||
|
end
|
||||||
|
render_success(data: result)
|
||||||
|
end
|
||||||
|
|
||||||
|
# rubocop:disable Metrics/MethodLength
|
||||||
|
api :get, '/repp/v1/stats/market_share_growth_rate'
|
||||||
|
desc 'Get market share and growth rate of registrars'
|
||||||
|
param :q, Hash, required: true, desc: 'Period parameters for data' do
|
||||||
|
param :end_date, String, required: true, desc: 'Period end date'
|
||||||
|
param :compare_to_date, String, required: true, desc: 'Comparison date'
|
||||||
|
end
|
||||||
|
def market_share_growth_rate
|
||||||
|
registrars = ::Registrar.where(test_registrar: false).joins(:domains)
|
||||||
|
|
||||||
|
domains_by_rar = registrars.where(from_condition).where(to_condition).group(:name).count
|
||||||
|
prev_domains_by_rar = registrars.where(compare_to_condition).group(:name).count
|
||||||
|
|
||||||
|
set_zero_values!(domains_by_rar, prev_domains_by_rar)
|
||||||
|
|
||||||
|
market_share_by_rar = calculate_market_share(domains_by_rar)
|
||||||
|
prev_market_share_by_rar = calculate_market_share(prev_domains_by_rar)
|
||||||
|
|
||||||
|
result = { prev_data: { name: search_params[:compare_to_date],
|
||||||
|
domains: serialize(prev_domains_by_rar),
|
||||||
|
market_share: serialize(prev_market_share_by_rar) },
|
||||||
|
data: { name: search_params[:end_date],
|
||||||
|
domains: serialize(domains_by_rar),
|
||||||
|
market_share: serialize(market_share_by_rar) } }
|
||||||
|
render_success(data: result)
|
||||||
|
end
|
||||||
|
# rubocop:enable Metrics/MethodLength
|
||||||
|
|
||||||
|
private
|
||||||
|
|
||||||
|
def search_params
|
||||||
|
params.permit(:q, q: %i[start_date end_date compare_to_date])
|
||||||
|
.fetch(:q, {}) || {}
|
||||||
|
end
|
||||||
|
|
||||||
|
def from_condition
|
||||||
|
return unless search_params[:start_date]
|
||||||
|
|
||||||
|
"domains.created_at >= '#{to_date(search_params[:start_date])}'"
|
||||||
|
end
|
||||||
|
|
||||||
|
def to_condition
|
||||||
|
return unless search_params[:end_date]
|
||||||
|
|
||||||
|
"domains.created_at <= '#{to_date(search_params[:end_date]).end_of_month}'"
|
||||||
|
end
|
||||||
|
|
||||||
|
def compare_to_condition
|
||||||
|
return unless search_params[:compare_to_date]
|
||||||
|
|
||||||
|
"domains.created_at <= '#{to_date(search_params[:compare_to_date]).end_of_month}'"
|
||||||
|
end
|
||||||
|
|
||||||
|
def to_date(date_param)
|
||||||
|
Date.strptime(date_param, '%m.%y')
|
||||||
|
end
|
||||||
|
|
||||||
|
def serialize(rars)
|
||||||
|
rars.map { |key, value| [key, value] }
|
||||||
|
end
|
||||||
|
|
||||||
|
def set_zero_values!(cur, prev)
|
||||||
|
cur_dup = cur.dup
|
||||||
|
cur_dup.each_key do |k|
|
||||||
|
cur_dup[k] = prev[k] || 0
|
||||||
|
end
|
||||||
|
prev.clear.merge!(cur_dup)
|
||||||
|
end
|
||||||
|
|
||||||
|
def calculate_market_share(domains_by_rar)
|
||||||
|
sum = domains_by_rar.values.sum
|
||||||
|
domains_by_rar.transform_values do |v|
|
||||||
|
value = v.to_f / sum * 100.0
|
||||||
|
value < 0.1 ? value.round(3) : value.round(1)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
19
app/helpers/auction_helper.rb
Normal file
19
app/helpers/auction_helper.rb
Normal file
|
@ -0,0 +1,19 @@
|
||||||
|
module AuctionHelper
|
||||||
|
include ActionView::Helpers::TagHelper
|
||||||
|
|
||||||
|
def colorize_auction(auction)
|
||||||
|
case auction.status
|
||||||
|
when 'started' then render_status_black(auction.domain)
|
||||||
|
when 'awaiting_payment' then render_status_black(auction.domain)
|
||||||
|
else render_status_green(auction.domain)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def render_status_black(name)
|
||||||
|
tag.span name.to_s, style: 'color: black;'
|
||||||
|
end
|
||||||
|
|
||||||
|
def render_status_green(name)
|
||||||
|
tag.span name.to_s, style: 'color: green;'
|
||||||
|
end
|
||||||
|
end
|
|
@ -1,6 +0,0 @@
|
||||||
module Registrant::ApplicationHelper
|
|
||||||
def env_style
|
|
||||||
return '' if unstable_env.nil?
|
|
||||||
"background-image: url(#{image_path("registrar/bg-#{unstable_env}.png")});"
|
|
||||||
end
|
|
||||||
end
|
|
|
@ -19,12 +19,12 @@ module Actions
|
||||||
def maybe_change_email
|
def maybe_change_email
|
||||||
return if Rails.env.test?
|
return if Rails.env.test?
|
||||||
|
|
||||||
[:regex, :mx].each do |m|
|
%i[regex mx].each do |m|
|
||||||
result = Actions::SimpleMailValidator.run(email: contact.email, level: m)
|
result = Actions::SimpleMailValidator.run(email: contact.email, level: m)
|
||||||
|
|
||||||
next if result
|
next if result
|
||||||
|
|
||||||
contact.add_epp_error('2005', nil, "email didn't pass validation", I18n.t(:parameter_value_syntax_error))
|
err_text = "email '#{contact.email}' didn't pass validation"
|
||||||
|
contact.add_epp_error('2005', nil, nil, "#{I18n.t(:parameter_value_syntax_error)} #{err_text}")
|
||||||
@error = true
|
@error = true
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
|
|
|
@ -23,11 +23,12 @@ module Actions
|
||||||
def maybe_change_email
|
def maybe_change_email
|
||||||
return if Rails.env.test?
|
return if Rails.env.test?
|
||||||
|
|
||||||
[:regex, :mx].each do |m|
|
%i[regex mx].each do |m|
|
||||||
result = Actions::SimpleMailValidator.run(email: @new_attributes[:email], level: m)
|
result = Actions::SimpleMailValidator.run(email: @new_attributes[:email], level: m)
|
||||||
next if result
|
next if result
|
||||||
|
|
||||||
contact.add_epp_error('2005', nil, "email didn't pass validation", I18n.t(:parameter_value_syntax_error))
|
err_text = "email '#{new_attributes[:email]}' didn't pass validation"
|
||||||
|
contact.add_epp_error('2005', nil, nil, "#{I18n.t(:parameter_value_syntax_error)} #{err_text}")
|
||||||
@error = true
|
@error = true
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
|
@ -115,8 +116,9 @@ module Actions
|
||||||
contact.email_history = old_email
|
contact.email_history = old_email
|
||||||
updated = contact.save
|
updated = contact.save
|
||||||
|
|
||||||
if updated && email_changed && contact.registrant?
|
if updated && email_changed
|
||||||
ContactMailer.email_changed(contact: contact, old_email: old_email).deliver_now
|
contact.validation_events.where('event_data @> ?', { 'email': old_email }.to_json).destroy_all
|
||||||
|
ContactMailer.email_changed(contact: contact, old_email: old_email).deliver_now if contact.registrant?
|
||||||
end
|
end
|
||||||
|
|
||||||
updated
|
updated
|
||||||
|
|
|
@ -120,7 +120,7 @@ module Actions
|
||||||
contact = Contact.find_by(code: contact_code)
|
contact = Contact.find_by(code: contact_code)
|
||||||
arr = admin ? @admin_contacts : @tech_contacts
|
arr = admin ? @admin_contacts : @tech_contacts
|
||||||
if contact
|
if contact
|
||||||
arr << { contact_id: contact.id, contact_code_cache: contact.code }
|
arr << { contact_id: contact.id, contact_code: contact.code }
|
||||||
else
|
else
|
||||||
domain.add_epp_error('2303', 'contact', contact_code, %i[domain_contacts not_found])
|
domain.add_epp_error('2303', 'contact', contact_code, %i[domain_contacts not_found])
|
||||||
end
|
end
|
||||||
|
|
|
@ -32,7 +32,7 @@ module Actions
|
||||||
|
|
||||||
def verify?
|
def verify?
|
||||||
return false unless Setting.request_confirmation_on_domain_deletion_enabled
|
return false unless Setting.request_confirmation_on_domain_deletion_enabled
|
||||||
return false if params[:delete][:verified] == true
|
return false if true?(params[:delete][:verified])
|
||||||
|
|
||||||
true
|
true
|
||||||
end
|
end
|
||||||
|
@ -51,5 +51,9 @@ module Actions
|
||||||
end
|
end
|
||||||
true
|
true
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def true?(obj)
|
||||||
|
obj.to_s.downcase == 'true'
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -14,6 +14,7 @@ module Actions
|
||||||
assign_new_registrant if params[:registrant]
|
assign_new_registrant if params[:registrant]
|
||||||
assign_relational_modifications
|
assign_relational_modifications
|
||||||
assign_requested_statuses
|
assign_requested_statuses
|
||||||
|
|
||||||
::Actions::BaseAction.maybe_attach_legal_doc(domain, params[:legal_document])
|
::Actions::BaseAction.maybe_attach_legal_doc(domain, params[:legal_document])
|
||||||
|
|
||||||
commit
|
commit
|
||||||
|
@ -45,6 +46,10 @@ module Actions
|
||||||
def assign_new_registrant
|
def assign_new_registrant
|
||||||
domain.add_epp_error('2306', nil, nil, %i[registrant cannot_be_missing]) unless params[:registrant][:code]
|
domain.add_epp_error('2306', nil, nil, %i[registrant cannot_be_missing]) unless params[:registrant][:code]
|
||||||
|
|
||||||
|
contact_code = params[:registrant][:code]
|
||||||
|
contact = Contact.find_by(code: contact_code)
|
||||||
|
validate_email(contact.email) if contact
|
||||||
|
|
||||||
regt = Registrant.find_by(code: params[:registrant][:code])
|
regt = Registrant.find_by(code: params[:registrant][:code])
|
||||||
unless regt
|
unless regt
|
||||||
domain.add_epp_error('2303', 'registrant', params[:registrant], %i[registrant not_found])
|
domain.add_epp_error('2303', 'registrant', params[:registrant], %i[registrant not_found])
|
||||||
|
@ -120,9 +125,35 @@ module Actions
|
||||||
@dnskeys << { id: dnkey.id, _destroy: 1 } if dnkey
|
@dnskeys << { id: dnkey.id, _destroy: 1 } if dnkey
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def start_validate_email(props)
|
||||||
|
contact = Contact.find_by(code: props[0][:contact_code])
|
||||||
|
|
||||||
|
return if contact.nil?
|
||||||
|
|
||||||
|
validate_email(contact.email)
|
||||||
|
end
|
||||||
|
|
||||||
|
def validate_email(email)
|
||||||
|
return true if Rails.env.test?
|
||||||
|
|
||||||
|
%i[regex mx].each do |m|
|
||||||
|
result = Actions::SimpleMailValidator.run(email: email, level: m)
|
||||||
|
next if result
|
||||||
|
|
||||||
|
err_text = "email #{email} didn't pass validation"
|
||||||
|
domain.add_epp_error('2005', nil, nil, "#{I18n.t(:parameter_value_syntax_error)} #{err_text}")
|
||||||
|
@error = true
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
|
true
|
||||||
|
end
|
||||||
|
|
||||||
def assign_admin_contact_changes
|
def assign_admin_contact_changes
|
||||||
props = gather_domain_contacts(params[:contacts].select { |c| c[:type] == 'admin' })
|
props = gather_domain_contacts(params[:contacts].select { |c| c[:type] == 'admin' })
|
||||||
|
|
||||||
|
start_validate_email(props) if props.present?
|
||||||
|
|
||||||
if props.any? && domain.admin_change_prohibited?
|
if props.any? && domain.admin_change_prohibited?
|
||||||
domain.add_epp_error('2304', 'admin', DomainStatus::SERVER_ADMIN_CHANGE_PROHIBITED,
|
domain.add_epp_error('2304', 'admin', DomainStatus::SERVER_ADMIN_CHANGE_PROHIBITED,
|
||||||
I18n.t(:object_status_prohibits_operation))
|
I18n.t(:object_status_prohibits_operation))
|
||||||
|
@ -136,6 +167,8 @@ module Actions
|
||||||
props = gather_domain_contacts(params[:contacts].select { |c| c[:type] == 'tech' },
|
props = gather_domain_contacts(params[:contacts].select { |c| c[:type] == 'tech' },
|
||||||
admin: false)
|
admin: false)
|
||||||
|
|
||||||
|
start_validate_email(props) if props.present?
|
||||||
|
|
||||||
if props.any? && domain.tech_change_prohibited?
|
if props.any? && domain.tech_change_prohibited?
|
||||||
domain.add_epp_error('2304', 'tech', DomainStatus::SERVER_TECH_CHANGE_PROHIBITED,
|
domain.add_epp_error('2304', 'tech', DomainStatus::SERVER_TECH_CHANGE_PROHIBITED,
|
||||||
I18n.t(:object_status_prohibits_operation))
|
I18n.t(:object_status_prohibits_operation))
|
||||||
|
@ -173,7 +206,7 @@ module Actions
|
||||||
domain.add_epp_error('2306', 'contact', code,
|
domain.add_epp_error('2306', 'contact', code,
|
||||||
%i[domain_contacts admin_contact_can_be_only_private_person])
|
%i[domain_contacts admin_contact_can_be_only_private_person])
|
||||||
else
|
else
|
||||||
add ? { contact_id: obj.id, contact_code_cache: obj.code } : { id: obj.id, _destroy: 1 }
|
add ? { contact_id: obj.id, contact_code: obj.code } : { id: obj.id, _destroy: 1 }
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -208,7 +241,7 @@ module Actions
|
||||||
|
|
||||||
def verify_registrant_change?
|
def verify_registrant_change?
|
||||||
return validate_dispute_case if params[:reserved_pw]
|
return validate_dispute_case if params[:reserved_pw]
|
||||||
return false if !@changes_registrant || params[:registrant][:verified] == true
|
return false if !@changes_registrant || true?(params[:registrant][:verified])
|
||||||
return true unless domain.disputed?
|
return true unless domain.disputed?
|
||||||
|
|
||||||
domain.add_epp_error('2304', nil, nil, 'Required parameter missing; reservedpw element ' \
|
domain.add_epp_error('2304', nil, nil, 'Required parameter missing; reservedpw element ' \
|
||||||
|
@ -250,5 +283,9 @@ module Actions
|
||||||
|
|
||||||
false
|
false
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def true?(obj)
|
||||||
|
obj.to_s.downcase == 'true'
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -50,21 +50,21 @@ module Actions
|
||||||
end
|
end
|
||||||
|
|
||||||
def save_result(result)
|
def save_result(result)
|
||||||
if !result.success && @check_level == "mx"
|
contacts = Contact.where(email: email)
|
||||||
|
|
||||||
|
if !result.success && @check_level == 'mx'
|
||||||
result_validation = Actions::AAndAaaaEmailValidation.call(email: @email, value: 'A')
|
result_validation = Actions::AAndAaaaEmailValidation.call(email: @email, value: 'A')
|
||||||
output_a_and_aaaa_validation_results(email: @email,
|
output_a_and_aaaa_validation_results(email: @email, result: result_validation, type: 'A')
|
||||||
result: result_validation,
|
|
||||||
type: 'A')
|
|
||||||
|
|
||||||
result_validation = Actions::AAndAaaaEmailValidation.call(email: @email, value: 'AAAA') if result_validation.empty?
|
result_validation = Actions::AAndAaaaEmailValidation.call(email: @email, value: 'AAAA') if result_validation.empty?
|
||||||
output_a_and_aaaa_validation_results(email: @email,
|
output_a_and_aaaa_validation_results(email: @email, result: result_validation, type: 'AAAA')
|
||||||
result: result_validation,
|
result.success = result_validation.present?
|
||||||
type: 'AAAA')
|
end
|
||||||
|
|
||||||
result_validation.present? ? result.success = true : result.success = false
|
contacts.find_in_batches(batch_size: 500) do |contact_batches|
|
||||||
validation_eventable.validation_events.create(validation_event_attrs(result))
|
contact_batches.each do |contact|
|
||||||
else
|
contact.validation_events.create(validation_event_attrs(result))
|
||||||
validation_eventable.validation_events.create(validation_event_attrs(result))
|
end
|
||||||
end
|
end
|
||||||
rescue ActiveRecord::RecordNotSaved
|
rescue ActiveRecord::RecordNotSaved
|
||||||
logger.info "Cannot save validation result for #{log_object_id}"
|
logger.info "Cannot save validation result for #{log_object_id}"
|
||||||
|
@ -92,8 +92,7 @@ module Actions
|
||||||
when 'AAAA'
|
when 'AAAA'
|
||||||
ress = dns.getresources domain, Resolv::DNS::Resource::IN::AAAA
|
ress = dns.getresources domain, Resolv::DNS::Resource::IN::AAAA
|
||||||
end
|
end
|
||||||
|
result = ress.map(&:address)
|
||||||
result = ress.map { |r| r.address }
|
|
||||||
end
|
end
|
||||||
|
|
||||||
result
|
result
|
||||||
|
|
15
app/interactions/actions/invoice_cancel.rb
Normal file
15
app/interactions/actions/invoice_cancel.rb
Normal file
|
@ -0,0 +1,15 @@
|
||||||
|
module Actions
|
||||||
|
class InvoiceCancel
|
||||||
|
attr_reader :invoice
|
||||||
|
|
||||||
|
def initialize(invoice)
|
||||||
|
@invoice = invoice
|
||||||
|
end
|
||||||
|
|
||||||
|
def call
|
||||||
|
return false unless @invoice.can_be_cancelled?
|
||||||
|
|
||||||
|
@invoice.update(cancelled_at: Time.zone.now)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
|
@ -6,7 +6,6 @@ module Domains
|
||||||
domain.statuses += domain.admin_store_statuses_history || []
|
domain.statuses += domain.admin_store_statuses_history || []
|
||||||
domain.statuses.uniq!
|
domain.statuses.uniq!
|
||||||
|
|
||||||
domain.statuses_before_force_delete = nil
|
|
||||||
domain.force_delete_domain_statuses_history = nil
|
domain.force_delete_domain_statuses_history = nil
|
||||||
domain.admin_store_statuses_history = nil
|
domain.admin_store_statuses_history = nil
|
||||||
domain.save(validate: false)
|
domain.save(validate: false)
|
||||||
|
|
|
@ -6,18 +6,26 @@ module Domains
|
||||||
end
|
end
|
||||||
|
|
||||||
def notify_without_email
|
def notify_without_email
|
||||||
domain.registrar.notifications.create!(text: I18n.t('force_delete_set_on_domain',
|
template = I18n.t('force_delete_set_on_domain',
|
||||||
domain_name: domain.name,
|
domain_name: domain.name,
|
||||||
outzone_date: domain.outzone_date,
|
outzone_date: domain.outzone_date,
|
||||||
purge_date: domain.purge_date))
|
purge_date: domain.purge_date)
|
||||||
|
|
||||||
|
return if domain.registrar&.notifications&.last&.text&.include? template
|
||||||
|
|
||||||
|
domain.registrar.notifications.create!(text: template)
|
||||||
end
|
end
|
||||||
|
|
||||||
def notify_with_email
|
def notify_with_email
|
||||||
domain.registrar.notifications.create!(text: I18n.t('force_delete_auto_email',
|
template = I18n.t('force_delete_auto_email',
|
||||||
domain_name: domain.name,
|
domain_name: domain.name,
|
||||||
outzone_date: domain.outzone_date,
|
outzone_date: domain.outzone_date,
|
||||||
purge_date: domain.purge_date,
|
purge_date: domain.purge_date,
|
||||||
email: email))
|
email: email)
|
||||||
|
|
||||||
|
return if domain.registrar&.notifications&.last&.text&.include? template
|
||||||
|
|
||||||
|
domain.registrar.notifications.create!(text: template)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -7,7 +7,6 @@ module Domains
|
||||||
|
|
||||||
def execute
|
def execute
|
||||||
domain.force_delete_domain_statuses_history = domain.statuses
|
domain.force_delete_domain_statuses_history = domain.statuses
|
||||||
domain.statuses_before_force_delete = domain.statuses
|
|
||||||
domain.statuses |= STATUSES_TO_SET
|
domain.statuses |= STATUSES_TO_SET
|
||||||
domain.save(validate: false)
|
domain.save(validate: false)
|
||||||
end
|
end
|
||||||
|
|
|
@ -31,18 +31,21 @@ module Domains
|
||||||
def before_execute_force_delete(domain)
|
def before_execute_force_delete(domain)
|
||||||
if domain.force_delete_scheduled? && !domain.status_notes[DomainStatus::FORCE_DELETE].nil?
|
if domain.force_delete_scheduled? && !domain.status_notes[DomainStatus::FORCE_DELETE].nil?
|
||||||
added_additional_email_into_notes(domain)
|
added_additional_email_into_notes(domain)
|
||||||
notify_registrar(domain)
|
|
||||||
else
|
else
|
||||||
process_force_delete(domain)
|
process_force_delete(domain)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def notify_registrar(domain)
|
def notify_registrar(domain)
|
||||||
domain.registrar.notifications.create!(text: I18n.t('force_delete_auto_email',
|
template = I18n.t('force_delete_auto_email',
|
||||||
domain_name: domain.name,
|
domain_name: domain.name,
|
||||||
outzone_date: domain.outzone_date,
|
outzone_date: domain.outzone_date,
|
||||||
purge_date: domain.purge_date,
|
purge_date: domain.purge_date,
|
||||||
email: domain.status_notes[DomainStatus::FORCE_DELETE]))
|
email: domain.status_notes[DomainStatus::FORCE_DELETE])
|
||||||
|
|
||||||
|
return if domain.registrar.notifications.last.text.include? template
|
||||||
|
|
||||||
|
domain.registrar.notifications.create!(text: template)
|
||||||
end
|
end
|
||||||
|
|
||||||
def process_force_delete(domain)
|
def process_force_delete(domain)
|
||||||
|
@ -56,6 +59,8 @@ module Domains
|
||||||
def added_additional_email_into_notes(domain)
|
def added_additional_email_into_notes(domain)
|
||||||
return if domain.status_notes[DomainStatus::FORCE_DELETE].include? email
|
return if domain.status_notes[DomainStatus::FORCE_DELETE].include? email
|
||||||
|
|
||||||
|
# notify_registrar(domain)
|
||||||
|
|
||||||
domain.status_notes[DomainStatus::FORCE_DELETE].concat(" #{email}")
|
domain.status_notes[DomainStatus::FORCE_DELETE].concat(" #{email}")
|
||||||
domain.save(validate: false)
|
domain.save(validate: false)
|
||||||
end
|
end
|
||||||
|
|
43
app/jobs/check_force_delete_job.rb
Normal file
43
app/jobs/check_force_delete_job.rb
Normal file
|
@ -0,0 +1,43 @@
|
||||||
|
class CheckForceDeleteJob < ApplicationJob
|
||||||
|
def perform(contact_ids)
|
||||||
|
contacts = Contact.find(contact_ids)
|
||||||
|
|
||||||
|
contacts.each do |contact|
|
||||||
|
email = contact.email
|
||||||
|
|
||||||
|
if contact.need_to_start_force_delete?
|
||||||
|
Domains::ForceDeleteEmail::Base.run(email: email)
|
||||||
|
elsif contact.need_to_lift_force_delete?
|
||||||
|
domain_list(email).each { |domain| refresh_status_notes(contact, domain) }
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
private
|
||||||
|
|
||||||
|
def refresh_status_notes(contact, domain)
|
||||||
|
force_delete_emails = domain.status_notes[DomainStatus::FORCE_DELETE]
|
||||||
|
return unless force_delete_emails
|
||||||
|
|
||||||
|
force_delete_emails.slice!(contact.email_history)
|
||||||
|
force_delete_emails.lstrip!
|
||||||
|
domain.save(validate: false)
|
||||||
|
|
||||||
|
notify_registrar(domain) unless force_delete_emails.empty?
|
||||||
|
end
|
||||||
|
|
||||||
|
def domain_list(email)
|
||||||
|
domain_contacts = Contact.where(email: email).map(&:domain_contacts).flatten
|
||||||
|
registrant_ids = Registrant.where(email: email).pluck(:id)
|
||||||
|
|
||||||
|
(domain_contacts.map(&:domain).flatten + Domain.where(registrant_id: registrant_ids)).uniq
|
||||||
|
end
|
||||||
|
|
||||||
|
def notify_registrar(domain)
|
||||||
|
domain.registrar.notifications.create!(text: I18n.t('force_delete_auto_email',
|
||||||
|
domain_name: domain.name,
|
||||||
|
outzone_date: domain.outzone_date,
|
||||||
|
purge_date: domain.purge_date,
|
||||||
|
email: domain.status_notes[DomainStatus::FORCE_DELETE]))
|
||||||
|
end
|
||||||
|
end
|
10
app/jobs/delete_monthly_invoices_job.rb
Normal file
10
app/jobs/delete_monthly_invoices_job.rb
Normal file
|
@ -0,0 +1,10 @@
|
||||||
|
class DeleteMonthlyInvoicesJob < ApplicationJob
|
||||||
|
queue_as :default
|
||||||
|
|
||||||
|
def perform
|
||||||
|
@month = Time.zone.now - 1.month
|
||||||
|
invoices = Invoice.where(monthly_invoice: true, issue_date: @month.end_of_month.to_date,
|
||||||
|
in_directo: false, e_invoice_sent_at: nil)
|
||||||
|
invoices.delete_all
|
||||||
|
end
|
||||||
|
end
|
|
@ -1,59 +1,31 @@
|
||||||
class DirectoInvoiceForwardJob < ApplicationJob
|
class DirectoInvoiceForwardJob < ApplicationJob
|
||||||
def perform(monthly: false, dry: false)
|
def perform(monthly: false, dry: false)
|
||||||
@dry = dry
|
data = nil
|
||||||
(@month = Time.zone.now - 1.month) if monthly
|
|
||||||
|
|
||||||
@client = new_directo_client
|
if monthly
|
||||||
monthly ? send_monthly_invoices : send_receipts
|
@month = Time.zone.now - 1.month
|
||||||
|
data = collect_monthly_data
|
||||||
|
else
|
||||||
|
data = collect_receipts_data
|
||||||
end
|
end
|
||||||
|
|
||||||
def new_directo_client
|
EisBilling::SendDataToDirecto.send_request(object_data: data, monthly: monthly, dry: dry)
|
||||||
DirectoApi::Client.new(ENV['directo_invoice_url'], Setting.directo_sales_agent,
|
|
||||||
Setting.directo_receipt_payment_term)
|
|
||||||
end
|
end
|
||||||
|
|
||||||
def send_receipts
|
def collect_receipts_data
|
||||||
unsent_invoices = Invoice.where(in_directo: false).non_cancelled
|
unsent_invoices = Invoice.where(in_directo: false).non_cancelled
|
||||||
|
collected_data = []
|
||||||
|
|
||||||
Rails.logger.info("[DIRECTO] Trying to send #{unsent_invoices.count} prepayment invoices")
|
|
||||||
unsent_invoices.each do |invoice|
|
unsent_invoices.each do |invoice|
|
||||||
unless valid_invoice_conditions?(invoice)
|
unless valid_invoice_conditions?(invoice)
|
||||||
Rails.logger.info "[DIRECTO] Invoice #{invoice.number} has been skipped"
|
Rails.logger.info "[DIRECTO] Invoice #{invoice.number} has been skipped"
|
||||||
next
|
next
|
||||||
end
|
end
|
||||||
@client.invoices.add_with_schema(invoice: invoice.as_directo_json, schema: 'prepayment')
|
|
||||||
|
collected_data << invoice.as_directo_json
|
||||||
end
|
end
|
||||||
|
|
||||||
sync_with_directo
|
collected_data
|
||||||
end
|
|
||||||
|
|
||||||
def send_monthly_invoices
|
|
||||||
Registrar.where.not(test_registrar: true).find_each do |registrar|
|
|
||||||
next unless registrar.cash_account
|
|
||||||
|
|
||||||
@client = new_directo_client
|
|
||||||
send_invoice_for_registrar(registrar)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
def send_invoice_for_registrar(registrar)
|
|
||||||
summary = registrar.monthly_summary(month: @month)
|
|
||||||
@client.invoices.add_with_schema(invoice: summary, schema: 'summary') unless summary.nil?
|
|
||||||
|
|
||||||
sync_with_directo if @client.invoices.count.positive?
|
|
||||||
end
|
|
||||||
|
|
||||||
def assign_monthly_numbers
|
|
||||||
raise 'Directo Counter is going to be out of period!' if directo_counter_exceedable?(@client.invoices.count)
|
|
||||||
|
|
||||||
min_directo = Setting.directo_monthly_number_min.presence.try(:to_i)
|
|
||||||
directo_number = [Setting.directo_monthly_number_last.presence.try(:to_i),
|
|
||||||
min_directo].compact.max || 0
|
|
||||||
|
|
||||||
@client.invoices.each do |inv|
|
|
||||||
directo_number += 1
|
|
||||||
inv.number = directo_number
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
|
||||||
def valid_invoice_conditions?(invoice)
|
def valid_invoice_conditions?(invoice)
|
||||||
|
@ -67,28 +39,17 @@ class DirectoInvoiceForwardJob < ApplicationJob
|
||||||
true
|
true
|
||||||
end
|
end
|
||||||
|
|
||||||
def sync_with_directo
|
def collect_monthly_data
|
||||||
assign_monthly_numbers if @month
|
registrars_data = []
|
||||||
Rails.logger.info("[Directo] - attempting to send following XML:\n #{@client.invoices.as_xml}")
|
|
||||||
return if @dry
|
|
||||||
|
|
||||||
res = @client.invoices.deliver(ssl_verify: false)
|
Registrar.where.not(test_registrar: true).find_each do |registrar|
|
||||||
process_directo_response(res.body, @client.invoices.as_xml)
|
registrars_data << {
|
||||||
rescue SocketError, Errno::ECONNREFUSED, Timeout::Error, Errno::EINVAL, Errno::ECONNRESET,
|
registrar: registrar,
|
||||||
EOFError, Net::HTTPBadResponse, Net::HTTPHeaderSyntaxError, Net::ProtocolError
|
registrar_summery: registrar.monthly_summary(month: @month),
|
||||||
Rails.logger.info('[Directo] Failed to communicate via API')
|
}
|
||||||
end
|
end
|
||||||
|
|
||||||
def process_directo_response(xml, req)
|
registrars_data
|
||||||
Rails.logger.info "[Directo] - Responded with body: #{xml}"
|
|
||||||
Nokogiri::XML(xml).css('Result').each do |res|
|
|
||||||
if @month
|
|
||||||
mark_invoice_as_sent(res: res, req: req)
|
|
||||||
else
|
|
||||||
inv = Invoice.find_by(number: res.attributes['docid'].value.to_i)
|
|
||||||
mark_invoice_as_sent(invoice: inv, res: res, req: req)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
|
||||||
def mark_invoice_as_sent(invoice: nil, res:, req:)
|
def mark_invoice_as_sent(invoice: nil, res:, req:)
|
||||||
|
|
125
app/jobs/directo_invoice_forward_legacy_job.rb
Normal file
125
app/jobs/directo_invoice_forward_legacy_job.rb
Normal file
|
@ -0,0 +1,125 @@
|
||||||
|
class DirectoInvoiceForwardLegacyJob < ApplicationJob
|
||||||
|
def perform(monthly: false, dry: false)
|
||||||
|
@dry = dry
|
||||||
|
(@month = Time.zone.now - 1.month) if monthly
|
||||||
|
|
||||||
|
@client = new_directo_client
|
||||||
|
monthly ? send_monthly_invoices : send_receipts
|
||||||
|
end
|
||||||
|
|
||||||
|
def new_directo_client
|
||||||
|
DirectoApi::Client.new(ENV['directo_invoice_url'], Setting.directo_sales_agent,
|
||||||
|
Setting.directo_receipt_payment_term)
|
||||||
|
end
|
||||||
|
|
||||||
|
def send_receipts
|
||||||
|
unsent_invoices = Invoice.where(in_directo: false).non_cancelled
|
||||||
|
|
||||||
|
Rails.logger.info("[DIRECTO] Trying to send #{unsent_invoices.count} prepayment invoices")
|
||||||
|
unsent_invoices.each do |invoice|
|
||||||
|
unless valid_invoice_conditions?(invoice)
|
||||||
|
Rails.logger.info "[DIRECTO] Invoice #{invoice.number} has been skipped"
|
||||||
|
next
|
||||||
|
end
|
||||||
|
|
||||||
|
@client.invoices.add_with_schema(invoice: invoice.as_directo_json, schema: 'prepayment')
|
||||||
|
end
|
||||||
|
|
||||||
|
sync_with_directo
|
||||||
|
end
|
||||||
|
|
||||||
|
def send_monthly_invoices
|
||||||
|
Registrar.where.not(test_registrar: true).find_each do |registrar|
|
||||||
|
next unless registrar.cash_account
|
||||||
|
|
||||||
|
@client = new_directo_client
|
||||||
|
send_invoice_for_registrar(registrar)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def send_invoice_for_registrar(registrar)
|
||||||
|
summary = registrar.monthly_summary(month: @month)
|
||||||
|
@client.invoices.add_with_schema(invoice: summary, schema: 'summary') unless summary.nil?
|
||||||
|
|
||||||
|
sync_with_directo if @client.invoices.count.positive?
|
||||||
|
end
|
||||||
|
|
||||||
|
def assign_monthly_numbers
|
||||||
|
raise 'Directo Counter is going to be out of period!' if directo_counter_exceedable?(@client.invoices.count)
|
||||||
|
|
||||||
|
min_directo = Setting.directo_monthly_number_min.presence.try(:to_i)
|
||||||
|
directo_number = [Setting.directo_monthly_number_last.presence.try(:to_i),
|
||||||
|
min_directo].compact.max || 0
|
||||||
|
|
||||||
|
@client.invoices.each do |inv|
|
||||||
|
directo_number += 1
|
||||||
|
inv.number = directo_number
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def valid_invoice_conditions?(invoice)
|
||||||
|
if invoice.account_activity.nil? || invoice.account_activity.bank_transaction.nil? ||
|
||||||
|
invoice.account_activity.bank_transaction.sum.nil? ||
|
||||||
|
invoice.account_activity.bank_transaction.sum != invoice.total
|
||||||
|
return false
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
true
|
||||||
|
end
|
||||||
|
|
||||||
|
def sync_with_directo
|
||||||
|
assign_monthly_numbers if @month
|
||||||
|
|
||||||
|
Rails.logger.info("[Directo] - attempting to send following XML:\n #{@client.invoices.as_xml}")
|
||||||
|
return if @dry
|
||||||
|
|
||||||
|
res = @client.invoices.deliver(ssl_verify: false)
|
||||||
|
process_directo_response(res.body, @client.invoices.as_xml)
|
||||||
|
rescue SocketError, Errno::ECONNREFUSED, Timeout::Error, Errno::EINVAL, Errno::ECONNRESET,
|
||||||
|
EOFError, Net::HTTPBadResponse, Net::HTTPHeaderSyntaxError, Net::ProtocolError
|
||||||
|
Rails.logger.info('[Directo] Failed to communicate via API')
|
||||||
|
end
|
||||||
|
|
||||||
|
def process_directo_response(xml, req)
|
||||||
|
Rails.logger.info "[Directo] - Responded with body: #{xml}"
|
||||||
|
Nokogiri::XML(xml).css('Result').each do |res|
|
||||||
|
if @month
|
||||||
|
mark_invoice_as_sent(res: res, req: req)
|
||||||
|
else
|
||||||
|
inv = Invoice.find_by(number: res.attributes['docid'].value.to_i)
|
||||||
|
mark_invoice_as_sent(invoice: inv, res: res, req: req)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def mark_invoice_as_sent(invoice: nil, res:, req:)
|
||||||
|
directo_record = Directo.new(response: res.as_json.to_h,
|
||||||
|
request: req, invoice_number: res.attributes['docid'].value.to_i)
|
||||||
|
if invoice
|
||||||
|
directo_record.item = invoice
|
||||||
|
invoice.update(in_directo: true)
|
||||||
|
else
|
||||||
|
update_directo_number(num: directo_record.invoice_number)
|
||||||
|
end
|
||||||
|
|
||||||
|
directo_record.save!
|
||||||
|
end
|
||||||
|
|
||||||
|
def update_directo_number(num:)
|
||||||
|
return unless num.to_i > Setting.directo_monthly_number_last.to_i
|
||||||
|
|
||||||
|
Setting.directo_monthly_number_last = num.to_i
|
||||||
|
end
|
||||||
|
|
||||||
|
def directo_counter_exceedable?(invoice_count)
|
||||||
|
min_directo = Setting.directo_monthly_number_min.presence.try(:to_i)
|
||||||
|
max_directo = Setting.directo_monthly_number_max.presence.try(:to_i)
|
||||||
|
last_directo = [Setting.directo_monthly_number_last.presence.try(:to_i),
|
||||||
|
min_directo].compact.max || 0
|
||||||
|
|
||||||
|
return true if max_directo && max_directo < (last_directo + invoice_count)
|
||||||
|
|
||||||
|
false
|
||||||
|
end
|
||||||
|
end
|
|
@ -64,12 +64,11 @@ class NameserverRecordValidationJob < ApplicationJob
|
||||||
nameserver.save
|
nameserver.save
|
||||||
end
|
end
|
||||||
|
|
||||||
def add_nameserver_to_failed(nameserver:, reason:)
|
def add_nameserver_to_failed(nameserver:, reason:, result_reason:)
|
||||||
if nameserver.validation_counter.nil?
|
return cname_case_handle(nameserver: nameserver, reason: reason) if result_reason == 'cname'
|
||||||
nameserver.validation_counter = 1
|
|
||||||
else
|
nameserver.validation_counter = 1 if nameserver.validation_counter.nil?
|
||||||
nameserver.validation_counter = nameserver.validation_counter + 1
|
nameserver.validation_counter = nameserver.validation_counter + 1
|
||||||
end
|
|
||||||
|
|
||||||
nameserver.failed_validation_reason = reason
|
nameserver.failed_validation_reason = reason
|
||||||
nameserver.save
|
nameserver.save
|
||||||
|
@ -77,15 +76,25 @@ class NameserverRecordValidationJob < ApplicationJob
|
||||||
failed_log(text: reason, nameserver: nameserver, domain: nameserver.domain) if nameserver.failed_validation?
|
failed_log(text: reason, nameserver: nameserver, domain: nameserver.domain) if nameserver.failed_validation?
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def cname_case_handle(nameserver:, reason:)
|
||||||
|
nameserver.validation_datetime = Time.zone.now
|
||||||
|
nameserver.failed_validation_reason = reason
|
||||||
|
nameserver.save
|
||||||
|
|
||||||
|
failed_log(text: reason, nameserver: nameserver, domain: nameserver.domain)
|
||||||
|
end
|
||||||
|
|
||||||
def parse_result(result, nameserver)
|
def parse_result(result, nameserver)
|
||||||
domain = Domain.find(nameserver.domain_id)
|
domain = Domain.find(nameserver.domain_id)
|
||||||
|
|
||||||
text = ""
|
text = ''
|
||||||
case result[:reason]
|
case result[:reason]
|
||||||
when 'answer'
|
when 'answer'
|
||||||
text = "No any answer comes from **#{nameserver.hostname}**. Nameserver not exist"
|
text = "DNS Server **#{nameserver.hostname}** not responding"
|
||||||
when 'serial'
|
when 'serial'
|
||||||
text = "Serial number for nameserver hostname **#{nameserver.hostname}** doesn't present. SOA validation failed."
|
text = "Serial number for nameserver hostname **#{nameserver.hostname}** of #{nameserver.domain.name} doesn't present in zone. SOA validation failed."
|
||||||
|
when 'cname'
|
||||||
|
text = "Warning: SOA record expected but CNAME found instead. This setup can lead to unexpected errors when using the domain: hostname - **#{nameserver.hostname}** of #{nameserver.domain.name}"
|
||||||
when 'not found'
|
when 'not found'
|
||||||
text = "Seems nameserver hostname **#{nameserver.hostname}** doesn't exist"
|
text = "Seems nameserver hostname **#{nameserver.hostname}** doesn't exist"
|
||||||
when 'exception'
|
when 'exception'
|
||||||
|
@ -97,7 +106,7 @@ class NameserverRecordValidationJob < ApplicationJob
|
||||||
end
|
end
|
||||||
|
|
||||||
logger.info text
|
logger.info text
|
||||||
add_nameserver_to_failed(nameserver: nameserver, reason: text)
|
add_nameserver_to_failed(nameserver: nameserver, reason: text, result_reason: result[:reason])
|
||||||
false
|
false
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
@ -6,7 +6,8 @@ class SendEInvoiceJob < ApplicationJob
|
||||||
invoice = Invoice.find_by(id: invoice_id)
|
invoice = Invoice.find_by(id: invoice_id)
|
||||||
return unless need_to_process_invoice?(invoice: invoice, payable: payable)
|
return unless need_to_process_invoice?(invoice: invoice, payable: payable)
|
||||||
|
|
||||||
process(invoice: invoice, payable: payable)
|
send_invoice_to_eis_billing(invoice: invoice, payable: payable)
|
||||||
|
invoice.update(e_invoice_sent_at: Time.zone.now)
|
||||||
rescue StandardError => e
|
rescue StandardError => e
|
||||||
log_error(invoice: invoice, error: e)
|
log_error(invoice: invoice, error: e)
|
||||||
raise e
|
raise e
|
||||||
|
@ -22,16 +23,9 @@ class SendEInvoiceJob < ApplicationJob
|
||||||
true
|
true
|
||||||
end
|
end
|
||||||
|
|
||||||
def process(invoice:, payable:)
|
def send_invoice_to_eis_billing(invoice:, payable:)
|
||||||
invoice.to_e_invoice(payable: payable).deliver unless Rails.env.development?
|
result = EisBilling::SendEInvoice.send_request(invoice: invoice, payable: payable)
|
||||||
invoice.update(e_invoice_sent_at: Time.zone.now)
|
logger.info result.body
|
||||||
log_success(invoice)
|
|
||||||
end
|
|
||||||
|
|
||||||
def log_success(invoice)
|
|
||||||
id = invoice.try(:id) || invoice
|
|
||||||
message = "E-Invoice for an invoice with ID # #{id} was sent successfully"
|
|
||||||
logger.info message
|
|
||||||
end
|
end
|
||||||
|
|
||||||
def log_error(invoice:, error:)
|
def log_error(invoice:, error:)
|
||||||
|
|
51
app/jobs/send_e_invoice_legacy_job.rb
Normal file
51
app/jobs/send_e_invoice_legacy_job.rb
Normal file
|
@ -0,0 +1,51 @@
|
||||||
|
class SendEInvoiceLegacyJob < ApplicationJob
|
||||||
|
discard_on HTTPClient::TimeoutError
|
||||||
|
|
||||||
|
def perform(invoice_id, payable: true)
|
||||||
|
logger.info "Started to process e-invoice for invoice_id #{invoice_id}"
|
||||||
|
invoice = Invoice.find_by(id: invoice_id)
|
||||||
|
return unless need_to_process_invoice?(invoice: invoice, payable: payable)
|
||||||
|
|
||||||
|
process(invoice: invoice, payable: payable)
|
||||||
|
rescue StandardError => e
|
||||||
|
log_error(invoice: invoice, error: e)
|
||||||
|
raise e
|
||||||
|
end
|
||||||
|
|
||||||
|
private
|
||||||
|
|
||||||
|
def need_to_process_invoice?(invoice:, payable:)
|
||||||
|
logger.info "Checking if need to process e-invoice #{invoice}, payable: #{payable}"
|
||||||
|
unprocessable = invoice.do_not_send_e_invoice? && (invoice.monthly_invoice ? true : payable)
|
||||||
|
return false if invoice.blank?
|
||||||
|
return false if unprocessable
|
||||||
|
|
||||||
|
true
|
||||||
|
end
|
||||||
|
|
||||||
|
def process(invoice:, payable:)
|
||||||
|
invoice.to_e_invoice(payable: payable).deliver unless Rails.env.development?
|
||||||
|
invoice.update(e_invoice_sent_at: Time.zone.now)
|
||||||
|
log_success(invoice)
|
||||||
|
end
|
||||||
|
|
||||||
|
def log_success(invoice)
|
||||||
|
id = invoice.try(:id) || invoice
|
||||||
|
message = "E-Invoice for an invoice with ID # #{id} was sent successfully"
|
||||||
|
logger.info message
|
||||||
|
end
|
||||||
|
|
||||||
|
def log_error(invoice:, error:)
|
||||||
|
id = invoice.try(:id) || invoice
|
||||||
|
message = <<~TEXT.squish
|
||||||
|
There was an error sending e-invoice for invoice with ID # #{id}.
|
||||||
|
The error message was the following: #{error}
|
||||||
|
This job will retry.
|
||||||
|
TEXT
|
||||||
|
logger.error message
|
||||||
|
end
|
||||||
|
|
||||||
|
def logger
|
||||||
|
Rails.logger
|
||||||
|
end
|
||||||
|
end
|
147
app/jobs/send_monthly_invoices_job.rb
Normal file
147
app/jobs/send_monthly_invoices_job.rb
Normal file
|
@ -0,0 +1,147 @@
|
||||||
|
class SendMonthlyInvoicesJob < ApplicationJob # rubocop:disable Metrics/ClassLength
|
||||||
|
queue_as :default
|
||||||
|
|
||||||
|
def perform(dry: false)
|
||||||
|
@dry = dry
|
||||||
|
@month = Time.zone.now - 1.month
|
||||||
|
@directo_client = new_directo_client
|
||||||
|
@min_directo_num = Setting.directo_monthly_number_min.presence.try(:to_i)
|
||||||
|
@max_directo_num = Setting.directo_monthly_number_max.presence.try(:to_i)
|
||||||
|
|
||||||
|
send_monthly_invoices
|
||||||
|
end
|
||||||
|
|
||||||
|
def new_directo_client
|
||||||
|
DirectoApi::Client.new(ENV['directo_invoice_url'], Setting.directo_sales_agent,
|
||||||
|
Setting.directo_receipt_payment_term)
|
||||||
|
end
|
||||||
|
|
||||||
|
# rubocop:disable Metrics/MethodLength
|
||||||
|
def send_monthly_invoices
|
||||||
|
Registrar.with_cash_accounts.find_each do |registrar|
|
||||||
|
summary = registrar.monthly_summary(month: @month)
|
||||||
|
next if summary.nil?
|
||||||
|
|
||||||
|
invoice = registrar.monthly_invoice(month: @month) || create_invoice(summary, registrar)
|
||||||
|
next if invoice.nil? || @dry
|
||||||
|
|
||||||
|
send_email_to_registrar(invoice: invoice, registrar: registrar)
|
||||||
|
send_e_invoice(invoice.id)
|
||||||
|
next if invoice.in_directo
|
||||||
|
|
||||||
|
Rails.logger.info("[DIRECTO] Trying to send monthly invoice #{invoice.number}")
|
||||||
|
@directo_client = new_directo_client
|
||||||
|
directo_invoices = @directo_client.invoices.add_with_schema(invoice: summary,
|
||||||
|
schema: 'summary')
|
||||||
|
next unless directo_invoices.size.positive?
|
||||||
|
|
||||||
|
directo_invoices.last.number = invoice.number
|
||||||
|
sync_with_directo
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
# rubocop:enable Metrics/MethodLength
|
||||||
|
|
||||||
|
def send_email_to_registrar(invoice:, registrar:)
|
||||||
|
InvoiceMailer.invoice_email(invoice: invoice,
|
||||||
|
recipient: registrar.billing_email)
|
||||||
|
.deliver_now
|
||||||
|
end
|
||||||
|
|
||||||
|
def send_e_invoice(invoice_id)
|
||||||
|
SendEInvoiceLegacyJob.set(wait: 1.minute).perform_later(invoice_id, payable: false)
|
||||||
|
end
|
||||||
|
|
||||||
|
def create_invoice(summary, registrar)
|
||||||
|
invoice = registrar.init_monthly_invoice(normalize(summary))
|
||||||
|
invoice.number = assign_monthly_number
|
||||||
|
return unless invoice.save!
|
||||||
|
|
||||||
|
update_monthly_invoice_number(num: invoice.number)
|
||||||
|
invoice
|
||||||
|
end
|
||||||
|
|
||||||
|
def sync_with_directo
|
||||||
|
invoices_xml = @directo_client.invoices.as_xml
|
||||||
|
|
||||||
|
Rails.logger.info("[Directo] - attempting to send following XML:\n #{invoices_xml}")
|
||||||
|
|
||||||
|
res = @directo_client.invoices.deliver(ssl_verify: false)
|
||||||
|
process_directo_response(res.body, invoices_xml)
|
||||||
|
rescue SocketError, Errno::ECONNREFUSED, Timeout::Error, Errno::EINVAL, Errno::ECONNRESET,
|
||||||
|
EOFError, Net::HTTPBadResponse, Net::HTTPHeaderSyntaxError, Net::ProtocolError
|
||||||
|
Rails.logger.info('[Directo] Failed to communicate via API')
|
||||||
|
end
|
||||||
|
|
||||||
|
def assign_monthly_number
|
||||||
|
last_directo_num = [Setting.directo_monthly_number_last.presence.try(:to_i),
|
||||||
|
@min_directo_num].compact.max || 0
|
||||||
|
raise 'Directo Counter is out of period!' if directo_counter_exceedable?(1, last_directo_num)
|
||||||
|
|
||||||
|
last_directo_num + 1
|
||||||
|
end
|
||||||
|
|
||||||
|
def directo_counter_exceedable?(invoices_count, last_directo_num)
|
||||||
|
return true if @max_directo_num && @max_directo_num < (last_directo_num + invoices_count)
|
||||||
|
|
||||||
|
false
|
||||||
|
end
|
||||||
|
|
||||||
|
def process_directo_response(body, req)
|
||||||
|
Rails.logger.info "[Directo] - Responded with body: #{body}"
|
||||||
|
Nokogiri::XML(body).css('Result').each do |res|
|
||||||
|
inv = Invoice.find_by(number: res.attributes['docid'].value.to_i)
|
||||||
|
mark_invoice_as_sent_to_directo(res: res, req: req, invoice: inv)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def mark_invoice_as_sent_to_directo(res:, req:, invoice: nil)
|
||||||
|
directo_record = Directo.new(response: res.as_json.to_h,
|
||||||
|
request: req, invoice_number: res.attributes['docid'].value.to_i)
|
||||||
|
directo_record.item = invoice
|
||||||
|
invoice.update(in_directo: true)
|
||||||
|
|
||||||
|
directo_record.save!
|
||||||
|
end
|
||||||
|
|
||||||
|
def update_monthly_invoice_number(num:)
|
||||||
|
return unless num.to_i > Setting.directo_monthly_number_last.to_i
|
||||||
|
|
||||||
|
Setting.directo_monthly_number_last = num.to_i
|
||||||
|
end
|
||||||
|
|
||||||
|
private
|
||||||
|
|
||||||
|
# rubocop:disable Metrics/MethodLength
|
||||||
|
def normalize(summary, lines: [])
|
||||||
|
sum = summary.dup
|
||||||
|
line_map = Hash.new 0
|
||||||
|
sum['invoice_lines'].each { |l| line_map[l] += 1 }
|
||||||
|
|
||||||
|
line_map.each_key do |count|
|
||||||
|
count['quantity'] = line_map[count] unless count['unit'].nil?
|
||||||
|
regex = /Domeenide ettemaks|Domains prepayment/
|
||||||
|
count['quantity'] = -1 if count['description'].match?(regex)
|
||||||
|
lines << count
|
||||||
|
end
|
||||||
|
|
||||||
|
sum['invoice_lines'] = summarize_lines(lines)
|
||||||
|
sum
|
||||||
|
end
|
||||||
|
# rubocop:enable Metrics/MethodLength
|
||||||
|
|
||||||
|
def summarize_lines(invoice_lines, lines: [])
|
||||||
|
line_map = Hash.new 0
|
||||||
|
invoice_lines.each do |l|
|
||||||
|
hash = l.with_indifferent_access.except(:start_date, :end_date)
|
||||||
|
line_map[hash] += 1
|
||||||
|
end
|
||||||
|
|
||||||
|
line_map.each_key do |count|
|
||||||
|
count['price'] = (line_map[count] * count['price'].to_f).round(3) unless count['price'].nil?
|
||||||
|
lines << count
|
||||||
|
end
|
||||||
|
|
||||||
|
lines
|
||||||
|
end
|
||||||
|
end
|
|
@ -36,7 +36,7 @@ class ValidateDnssecJob < ApplicationJob
|
||||||
domain.nameservers.each do |n|
|
domain.nameservers.each do |n|
|
||||||
next unless n.validated?
|
next unless n.validated?
|
||||||
|
|
||||||
validate(hostname: n.hostname, domain: domain)
|
validate(nameserver: n, domain: domain)
|
||||||
|
|
||||||
notify_contacts(domain)
|
notify_contacts(domain)
|
||||||
logger.info "----------------------------"
|
logger.info "----------------------------"
|
||||||
|
@ -54,25 +54,26 @@ class ValidateDnssecJob < ApplicationJob
|
||||||
# ContactNotification.notify_tech_contact(domain: domain, reason: 'dnssec')
|
# ContactNotification.notify_tech_contact(domain: domain, reason: 'dnssec')
|
||||||
end
|
end
|
||||||
|
|
||||||
def validate(hostname:, domain:, type: 'DNSKEY', klass: 'IN')
|
def validate(nameserver:, domain:, type: 'DNSKEY', klass: 'IN')
|
||||||
resolver = prepare_validator(hostname)
|
resolver = prepare_validator(nameserver.hostname)
|
||||||
answer = resolver.query(domain.name, type, klass)
|
answer = resolver.query(domain.name, type, klass)
|
||||||
|
|
||||||
return logger.info "no any data for #{domain.name} | hostname - #{hostname}" if answer.nil?
|
return logger.info "no any data for #{domain.name} | hostname - #{nameserver.hostname}" if answer.nil?
|
||||||
|
|
||||||
logger.info "-----------"
|
logger.info "-----------"
|
||||||
logger.info "data for domain name - #{domain.name} | hostname - #{hostname}"
|
logger.info "data for domain name - #{domain.name} | hostname - #{nameserver.hostname}"
|
||||||
logger.info "-----------"
|
logger.info "-----------"
|
||||||
|
|
||||||
response_container = parse_response(answer)
|
response_container = parse_response(answer)
|
||||||
|
|
||||||
compare_dnssec_data(response_container: response_container, domain: domain)
|
compare_dnssec_data(response_container: response_container, domain: domain, nameserver: nameserver)
|
||||||
rescue Exception => e
|
rescue Exception => e
|
||||||
logger.error "#{e.message} - domain name: #{domain.name} - hostname: #{hostname}"
|
logger.error "#{e.message} - domain name: #{domain.name} - hostname: #{nameserver.hostname}"
|
||||||
|
nameserver.update(failed_validation_reason: "#{e.message} - domain name: #{domain.name} - hostname: #{nameserver.hostname}")
|
||||||
nil
|
nil
|
||||||
end
|
end
|
||||||
|
|
||||||
def compare_dnssec_data(response_container:, domain:)
|
def compare_dnssec_data(response_container:, domain:, nameserver:)
|
||||||
domain.dnskeys.each do |key|
|
domain.dnskeys.each do |key|
|
||||||
next unless key.flags.to_s == '257'
|
next unless key.flags.to_s == '257'
|
||||||
next if key.validation_datetime.present?
|
next if key.validation_datetime.present?
|
||||||
|
@ -82,11 +83,15 @@ class ValidateDnssecJob < ApplicationJob
|
||||||
|
|
||||||
if flag
|
if flag
|
||||||
key.validation_datetime = Time.zone.now
|
key.validation_datetime = Time.zone.now
|
||||||
|
key.failed_validation_reason = nil
|
||||||
key.save
|
key.save
|
||||||
|
nameserver.failed_validation_reason = nil
|
||||||
|
nameserver.save
|
||||||
|
|
||||||
logger.info text + " ------->> succesfully!"
|
logger.info text + " ------->> succesfully!"
|
||||||
else
|
else
|
||||||
logger.info text + " ------->> not found in zone!"
|
key.update!(failed_validation_reason: text + " not found in zone! Domain name - #{domain.name}. Hostname - #{nameserver.hostname}")
|
||||||
|
logger.info text + " ------->> not found in zone! Domain name - #{domain.name}. Hostname - #{nameserver.hostname}"
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
@ -133,10 +138,11 @@ class ValidateDnssecJob < ApplicationJob
|
||||||
inner_resolver.nameserver = nameserver
|
inner_resolver.nameserver = nameserver
|
||||||
inner_resolver.packet_timeout = timeouts.to_i
|
inner_resolver.packet_timeout = timeouts.to_i
|
||||||
inner_resolver.query_timeout = timeouts.to_i
|
inner_resolver.query_timeout = timeouts.to_i
|
||||||
resolver = Dnsruby::Recursor.new(inner_resolver)
|
# resolver = Dnsruby::Recursor.new(inner_resolver)
|
||||||
resolver.dnssec = true
|
# resolver.dnssec = true
|
||||||
|
|
||||||
resolver
|
# resolver
|
||||||
|
inner_resolver
|
||||||
end
|
end
|
||||||
|
|
||||||
def logger
|
def logger
|
||||||
|
|
|
@ -1,8 +1,13 @@
|
||||||
class VerifyEmailsJob < ApplicationJob
|
class VerifyEmailsJob < ApplicationJob
|
||||||
discard_on StandardError
|
discard_on StandardError
|
||||||
|
|
||||||
def perform(contact:, check_level: 'mx')
|
def perform(email:, check_level: 'mx')
|
||||||
contact_not_found(contact.id) unless contact
|
contact = Contact.find_by(email: email)
|
||||||
|
|
||||||
|
return Rails.logger.info "No found #{email} contact" if contact.nil?
|
||||||
|
|
||||||
|
return unless filter_check_level(contact)
|
||||||
|
|
||||||
validate_check_level(check_level)
|
validate_check_level(check_level)
|
||||||
action = Actions::EmailCheck.new(email: contact.email,
|
action = Actions::EmailCheck.new(email: contact.email,
|
||||||
validation_eventable: contact,
|
validation_eventable: contact,
|
||||||
|
@ -15,10 +20,6 @@ class VerifyEmailsJob < ApplicationJob
|
||||||
|
|
||||||
private
|
private
|
||||||
|
|
||||||
def contact_not_found(contact_id)
|
|
||||||
raise StandardError, "Contact with contact_id #{contact_id} not found"
|
|
||||||
end
|
|
||||||
|
|
||||||
def validate_check_level(check_level)
|
def validate_check_level(check_level)
|
||||||
return if valid_check_levels.include? check_level
|
return if valid_check_levels.include? check_level
|
||||||
|
|
||||||
|
@ -32,4 +33,13 @@ class VerifyEmailsJob < ApplicationJob
|
||||||
def valid_check_levels
|
def valid_check_levels
|
||||||
ValidationEvent::VALID_CHECK_LEVELS
|
ValidationEvent::VALID_CHECK_LEVELS
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def filter_check_level(contact)
|
||||||
|
return true unless contact.validation_events.exists?
|
||||||
|
|
||||||
|
data = contact.validation_events.order(created_at: :asc).last
|
||||||
|
return true if data.successful? && data.created_at < (Time.zone.now - ValidationEvent::VALIDATION_PERIOD)
|
||||||
|
|
||||||
|
!(data.failed? && data.event_data['check_level'] == 'regex')
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -4,6 +4,7 @@ class InvoiceMailer < ApplicationMailer
|
||||||
|
|
||||||
subject = default_i18n_subject(invoice_number: invoice.number)
|
subject = default_i18n_subject(invoice_number: invoice.number)
|
||||||
subject << I18n.t('invoice.already_paid') if paid
|
subject << I18n.t('invoice.already_paid') if paid
|
||||||
|
subject << I18n.t('invoice.monthly_invoice') if invoice.monthly_invoice
|
||||||
attachments["invoice-#{invoice.number}.pdf"] = invoice.as_pdf
|
attachments["invoice-#{invoice.number}.pdf"] = invoice.as_pdf
|
||||||
mail(to: recipient, subject: subject)
|
mail(to: recipient, subject: subject)
|
||||||
end
|
end
|
||||||
|
|
|
@ -37,6 +37,8 @@ class Ability
|
||||||
can :manage, Depp::Domain
|
can :manage, Depp::Domain
|
||||||
end
|
end
|
||||||
|
|
||||||
|
can :manage, Account
|
||||||
|
|
||||||
# Poll
|
# Poll
|
||||||
can :manage, :poll
|
can :manage, :poll
|
||||||
|
|
||||||
|
@ -71,6 +73,7 @@ class Ability
|
||||||
|
|
||||||
def billing # Registrar/api_user dynamic role
|
def billing # Registrar/api_user dynamic role
|
||||||
can(:manage, Invoice) { |i| i.buyer_id == @user.registrar_id }
|
can(:manage, Invoice) { |i| i.buyer_id == @user.registrar_id }
|
||||||
|
can :manage, Account
|
||||||
can :manage, :deposit
|
can :manage, :deposit
|
||||||
can :read, AccountActivity
|
can :read, AccountActivity
|
||||||
can :manage, :balance_auto_reload
|
can :manage, :balance_auto_reload
|
||||||
|
@ -95,6 +98,7 @@ class Ability
|
||||||
can :manage, User
|
can :manage, User
|
||||||
can :manage, ApiUser
|
can :manage, ApiUser
|
||||||
can :manage, AdminUser
|
can :manage, AdminUser
|
||||||
|
can :manage, Auction
|
||||||
can :manage, Certificate
|
can :manage, Certificate
|
||||||
can :manage, LegalDocument
|
can :manage, LegalDocument
|
||||||
can :manage, BankStatement
|
can :manage, BankStatement
|
||||||
|
|
|
@ -28,14 +28,20 @@ class Action < ApplicationRecord
|
||||||
end
|
end
|
||||||
|
|
||||||
def to_non_available_contact_codes
|
def to_non_available_contact_codes
|
||||||
return [] unless bulk_action?
|
return [serialized_contact(contact)] unless bulk_action?
|
||||||
|
|
||||||
subactions.map do |a|
|
subactions.map do |a|
|
||||||
|
serialized_contact(a.contact)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
private
|
||||||
|
|
||||||
|
def serialized_contact(contact)
|
||||||
{
|
{
|
||||||
code: a.contact.code,
|
code: contact.code,
|
||||||
avail: 0,
|
avail: 0,
|
||||||
reason: 'in use',
|
reason: 'in use',
|
||||||
}
|
}
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
|
||||||
|
|
|
@ -6,7 +6,7 @@ class AdminDomainContact < DomainContact
|
||||||
skipped_domains = []
|
skipped_domains = []
|
||||||
admin_contacts = where(contact: current_contact)
|
admin_contacts = where(contact: current_contact)
|
||||||
|
|
||||||
admin_contacts.each do |admin_contact|
|
admin_contacts.includes(:domain).find_each do |admin_contact|
|
||||||
if admin_contact.domain.bulk_update_prohibited?
|
if admin_contact.domain.bulk_update_prohibited?
|
||||||
skipped_domains << admin_contact.domain.name
|
skipped_domains << admin_contact.domain.name
|
||||||
next
|
next
|
||||||
|
|
|
@ -30,11 +30,11 @@ class ApiUser < User
|
||||||
|
|
||||||
alias_attribute :login, :username
|
alias_attribute :login, :username
|
||||||
|
|
||||||
SUPER = 'super'
|
SUPER = 'super'.freeze
|
||||||
EPP = 'epp'
|
EPP = 'epp'.freeze
|
||||||
BILLING = 'billing'
|
BILLING = 'billing'.freeze
|
||||||
|
|
||||||
ROLES = %w(super epp billing) # should not match to admin roles
|
ROLES = %w[super epp billing].freeze # should not match to admin roles
|
||||||
|
|
||||||
def ability
|
def ability
|
||||||
@ability ||= Ability.new(self)
|
@ability ||= Ability.new(self)
|
||||||
|
@ -74,6 +74,7 @@ class ApiUser < User
|
||||||
self.class.where(identity_code: identity_code)
|
self.class.where(identity_code: identity_code)
|
||||||
.where("identity_code IS NOT NULL AND identity_code != ''")
|
.where("identity_code IS NOT NULL AND identity_code != ''")
|
||||||
.where.not(id: id)
|
.where.not(id: id)
|
||||||
|
.includes(:registrar)
|
||||||
end
|
end
|
||||||
|
|
||||||
def linked_with?(another_api_user)
|
def linked_with?(another_api_user)
|
||||||
|
|
|
@ -9,11 +9,30 @@ class Auction < ApplicationRecord
|
||||||
domain_not_registered: 'domain_not_registered',
|
domain_not_registered: 'domain_not_registered',
|
||||||
}
|
}
|
||||||
|
|
||||||
|
enum platform: %i[auto manual]
|
||||||
|
|
||||||
PENDING_STATUSES = [statuses[:started],
|
PENDING_STATUSES = [statuses[:started],
|
||||||
statuses[:awaiting_payment],
|
statuses[:awaiting_payment],
|
||||||
statuses[:payment_received]].freeze
|
statuses[:payment_received]].freeze
|
||||||
|
|
||||||
private_constant :PENDING_STATUSES
|
private_constant :PENDING_STATUSES
|
||||||
|
|
||||||
|
scope :with_status, ->(status) {
|
||||||
|
where(status: status) if status.present?
|
||||||
|
}
|
||||||
|
|
||||||
|
scope :with_start_created_at_date, ->(start_created_at) {
|
||||||
|
where('created_at >= ?', start_created_at) if start_created_at.present?
|
||||||
|
}
|
||||||
|
|
||||||
|
scope :with_end_created_at_date, ->(end_created_at) {
|
||||||
|
where('created_at <= ?', end_created_at) if end_created_at.present?
|
||||||
|
}
|
||||||
|
|
||||||
|
scope :with_domain_name, ->(domain_name) {
|
||||||
|
where('domain ilike ?', "%#{domain_name.strip}%") if domain_name.present?
|
||||||
|
}
|
||||||
|
|
||||||
def self.pending(domain_name)
|
def self.pending(domain_name)
|
||||||
find_by(domain: domain_name.to_s, status: PENDING_STATUSES)
|
find_by(domain: domain_name.to_s, status: PENDING_STATUSES)
|
||||||
end
|
end
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
module BalanceAutoReloadTypes
|
module BalanceAutoReloadTypes
|
||||||
class Threshold
|
class Threshold
|
||||||
include ActiveModel::Model
|
include ActiveModel::Model
|
||||||
|
include ActiveModel::Validations
|
||||||
|
|
||||||
attr_accessor :amount, :threshold
|
attr_accessor :amount, :threshold
|
||||||
|
|
||||||
|
@ -11,8 +12,9 @@ module BalanceAutoReloadTypes
|
||||||
Setting.minimum_deposit
|
Setting.minimum_deposit
|
||||||
end
|
end
|
||||||
|
|
||||||
def as_json(options)
|
def as_json(options = nil)
|
||||||
{ name: name }.merge(super)
|
{ name: name }.merge(super)
|
||||||
|
.except('errors', 'validation_context')
|
||||||
end
|
end
|
||||||
|
|
||||||
private
|
private
|
||||||
|
|
|
@ -33,10 +33,10 @@ class BankTransaction < ApplicationRecord
|
||||||
return unless autobindable?
|
return unless autobindable?
|
||||||
|
|
||||||
channel = manual ? 'admin_payment' : 'system_payment'
|
channel = manual ? 'admin_payment' : 'system_payment'
|
||||||
create_internal_payment_record(channel: channel, invoice: invoice, registrar: registrar)
|
create_internal_payment_record(invoice: invoice, registrar: registrar, channel: channel)
|
||||||
end
|
end
|
||||||
|
|
||||||
def create_internal_payment_record(channel: nil, invoice:, registrar:)
|
def create_internal_payment_record(invoice:, registrar:, channel: nil)
|
||||||
if channel.nil?
|
if channel.nil?
|
||||||
create_activity(invoice.buyer, invoice)
|
create_activity(invoice.buyer, invoice)
|
||||||
return
|
return
|
||||||
|
@ -47,9 +47,12 @@ class BankTransaction < ApplicationRecord
|
||||||
|
|
||||||
if create_activity(registrar, invoice)
|
if create_activity(registrar, invoice)
|
||||||
payment_order.paid!
|
payment_order.paid!
|
||||||
|
EisBilling::SendInvoiceStatus.send_info(invoice_number: invoice.number,
|
||||||
|
status: 'paid')
|
||||||
else
|
else
|
||||||
payment_order.update(notes: 'Failed to create activity', status: 'failed')
|
payment_order.update(notes: 'Failed to create activity', status: 'failed')
|
||||||
end
|
end
|
||||||
|
invoice
|
||||||
end
|
end
|
||||||
|
|
||||||
def bind_invoice(invoice_no, manual: false)
|
def bind_invoice(invoice_no, manual: false)
|
||||||
|
@ -62,8 +65,8 @@ class BankTransaction < ApplicationRecord
|
||||||
validate_invoice_data(invoice)
|
validate_invoice_data(invoice)
|
||||||
return if errors.any?
|
return if errors.any?
|
||||||
|
|
||||||
create_internal_payment_record(channel: (manual ? 'admin_payment' : nil), invoice: invoice,
|
create_internal_payment_record(invoice: invoice, registrar: invoice.buyer,
|
||||||
registrar: invoice.buyer)
|
channel: (manual ? 'admin_payment' : nil))
|
||||||
end
|
end
|
||||||
|
|
||||||
def validate_invoice_data(invoice)
|
def validate_invoice_data(invoice)
|
||||||
|
|
|
@ -4,8 +4,8 @@ module Billing
|
||||||
MULTI_REGEXP = /(\d{2,20})/
|
MULTI_REGEXP = /(\d{2,20})/
|
||||||
|
|
||||||
def self.generate
|
def self.generate
|
||||||
base = Base.generate
|
result = EisBilling::GetReferenceNumber.send_request
|
||||||
"#{base}#{base.check_digit}"
|
JSON.parse(result.body)['reference_number']
|
||||||
end
|
end
|
||||||
|
|
||||||
def self.valid?(ref)
|
def self.valid?(ref)
|
||||||
|
|
|
@ -1 +0,0 @@
|
||||||
class BulkAction < Action; end
|
|
|
@ -1,22 +0,0 @@
|
||||||
module Contact::Disclosable
|
|
||||||
extend ActiveSupport::Concern
|
|
||||||
|
|
||||||
class_methods do
|
|
||||||
attr_accessor :disclosable_attributes
|
|
||||||
end
|
|
||||||
|
|
||||||
included do
|
|
||||||
self.disclosable_attributes = %w[name email]
|
|
||||||
validate :validate_disclosed_attributes
|
|
||||||
end
|
|
||||||
|
|
||||||
private
|
|
||||||
|
|
||||||
def validate_disclosed_attributes
|
|
||||||
return if disclosed_attributes.empty?
|
|
||||||
|
|
||||||
has_undisclosable_attributes = (disclosed_attributes - self.class.disclosable_attributes)
|
|
||||||
.any?
|
|
||||||
errors.add(:disclosed_attributes, :invalid) if has_undisclosable_attributes
|
|
||||||
end
|
|
||||||
end
|
|
|
@ -18,9 +18,7 @@ module EmailVerifable
|
||||||
def need_to_start_force_delete?
|
def need_to_start_force_delete?
|
||||||
flag = false
|
flag = false
|
||||||
ValidationEvent::INVALID_EVENTS_COUNT_BY_LEVEL.each do |level, count|
|
ValidationEvent::INVALID_EVENTS_COUNT_BY_LEVEL.each do |level, count|
|
||||||
if validation_events.count >= count && validate_email_data(level: level, count: count)
|
flag = true if validation_events.count >= count && validate_email_data(level: level, count: count)
|
||||||
flag = true
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
|
||||||
flag
|
flag
|
||||||
|
|
|
@ -5,12 +5,22 @@ module Invoice::Cancellable
|
||||||
scope :non_cancelled, -> { where(cancelled_at: nil) }
|
scope :non_cancelled, -> { where(cancelled_at: nil) }
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def can_be_cancelled?
|
||||||
|
unless cancellable?
|
||||||
|
errors.add(:base, :invoice_status_prohibits_operation)
|
||||||
|
return false
|
||||||
|
end
|
||||||
|
|
||||||
|
true
|
||||||
|
end
|
||||||
|
|
||||||
def cancellable?
|
def cancellable?
|
||||||
unpaid? && not_cancelled?
|
unpaid? && not_cancelled?
|
||||||
end
|
end
|
||||||
|
|
||||||
def cancel
|
def cancel
|
||||||
raise 'Invoice cannot be cancelled' unless cancellable?
|
raise 'Invoice cannot be cancelled' unless cancellable?
|
||||||
|
|
||||||
update!(cancelled_at: Time.zone.now)
|
update!(cancelled_at: Time.zone.now)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
@ -15,6 +15,8 @@ module Invoice::Payable
|
||||||
end
|
end
|
||||||
|
|
||||||
def receipt_date
|
def receipt_date
|
||||||
|
return unless paid?
|
||||||
|
|
||||||
account_activity.created_at.to_date
|
account_activity.created_at.to_date
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
@ -1,22 +1,27 @@
|
||||||
module Registrar::BookKeeping
|
module Registrar::BookKeeping # rubocop:disable Metrics/ModuleLength
|
||||||
extend ActiveSupport::Concern
|
extend ActiveSupport::Concern
|
||||||
|
|
||||||
DOMAIN_TO_PRODUCT = { 'ee': '01EE', 'com.ee': '02COM', 'pri.ee': '03PRI',
|
DOMAIN_TO_PRODUCT = { 'ee': '01EE', 'com.ee': '02COM', 'pri.ee': '03PRI',
|
||||||
'fie.ee': '04FIE', 'med.ee': '05MED' }.freeze
|
'fie.ee': '04FIE', 'med.ee': '05MED' }.freeze
|
||||||
|
|
||||||
|
included do
|
||||||
|
scope :with_cash_accounts, (lambda do
|
||||||
|
joins(:accounts).where('accounts.account_type = ? AND test_registrar != ?',
|
||||||
|
Account::CASH,
|
||||||
|
true)
|
||||||
|
end)
|
||||||
|
end
|
||||||
|
|
||||||
def monthly_summary(month:)
|
def monthly_summary(month:)
|
||||||
activities = monthly_activites(month)
|
activities = monthly_activites(month)
|
||||||
return unless activities.any?
|
return unless activities.any?
|
||||||
|
|
||||||
invoice = {
|
invoice = {
|
||||||
'number': 1,
|
'number': 1, 'customer': compose_directo_customer,
|
||||||
'customer': compose_directo_customer,
|
|
||||||
'language': language == 'en' ? 'ENG' : '', 'currency': activities.first.currency,
|
'language': language == 'en' ? 'ENG' : '', 'currency': activities.first.currency,
|
||||||
'date': month.end_of_month.strftime('%Y-%m-%d')
|
'date': month.end_of_month.strftime('%Y-%m-%d')
|
||||||
}.as_json
|
}.as_json
|
||||||
|
|
||||||
invoice['invoice_lines'] = prepare_invoice_lines(month: month, activities: activities)
|
invoice['invoice_lines'] = prepare_invoice_lines(month: month, activities: activities)
|
||||||
|
|
||||||
invoice
|
invoice
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -55,20 +60,25 @@ module Registrar::BookKeeping
|
||||||
.where(activity_type: [AccountActivity::CREATE, AccountActivity::RENEW])
|
.where(activity_type: [AccountActivity::CREATE, AccountActivity::RENEW])
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def monthly_invoice(month:)
|
||||||
|
invoices.where(monthly_invoice: true, issue_date: month.end_of_month.to_date,
|
||||||
|
cancelled_at: nil).first
|
||||||
|
end
|
||||||
|
|
||||||
def new_monthly_invoice_line(activity:, duration: nil)
|
def new_monthly_invoice_line(activity:, duration: nil)
|
||||||
price = load_price(activity)
|
price = load_price(activity)
|
||||||
line = {
|
line = {
|
||||||
'product_id': DOMAIN_TO_PRODUCT[price.zone_name.to_sym],
|
'product_id': DOMAIN_TO_PRODUCT[price.zone_name.to_sym],
|
||||||
'quantity': 1,
|
'quantity': 1,
|
||||||
'unit': language == 'en' ? 'pc' : 'tk',
|
'unit': language == 'en' ? 'pc' : 'tk',
|
||||||
}
|
}.with_indifferent_access
|
||||||
|
|
||||||
finalize_invoice_line(line, price: price, duration: duration, activity: activity)
|
finalize_invoice_line(line, price: price, duration: duration, activity: activity)
|
||||||
end
|
end
|
||||||
|
|
||||||
def finalize_invoice_line(line, price:, activity:, duration:)
|
def finalize_invoice_line(line, price:, activity:, duration:)
|
||||||
yearly = price.duration.in_years.to_i >= 1
|
yearly = price.duration.in_years.to_i >= 1
|
||||||
line['price'] = yearly ? (price.price.amount / price.duration.in_years.to_i) : price.price.amount
|
line['price'] = yearly ? (price.price.amount / price.duration.in_years.to_i).to_f : price.price.amount.to_f
|
||||||
line['description'] = description_in_language(price: price, yearly: yearly)
|
line['description'] = description_in_language(price: price, yearly: yearly)
|
||||||
|
|
||||||
add_product_timeframe(line: line, activity: activity, duration: duration) if duration.present? && (duration > 1)
|
add_product_timeframe(line: line, activity: activity, duration: duration) if duration.present? && (duration > 1)
|
||||||
|
@ -79,15 +89,16 @@ module Registrar::BookKeeping
|
||||||
def add_product_timeframe(line:, activity:, duration:)
|
def add_product_timeframe(line:, activity:, duration:)
|
||||||
create_time = activity.created_at
|
create_time = activity.created_at
|
||||||
line['start_date'] = (create_time + (duration - 1).year).end_of_month.strftime('%Y-%m-%d')
|
line['start_date'] = (create_time + (duration - 1).year).end_of_month.strftime('%Y-%m-%d')
|
||||||
line['end_date'] = (create_time + (duration - 1).year + 1).end_of_month.strftime('%Y-%m-%d')
|
line['end_date'] = (create_time + duration.year).end_of_month.strftime('%Y-%m-%d')
|
||||||
end
|
end
|
||||||
|
|
||||||
def description_in_language(price:, yearly:)
|
def description_in_language(price:, yearly:)
|
||||||
timeframe_string = yearly ? 'yearly' : 'monthly'
|
timeframe_string = yearly ? 'yearly' : 'monthly'
|
||||||
locale_string = "registrar.invoice_#{timeframe_string}_product_description"
|
locale_string = "registrar.invoice_#{timeframe_string}_product_description"
|
||||||
|
length = yearly ? price.duration.in_years.to_i : price.duration.in_months.to_i
|
||||||
|
|
||||||
I18n.with_locale(language == 'en' ? 'en' : 'et') do
|
I18n.with_locale(language == 'en' ? 'en' : 'et') do
|
||||||
I18n.t(locale_string, tld: ".#{price.zone_name}", length: price.duration.in_years.to_i)
|
I18n.t(locale_string, tld: ".#{price.zone_name}", length: length)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
@ -7,7 +7,6 @@ class Contact < ApplicationRecord
|
||||||
include UserEvents
|
include UserEvents
|
||||||
include Contact::Transferable
|
include Contact::Transferable
|
||||||
include Contact::Identical
|
include Contact::Identical
|
||||||
include Contact::Disclosable
|
|
||||||
include Contact::Archivable
|
include Contact::Archivable
|
||||||
include EmailVerifable
|
include EmailVerifable
|
||||||
|
|
||||||
|
@ -16,7 +15,7 @@ class Contact < ApplicationRecord
|
||||||
has_many :domain_contacts
|
has_many :domain_contacts
|
||||||
has_many :domains, through: :domain_contacts
|
has_many :domains, through: :domain_contacts
|
||||||
has_many :legal_documents, as: :documentable
|
has_many :legal_documents, as: :documentable
|
||||||
has_many :validation_events, as: :validation_eventable
|
has_many :validation_events, as: :validation_eventable, dependent: :destroy
|
||||||
has_many :registrant_domains, class_name: 'Domain', foreign_key: 'registrant_id'
|
has_many :registrant_domains, class_name: 'Domain', foreign_key: 'registrant_id'
|
||||||
has_many :actions, dependent: :destroy
|
has_many :actions, dependent: :destroy
|
||||||
|
|
||||||
|
@ -55,7 +54,7 @@ class Contact < ApplicationRecord
|
||||||
|
|
||||||
validates :phone, presence: true, e164: true, phone: true
|
validates :phone, presence: true, e164: true, phone: true
|
||||||
|
|
||||||
validate :correct_email_format, if: proc { |c| c.will_save_change_to_email? }
|
# validate :correct_email_format, if: proc { |c| c.will_save_change_to_email? }
|
||||||
|
|
||||||
validates :code,
|
validates :code,
|
||||||
uniqueness: { message: :epp_id_taken },
|
uniqueness: { message: :epp_id_taken },
|
||||||
|
@ -86,41 +85,41 @@ class Contact < ApplicationRecord
|
||||||
|
|
||||||
self.ignored_columns = %w[legacy_id legacy_history_id]
|
self.ignored_columns = %w[legacy_id legacy_history_id]
|
||||||
|
|
||||||
ORG = 'org'
|
ORG = 'org'.freeze
|
||||||
PRIV = 'priv'
|
PRIV = 'priv'.freeze
|
||||||
|
|
||||||
# For foreign private persons who has no national identification number
|
# For foreign private persons who has no national identification number
|
||||||
BIRTHDAY = 'birthday'.freeze
|
BIRTHDAY = 'birthday'.freeze
|
||||||
|
|
||||||
# From old registry software ("Fred"). No new contact can be created with this status
|
# From old registry software ("Fred"). No new contact can be created with this status
|
||||||
PASSPORT = 'passport'
|
PASSPORT = 'passport'.freeze
|
||||||
|
|
||||||
#
|
#
|
||||||
# STATUSES
|
# STATUSES
|
||||||
#
|
#
|
||||||
# Requests to delete the object MUST be rejected.
|
# Requests to delete the object MUST be rejected.
|
||||||
CLIENT_DELETE_PROHIBITED = 'clientDeleteProhibited'
|
CLIENT_DELETE_PROHIBITED = 'clientDeleteProhibited'.freeze
|
||||||
SERVER_DELETE_PROHIBITED = 'serverDeleteProhibited'
|
SERVER_DELETE_PROHIBITED = 'serverDeleteProhibited'.freeze
|
||||||
|
|
||||||
# Requests to transfer the object MUST be rejected.
|
# Requests to transfer the object MUST be rejected.
|
||||||
CLIENT_TRANSFER_PROHIBITED = 'clientTransferProhibited'
|
CLIENT_TRANSFER_PROHIBITED = 'clientTransferProhibited'.freeze
|
||||||
SERVER_TRANSFER_PROHIBITED = 'serverTransferProhibited'
|
SERVER_TRANSFER_PROHIBITED = 'serverTransferProhibited'.freeze
|
||||||
|
|
||||||
# The contact object has at least one active association with
|
# The contact object has at least one active association with
|
||||||
# another object, such as a domain object. Servers SHOULD provide
|
# another object, such as a domain object. Servers SHOULD provide
|
||||||
# services to determine existing object associations.
|
# services to determine existing object associations.
|
||||||
# "linked" status MAY be combined with any status.
|
# "linked" status MAY be combined with any status.
|
||||||
LINKED = 'linked'
|
LINKED = 'linked'.freeze
|
||||||
|
|
||||||
# This is the normal status value for an object that has no pending
|
# This is the normal status value for an object that has no pending
|
||||||
# operations or prohibitions. This value is set and removed by the
|
# operations or prohibitions. This value is set and removed by the
|
||||||
# server as other status values are added or removed.
|
# server as other status values are added or removed.
|
||||||
# "ok" status MAY only be combined with "linked" status.
|
# "ok" status MAY only be combined with "linked" status.
|
||||||
OK = 'ok'
|
OK = 'ok'.freeze
|
||||||
|
|
||||||
# Requests to update the object (other than to remove this status) MUST be rejected.
|
# Requests to update the object (other than to remove this status) MUST be rejected.
|
||||||
CLIENT_UPDATE_PROHIBITED = 'clientUpdateProhibited'
|
CLIENT_UPDATE_PROHIBITED = 'clientUpdateProhibited'.freeze
|
||||||
SERVER_UPDATE_PROHIBITED = 'serverUpdateProhibited'
|
SERVER_UPDATE_PROHIBITED = 'serverUpdateProhibited'.freeze
|
||||||
|
|
||||||
# A transform command has been processed for the object, but the
|
# A transform command has been processed for the object, but the
|
||||||
# action has not been completed by the server. Server operators can
|
# action has not been completed by the server. Server operators can
|
||||||
|
@ -135,16 +134,16 @@ class Contact < ApplicationRecord
|
||||||
# the status of the object has changed.
|
# the status of the object has changed.
|
||||||
# The pendingCreate, pendingDelete, pendingTransfer, and pendingUpdate
|
# The pendingCreate, pendingDelete, pendingTransfer, and pendingUpdate
|
||||||
# status values MUST NOT be combined with each other.
|
# status values MUST NOT be combined with each other.
|
||||||
PENDING_CREATE = 'pendingCreate'
|
PENDING_CREATE = 'pendingCreate'.freeze
|
||||||
# "pendingTransfer" status MUST NOT be combined with either
|
# "pendingTransfer" status MUST NOT be combined with either
|
||||||
# "clientTransferProhibited" or "serverTransferProhibited" status.
|
# "clientTransferProhibited" or "serverTransferProhibited" status.
|
||||||
PENDING_TRANSFER = 'pendingTransfer'
|
PENDING_TRANSFER = 'pendingTransfer'.freeze
|
||||||
# "pendingUpdate" status MUST NOT be combined with either
|
# "pendingUpdate" status MUST NOT be combined with either
|
||||||
# "clientUpdateProhibited" or "serverUpdateProhibited" status.
|
# "clientUpdateProhibited" or "serverUpdateProhibited" status.
|
||||||
PENDING_UPDATE = 'pendingUpdate'
|
PENDING_UPDATE = 'pendingUpdate'.freeze
|
||||||
# "pendingDelete" MUST NOT be combined with either
|
# "pendingDelete" MUST NOT be combined with either
|
||||||
# "clientDeleteProhibited" or "serverDeleteProhibited" status.
|
# "clientDeleteProhibited" or "serverDeleteProhibited" status.
|
||||||
PENDING_DELETE = 'pendingDelete'
|
PENDING_DELETE = 'pendingDelete'.freeze
|
||||||
|
|
||||||
STATUSES = [
|
STATUSES = [
|
||||||
CLIENT_DELETE_PROHIBITED, SERVER_DELETE_PROHIBITED,
|
CLIENT_DELETE_PROHIBITED, SERVER_DELETE_PROHIBITED,
|
||||||
|
@ -152,18 +151,18 @@ class Contact < ApplicationRecord
|
||||||
SERVER_TRANSFER_PROHIBITED, CLIENT_UPDATE_PROHIBITED, SERVER_UPDATE_PROHIBITED,
|
SERVER_TRANSFER_PROHIBITED, CLIENT_UPDATE_PROHIBITED, SERVER_UPDATE_PROHIBITED,
|
||||||
OK, PENDING_CREATE, PENDING_DELETE, PENDING_TRANSFER,
|
OK, PENDING_CREATE, PENDING_DELETE, PENDING_TRANSFER,
|
||||||
PENDING_UPDATE, LINKED
|
PENDING_UPDATE, LINKED
|
||||||
]
|
].freeze
|
||||||
|
|
||||||
CLIENT_STATUSES = [
|
CLIENT_STATUSES = [
|
||||||
CLIENT_DELETE_PROHIBITED, CLIENT_TRANSFER_PROHIBITED,
|
CLIENT_DELETE_PROHIBITED, CLIENT_TRANSFER_PROHIBITED,
|
||||||
CLIENT_UPDATE_PROHIBITED
|
CLIENT_UPDATE_PROHIBITED
|
||||||
]
|
].freeze
|
||||||
|
|
||||||
SERVER_STATUSES = [
|
SERVER_STATUSES = [
|
||||||
SERVER_UPDATE_PROHIBITED,
|
SERVER_UPDATE_PROHIBITED,
|
||||||
SERVER_DELETE_PROHIBITED,
|
SERVER_DELETE_PROHIBITED,
|
||||||
SERVER_TRANSFER_PROHIBITED
|
SERVER_TRANSFER_PROHIBITED,
|
||||||
]
|
].freeze
|
||||||
#
|
#
|
||||||
# END OF STATUSES
|
# END OF STATUSES
|
||||||
#
|
#
|
||||||
|
@ -361,7 +360,7 @@ class Contact < ApplicationRecord
|
||||||
@desc[dom.name][:roles] << :registrant
|
@desc[dom.name][:roles] << :registrant
|
||||||
end
|
end
|
||||||
|
|
||||||
domain_contacts.each do |dc|
|
domain_contacts.includes(:domain).each do |dc|
|
||||||
@desc[dc.domain.name] ||= { id: dc.domain.uuid, roles: [] }
|
@desc[dc.domain.name] ||= { id: dc.domain.uuid, roles: [] }
|
||||||
@desc[dc.domain.name][:roles] << dc.name.downcase.to_sym
|
@desc[dc.domain.name][:roles] << dc.name.downcase.to_sym
|
||||||
@desc[dc.domain.name] = @desc[dc.domain.name].compact
|
@desc[dc.domain.name] = @desc[dc.domain.name].compact
|
||||||
|
@ -389,6 +388,10 @@ class Contact < ApplicationRecord
|
||||||
"#{code} #{name}"
|
"#{code} #{name}"
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def name_disclosed_by_registrar(reg_id)
|
||||||
|
registrar_id == reg_id ? name : 'N/A'
|
||||||
|
end
|
||||||
|
|
||||||
def strip_email
|
def strip_email
|
||||||
self.email = email.to_s.strip
|
self.email = email.to_s.strip
|
||||||
end
|
end
|
||||||
|
@ -411,7 +414,7 @@ class Contact < ApplicationRecord
|
||||||
|
|
||||||
# using small rails hack to generate outer join
|
# using small rails hack to generate outer join
|
||||||
domains = if sorts.first == 'registrar_name'.freeze
|
domains = if sorts.first == 'registrar_name'.freeze
|
||||||
domains.includes(:registrar).where.not(registrars: { id: nil })
|
domains.where.not(registrars: { id: nil })
|
||||||
.order("registrars.name #{order} NULLS LAST")
|
.order("registrars.name #{order} NULLS LAST")
|
||||||
else
|
else
|
||||||
domains.order("#{sort} #{order} NULLS LAST")
|
domains.order("#{sort} #{order} NULLS LAST")
|
||||||
|
@ -428,7 +431,6 @@ class Contact < ApplicationRecord
|
||||||
end
|
end
|
||||||
|
|
||||||
domains.each { |d| d.roles = domain_c[d.id].uniq }
|
domains.each { |d| d.roles = domain_c[d.id].uniq }
|
||||||
|
|
||||||
domains
|
domains
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -444,18 +446,28 @@ class Contact < ApplicationRecord
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def qualified_domain_ids(domain_filter)
|
def qualified_domain_ids(filters)
|
||||||
registrant_ids = registrant_domains.pluck(:id)
|
rant_domains = registrant_domains.map { |d| { id: d.id, type: ['Registrant'] } }
|
||||||
return registrant_ids if domain_filter == 'Registrant'
|
contact_domains = domain_contacts.map { |dc| { id: dc.domain_id, type: [dc.type] } }
|
||||||
|
grouped_domains = group_by_id_and_type(rant_domains + contact_domains)
|
||||||
|
return grouped_domains.keys if filters.nil? || filters == ''
|
||||||
|
|
||||||
if %w[AdminDomainContact TechDomainContact].include? domain_filter
|
# use domain_filters.sort == v.sort if should be exact match
|
||||||
DomainContact.select('domain_id').where(contact_id: id, type: domain_filter)
|
grouped_domains.reject { |_, v| ([].push(filters).flatten & v).empty? }.keys
|
||||||
else
|
|
||||||
(DomainContact.select('domain_id').where(contact_id: id).pluck(:domain_id) +
|
|
||||||
registrant_ids).uniq
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
|
||||||
|
# def qualified_domain_ids(domain_filter)
|
||||||
|
# registrant_ids = registrant_domains.pluck(:id)
|
||||||
|
# return registrant_ids if domain_filter == 'Registrant'
|
||||||
|
|
||||||
|
# if %w[AdminDomainContact TechDomainContact].include? domain_filter
|
||||||
|
# DomainContact.where(contact_id: id, type: domain_filter).pluck(:domain_id)
|
||||||
|
# else
|
||||||
|
# (DomainContact.where(contact_id: id).pluck(:domain_id) +
|
||||||
|
# registrant_ids).uniq
|
||||||
|
# end
|
||||||
|
# end
|
||||||
|
|
||||||
def update_prohibited?
|
def update_prohibited?
|
||||||
(statuses & [
|
(statuses & [
|
||||||
CLIENT_UPDATE_PROHIBITED,
|
CLIENT_UPDATE_PROHIBITED,
|
||||||
|
@ -465,7 +477,7 @@ class Contact < ApplicationRecord
|
||||||
PENDING_CREATE,
|
PENDING_CREATE,
|
||||||
PENDING_TRANSFER,
|
PENDING_TRANSFER,
|
||||||
PENDING_UPDATE,
|
PENDING_UPDATE,
|
||||||
PENDING_DELETE
|
PENDING_DELETE,
|
||||||
]).present?
|
]).present?
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -596,4 +608,14 @@ class Contact < ApplicationRecord
|
||||||
def self.csv_header
|
def self.csv_header
|
||||||
['Name', 'ID', 'Ident', 'E-mail', 'Created at', 'Registrar', 'Phone']
|
['Name', 'ID', 'Ident', 'E-mail', 'Created at', 'Registrar', 'Phone']
|
||||||
end
|
end
|
||||||
|
|
||||||
|
private
|
||||||
|
|
||||||
|
def group_by_id_and_type(domains_hash_array)
|
||||||
|
domains_hash_array.group_by { |d| d[:id] }
|
||||||
|
.transform_values do |v|
|
||||||
|
v.each.with_object(:type)
|
||||||
|
.map(&:[]).flatten
|
||||||
|
end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
1
app/models/contact_update_action.rb
Normal file
1
app/models/contact_update_action.rb
Normal file
|
@ -0,0 +1 @@
|
||||||
|
class ContactUpdateAction < Action; end
|
|
@ -33,6 +33,7 @@ class Deposit
|
||||||
|
|
||||||
def issue_prepayment_invoice
|
def issue_prepayment_invoice
|
||||||
return unless valid?
|
return unless valid?
|
||||||
|
|
||||||
registrar.issue_prepayment_invoice(amount, description)
|
registrar.issue_prepayment_invoice(amount, description)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -35,6 +35,7 @@ module DNS
|
||||||
def sell_at_auction
|
def sell_at_auction
|
||||||
auction = Auction.new
|
auction = Auction.new
|
||||||
auction.domain = name
|
auction.domain = name
|
||||||
|
auction.platform = 'auto'
|
||||||
auction.start
|
auction.start
|
||||||
ToStdout.msg "Created the auction: #{auction.inspect}"
|
ToStdout.msg "Created the auction: #{auction.inspect}"
|
||||||
update_whois_from_auction(auction)
|
update_whois_from_auction(auction)
|
||||||
|
|
|
@ -161,14 +161,6 @@ class Domain < ApplicationRecord
|
||||||
attribute: 'hostname'
|
attribute: 'hostname'
|
||||||
}
|
}
|
||||||
|
|
||||||
validates :tech_domain_contacts, uniqueness_multi: {
|
|
||||||
attribute: 'contact_code_cache'
|
|
||||||
}
|
|
||||||
|
|
||||||
validates :admin_domain_contacts, uniqueness_multi: {
|
|
||||||
attribute: 'contact_code_cache'
|
|
||||||
}
|
|
||||||
|
|
||||||
validates :dnskeys, uniqueness_multi: {
|
validates :dnskeys, uniqueness_multi: {
|
||||||
attribute: 'public_key'
|
attribute: 'public_key'
|
||||||
}
|
}
|
||||||
|
@ -726,7 +718,6 @@ class Domain < ApplicationRecord
|
||||||
hash = super
|
hash = super
|
||||||
hash['auth_info'] = hash.delete('transfer_code') # API v1 requirement
|
hash['auth_info'] = hash.delete('transfer_code') # API v1 requirement
|
||||||
hash['valid_from'] = hash['created_at'] # API v1 requirement
|
hash['valid_from'] = hash['created_at'] # API v1 requirement
|
||||||
hash.delete('statuses_before_force_delete')
|
|
||||||
hash
|
hash
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
@ -6,32 +6,21 @@ class DomainContact < ApplicationRecord
|
||||||
belongs_to :contact
|
belongs_to :contact
|
||||||
belongs_to :domain
|
belongs_to :domain
|
||||||
|
|
||||||
|
validates :contact, presence: true
|
||||||
|
|
||||||
|
after_destroy :update_contact
|
||||||
attr_accessor :value_typeahead
|
attr_accessor :value_typeahead
|
||||||
|
attr_writer :contact_code
|
||||||
|
|
||||||
self.ignored_columns = %w[legacy_domain_id legacy_contact_id]
|
self.ignored_columns = %w[legacy_domain_id legacy_contact_id]
|
||||||
|
|
||||||
def epp_code_map
|
|
||||||
{
|
|
||||||
'2302' => [
|
|
||||||
[:contact_code_cache, :taken, { value: { obj: 'contact', val: contact_code_cache } }]
|
|
||||||
]
|
|
||||||
}
|
|
||||||
end
|
|
||||||
|
|
||||||
def name
|
def name
|
||||||
return 'Tech' if type == 'TechDomainContact'
|
return 'Tech' if type == 'TechDomainContact'
|
||||||
return 'Admin' if type == 'AdminDomainContact'
|
return 'Admin' if type == 'AdminDomainContact'
|
||||||
|
|
||||||
''
|
''
|
||||||
end
|
end
|
||||||
|
|
||||||
validates :contact, presence: true
|
|
||||||
|
|
||||||
before_save :update_contact_code_cache
|
|
||||||
def update_contact_code_cache
|
|
||||||
self.contact_code_cache = contact.code
|
|
||||||
end
|
|
||||||
|
|
||||||
after_destroy :update_contact
|
|
||||||
def update_contact
|
def update_contact
|
||||||
Contact.find(contact_id).save
|
Contact.find(contact_id).save
|
||||||
end
|
end
|
||||||
|
|
|
@ -4,10 +4,10 @@ class DomainTransfer < ApplicationRecord
|
||||||
belongs_to :old_registrar, class_name: 'Registrar'
|
belongs_to :old_registrar, class_name: 'Registrar'
|
||||||
belongs_to :new_registrar, class_name: 'Registrar'
|
belongs_to :new_registrar, class_name: 'Registrar'
|
||||||
|
|
||||||
PENDING = 'pending'
|
PENDING = 'pending'.freeze
|
||||||
CLIENT_APPROVED = 'clientApproved'
|
CLIENT_APPROVED = 'clientApproved'.freeze
|
||||||
CLIENT_REJECTED = 'clientRejected'
|
CLIENT_REJECTED = 'clientRejected'.freeze
|
||||||
SERVER_APPROVED = 'serverApproved'
|
SERVER_APPROVED = 'serverApproved'.freeze
|
||||||
|
|
||||||
before_create :set_wait_until
|
before_create :set_wait_until
|
||||||
|
|
||||||
|
|
|
@ -1,13 +1,7 @@
|
||||||
class Feature
|
class Feature
|
||||||
# def self.obj_and_extensions_statuses_enabled?
|
def self.billing_system_integrated?
|
||||||
# return false if ENV['obj_and_extensions_prohibited'] == 'false'
|
return false if ENV['billing_system_integrated'] == 'false'
|
||||||
#
|
|
||||||
# ENV['obj_and_extensions_prohibited'] || false
|
ENV['billing_system_integrated'] || false
|
||||||
# end
|
end
|
||||||
#
|
|
||||||
# def self.enable_lock_domain_with_new_statuses?
|
|
||||||
# return false if ENV['enable_lock_domain_with_new_statuses'] == 'false'
|
|
||||||
#
|
|
||||||
# ENV['enable_lock_domain_with_new_statuses'] || false
|
|
||||||
# end
|
|
||||||
end
|
end
|
||||||
|
|
|
@ -32,30 +32,43 @@ class Invoice < ApplicationRecord
|
||||||
# rubocop:enable Layout/LineLength
|
# rubocop:enable Layout/LineLength
|
||||||
# rubocop:enable Style/MultilineBlockLayout
|
# rubocop:enable Style/MultilineBlockLayout
|
||||||
validates :due_date, :currency, :seller_name,
|
validates :due_date, :currency, :seller_name,
|
||||||
:seller_iban, :buyer_name, :items, presence: true
|
:seller_iban, :buyer_name, presence: true
|
||||||
|
validates :items, presence: true, unless: -> { monthly_invoice }
|
||||||
|
|
||||||
before_create :set_invoice_number
|
before_create :set_invoice_number
|
||||||
before_create :calculate_total, unless: :total?
|
before_create :calculate_total, unless: :total?
|
||||||
before_create :apply_default_buyer_vat_no, unless: :buyer_vat_no?
|
before_create :apply_default_buyer_vat_no, unless: :buyer_vat_no?
|
||||||
|
skip_callback :create, :before, :set_invoice_number, if: -> { monthly_invoice }
|
||||||
|
skip_callback :create, :before, :calculate_total, if: -> { monthly_invoice }
|
||||||
|
|
||||||
attribute :vat_rate, ::Type::VatRate.new
|
attribute :vat_rate, ::Type::VatRate.new
|
||||||
|
|
||||||
def set_invoice_number
|
def validate_invoice_number(result)
|
||||||
last_no = Invoice.order(number: :desc).limit(1).pick(:number)
|
response = JSON.parse(result.body)
|
||||||
|
|
||||||
if last_no && last_no >= Setting.invoice_number_min.to_i
|
billing_restrictions_issue if response['code'] == '403'
|
||||||
self.number = last_no + 1
|
billing_out_of_range_issue if response['error'] == 'out of range'
|
||||||
else
|
|
||||||
self.number = Setting.invoice_number_min.to_i
|
|
||||||
end
|
end
|
||||||
|
|
||||||
return if number <= Setting.invoice_number_max.to_i
|
def billing_restrictions_issue
|
||||||
|
errors.add(:base, I18n.t('cannot get access'))
|
||||||
|
logger.error('PROBLEM WITH TOKEN')
|
||||||
|
throw(:abort)
|
||||||
|
end
|
||||||
|
|
||||||
|
def billing_out_of_range_issue
|
||||||
errors.add(:base, I18n.t('failed_to_generate_invoice_invoice_number_limit_reached'))
|
errors.add(:base, I18n.t('failed_to_generate_invoice_invoice_number_limit_reached'))
|
||||||
logger.error('INVOICE NUMBER LIMIT REACHED, COULD NOT GENERATE INVOICE')
|
logger.error('INVOICE NUMBER LIMIT REACHED, COULD NOT GENERATE INVOICE')
|
||||||
throw(:abort)
|
throw(:abort)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def set_invoice_number
|
||||||
|
result = EisBilling::GetInvoiceNumber.send_invoice
|
||||||
|
validate_invoice_number(result)
|
||||||
|
|
||||||
|
self.number = JSON.parse(result.body)['invoice_number'].to_i
|
||||||
|
end
|
||||||
|
|
||||||
def to_s
|
def to_s
|
||||||
I18n.t('invoice_no', no: number)
|
I18n.t('invoice_no', no: number)
|
||||||
end
|
end
|
||||||
|
@ -82,7 +95,7 @@ class Invoice < ApplicationRecord
|
||||||
end
|
end
|
||||||
|
|
||||||
def subtotal
|
def subtotal
|
||||||
items.map(&:item_sum_without_vat).reduce(:+)
|
items.map(&:item_sum_without_vat).reduce(:+) || 0
|
||||||
end
|
end
|
||||||
|
|
||||||
def vat_amount
|
def vat_amount
|
||||||
|
@ -95,8 +108,12 @@ class Invoice < ApplicationRecord
|
||||||
end
|
end
|
||||||
|
|
||||||
def each(&block)
|
def each(&block)
|
||||||
|
if monthly_invoice
|
||||||
|
metadata['items'].map { |el| OpenStruct.new(el) }.each(&block)
|
||||||
|
else
|
||||||
items.each(&block)
|
items.each(&block)
|
||||||
end
|
end
|
||||||
|
end
|
||||||
|
|
||||||
def as_pdf
|
def as_pdf
|
||||||
generator = PdfGenerator.new(self)
|
generator = PdfGenerator.new(self)
|
||||||
|
@ -144,6 +161,13 @@ class Invoice < ApplicationRecord
|
||||||
|
|
||||||
private
|
private
|
||||||
|
|
||||||
|
ransacker :number_str do
|
||||||
|
Arel.sql(
|
||||||
|
"regexp_replace(
|
||||||
|
to_char(\"#{table_name}\".\"number\", '999999999999'), ' ', '', 'g')"
|
||||||
|
)
|
||||||
|
end
|
||||||
|
|
||||||
def receipt_date_status
|
def receipt_date_status
|
||||||
if paid?
|
if paid?
|
||||||
receipt_date
|
receipt_date
|
||||||
|
|
|
@ -41,22 +41,16 @@ class Invoice
|
||||||
|
|
||||||
e_invoice_invoice_items = []
|
e_invoice_invoice_items = []
|
||||||
invoice.each do |invoice_item|
|
invoice.each do |invoice_item|
|
||||||
e_invoice_invoice_item = EInvoice::InvoiceItem.new.tap do |i|
|
e_invoice_invoice_item = generate_invoice_item(invoice, invoice_item)
|
||||||
i.description = invoice_item.description
|
|
||||||
i.price = invoice_item.price
|
|
||||||
i.quantity = invoice_item.quantity
|
|
||||||
i.unit = invoice_item.unit
|
|
||||||
i.subtotal = invoice_item.subtotal
|
|
||||||
i.vat_rate = invoice_item.vat_rate
|
|
||||||
i.vat_amount = invoice_item.vat_amount
|
|
||||||
i.total = invoice_item.total
|
|
||||||
end
|
|
||||||
e_invoice_invoice_items << e_invoice_invoice_item
|
e_invoice_invoice_items << e_invoice_invoice_item
|
||||||
end
|
end
|
||||||
|
|
||||||
|
e_invoice_name_item = e_invoice_invoice_items.shift if invoice.monthly_invoice
|
||||||
|
|
||||||
e_invoice_invoice = EInvoice::Invoice.new.tap do |i|
|
e_invoice_invoice = EInvoice::Invoice.new.tap do |i|
|
||||||
i.seller = seller
|
i.seller = seller
|
||||||
i.buyer = buyer
|
i.buyer = buyer
|
||||||
|
i.name = e_invoice_name_item&.description
|
||||||
i.items = e_invoice_invoice_items
|
i.items = e_invoice_invoice_items
|
||||||
i.number = invoice.number
|
i.number = invoice.number
|
||||||
i.date = invoice.issue_date
|
i.date = invoice.issue_date
|
||||||
|
@ -72,9 +66,33 @@ class Invoice
|
||||||
i.currency = invoice.currency
|
i.currency = invoice.currency
|
||||||
i.delivery_channel = %i[internet_bank portal]
|
i.delivery_channel = %i[internet_bank portal]
|
||||||
i.payable = payable
|
i.payable = payable
|
||||||
|
i.monthly_invoice = invoice.monthly_invoice
|
||||||
end
|
end
|
||||||
|
|
||||||
EInvoice::EInvoice.new(date: Time.zone.today, invoice: e_invoice_invoice)
|
EInvoice::EInvoice.new(date: Time.zone.today, invoice: e_invoice_invoice)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
private
|
||||||
|
|
||||||
|
def generate_invoice_item(invoice, item)
|
||||||
|
EInvoice::InvoiceItem.new.tap do |i|
|
||||||
|
i.description = item.description
|
||||||
|
i.unit = item.unit
|
||||||
|
i.price = item.price
|
||||||
|
i.quantity = item.quantity
|
||||||
|
if invoice.monthly_invoice && item.price && item.quantity
|
||||||
|
i.product_id = item.product_id
|
||||||
|
i.vat_rate = invoice.vat_rate
|
||||||
|
i.subtotal = (item.price * item.quantity).round(3)
|
||||||
|
i.vat_amount = i.subtotal * (i.vat_rate / 100)
|
||||||
|
i.total = i.subtotal + i.vat_amount
|
||||||
|
else
|
||||||
|
i.subtotal = item.subtotal
|
||||||
|
i.vat_rate = item.vat_rate
|
||||||
|
i.vat_amount = item.vat_amount
|
||||||
|
i.total = item.total
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -14,7 +14,8 @@ class Invoice
|
||||||
private
|
private
|
||||||
|
|
||||||
def invoice_html
|
def invoice_html
|
||||||
ApplicationController.render(template: 'invoice/pdf', assigns: { invoice: invoice })
|
template = invoice.monthly_invoice ? 'invoice/monthly_pdf' : 'invoice/pdf'
|
||||||
|
ApplicationController.render(template: template, assigns: { invoice: invoice })
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
class Notification < ApplicationRecord
|
class Notification < ApplicationRecord
|
||||||
include Versions # version/notification_version.rb
|
include Versions # version/notification_version.rb
|
||||||
|
include EppErrors
|
||||||
|
|
||||||
belongs_to :registrar
|
belongs_to :registrar
|
||||||
belongs_to :action, optional: true
|
belongs_to :action, optional: true
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
class Registrar < ApplicationRecord
|
class Registrar < ApplicationRecord # rubocop:disable Metrics/ClassLength
|
||||||
include Versions # version/registrar_version.rb
|
include Versions # version/registrar_version.rb
|
||||||
include Registrar::BookKeeping
|
include Registrar::BookKeeping
|
||||||
include EmailVerifable
|
include EmailVerifable
|
||||||
|
@ -34,12 +34,12 @@ class Registrar < ApplicationRecord
|
||||||
attribute :vat_rate, ::Type::VatRate.new
|
attribute :vat_rate, ::Type::VatRate.new
|
||||||
after_initialize :set_defaults
|
after_initialize :set_defaults
|
||||||
|
|
||||||
validate :correct_email_format, if: proc { |c| c.will_save_change_to_email? }
|
# validate :correct_email_format, if: proc { |c| c.will_save_change_to_email? }
|
||||||
validate :correct_billing_email_format
|
# validate :correct_billing_email_format
|
||||||
|
|
||||||
alias_attribute :contact_email, :email
|
alias_attribute :contact_email, :email
|
||||||
|
|
||||||
WHOIS_TRIGGERS = %w(name email phone street city state zip)
|
WHOIS_TRIGGERS = %w[name email phone street city state zip].freeze
|
||||||
|
|
||||||
after_commit :update_whois_records
|
after_commit :update_whois_records
|
||||||
def update_whois_records
|
def update_whois_records
|
||||||
|
@ -56,9 +56,48 @@ class Registrar < ApplicationRecord
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def issue_prepayment_invoice(amount, description = nil, payable: true)
|
# rubocop:disable Metrics/MethodLength
|
||||||
vat_rate = ::Invoice::VatRateCalculator.new(registrar: self).calculate
|
def init_monthly_invoice(summary)
|
||||||
|
Invoice.new(
|
||||||
|
issue_date: summary['date'].to_date,
|
||||||
|
due_date: summary['date'].to_date,
|
||||||
|
currency: 'EUR',
|
||||||
|
description: I18n.t('invoice.monthly_invoice_description'),
|
||||||
|
seller_name: Setting.registry_juridical_name,
|
||||||
|
seller_reg_no: Setting.registry_reg_no,
|
||||||
|
seller_iban: Setting.registry_iban,
|
||||||
|
seller_bank: Setting.registry_bank,
|
||||||
|
seller_swift: Setting.registry_swift,
|
||||||
|
seller_vat_no: Setting.registry_vat_no,
|
||||||
|
seller_country_code: Setting.registry_country_code,
|
||||||
|
seller_state: Setting.registry_state,
|
||||||
|
seller_street: Setting.registry_street,
|
||||||
|
seller_city: Setting.registry_city,
|
||||||
|
seller_zip: Setting.registry_zip,
|
||||||
|
seller_phone: Setting.registry_phone,
|
||||||
|
seller_url: Setting.registry_url,
|
||||||
|
seller_email: Setting.registry_email,
|
||||||
|
seller_contact_name: Setting.registry_invoice_contact,
|
||||||
|
buyer: self,
|
||||||
|
buyer_name: name,
|
||||||
|
buyer_reg_no: reg_no,
|
||||||
|
buyer_country_code: address_country_code,
|
||||||
|
buyer_state: address_state,
|
||||||
|
buyer_street: address_street,
|
||||||
|
buyer_city: address_city,
|
||||||
|
buyer_zip: address_zip,
|
||||||
|
buyer_phone: phone,
|
||||||
|
buyer_url: website,
|
||||||
|
buyer_email: email,
|
||||||
|
reference_no: reference_no,
|
||||||
|
vat_rate: calculate_vat_rate,
|
||||||
|
monthly_invoice: true,
|
||||||
|
metadata: { items: summary['invoice_lines'] },
|
||||||
|
total: 0
|
||||||
|
)
|
||||||
|
end
|
||||||
|
|
||||||
|
def issue_prepayment_invoice(amount, description = nil, payable: true)
|
||||||
invoice = invoices.create!(
|
invoice = invoices.create!(
|
||||||
issue_date: Time.zone.today,
|
issue_date: Time.zone.today,
|
||||||
due_date: (Time.zone.now + Setting.days_to_keep_invoices_active.days).to_date,
|
due_date: (Time.zone.now + Setting.days_to_keep_invoices_active.days).to_date,
|
||||||
|
@ -91,14 +130,14 @@ class Registrar < ApplicationRecord
|
||||||
buyer_url: website,
|
buyer_url: website,
|
||||||
buyer_email: email,
|
buyer_email: email,
|
||||||
reference_no: reference_no,
|
reference_no: reference_no,
|
||||||
vat_rate: vat_rate,
|
vat_rate: calculate_vat_rate,
|
||||||
items_attributes: [
|
items_attributes: [
|
||||||
{
|
{
|
||||||
description: 'prepayment',
|
description: 'prepayment',
|
||||||
unit: 'piece',
|
unit: 'piece',
|
||||||
quantity: 1,
|
quantity: 1,
|
||||||
price: amount
|
price: amount,
|
||||||
}
|
},
|
||||||
]
|
]
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -107,10 +146,17 @@ class Registrar < ApplicationRecord
|
||||||
.deliver_later(wait: 1.minute)
|
.deliver_later(wait: 1.minute)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
add_invoice_instance = EisBilling::AddDeposits.new(invoice)
|
||||||
|
result = add_invoice_instance.send_invoice
|
||||||
|
|
||||||
|
link = JSON.parse(result.body)['everypay_link']
|
||||||
|
|
||||||
|
invoice.update(payment_link: link)
|
||||||
SendEInvoiceJob.set(wait: 1.minute).perform_now(invoice.id, payable: payable)
|
SendEInvoiceJob.set(wait: 1.minute).perform_now(invoice.id, payable: payable)
|
||||||
|
|
||||||
invoice
|
invoice
|
||||||
end
|
end
|
||||||
|
# rubocop:enable Metrics/MethodLength
|
||||||
|
|
||||||
def cash_account
|
def cash_account
|
||||||
accounts.find_by(account_type: Account::CASH)
|
accounts.find_by(account_type: Account::CASH)
|
||||||
|
@ -175,9 +221,9 @@ class Registrar < ApplicationRecord
|
||||||
end
|
end
|
||||||
|
|
||||||
def add_nameservers(new_attributes, domains: [])
|
def add_nameservers(new_attributes, domains: [])
|
||||||
transaction do
|
return [] if domains.empty?
|
||||||
return if domains.empty?
|
|
||||||
|
|
||||||
|
transaction do
|
||||||
approved_list = domain_list_processing(domains: domains, new_attributes: new_attributes)
|
approved_list = domain_list_processing(domains: domains, new_attributes: new_attributes)
|
||||||
|
|
||||||
self.domains.where(name: approved_list).find_each(&:update_whois_record) if approved_list.any?
|
self.domains.where(name: approved_list).find_each(&:update_whois_record) if approved_list.any?
|
||||||
|
@ -220,13 +266,9 @@ class Registrar < ApplicationRecord
|
||||||
def notify(action)
|
def notify(action)
|
||||||
text = I18n.t("notifications.texts.#{action.notification_key}", contact: action.contact&.code,
|
text = I18n.t("notifications.texts.#{action.notification_key}", contact: action.contact&.code,
|
||||||
count: action.subactions&.count)
|
count: action.subactions&.count)
|
||||||
if action.bulk_action?
|
|
||||||
notifications.create!(text: text, action_id: action.id,
|
notifications.create!(text: text, action_id: action.id,
|
||||||
attached_obj_type: 'BulkAction',
|
attached_obj_type: 'ContactUpdateAction',
|
||||||
attached_obj_id: action.id)
|
attached_obj_id: action.id)
|
||||||
else
|
|
||||||
notifications.create!(text: text)
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
|
||||||
def e_invoice_iban
|
def e_invoice_iban
|
||||||
|
@ -256,4 +298,8 @@ class Registrar < ApplicationRecord
|
||||||
def vat_liable_in_foreign_country?
|
def vat_liable_in_foreign_country?
|
||||||
!vat_liable_locally?
|
!vat_liable_locally?
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def calculate_vat_rate
|
||||||
|
::Invoice::VatRateCalculator.new(registrar: self).calculate
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -5,7 +5,7 @@ class TechDomainContact < DomainContact
|
||||||
skipped_domains = []
|
skipped_domains = []
|
||||||
tech_contacts = where(contact: current_contact)
|
tech_contacts = where(contact: current_contact)
|
||||||
|
|
||||||
tech_contacts.each do |tech_contact|
|
tech_contacts.includes(:domain).find_each do |tech_contact|
|
||||||
if irreplaceable?(tech_contact)
|
if irreplaceable?(tech_contact)
|
||||||
skipped_domains << tech_contact.domain.name
|
skipped_domains << tech_contact.domain.name
|
||||||
next
|
next
|
||||||
|
|
|
@ -13,9 +13,9 @@ class User < ApplicationRecord
|
||||||
|
|
||||||
def self.from_omniauth(omniauth_hash)
|
def self.from_omniauth(omniauth_hash)
|
||||||
uid = omniauth_hash['uid']
|
uid = omniauth_hash['uid']
|
||||||
identity_code = uid.slice(2..-1)
|
identity_code = uid&.slice(2..-1)
|
||||||
# country_code = uid.slice(0..1)
|
# country_code = uid.slice(0..1)
|
||||||
|
|
||||||
find_by(identity_code: identity_code)
|
find_by(identity_code: identity_code, active: true)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -27,7 +27,7 @@ class ValidationEvent < ApplicationRecord
|
||||||
|
|
||||||
belongs_to :validation_eventable, polymorphic: true
|
belongs_to :validation_eventable, polymorphic: true
|
||||||
|
|
||||||
scope :recent, -> { where('created_at < ?', Time.zone.now - VALIDATION_PERIOD) }
|
scope :old_records, -> { where('created_at < ?', Time.zone.now - VALIDATION_PERIOD) }
|
||||||
scope :successful, -> { where(success: true) }
|
scope :successful, -> { where(success: true) }
|
||||||
scope :failed, -> { where(success: false) }
|
scope :failed, -> { where(success: false) }
|
||||||
scope :regex, -> { where('event_data @> ?', { 'check_level': 'regex' }.to_json) }
|
scope :regex, -> { where('event_data @> ?', { 'check_level': 'regex' }.to_json) }
|
||||||
|
@ -35,10 +35,10 @@ class ValidationEvent < ApplicationRecord
|
||||||
scope :smtp, -> { where('event_data @> ?', { 'check_level': 'smtp' }.to_json) }
|
scope :smtp, -> { where('event_data @> ?', { 'check_level': 'smtp' }.to_json) }
|
||||||
scope :by_object, ->(object) { where(validation_eventable: object) }
|
scope :by_object, ->(object) { where(validation_eventable: object) }
|
||||||
|
|
||||||
after_create :check_for_force_delete
|
|
||||||
|
|
||||||
def self.validated_ids_by(klass)
|
def self.validated_ids_by(klass)
|
||||||
recent.successful.where('validation_eventable_type = ?', klass)
|
old_records
|
||||||
|
.successful
|
||||||
|
.where('validation_eventable_type = ?', klass)
|
||||||
.pluck(:validation_eventable_id)
|
.pluck(:validation_eventable_id)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -57,56 +57,4 @@ class ValidationEvent < ApplicationRecord
|
||||||
def object
|
def object
|
||||||
validation_eventable
|
validation_eventable
|
||||||
end
|
end
|
||||||
|
|
||||||
def check_for_force_delete
|
|
||||||
if object.need_to_start_force_delete?
|
|
||||||
start_force_delete
|
|
||||||
elsif object.need_to_lift_force_delete?
|
|
||||||
refresh_status_notes
|
|
||||||
lift_force_delete
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
def start_force_delete
|
|
||||||
Domains::ForceDeleteEmail::Base.run(email: email)
|
|
||||||
end
|
|
||||||
|
|
||||||
def refresh_status_notes
|
|
||||||
domain_list.each do |domain|
|
|
||||||
next unless domain.status_notes[DomainStatus::FORCE_DELETE]
|
|
||||||
|
|
||||||
domain.status_notes[DomainStatus::FORCE_DELETE].slice!(object.email_history)
|
|
||||||
domain.status_notes[DomainStatus::FORCE_DELETE].lstrip!
|
|
||||||
domain.save(validate: false)
|
|
||||||
|
|
||||||
notify_registrar(domain) unless domain.status_notes[DomainStatus::FORCE_DELETE].empty?
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
def domain_list
|
|
||||||
domain_contacts = Contact.where(email: email).map(&:domain_contacts).flatten
|
|
||||||
registrant_ids = Registrant.where(email: email).pluck(:id)
|
|
||||||
|
|
||||||
(domain_contacts.map(&:domain).flatten + Domain.where(registrant_id: registrant_ids)).uniq
|
|
||||||
end
|
|
||||||
|
|
||||||
def notify_registrar(domain)
|
|
||||||
domain.registrar.notifications.create!(text: I18n.t('force_delete_auto_email',
|
|
||||||
domain_name: domain.name,
|
|
||||||
outzone_date: domain.outzone_date,
|
|
||||||
purge_date: domain.purge_date,
|
|
||||||
email: domain.status_notes[DomainStatus::FORCE_DELETE]))
|
|
||||||
end
|
|
||||||
|
|
||||||
def lift_force_delete
|
|
||||||
# domain_contacts = Contact.where(email: email).map(&:domain_contacts).flatten
|
|
||||||
# registrant_ids = Registrant.where(email: email).pluck(:id)
|
|
||||||
#
|
|
||||||
# domains = domain_contacts.map(&:domain).flatten +
|
|
||||||
# Domain.where(registrant_id: registrant_ids)
|
|
||||||
#
|
|
||||||
# domains.each do |domain|
|
|
||||||
# Domains::ForceDeleteLift::Base.run(domain: domain)
|
|
||||||
# end
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
|
|
@ -17,13 +17,13 @@ class Registrar::DomainListCsvPresenter
|
||||||
private
|
private
|
||||||
|
|
||||||
def header
|
def header
|
||||||
columns = %w(
|
columns = %w[
|
||||||
domain_name
|
domain_name
|
||||||
transfer_code
|
transfer_code
|
||||||
registrant_name
|
registrant_name
|
||||||
registrant_code
|
registrant_code
|
||||||
expire_time
|
expire_time
|
||||||
)
|
]
|
||||||
|
|
||||||
columns.map! { |column| view.t("registrar.domains.index.csv.#{column}") }
|
columns.map! { |column| view.t("registrar.domains.index.csv.#{column}") }
|
||||||
|
|
||||||
|
@ -37,7 +37,6 @@ class Registrar::DomainListCsvPresenter
|
||||||
row[2] = domain.registrant.name
|
row[2] = domain.registrant.name
|
||||||
row[3] = domain.registrant.code
|
row[3] = domain.registrant.code
|
||||||
row[4] = domain.expire_date
|
row[4] = domain.expire_date
|
||||||
row
|
|
||||||
|
|
||||||
CSV::Row.new([], row)
|
CSV::Row.new([], row)
|
||||||
end
|
end
|
||||||
|
|
38
app/services/eis_billing/add_deposits.rb
Normal file
38
app/services/eis_billing/add_deposits.rb
Normal file
|
@ -0,0 +1,38 @@
|
||||||
|
module EisBilling
|
||||||
|
class AddDeposits < EisBilling::Base
|
||||||
|
attr_reader :invoice
|
||||||
|
|
||||||
|
def initialize(invoice)
|
||||||
|
@invoice = invoice
|
||||||
|
end
|
||||||
|
|
||||||
|
def send_invoice
|
||||||
|
send_request(json_obj: parse_invoice)
|
||||||
|
end
|
||||||
|
|
||||||
|
private
|
||||||
|
|
||||||
|
def parse_invoice
|
||||||
|
data = {}
|
||||||
|
data[:transaction_amount] = invoice.total.to_s
|
||||||
|
data[:order_reference] = invoice.number
|
||||||
|
data[:customer_name] = invoice.buyer_name
|
||||||
|
data[:customer_email] = invoice.buyer_email
|
||||||
|
data[:custom_field1] = invoice.description
|
||||||
|
data[:custom_field2] = INITIATOR
|
||||||
|
data[:invoice_number] = invoice.number
|
||||||
|
data[:reference_number] = invoice.reference_no
|
||||||
|
|
||||||
|
data
|
||||||
|
end
|
||||||
|
|
||||||
|
def send_request(json_obj:)
|
||||||
|
http = EisBilling::Base.base_request(url: invoice_generator_url)
|
||||||
|
http.post(invoice_generator_url, json_obj.to_json, EisBilling::Base.headers)
|
||||||
|
end
|
||||||
|
|
||||||
|
def invoice_generator_url
|
||||||
|
"#{BASE_URL}/api/v1/invoice_generator/invoice_generator"
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
35
app/services/eis_billing/base.rb
Normal file
35
app/services/eis_billing/base.rb
Normal file
|
@ -0,0 +1,35 @@
|
||||||
|
module EisBilling
|
||||||
|
class Base
|
||||||
|
BASE_URL = ENV['eis_billing_system_base_url'] || 'https://st-billing.infra.tld.ee'
|
||||||
|
INITIATOR = 'registry'.freeze
|
||||||
|
|
||||||
|
def self.base_request(url:)
|
||||||
|
uri = URI(url)
|
||||||
|
http = Net::HTTP.new(uri.host, uri.port)
|
||||||
|
|
||||||
|
http.use_ssl = true unless Rails.env.development?
|
||||||
|
http.verify_mode = OpenSSL::SSL::VERIFY_NONE if Rails.env.development?
|
||||||
|
|
||||||
|
http
|
||||||
|
end
|
||||||
|
|
||||||
|
def self.generate_token
|
||||||
|
JWT.encode(payload, billing_secret)
|
||||||
|
end
|
||||||
|
|
||||||
|
def self.payload
|
||||||
|
{ initiator: INITIATOR }
|
||||||
|
end
|
||||||
|
|
||||||
|
def self.headers
|
||||||
|
{
|
||||||
|
'Authorization' => "Bearer #{generate_token}",
|
||||||
|
'Content-Type' => 'application/json',
|
||||||
|
}
|
||||||
|
end
|
||||||
|
|
||||||
|
def self.billing_secret
|
||||||
|
ENV['billing_secret']
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
16
app/services/eis_billing/get_invoice_number.rb
Normal file
16
app/services/eis_billing/get_invoice_number.rb
Normal file
|
@ -0,0 +1,16 @@
|
||||||
|
module EisBilling
|
||||||
|
class GetInvoiceNumber < EisBilling::Base
|
||||||
|
def self.send_invoice
|
||||||
|
send_request
|
||||||
|
end
|
||||||
|
|
||||||
|
def self.send_request
|
||||||
|
http = EisBilling::Base.base_request(url: invoice_number_generator_url)
|
||||||
|
http.post(invoice_number_generator_url, nil, EisBilling::Base.headers)
|
||||||
|
end
|
||||||
|
|
||||||
|
def self.invoice_number_generator_url
|
||||||
|
"#{BASE_URL}/api/v1/invoice_generator/invoice_number_generator"
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
22
app/services/eis_billing/get_reference_number.rb
Normal file
22
app/services/eis_billing/get_reference_number.rb
Normal file
|
@ -0,0 +1,22 @@
|
||||||
|
module EisBilling
|
||||||
|
class GetReferenceNumber < EisBilling::Base
|
||||||
|
def self.send_request
|
||||||
|
send_it
|
||||||
|
end
|
||||||
|
|
||||||
|
def self.obj_data
|
||||||
|
{
|
||||||
|
initiator: INITIATOR,
|
||||||
|
}
|
||||||
|
end
|
||||||
|
|
||||||
|
def self.send_it
|
||||||
|
http = EisBilling::Base.base_request(url: reference_number_generator_url)
|
||||||
|
http.post(reference_number_generator_url, obj_data.to_json, EisBilling::Base.headers)
|
||||||
|
end
|
||||||
|
|
||||||
|
def self.reference_number_generator_url
|
||||||
|
"#{EisBilling::Base::BASE_URL}/api/v1/invoice_generator/reference_number_generator"
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
23
app/services/eis_billing/send_data_to_directo.rb
Normal file
23
app/services/eis_billing/send_data_to_directo.rb
Normal file
|
@ -0,0 +1,23 @@
|
||||||
|
module EisBilling
|
||||||
|
class SendDataToDirecto < EisBilling::Base
|
||||||
|
def self.send_request(object_data:, monthly:, dry:)
|
||||||
|
send_info(object_data: object_data, monthly: monthly, dry: dry)
|
||||||
|
end
|
||||||
|
|
||||||
|
def self.send_info(object_data:, monthly:, dry:)
|
||||||
|
prepared_data = {
|
||||||
|
invoice_data: object_data,
|
||||||
|
monthly: monthly,
|
||||||
|
dry: dry,
|
||||||
|
initiator: INITIATOR,
|
||||||
|
}
|
||||||
|
|
||||||
|
http = EisBilling::Base.base_request(url: directo_url)
|
||||||
|
http.post(directo_url, prepared_data.to_json, EisBilling::Base.headers)
|
||||||
|
end
|
||||||
|
|
||||||
|
def self.directo_url
|
||||||
|
"#{BASE_URL}/api/v1/directo/directo"
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
52
app/services/eis_billing/send_e_invoice.rb
Normal file
52
app/services/eis_billing/send_e_invoice.rb
Normal file
|
@ -0,0 +1,52 @@
|
||||||
|
module EisBilling
|
||||||
|
class SendEInvoice < EisBilling::Base
|
||||||
|
def self.send_request(invoice:, payable:)
|
||||||
|
send_info(invoice: invoice, payable: payable)
|
||||||
|
end
|
||||||
|
|
||||||
|
def self.send_info(invoice:, payable:)
|
||||||
|
items = []
|
||||||
|
prepared_data = prepare_data(invoice: invoice, payable: payable)
|
||||||
|
|
||||||
|
invoice.items.each do |invoice_item|
|
||||||
|
items << prepare_item(invoice_item)
|
||||||
|
end
|
||||||
|
|
||||||
|
prepared_data[:items] = items
|
||||||
|
|
||||||
|
http = EisBilling::Base.base_request(url: e_invoice_url)
|
||||||
|
http.post(e_invoice_url, prepared_data.to_json, EisBilling::Base.headers)
|
||||||
|
end
|
||||||
|
|
||||||
|
def self.prepare_item(invoice_item)
|
||||||
|
{
|
||||||
|
description: invoice_item.description,
|
||||||
|
price: invoice_item.price,
|
||||||
|
quantity: invoice_item.quantity,
|
||||||
|
unit: invoice_item.unit,
|
||||||
|
subtotal: invoice_item.subtotal,
|
||||||
|
vat_rate: invoice_item.vat_rate,
|
||||||
|
vat_amount: invoice_item.vat_amount,
|
||||||
|
total: invoice_item.total,
|
||||||
|
}
|
||||||
|
end
|
||||||
|
|
||||||
|
def self.prepare_data(invoice:, payable:)
|
||||||
|
{
|
||||||
|
invoice: invoice,
|
||||||
|
vat_amount: invoice.vat_amount,
|
||||||
|
invoice_subtotal: invoice.subtotal,
|
||||||
|
buyer_billing_email: invoice.buyer.billing_email,
|
||||||
|
buyer_e_invoice_iban: invoice.buyer.e_invoice_iban,
|
||||||
|
seller_country_code: invoice.seller_country_code,
|
||||||
|
buyer_country_code: invoice.buyer_country_code,
|
||||||
|
payable: payable,
|
||||||
|
initiator: EisBilling::Base::INITIATOR,
|
||||||
|
}
|
||||||
|
end
|
||||||
|
|
||||||
|
def self.e_invoice_url
|
||||||
|
"#{BASE_URL}/api/v1/e_invoice/e_invoice"
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue