Merge branch 'master' into registry-787

# Conflicts:
#	db/structure.sql
This commit is contained in:
Artur Beljajev 2018-04-17 12:38:55 +03:00
commit 96e2136c38
92 changed files with 860 additions and 271 deletions

1
.reek
View file

@ -289,7 +289,6 @@ DuplicateMethodCall:
- Domain#renewable?
- Domain#set_graceful_expired
- DomainCron#self.clean_expired_pendings
- DomainCron#self.delete_legal_doc_duplicates
- DomainCron#self.destroy_delete_candidates
- DomainCron#self.start_expire_period
- DomainCron#self.start_redemption_grace_period

View file

@ -1,3 +1,12 @@
03.04.2018
* BUG: Fixed bug with sometimes failing bank-link payments [#642](https://github.com/internetee/registry/issues/642)
* EPP: Domain and associated objects are now validated on domain renew [#678](https://github.com/internetee/registry/issues/678)
* Admin: drop uniqueness requirement from registrar's registry number field [#776](https://github.com/internetee/registry/issues/776)
* Security: Loofah gem update to 2.2.2 [#783](https://github.com/internetee/registry/pull/783)
* Disabled spellcheck for browsers to cleanup UI [#759](https://github.com/internetee/registry/issues/759)
* Admin: refactored registrar management [#770](https://github.com/internetee/registry/pull/770)
* Fix structure.sql [#796](https://github.com/internetee/registry/pull/796)
19.03.2018
* EPP transfer and REPP bulk transfer reuses contact objects [#746](https://github.com/internetee/registry/issues/746)
* Gems: Rack (1.6.9) and Rack-protection (1.5.5) update [#768](https://github.com/internetee/registry/issues/768)

23
Dockerfile Normal file
View file

@ -0,0 +1,23 @@
FROM ruby:2.2
MAINTAINER maciej.szlosarczyk@internet.ee
RUN apt-get update > /dev/null && apt-get install -y > /dev/null \
build-essential \
nodejs \
imagemagick \
postgresql-client
RUN apt-get install -y > /dev/null \
qt5-default \
libqt5webkit5-dev \
gstreamer1.0-plugins-base \
gstreamer1.0-tools \
qtdeclarative5-dev \
gstreamer1.0-x
RUN mkdir -p /opt/webapps/app/tmp/pids
WORKDIR /opt/webapps/app
COPY Gemfile Gemfile.lock ./
RUN gem install bundler && bundle install --jobs 20 --retry 5
EXPOSE 3000

View file

@ -24,7 +24,7 @@ module Admin
@invoice = Invoice.find_by(id: params[:invoice_id])
@bank_transaction = @bank_statement.bank_transactions.build(
description: @invoice.to_s,
sum: @invoice.sum,
sum: @invoice.total,
reference_no: @invoice.reference_no,
paid_at: Time.zone.now.to_date,
currency: 'EUR'

View file

@ -61,7 +61,6 @@ module Admin
def registrar_params
params.require(:registrar).permit(:name,
:reg_no,
:vat_no,
:street,
:city,
:state,
@ -70,10 +69,12 @@ module Admin
:email,
:phone,
:website,
:billing_email,
:code,
:test_registrar,
:vat_no,
:vat_rate,
:accounting_customer_code,
:billing_email,
:language)
end
end

View file

@ -55,8 +55,8 @@ class Registrar
end
def normalize_search_parameters
params[:q][:sum_cache_gteq].gsub!(',', '.') if params[:q][:sum_cache_gteq]
params[:q][:sum_cache_lteq].gsub!(',', '.') if params[:q][:sum_cache_lteq]
params[:q][:total_gteq].gsub!(',', '.') if params[:q][:total_gteq]
params[:q][:total_lteq].gsub!(',', '.') if params[:q][:total_lteq]
ca_cache = params[:q][:due_date_lteq]
begin

View file

@ -29,7 +29,7 @@ class BankLink
hash["VK_VERSION"] = "008"
hash["VK_SND_ID"] = ENV["payments_#{type}_seller_account"]
hash["VK_STAMP"] = invoice.number
hash["VK_AMOUNT"] = number_with_precision(invoice.sum_cache, :precision => 2, :separator => ".")
hash["VK_AMOUNT"] = number_with_precision(invoice.total, :precision => 2, :separator => ".")
hash["VK_CURR"] = invoice.currency
hash["VK_REF"] = ""
hash["VK_MSG"] = invoice.order
@ -140,7 +140,7 @@ class BankLink
def validate_amount
source = number_with_precision(BigDecimal.new(params["VK_AMOUNT"].to_s), precision: 2, separator: ".")
target = number_with_precision(invoice.sum_cache, precision: 2, separator: ".")
target = number_with_precision(invoice.total, precision: 2, separator: ".")
source == target
end

View file

@ -47,7 +47,7 @@ class BankTransaction < ActiveRecord::Base
return if invoice.binded?
return if invoice.cancelled?
return if invoice.sum != sum
return if invoice.total != sum
create_activity(registrar, invoice)
end
# rubocop: enable Metrics/PerceivedComplexity
@ -76,7 +76,7 @@ class BankTransaction < ActiveRecord::Base
return
end
if invoice.sum != sum
if invoice.total != sum
errors.add(:base, I18n.t('invoice_and_transaction_sums_do_not_match'))
return
end
@ -88,7 +88,7 @@ class BankTransaction < ActiveRecord::Base
create_account_activity(
account: registrar.cash_account,
invoice: invoice,
sum: invoice.sum_without_vat,
sum: invoice.subtotal,
currency: currency,
description: description,
activity_type: AccountActivity::ADD_CREDIT

View file

@ -3,7 +3,7 @@ class Directo < ActiveRecord::Base
belongs_to :item, polymorphic: true
def self.send_receipts
new_trans = Invoice.where(invoice_type: "DEB", in_directo: false).where(cancelled_at: nil)
new_trans = Invoice.where(in_directo: false).where(cancelled_at: nil)
total = new_trans.count
counter = 0
Rails.logger.info("[DIRECTO] Will try to send #{total} invoices")
@ -15,7 +15,7 @@ class Directo < ActiveRecord::Base
group.each do |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.sum_cache
invoice.account_activity.bank_transaction.sum.nil? || invoice.account_activity.bank_transaction.sum != invoice.total
Rails.logger.info("[DIRECTO] Invoice #{invoice.number} has been skipped")
next
end
@ -29,12 +29,14 @@ class Directo < ActiveRecord::Base
"InvoiceDate" => invoice.created_at.strftime("%Y-%m-%dT%H:%M:%S"),
"PaymentTerm" => Setting.directo_receipt_payment_term,
"Currency" => invoice.currency,
"CustomerCode"=> invoice.buyer.accounting_customer_code
"CustomerCode"=> invoice.buyer.accounting_customer_code,
'TotalVAT' => ActionController::Base.helpers.number_with_precision(invoice.vat_amount, precision: 2, separator: '.')
){
xml.line(
"ProductID" => Setting.directo_receipt_product_name,
"Quantity" => 1,
"UnitPriceWoVAT" => ActionController::Base.helpers.number_with_precision(invoice.sum_cache/(1+invoice.vat_prc), precision: 2, separator: "."),
"UnitPriceWoVAT" => ActionController::Base.helpers.number_with_precision(invoice.subtotal, precision: 2, separator: '.'),
'VATCode' => invoice.buyer_vat_no,
"ProductName" => invoice.order
)
}

View file

@ -209,28 +209,12 @@ class Domain < ActiveRecord::Base
DomainCron.send(__method__)
end
def self.start_delete_period
ActiveSupport::Deprecation.instance.deprecation_warning(DomainCron, __method__)
DomainCron.send(__method__)
end
def self.destroy_delete_candidates
ActiveSupport::Deprecation.instance.deprecation_warning(DomainCron, __method__)
DomainCron.send(__method__)
end
class << self
def included
includes(
:registrant,
:registrar,
:nameservers,
:whois_record,
{ tech_contacts: :registrar },
{ admin_contacts: :registrar }
)
end
def nameserver_required?
Setting.nameserver_required
end

View file

@ -76,29 +76,6 @@ class DomainCron
marked
end
#doing nothing, deprecated
def self.start_delete_period
# begin
# STDOUT << "#{Time.zone.now.utc} - Setting delete_candidate to domains\n" unless Rails.env.test?
#
# d = Domain.where('delete_at <= ?', Time.zone.now)
# marked = 0
# real = 0
# d.each do |domain|
# next unless domain.delete_candidateable?
# real += 1
# domain.statuses << DomainStatus::DELETE_CANDIDATE
# STDOUT << "#{Time.zone.now.utc} DomainCron.start_delete_period: ##{domain.id} (#{domain.name})\n" unless Rails.env.test?
# ::PaperTrail.whodunnit = "cron - #{__method__}"
# domain.save(validate: false) and marked += 1
# end
# ensure # the operator should see what was accomplished
# STDOUT << "#{Time.zone.now.utc} - Finished setting delete_candidate - #{marked} out of #{real} successfully set\n" unless Rails.env.test?
# end
# marked
end
def self.destroy_delete_candidates
STDOUT << "#{Time.zone.now.utc} - Destroying domains\n" unless Rails.env.test?
@ -128,23 +105,4 @@ class DomainCron
STDOUT << "#{Time.zone.now.utc} - Job destroy added for #{c} domains\n" unless Rails.env.test?
end
# rubocop: enable Metrics/AbcSize
# rubocop:enable Rails/FindEach
# rubocop: enable Metrics/LineLength
def self.destroy_with_message(domain)
domain.destroy
bye_bye = domain.versions.last
domain.registrar.messages.create!(
body: "#{I18n.t(:domain_deleted)}: #{domain.name}",
attached_obj_id: bye_bye.id,
attached_obj_type: bye_bye.class.to_s # DomainVersion
)
end
def self.delete_legal_doc_duplicates
Rake::Task['legal_doc:remove_duplicates'].reenable
Rake::Task['legal_doc:remove_duplicates'].invoke
end
end

View file

@ -18,7 +18,7 @@ class Epp::Domain < Domain
after_validation :validate_contacts
def validate_contacts
return true if is_renewal || is_transfer
return true if is_transfer
ok = true
active_admins = admin_domain_contacts.select { |x| !x.marked_for_destruction? }
@ -38,16 +38,6 @@ class Epp::Domain < Domain
ok
end
before_save :link_contacts
def link_contacts
#TODO: cleanup cache if we think to cache dynamic statuses
end
after_destroy :unlink_contacts
def unlink_contacts
#TODO: cleanup cache if we think to cache dynamic statuses
end
class << self
def new_from_epp(frame, current_user)
domain = Epp::Domain.new

View file

@ -27,12 +27,18 @@ class Invoice < ActiveRecord::Base
attr_accessor :billing_email
validates :billing_email, email_format: { message: :invalid }, allow_blank: true
validates :invoice_type, :due_date, :currency, :seller_name,
:seller_iban, :buyer_name, :invoice_items, :vat_prc, presence: true
validates :due_date, :currency, :seller_name,
:seller_iban, :buyer_name, :invoice_items, presence: true
validates :vat_rate, numericality: { greater_than_or_equal_to: 0, less_than: 100 },
allow_nil: true
before_create :set_invoice_number, :check_vat
before_create :set_invoice_number
before_create :apply_default_vat_rate, unless: :vat_rate?
before_create :calculate_total, unless: :total?
before_create :apply_default_buyer_vat_no, unless: :buyer_vat_no?
before_save :check_vat
attribute :vat_rate, ::Type::VATRate.new
attr_readonly :vat_rate
def set_invoice_number
last_no = Invoice.order(number: :desc).where('number IS NOT NULL').limit(1).pluck(:number).first
@ -50,14 +56,6 @@ class Invoice < ActiveRecord::Base
false
end
def check_vat
if buyer.country_code != 'EE' && buyer.vat_no.present?
self.vat_prc = 0
end
end
before_save -> { self.sum_cache = sum }
class << self
def cancel_overdue_invoices
STDOUT << "#{Time.zone.now.utc} - Cancelling overdue invoices\n" unless Rails.env.test?
@ -152,15 +150,31 @@ class Invoice < ActiveRecord::Base
invoice_items
end
def sum_without_vat
(items.map(&:item_sum_without_vat).sum).round(2)
def subtotal
invoice_items.map(&:item_sum_without_vat).reduce(:+)
end
def vat
(sum_without_vat * vat_prc).round(2)
def vat_amount
return 0 unless vat_rate
subtotal * vat_rate / 100
end
def sum
(sum_without_vat + vat).round(2)
def total
calculate_total unless total?
read_attribute(:total)
end
private
def apply_default_vat_rate
self.vat_rate = buyer.effective_vat_rate
end
def apply_default_buyer_vat_no
self.buyer_vat_no = buyer.vat_no
end
def calculate_total
self.total = subtotal + vat_amount
end
end

View file

@ -19,6 +19,15 @@ class Registrar < ActiveRecord::Base
validates :language, presence: true
validate :forbid_special_code
validates :vat_rate, presence: true, if: 'foreign_vat_payer? && vat_no.blank?'
validates :vat_rate, absence: true, if: :home_vat_payer?
validates :vat_rate, absence: true, if: 'foreign_vat_payer? && vat_no?'
validates :vat_rate, numericality: { greater_than_or_equal_to: 0, less_than: 100 },
allow_nil: true
validate :forbid_special_code
attribute :vat_rate, ::Type::VATRate.new
after_initialize :set_defaults
before_validation :generate_iso_11649_reference_no
@ -49,12 +58,10 @@ class Registrar < ActiveRecord::Base
# rubocop:disable Metrics/AbcSize
def issue_prepayment_invoice(amount, description = nil)
invoices.create(
invoice_type: 'DEB',
due_date: (Time.zone.now.to_date + Setting.days_to_keep_invoices_active.days).end_of_day,
payment_term: 'prepayment',
description: description,
currency: 'EUR',
vat_prc: Setting.registry_vat_prc,
seller_name: Setting.registry_juridical_name,
seller_reg_no: Setting.registry_reg_no,
seller_iban: Setting.registry_iban,
@ -70,7 +77,7 @@ class Registrar < ActiveRecord::Base
seller_url: Setting.registry_url,
seller_email: Setting.registry_email,
seller_contact_name: Setting.registry_invoice_contact,
buyer_id: id,
buyer: self,
buyer_name: name,
buyer_reg_no: reg_no,
buyer_country_code: country_code,
@ -105,11 +112,6 @@ class Registrar < ActiveRecord::Base
cash_account.account_activities.create!(args)
end
def credit!(args)
args[:currency] = 'EUR'
cash_account.account_activities.create!(args)
end
def address
[street, city, state, zip].reject(&:blank?).compact.join(', ')
end
@ -145,6 +147,14 @@ class Registrar < ActiveRecord::Base
end
end
def effective_vat_rate
if home_vat_payer?
Registry.instance.vat_rate
else
vat_rate
end
end
private
def set_defaults
@ -175,4 +185,12 @@ class Registrar < ActiveRecord::Base
break unless self.class.exists?(reference_no: reference_no)
end
end
def home_vat_payer?
country == Registry.instance.legal_address_country
end
def foreign_vat_payer?
!home_vat_payer?
end
end

11
app/models/registry.rb Normal file
View file

@ -0,0 +1,11 @@
class Registry
include Singleton
def vat_rate
Setting.registry_vat_prc.to_d * 100
end
def legal_address_country
Country.new(Setting.registry_country_code)
end
end

View file

@ -0,0 +1,11 @@
module Type
class VATRate < ActiveRecord::Type::Decimal
def type_cast_from_database(value)
super * 100 if value
end
def type_cast_for_database(value)
super / 100.0 if value
end
end
end

View file

@ -9,20 +9,6 @@ class WhoisRecord < ActiveRecord::Base
after_save :update_whois_server
after_destroy :destroy_whois_record
class << self
def included
includes(
domain: [
:registrant,
:registrar,
:nameservers,
{ tech_contacts: :registrar },
{ admin_contacts: :registrar }
]
)
end
end
def self.find_by_name(name)
WhoisRecord.where("lower(name) = ?", name.downcase)
end

View file

@ -37,7 +37,7 @@
= f.email_field :bcc, class: 'form-control'
.form-group
.col-md-12
= f.label :body, t(:html_body)
= f.label :body, t('admin.mail_templates.html_body')
= liquid_help
.col-md-12
= f.text_area(:body, class: 'form-control', size: '15x15')

View file

@ -1,3 +1,3 @@
= render 'shared/title', name: t(:new_mail_template)
= render 'shared/title', name: t('admin.mail_templates.new_mail_template')
= render 'form', mail_template: @mail_template

View file

@ -7,6 +7,9 @@
<dt><%= Registrar.human_attribute_name :vat_no %></dt>
<dd><%= registrar.vat_no %></dd>
<dt><%= Registrar.human_attribute_name :vat_rate %></dt>
<dd><%= number_to_percentage(registrar.vat_rate, precision: 1) %></dd>
<dt><%= Registrar.human_attribute_name :accounting_customer_code %></dt>
<dd><%= registrar.accounting_customer_code %></dd>

View file

@ -17,6 +17,19 @@
</div>
</div>
<div class="form-group">
<div class="col-md-4 control-label">
<%= f.label :vat_rate %>
</div>
<div class="col-md-3">
<div class="input-group">
<%= f.number_field :vat_rate, min: 0, max: 99.9, step: 0.1,
class: 'form-control' %>
<div class="input-group-addon">%</div>
</div>
</div>
</div>
<div class="form-group">
<div class="col-md-4 control-label">
<%= f.label :accounting_customer_code %>

View file

@ -33,11 +33,11 @@
.col-md-3
.form-group
= f.label t(:minimum_total)
= f.search_field :sum_cache_gteq, class: 'form-control', placeholder: t(:minimum_total), autocomplete: 'off'
= f.search_field :total_gteq, class: 'form-control', placeholder: t(:minimum_total), autocomplete: 'off'
.col-md-3
.form-group
= f.label t(:maximum_total)
= f.search_field :sum_cache_lteq, class: 'form-control', placeholder: t(:maximum_total), autocomplete: 'off'
= f.search_field :total_lteq, class: 'form-control', placeholder: t(:maximum_total), autocomplete: 'off'
.col-md-3{style: 'padding-top: 25px;'}
%button.btn.btn-default
&nbsp;
@ -67,7 +67,7 @@
%td{class: 'text-danger'}= t(:unpaid)
%td= l(x.due_date, format: :date_long)
%td= currency(x.sum)
%td= currency(x.total)
.row
.col-md-12
= paginate @invoices

View file

@ -20,13 +20,13 @@
%tfoot
%tr
%th{colspan: 3}
%th= t(:total_without_vat)
%td= currency(@invoice.sum_without_vat)
%th= Invoice.human_attribute_name :subtotal
%td= number_to_currency @invoice.subtotal
%tr
%th.no-border{colspan: 3}
%th= t('vat', vat_prc: (@invoice.vat_prc * 100).round)
%td= currency(@invoice.vat)
%th= "VAT #{number_to_percentage(@invoice.vat_rate, precision: 1)}"
%td= number_to_currency @invoice.vat_amount
%tr
%th.no-border{colspan: 3}
%th= t(:total)
%td= currency(@invoice.sum)
%td= number_to_currency @invoice.total

View file

@ -238,16 +238,16 @@
%tfoot
%tr
%th{colspan: 3}
%th= t(:total_without_vat)
%td= "#{currency(@invoice.sum_without_vat)} #{@invoice.currency}"
%th= Invoice.human_attribute_name :subtotal
%td= number_to_currency @invoice.subtotal
%tr
%th.no-border{colspan: 3}
%th= t('vat', vat_prc: (@invoice.vat_prc * 100).round)
%td= "#{currency(@invoice.vat)} #{@invoice.currency}"
%th= "VAT #{number_to_percentage(@invoice.vat_rate, precision: 1)}"
%td= number_to_currency @invoice.vat_amount
%tr
%th.no-border{colspan: 3}
%th= t(:total)
%td= "#{currency(@invoice.sum)} #{@invoice.currency}"
%td= number_to_currency @invoice.total
#footer
%hr

View file

@ -15,7 +15,13 @@ require 'rails/all'
# you've limited to :test, :development, or :production.
Bundler.require(*Rails.groups)
module Registry
# Add "db" to the list hosts on which you can run `rake db:setup:all`
# Only allow that in test and development.
if ['development', 'test'].include?(Rails.env)
ActiveRecord::Tasks::DatabaseTasks::LOCAL_HOSTS << "db"
end
module DomainNameRegistry
class Application < Rails::Application
# Settings in config/environments/* take precedence over those specified here.
# Application configuration should go into files in config/initializers

View file

@ -4,12 +4,12 @@
# Registrant example is at database-example-registrant.yml file
default: &default
host: localhost
adapter: postgresql
encoding: unicode
pool: 5
username: registry
password: registry_pwd
pool: <%= ENV.fetch("APP_DB_MAX_THREADS") { 5 } %>
host: <%= ENV.fetch("APP_DBHOST") { "localhost" } %>
username: <%= ENV.fetch("APP_DBUSER") { "postgres" } %>
password:
#
# Staging config For EPP, REPP, Admin, Registrar

View file

@ -43,6 +43,7 @@ Rails.application.configure do
config.log_level = :debug
config.active_job.queue_adapter = :test
config.logger = ActiveSupport::Logger.new(nil)
config.active_support.test_order = :random # :random is the default in Rails 5
end
# In this mode, any jobs you queue will be run in the same thread, synchronously

View file

@ -1,8 +0,0 @@
# Log all user issues raised by active record
# rubocop: disable Metrics/LineLength
class ActiveRecord::Base
after_validation do |m|
Rails.logger.info "USER MSG: ACTIVERECORD: #{m.class} ##{m.id} #{m.errors.full_messages} #{m.errors['epp_errors']}" if m.errors.present?
true
end
end

View file

@ -0,0 +1,5 @@
en:
admin:
mail_templates:
html_body: HTML body
new_mail_template: New mail template

View file

@ -19,6 +19,12 @@ en:
billing:
header: Billing
edit:
header: Edit registrar
billing:
header: Billing
create:
created: Registrar has been successfully created

View file

@ -538,7 +538,6 @@ en:
invoice_number: Invoice no.
seller: 'Seller'
prepayment: 'Prepayment'
vat: 'VAT (%{vat_prc}%)'
unpaid: 'Unpaid'
your_current_account_balance_is: 'Your current account balance is %{balance} %{currency}'
billing: 'Billing'
@ -556,7 +555,6 @@ en:
unit: 'Unit'
price: 'Price'
total: 'Total'
total_without_vat: 'Total without VAT'
paid_at: 'Paid at'
invoice: 'Invoice'
bank_statements: 'Bank statements'
@ -731,7 +729,6 @@ en:
is_registrant: 'Is registrant'
force_delete_set_on_domain: 'Force delete set on domain %{domain_name}'
mail_templates: Mail Templates
new_mail_template: New mail template
failure: "It was not saved"
contact_is_not_valid: 'Contact %{value} is not valid, please fix the invalid contact'
welcome_to_eis_registrar_portal: 'Welcome to EIS Registrar portal'
@ -763,5 +760,6 @@ en:
attributes:
vat_no: VAT number
vat_rate: VAT rate
ipv4: IPv4
ipv6: IPv6

View file

@ -46,10 +46,6 @@ if @cron_group == 'registry'
runner 'DomainCron.start_expire_period'
end
every 50.minutes do
runner 'DomainCron.start_delete_period'
end
every 52.minutes do
runner 'DomainCron.start_redemption_grace_period'
end

View file

@ -0,0 +1,5 @@
class AddRegistrarsVatRate < ActiveRecord::Migration
def change
add_column :registrars, :vat_rate, :decimal, precision: 4, scale: 3
end
end

View file

@ -0,0 +1,5 @@
class RenameInvoicesVatPrcToVatRate < ActiveRecord::Migration
def change
rename_column :invoices, :vat_prc, :vat_rate
end
end

View file

@ -0,0 +1,5 @@
class ChangeInvoicesVatRateType < ActiveRecord::Migration
def change
change_column :invoices, :vat_rate, :decimal, precision: 4, scale: 3
end
end

View file

@ -0,0 +1,5 @@
class ChangeInvoiceVatRateToNull < ActiveRecord::Migration
def change
change_column_null :invoices, :vat_rate, true
end
end

View file

@ -0,0 +1,5 @@
class RemoveRegistrarsVat < ActiveRecord::Migration
def change
remove_column :registrars, :vat, :boolean
end
end

View file

@ -0,0 +1,5 @@
class RemoveInvoicesInvoiceType < ActiveRecord::Migration
def change
remove_column :invoices, :invoice_type, :string
end
end

View file

@ -0,0 +1,5 @@
class RenameInvoicesSumCacheToTotal < ActiveRecord::Migration
def change
rename_column :invoices, :sum_cache, :total
end
end

View file

@ -0,0 +1,5 @@
class ChangeInvoicesTotalToNotNull < ActiveRecord::Migration
def change
change_column_null :invoices, :total, false
end
end

View file

@ -0,0 +1,5 @@
class AddInvoicesBuyerVatNo < ActiveRecord::Migration
def change
add_column :invoices, :buyer_vat_no, :string
end
end

View file

@ -997,13 +997,12 @@ CREATE TABLE invoices (
id integer NOT NULL,
created_at timestamp without time zone NOT NULL,
updated_at timestamp without time zone NOT NULL,
invoice_type character varying NOT NULL,
due_date timestamp without time zone NOT NULL,
payment_term character varying,
currency character varying NOT NULL,
description character varying,
reference_no character varying,
vat_prc numeric(10,2) NOT NULL,
vat_rate numeric(4,3),
paid_at timestamp without time zone,
seller_id integer,
seller_name character varying NOT NULL,
@ -1036,8 +1035,9 @@ CREATE TABLE invoices (
updator_str character varying,
number integer,
cancelled_at timestamp without time zone,
sum_cache numeric(10,2),
in_directo boolean DEFAULT false
total numeric(10,2) NOT NULL,
in_directo boolean DEFAULT false,
buyer_vat_no character varying
);
@ -2153,11 +2153,11 @@ CREATE TABLE registrars (
code character varying NOT NULL,
website character varying,
accounting_customer_code character varying NOT NULL,
vat boolean,
legacy_id integer,
reference_no character varying,
test_registrar boolean DEFAULT false,
language character varying NOT NULL
language character varying NOT NULL,
vat_rate numeric(4,3)
);
@ -4668,6 +4668,16 @@ INSERT INTO schema_migrations (version) VALUES ('20180214213743');
INSERT INTO schema_migrations (version) VALUES ('20180218004148');
INSERT INTO schema_migrations (version) VALUES ('20180228055259');
INSERT INTO schema_migrations (version) VALUES ('20180228064342');
INSERT INTO schema_migrations (version) VALUES ('20180228070102');
INSERT INTO schema_migrations (version) VALUES ('20180228070431');
INSERT INTO schema_migrations (version) VALUES ('20180228074442');
INSERT INTO schema_migrations (version) VALUES ('20180306180401');
INSERT INTO schema_migrations (version) VALUES ('20180306181538');
@ -4694,5 +4704,13 @@ INSERT INTO schema_migrations (version) VALUES ('20180309053921');
INSERT INTO schema_migrations (version) VALUES ('20180309054510');
INSERT INTO schema_migrations (version) VALUES ('20180310142630');
INSERT INTO schema_migrations (version) VALUES ('20180313090437');
INSERT INTO schema_migrations (version) VALUES ('20180313124751');
INSERT INTO schema_migrations (version) VALUES ('20180314122722');
INSERT INTO schema_migrations (version) VALUES ('20180327151906');

View file

@ -1488,7 +1488,6 @@
<text text-anchor="start" x="1600.5" y="-2399.3" font-family="Times,serif" font-size="14.00">zip :string</text>
<text text-anchor="start" x="1600.5" y="-2384.3" font-family="Times,serif" font-size="14.00">code :string</text>
<text text-anchor="start" x="1600.5" y="-2369.3" font-family="Times,serif" font-size="14.00">url :string</text>
<text text-anchor="start" x="1600.5" y="-2339.3" font-family="Times,serif" font-size="14.00">vat :boolean</text>
<text text-anchor="start" x="1600.5" y="-2324.3" font-family="Times,serif" font-size="14.00">legacy_id :integer</text>
<text text-anchor="start" x="1600.5" y="-2309.3" font-family="Times,serif" font-size="14.00">reference_no :string</text>
</g>
@ -1613,13 +1612,12 @@
<text text-anchor="start" x="121.5" y="-1571.3" font-family="Times,serif" font-size="14.00">id :integer</text>
<text text-anchor="start" x="121.5" y="-1556.3" font-family="Times,serif" font-size="14.00">created_at :datetime</text>
<text text-anchor="start" x="121.5" y="-1541.3" font-family="Times,serif" font-size="14.00">updated_at :datetime</text>
<text text-anchor="start" x="121.5" y="-1526.3" font-family="Times,serif" font-size="14.00">invoice_type :string</text>
<text text-anchor="start" x="121.5" y="-1511.3" font-family="Times,serif" font-size="14.00">due_date :datetime</text>
<text text-anchor="start" x="121.5" y="-1496.3" font-family="Times,serif" font-size="14.00">payment_term :string</text>
<text text-anchor="start" x="121.5" y="-1481.3" font-family="Times,serif" font-size="14.00">currency :string</text>
<text text-anchor="start" x="121.5" y="-1466.3" font-family="Times,serif" font-size="14.00">description :string</text>
<text text-anchor="start" x="121.5" y="-1451.3" font-family="Times,serif" font-size="14.00">reference_no :string</text>
<text text-anchor="start" x="121.5" y="-1436.3" font-family="Times,serif" font-size="14.00">vat_prc :decimal</text>
<text text-anchor="start" x="121.5" y="-1436.3" font-family="Times,serif" font-size="14.00">vat_rate :decimal</text>
<text text-anchor="start" x="121.5" y="-1421.3" font-family="Times,serif" font-size="14.00">paid_at :datetime</text>
<text text-anchor="start" x="121.5" y="-1406.3" font-family="Times,serif" font-size="14.00">seller_id :integer</text>
<text text-anchor="start" x="121.5" y="-1391.3" font-family="Times,serif" font-size="14.00">seller_name :string</text>
@ -1652,7 +1650,7 @@
<text text-anchor="start" x="121.5" y="-986.3" font-family="Times,serif" font-size="14.00">updator_str :string</text>
<text text-anchor="start" x="121.5" y="-971.3" font-family="Times,serif" font-size="14.00">number :integer</text>
<text text-anchor="start" x="121.5" y="-956.3" font-family="Times,serif" font-size="14.00">cancelled_at :datetime</text>
<text text-anchor="start" x="121.5" y="-941.3" font-family="Times,serif" font-size="14.00">sum_cache :decimal</text>
<text text-anchor="start" x="121.5" y="-941.3" font-family="Times,serif" font-size="14.00">total :decimal</text>
</g>
<!-- Registrar&#45;&gt;Invoice -->
<g id="edge64" class="edge"><title>Registrar&#45;&gt;Invoice</title>

Before

Width:  |  Height:  |  Size: 220 KiB

After

Width:  |  Height:  |  Size: 220 KiB

Before After
Before After

33
docker-compose.yml Normal file
View file

@ -0,0 +1,33 @@
version: "3.2"
services:
app:
tty: true
stdin_open: true
build:
context: .
dockerfile: Dockerfile
links:
- db
environment:
- APP_DBHOST=db
volumes:
- .:/opt/webapps/app
ports:
- "3000:3000"
command: bash -c "rm -f tmp/pids/server.pid && bundle exec rails server -p 3000 -b '0.0.0.0'"
web:
image: nginx
volumes:
- ./docker/nginx.template:/etc/nginx/conf.d/nginx.template
ports:
- "80:80"
links:
- app
environment:
APP: 'app'
command: /bin/bash -c "envsubst '$$APP' < /etc/nginx/conf.d/nginx.template > /etc/nginx/conf.d/default.conf && nginx -g 'daemon off;'"
db:
image: postgres:9.4

6
docker/docker_dev.sh Executable file
View file

@ -0,0 +1,6 @@
# /bin/sh
docker-compose down
docker-compose build
docker-compose run app rake db:setup:all
docker-compose run app rake db:migrate
docker-compose run app rake dev:prime

8
docker/docker_test.sh Executable file
View file

@ -0,0 +1,8 @@
# /bin/sh
docker-compose down
docker-compose build
# Setup test database
docker-compose run app rake db:setup:all test
# Finally run tests to check if everything is in order
docker-compose run app rspec

29
docker/nginx.template Normal file
View file

@ -0,0 +1,29 @@
log_format le_json '{ "time": "$time_iso8601", '
'"remote_addr": "$remote_addr", '
'"remote_user": "$remote_user", '
'"body_bytes_sent": "$body_bytes_sent", '
'"request_time": "$request_time", '
'"status": "$status", '
'"request": "$request", '
'"request_method": "$request_method", '
'"http_referrer": "$http_referer", '
'"http_user_agent": "$http_user_agent" }';
upstream app {
server ${APP}:3000;
}
server {
listen 80;
access_log /var/log/nginx/access.log le_json;
location / {
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header Host $http_host;
proxy_redirect off;
proxy_pass http://app;
break;
}
}

View file

@ -87,7 +87,6 @@ namespace :import do
zip: x.postalcode.try(:strip),
url: x.url.try(:strip),
accounting_customer_code: x.directo_handle.try(:strip),
vat: x.vat,
legacy_id: x.id,
creator_str: user,
updator_str: user,

View file

@ -3,12 +3,11 @@ FactoryBot.define do
buyer_name 'Registrar 1'
currency { 'EUR' }
due_date { Time.zone.now.to_date + 1.day }
invoice_type 'DEB'
seller_iban { '123' }
seller_name { 'EIS' }
seller_city { 'Tallinn' }
seller_street { 'Paldiski mnt. 123' }
vat_prc 0.2
vat_rate 0.2
buyer { FactoryBot.create(:registrar) }
after :build do |invoice|

View file

@ -13,10 +13,8 @@ describe Invoice do
"Currency is missing",
"Due date is missing",
"Invoice items is missing",
"Invoice type is missing",
"Seller iban is missing",
"Seller name is missing",
"Vat prc is missing"
])
end
@ -52,20 +50,6 @@ describe Invoice do
@invoice.seller_address.should == 'Paldiski mnt. 123, Tallinn'
end
it 'should calculate sums correctly' do
@invoice = create(:invoice)
@invoice.vat_prc.should == BigDecimal.new('0.2')
@invoice.sum_without_vat.should == BigDecimal.new('300.0')
@invoice.vat.should == BigDecimal.new('60.0')
@invoice.sum.should == BigDecimal.new('360.0')
ii = @invoice.items.first
ii.item_sum_without_vat.should == BigDecimal.new('150.0')
ii = @invoice.items.last
ii.item_sum_without_vat.should == BigDecimal.new('150.0')
end
it 'should cancel overdue invoices' do
create(:invoice, created_at: Time.zone.now - 35.days, due_date: Time.zone.now - 30.days)
Invoice.cancel_overdue_invoices

View file

@ -1,7 +1,31 @@
cash:
duration: 1 year
price_cents: 500
create_one_month:
duration: 1 month
price_cents: 100
operation_category: create
valid_from: 2010-07-05
valid_to: 2010-07-05
zone: test
renew_one_month:
duration: 1 month
price_cents: 100
operation_category: renew
valid_from: 2010-07-05
valid_to: 2010-07-05
zone: test
create_one_year:
duration: 1 year
price_cents: 1000
operation_category: create
valid_from: 2010-07-05
valid_to: 2010-07-05
zone: test
renew_one_year:
duration: 1 year
price_cents: 1000
operation_category: renew
valid_from: 2010-07-05
valid_to: 2010-07-05
zone: test

View file

@ -40,7 +40,7 @@ metro:
invalid:
name: invalid.test
transfer_code: any
valid_to: 2010-07-05
transfer_code: 1438d6
valid_to: <%= Time.zone.parse('2010-07-05').utc.to_s(:db) %>
registrar: bestnames
registrant: invalid

View file

@ -1,13 +1,13 @@
DEFAULTS: &DEFAULTS
one:
description: Acme services
price: 5
amount: 1
unit: pc
invoice: valid
two:
description: Acme services
price: 5
amount: 2
unit: pc
price: 5
valid:
<<: *DEFAULTS
invoice: valid
another:
<<: *DEFAULTS
invoice: valid

View file

@ -1,12 +1,13 @@
DEFAULTS: &DEFAULTS
created_at: <%= Date.parse '2010-07-05' %>
due_date: <%= Date.parse '2010-07-06' %>
invoice_type: DEB
currency: EUR
seller_name: John Doe
seller_iban: 1234
buyer: bestnames
buyer_name: Jane Doe
vat_prc: 0.2
vat_rate: 0.1
total: 16.50
valid:
<<: *DEFAULTS
@ -21,7 +22,7 @@ cancelled:
paid:
<<: *DEFAULTS
sum_cache: 1
total: 1
outstanding:
<<: *DEFAULTS

View file

@ -17,7 +17,8 @@ goodnames:
reg_no: 12345
code: goodnames
email: info@goodnames.test
country_code: US
country_code: DE
vat_no: DE123456789
accounting_customer_code: goodnames
language: en
@ -29,3 +30,23 @@ not_in_use:
country_code: US
accounting_customer_code: any
language: en
complete:
name: Complete Names
reg_no: 123456
code: completenames
email: completenames@example.com
country_code: US
accounting_customer_code: US0001
language: en
vat_no: US12345
vat_rate: 0.05
not_in_use:
name: any
reg_no: any
code: any
email: any@example.com
country_code: US
accounting_customer_code: any
language: en

View file

@ -3,7 +3,7 @@ require 'test_helper'
class AdminAreaDomainForceDeleteTest < ActionDispatch::IntegrationTest
include ActionMailer::TestHelper
def setup
setup do
login_as users(:admin)
@domain = domains(:shop)
ActionMailer::Base.deliveries.clear

View file

@ -1,7 +1,7 @@
require 'test_helper'
class AdminDomainsTestTest < ActionDispatch::IntegrationTest
def setup
setup do
login_as users(:admin)
end

View file

@ -0,0 +1,14 @@
require 'test_helper'
class AdminAreaNewMailTemplateTest < ActionDispatch::IntegrationTest
setup do
login_as users(:admin)
end
def test_new_mail_template_does_not_throw_template_error
visit admin_mail_templates_url
click_link_or_button 'New'
assert_text "HTML body"
assert_text "New mail template"
end
end

View file

@ -1,7 +1,7 @@
require 'test_helper'
class AdminAreaDeleteRegistrarTest < ActionDispatch::IntegrationTest
def setup
setup do
login_as users(:admin)
end

View file

@ -0,0 +1,18 @@
require 'test_helper'
class AdminAreaRegistrarDetailsTest < ActionDispatch::IntegrationTest
include ActionView::Helpers::NumberHelper
setup do
login_as users(:admin)
@registrar = registrars(:complete)
end
def test_registrar_details
visit admin_registrar_path(@registrar)
assert_text 'Accounting customer code US0001'
assert_text 'VAT number US12345'
assert_text 'VAT rate 5.0%'
assert_text 'Language English'
end
end

View file

@ -1,7 +1,7 @@
require 'test_helper'
class AdminAreaEditRegistrarTest < ActionDispatch::IntegrationTest
def setup
setup do
login_as users(:admin)
@registrar = registrars(:bestnames)
end

View file

@ -1,7 +1,7 @@
require 'test_helper'
class AdminAreaNewRegistrarTest < ActionDispatch::IntegrationTest
def setup
setup do
login_as users(:admin)
end
@ -12,6 +12,7 @@ class AdminAreaNewRegistrarTest < ActionDispatch::IntegrationTest
fill_in 'Name', with: 'Brand new names'
fill_in 'Reg no', with: '55555555'
fill_in 'Contact e-mail', with: 'test@example.com'
select 'United States', from: 'Country'
fill_in 'Accounting customer code', with: 'test'
fill_in 'Code', with: 'test'

View file

@ -1,19 +0,0 @@
require 'test_helper'
class ShowRegistrarTest < ActionDispatch::IntegrationTest
include ActionView::Helpers::NumberHelper
def setup
login_as users(:admin)
@registrar = registrars(:bestnames)
visit admin_registrar_path(@registrar)
end
def test_accounting_customer_code
assert_text 'bestnames'
end
def test_language
assert_text 'Language English'
end
end

View file

@ -1,7 +1,7 @@
require 'test_helper'
class APIDomainTransfersTest < ActionDispatch::IntegrationTest
def setup
setup do
@domain = domains(:shop)
@new_registrar = registrars(:goodnames)
Setting.transfer_wait_time = 0 # Auto-approval

View file

@ -1,7 +1,7 @@
require 'test_helper'
class EppDomainCreateTransferCodeTest < ActionDispatch::IntegrationTest
def setup
setup do
travel_to Time.zone.parse('2010-07-05')
end

View file

@ -0,0 +1,32 @@
require 'test_helper'
class EppDomainRenewTest < ActionDispatch::IntegrationTest
self.use_transactional_fixtures = false
setup do
travel_to Time.zone.parse('2010-07-05')
end
def test_domain_cannot_be_renewed_when_invalid
request_xml = <<-XML
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<epp xmlns="https://epp.tld.ee/schema/epp-ee-1.0.xsd">
<command>
<renew>
<domain:renew xmlns:domain="https://epp.tld.ee/schema/domain-eis-1.0.xsd">
<domain:name>invalid.test</domain:name>
<domain:curExpDate>2010-07-05</domain:curExpDate>
<domain:period unit="m">1</domain:period>
</domain:renew>
</renew>
</command>
</epp>
XML
assert_no_changes -> { domains(:invalid).valid_to } do
post '/epp/command/renew', { frame: request_xml }, 'HTTP_COOKIE' => 'session=api_bestnames'
end
assert_equal '2304', Nokogiri::XML(response.body).at_css('result')[:code],
Nokogiri::XML(response.body).css('result').text
end
end

View file

@ -1,7 +1,7 @@
require 'test_helper'
class EppDomainTransferRequestTest < ActionDispatch::IntegrationTest
def setup
setup do
@domain = domains(:shop)
@new_registrar = registrars(:goodnames)
Setting.transfer_wait_time = 0

View file

@ -1,7 +1,7 @@
require 'test_helper'
class EppLoginSessionLimitTest < ActionDispatch::IntegrationTest
def setup
setup do
travel_to Time.zone.parse('2010-07-05')
EppSession.delete_all
end

View file

@ -1,7 +1,7 @@
require 'test_helper'
class RegistrantDomainsTest < ActionDispatch::IntegrationTest
def setup
setup do
login_as users(:registrant)
Setting.days_to_keep_business_registry_cache = 1

View file

@ -0,0 +1,25 @@
require 'test_helper'
class BalanceTopUpTest < ActionDispatch::IntegrationTest
setup do
login_as users(:api_bestnames)
end
def test_creates_new_invoice
Setting.registry_vat_prc = 0.1
visit registrar_invoices_url
click_link_or_button 'Add deposit'
fill_in 'Amount', with: '25.5'
assert_difference 'Invoice.count' do
click_link_or_button 'Add'
end
invoice = Invoice.last
assert_equal BigDecimal(10), invoice.vat_rate
assert_equal BigDecimal('28.05'), invoice.total
assert_text 'Please pay the following invoice'
end
end

View file

@ -1,7 +1,7 @@
require 'test_helper'
class RegistrarDomainTransfersTest < ActionDispatch::IntegrationTest
def setup
setup do
WebMock.reset!
login_as users(:api_goodnames)
end

View file

@ -9,7 +9,7 @@ class RegistrarDomainsTest < ActionDispatch::IntegrationTest
Domain,Transfer code,Registrant name,Registrant code,Date of expiry
library.test,45118f5,Acme Ltd,acme-ltd-001,2010-07-05
shop.test,65078d5,John,john-001,2010-07-05
invalid.test,any,any,any,2010-07-05
invalid.test,1438d6,any,any,2010-07-05
airport.test,55438j5,John,john-001,2010-07-05
CSV

View file

@ -1,7 +1,7 @@
require 'test_helper'
class RegistrarNameserverReplacementTest < ActionDispatch::IntegrationTest
def setup
setup do
WebMock.reset!
login_as users(:api_goodnames)
end

View file

@ -1,7 +1,7 @@
require 'test_helper'
class ContactTest < ActiveSupport::TestCase
def setup
setup do
@contact = contacts(:john)
end

View file

@ -12,11 +12,16 @@ class ContactIdenticalTest < ActiveSupport::TestCase
org_name
]
def setup
setup do
@original_address_processing = Setting.address_processing
@contact = contacts(:william)
@identical = contacts(:identical_to_william)
end
teardown do
Setting.address_processing = @original_address_processing
end
def test_returns_identical
assert_equal @identical, @contact.identical(@identical.registrar)
end
@ -33,30 +38,24 @@ class ContactIdenticalTest < ActiveSupport::TestCase
assert_nil @contact.identical(@identical.registrar)
end
def test_takes_address_into_account_when_processing_enabled
def test_takes_address_into_account_when_address_processing_is_on
Setting.address_processing = true
Contact.address_attribute_names.each do |attribute|
previous_value = @identical.public_send(attribute)
@identical.update_attribute(attribute, 'other')
Contact.stub :address_processing?, true do
assert_nil @contact.identical(@identical.registrar)
end
@identical.update_attribute(attribute, previous_value)
end
end
def test_ignores_address_when_processing_disabled
def test_ignores_address_when_address_processing_is_off
Setting.address_processing = false
Contact.address_attribute_names.each do |attribute|
previous_value = @identical.public_send(attribute)
@identical.update_attribute(attribute, 'other')
Contact.stub :address_processing?, false do
assert_equal @identical, @contact.identical(@identical.registrar)
end
@identical.update_attribute(attribute, previous_value)
end
end

View file

@ -1,10 +1,15 @@
require 'test_helper'
class ContactPostalAddressTest < ActiveSupport::TestCase
def setup
setup do
@original_address_processing = Setting.address_processing
@contact = contacts(:john)
end
teardown do
Setting.address_processing = @original_address_processing
end
def test_invalid_if_country_code_is_invalid_and_address_processing_is_on
Setting.address_processing = true
@contact.country_code = 'invalid'

View file

@ -1,7 +1,7 @@
require 'test_helper'
class ContactTransferTest < ActiveSupport::TestCase
def setup
setup do
@contact = contacts(:john)
@new_registrar = registrars(:goodnames)
end

View file

@ -1,7 +1,7 @@
require 'test_helper'
class DomainTest < ActiveSupport::TestCase
def setup
setup do
@domain = domains(:shop)
end

View file

@ -1,7 +1,7 @@
require 'test_helper'
class DomainTransferableTest < ActiveSupport::TestCase
def setup
setup do
@domain = domains(:shop)
@new_registrar = registrars(:goodnames)
end

View file

@ -1,7 +1,7 @@
require 'test_helper'
class DomainTransferTest < ActiveSupport::TestCase
def setup
setup do
@domain_transfer = domain_transfers(:shop)
end

View file

@ -1,7 +1,7 @@
require 'test_helper'
class EppSessionTest < ActiveSupport::TestCase
def setup
setup do
@epp_session = epp_sessions(:api_bestnames)
end

109
test/models/invoice_test.rb Normal file
View file

@ -0,0 +1,109 @@
require 'test_helper'
class InvoiceTest < ActiveSupport::TestCase
setup do
@invoice = invoices(:valid)
end
def test_valid
assert @invoice.valid?
end
def test_optional_vat_rate
@invoice.vat_rate = nil
assert @invoice.valid?
end
def test_vat_rate_validation
@invoice.vat_rate = -1
assert @invoice.invalid?
@invoice.vat_rate = 0
assert @invoice.valid?
@invoice.vat_rate = 99.9
assert @invoice.valid?
@invoice.vat_rate = 100
assert @invoice.invalid?
end
def test_serializes_and_deserializes_vat_rate
invoice = @invoice.dup
invoice.invoice_items = @invoice.invoice_items
invoice.vat_rate = BigDecimal('25.5')
invoice.save!
invoice.reload
assert_equal BigDecimal('25.5'), invoice.vat_rate
end
def test_vat_rate_defaults_to_effective_vat_rate_of_a_registrar
registrar = registrars(:bestnames)
invoice = @invoice.dup
invoice.vat_rate = nil
invoice.buyer = registrar
invoice.invoice_items = @invoice.invoice_items
registrar.stub(:effective_vat_rate, BigDecimal(55)) do
invoice.save!
end
assert_equal BigDecimal(55), invoice.vat_rate
end
def test_vat_rate_cannot_be_updated
@invoice.vat_rate = BigDecimal(21)
@invoice.save!
@invoice.reload
refute_equal BigDecimal(21), @invoice.vat_rate
end
def test_calculates_vat_amount
assert_equal BigDecimal('1.5'), @invoice.vat_amount
end
def test_vat_amount_is_zero_when_vat_rate_is_blank
@invoice.vat_rate = nil
assert_equal 0, @invoice.vat_amount
end
def test_calculates_subtotal
line_item = InvoiceItem.new
invoice = Invoice.new(invoice_items: [line_item, line_item])
line_item.stub(:item_sum_without_vat, BigDecimal('2.5')) do
assert_equal BigDecimal(5), invoice.subtotal
end
end
def test_returns_persisted_total
assert_equal BigDecimal('16.50'), @invoice.total
end
def test_calculates_total
line_item = InvoiceItem.new
invoice = Invoice.new
invoice.vat_rate = 10
invoice.invoice_items = [line_item, line_item]
line_item.stub(:item_sum_without_vat, BigDecimal('2.5')) do
assert_equal BigDecimal('5.50'), invoice.total
end
end
def test_valid_without_buyer_vat_no
@invoice.buyer_vat_no = ''
assert @invoice.valid?
end
def test_buyer_vat_no_is_taken_from_registrar_by_default
registrar = registrars(:bestnames)
registrar.vat_no = 'US1234'
invoice = @invoice.dup
invoice.buyer_vat_no = nil
invoice.buyer = registrar
invoice.invoice_items = @invoice.invoice_items
invoice.save!
assert_equal 'US1234', invoice.buyer_vat_no
end
end

View file

@ -1,7 +1,7 @@
require 'test_helper'
class MessageTest < ActiveSupport::TestCase
def setup
setup do
@message = messages(:greeting)
end

View file

@ -1,7 +1,7 @@
require 'test_helper'
class NameserverGlueRecordTest < ActiveSupport::TestCase
def setup
setup do
@nameserver = nameservers(:shop_ns1)
end

View file

@ -1,7 +1,7 @@
require 'test_helper'
class NameserverTest < ActiveSupport::TestCase
def setup
setup do
@nameserver = nameservers(:shop_ns1)
end

View file

@ -1,7 +1,7 @@
require 'test_helper'
class RegistrarCodeTest < ActiveSupport::TestCase
def setup
setup do
@registrar = registrars(:bestnames).dup
end

View file

@ -1,7 +1,7 @@
require 'test_helper'
class DeleteRegistrarTest < ActiveSupport::TestCase
def setup
setup do
@registrar = registrars(:not_in_use)
end

View file

@ -0,0 +1,97 @@
require 'test_helper'
class RegistrarVATTest < ActiveSupport::TestCase
setup do
@registrar = registrars(:bestnames)
end
def test_optional_vat_no
@registrar.vat_no = ''
assert @registrar.valid?
@registrar.vat_no = 'any'
assert @registrar.valid?
end
def test_apply_vat_rate_from_registry_when_registrar_is_local_vat_payer
Setting.registry_country_code = 'US'
@registrar.country_code = 'US'
Registry.instance.stub(:vat_rate, BigDecimal('5.5')) do
assert_equal BigDecimal('5.5'), @registrar.effective_vat_rate
end
end
def test_require_no_vat_rate_when_registrar_is_local_vat_payer
@registrar.vat_rate = 1
assert @registrar.invalid?
@registrar.vat_rate = nil
assert @registrar.valid?
end
def test_apply_vat_rate_from_registrar_when_registrar_is_foreign_vat_payer
Setting.registry_country_code = 'US'
@registrar.country_code = 'DE'
@registrar.vat_rate = BigDecimal('5.6')
assert_equal BigDecimal('5.6'), @registrar.effective_vat_rate
end
def test_require_vat_rate_when_registrar_is_foreign_vat_payer_and_vat_no_is_absent
@registrar.country_code = 'DE'
@registrar.vat_no = ''
@registrar.vat_rate = ''
assert @registrar.invalid?
assert @registrar.errors.added?(:vat_rate, :blank)
@registrar.vat_rate = 5
assert @registrar.valid?
end
def test_require_no_vat_rate_when_registrar_is_foreign_vat_payer_and_vat_no_is_present
@registrar.country_code = 'DE'
@registrar.vat_no = 'valid'
@registrar.vat_rate = 1
assert @registrar.invalid?
@registrar.vat_rate = nil
assert @registrar.valid?
end
def test_vat_rate_validation
@registrar.country_code = 'DE'
@registrar.vat_no = ''
@registrar.vat_rate = -1
assert @registrar.invalid?
@registrar.vat_rate = 0
assert @registrar.valid?
@registrar.vat_rate = 99.9
assert @registrar.valid?
@registrar.vat_rate = 100
assert @registrar.invalid?
end
def test_serializes_and_deserializes_vat_rate
@registrar.country_code = 'DE'
@registrar.vat_rate = BigDecimal('25.5')
@registrar.save!
@registrar.reload
assert_equal BigDecimal('25.5'), @registrar.vat_rate
end
def test_parses_vat_rate_as_a_string
@registrar.vat_rate = '25.5'
assert_equal BigDecimal('25.5'), @registrar.vat_rate
end
def test_treats_empty_vat_rate_as_nil
@registrar.vat_rate = ''
assert_nil @registrar.vat_rate
end
end

View file

@ -1,7 +1,7 @@
require 'test_helper'
class RegistrarTest < ActiveSupport::TestCase
def setup
setup do
@registrar = registrars(:bestnames)
end
@ -29,7 +29,7 @@ class RegistrarTest < ActiveSupport::TestCase
assert @registrar.invalid?
end
def test_requires_country_code
def test_invalid_without_country_code
@registrar.country_code = ''
assert @registrar.invalid?
end

View file

@ -0,0 +1,16 @@
require 'test_helper'
class RegistryTest < ActiveSupport::TestCase
setup do
@registry = Registry.send(:new)
end
def test_implements_singleton
assert_equal Registry.instance.object_id, Registry.instance.object_id
end
def test_vat_rate
Setting.registry_vat_prc = 0.25
assert_equal BigDecimal(25), @registry.vat_rate
end
end

View file

@ -0,0 +1,94 @@
module ActiveSupport
module Testing
module Assertions
UNTRACKED = Object.new # :nodoc:
# Assertion that the result of evaluating an expression is changed before
# and after invoking the passed in block.
#
# assert_changes 'Status.all_good?' do
# post :create, params: { status: { ok: false } }
# end
#
# You can pass the block as a string to be evaluated in the context of
# the block. A lambda can be passed for the block as well.
#
# assert_changes -> { Status.all_good? } do
# post :create, params: { status: { ok: false } }
# end
#
# The assertion is useful to test side effects. The passed block can be
# anything that can be converted to string with #to_s.
#
# assert_changes :@object do
# @object = 42
# end
#
# The keyword arguments :from and :to can be given to specify the
# expected initial value and the expected value after the block was
# executed.
#
# assert_changes :@object, from: nil, to: :foo do
# @object = :foo
# end
#
# An error message can be specified.
#
# assert_changes -> { Status.all_good? }, 'Expected the status to be bad' do
# post :create, params: { status: { incident: true } }
# end
def assert_changes(expression, message = nil, from: UNTRACKED, to: UNTRACKED, &block)
exp = expression.respond_to?(:call) ? expression : -> { eval(expression.to_s, block.binding) }
before = exp.call
retval = yield
unless from == UNTRACKED
error = "#{expression.inspect} isn't #{from.inspect}"
error = "#{message}.\n#{error}" if message
assert from === before, error
end
after = exp.call
if to == UNTRACKED
error = "#{expression.inspect} didn't changed"
error = "#{message}.\n#{error}" if message
assert_not_equal before, after, error
else
error = "#{expression.inspect} didn't change to #{to}"
error = "#{message}.\n#{error}" if message
assert to === after, error
end
retval
end
# Assertion that the result of evaluating an expression is changed before
# and after invoking the passed in block.
#
# assert_no_changes 'Status.all_good?' do
# post :create, params: { status: { ok: true } }
# end
#
# An error message can be specified.
#
# assert_no_changes -> { Status.all_good? }, 'Expected the status to be good' do
# post :create, params: { status: { ok: false } }
# end
def assert_no_changes(expression, message = nil, &block)
exp = expression.respond_to?(:call) ? expression : -> { eval(expression.to_s, block.binding) }
before = exp.call
retval = yield
after = exp.call
error = "#{expression.inspect} did change to #{after}"
error = "#{message}.\n#{error}" if message
assert_equal before, after, error
retval
end
end
end
end

View file

@ -11,14 +11,20 @@ require 'minitest/mock'
require 'capybara/rails'
require 'capybara/minitest'
require 'webmock/minitest'
require 'support/rails5_assetions' # Remove once upgraded to Rails 5
Setting.address_processing = false
Setting.registry_country_code = 'US'
class ActiveSupport::TestCase
include FactoryBot::Syntax::Methods
ActiveRecord::Migration.check_pending!
fixtures :all
teardown do
travel_back
end
end
class ActionDispatch::IntegrationTest
@ -27,8 +33,9 @@ class ActionDispatch::IntegrationTest
include Capybara::Minitest::Assertions
include AbstractController::Translation
def teardown
teardown do
Warden.test_reset!
WebMock.reset!
Capybara.reset_sessions!
Capybara.use_default_driver
end