Merge remote-tracking branch 'origin/master' into refactor-contact-archivation

This commit is contained in:
Karl Erik Õunapuu 2020-09-16 10:24:55 +03:00
commit ab1fa9064e
No known key found for this signature in database
GPG key ID: C9DD647298A34764
47 changed files with 453 additions and 290 deletions

View file

@ -1,3 +1,26 @@
15.09.2020
* Fixed e-invoice sending issue with QUE [#1683](https://github.com/internetee/registry/pull/1683)
14.09.2020
* Restored version logging for registry prices [#980](https://github.com/internetee/registry/pull/980)
11.09.2020
* Registrars can now top up their credit accounts without generating invoice in advance [#1101](https://github.com/internetee/registry/issues/1101)
* Fixed typo in admin settings [#371](https://github.com/internetee/registry/issues/371)
10.09.2020
* New registrar ref nr are now always created 7 digits long [#1679](https://github.com/internetee/registry/pull/1679)
08.09.2020
* Removed bank statement import option [#1674](https://github.com/internetee/registry/pull/1674)
* Fixed error with reference nr not being found in the transaction [#1677](https://github.com/internetee/registry/issues/1677)
04.09.2020
* Removed reduntant domains.registered_at db column [#1445](https://github.com/internetee/registry/pull/1445)
* Certificate revocation lists are now hanlded outside of the application code [#1662](https://github.com/internetee/registry/pull/1662)
* Monthly invoices are sent one by one to elliminate reply delay from accounting system [#1671](https://github.com/internetee/registry/pull/1671)
* Fixed poll request ip whitelist issue [#1672](https://github.com/internetee/registry/pull/1672)
03.09.2020 03.09.2020
* Refactored session timeout management [#711](https://github.com/internetee/registry/issues/711) * Refactored session timeout management [#711](https://github.com/internetee/registry/issues/711)
* Improved error handling for epp requests without proper session [#1276](https://github.com/internetee/registry/pull/1276) * Improved error handling for epp requests without proper session [#1276](https://github.com/internetee/registry/pull/1276)

View file

@ -9,7 +9,7 @@ GIT
GIT GIT
remote: https://github.com/internetee/directo.git remote: https://github.com/internetee/directo.git
revision: 8ff8a382d004ffb85722a6a7a68a020bd4d7159b revision: e4ba54f601d1815fd8782a196788730d47861e86
branch: master branch: master
specs: specs:
directo (1.0.1) directo (1.0.1)
@ -18,7 +18,7 @@ GIT
GIT GIT
remote: https://github.com/internetee/e_invoice.git remote: https://github.com/internetee/e_invoice.git
revision: b374ffd7be77b559b30c7a0210dc0df5ac3ed723 revision: 5f8d0029bf1affdbf2bd6e3d1ce87d34066add4d
branch: master branch: master
specs: specs:
e_invoice (0.1.0) e_invoice (0.1.0)
@ -165,7 +165,7 @@ GEM
coffee-script-source coffee-script-source
execjs execjs
coffee-script-source (1.12.2) coffee-script-source (1.12.2)
concurrent-ruby (1.1.6) concurrent-ruby (1.1.7)
countries (3.0.1) countries (3.0.1)
i18n_data (~> 0.10.0) i18n_data (~> 0.10.0)
sixarm_ruby_unaccent (~> 1.1) sixarm_ruby_unaccent (~> 1.1)
@ -238,10 +238,10 @@ GEM
http-cookie (1.0.3) http-cookie (1.0.3)
domain_name (~> 0.5) domain_name (~> 0.5)
httpclient (2.8.3) httpclient (2.8.3)
httpi (2.4.4) httpi (2.4.5)
rack rack
socksify socksify
i18n (1.8.3) i18n (1.8.5)
concurrent-ruby (~> 1.0) concurrent-ruby (~> 1.0)
i18n_data (0.10.0) i18n_data (0.10.0)
isikukood (0.1.2) isikukood (0.1.2)
@ -467,7 +467,8 @@ GEM
i18n i18n
warden (1.2.8) warden (1.2.8)
rack (>= 2.0.6) rack (>= 2.0.6)
wasabi (3.5.0) wasabi (3.6.1)
addressable
httpi (~> 2.0) httpi (~> 2.0)
nokogiri (>= 1.4.2) nokogiri (>= 1.4.2)
webdrivers (4.4.1) webdrivers (4.4.1)

View file

@ -2,7 +2,7 @@ module Admin
class BankStatementsController < BaseController class BankStatementsController < BaseController
load_and_authorize_resource load_and_authorize_resource
before_action :set_bank_statement, only: [:show, :download_import_file, :bind_invoices] before_action :set_bank_statement, only: %i[show bind_invoices]
def index def index
@q = BankStatement.search(params[:q]) @q = BankStatement.search(params[:q])
@ -43,22 +43,6 @@ module Admin
end end
end end
def import
@bank_statement = BankStatement.new
end
def create_from_import
@bank_statement = BankStatement.new(bank_statement_params)
if @bank_statement.import
flash[:notice] = I18n.t('record_created')
redirect_to [:admin, @bank_statement]
else
flash.now[:alert] = I18n.t('failed_to_create_record')
render 'new'
end
end
def bind_invoices def bind_invoices
@bank_statement.bind_invoices(manual: true) @bank_statement.bind_invoices(manual: true)
@ -69,11 +53,6 @@ module Admin
redirect_to [:admin, @bank_statement] redirect_to [:admin, @bank_statement]
end end
def download_import_file
filename = @bank_statement.import_file_path.split('/').last
send_data File.open(@bank_statement.import_file_path, 'r').read, filename: filename
end
private private
def set_bank_statement def set_bank_statement
@ -81,7 +60,7 @@ module Admin
end end
def bank_statement_params def bank_statement_params
params.require(:bank_statement).permit(:th6_file, :bank_code, :iban, bank_transactions_attributes: [ params.require(:bank_statement).permit(:bank_code, :iban, bank_transactions_attributes: [
:description, :sum, :currency, :reference_no, :paid_at :description, :sum, :currency, :reference_no, :paid_at
]) ])
end end

View file

@ -2,15 +2,16 @@ class DirectoInvoiceForwardJob < Que::Job
def run(monthly: false, dry: false) def run(monthly: false, dry: false)
@dry = dry @dry = dry
(@month = Time.zone.now - 1.month) if monthly (@month = Time.zone.now - 1.month) if monthly
api_url = ENV['directo_invoice_url']
sales_agent = Setting.directo_sales_agent
payment_term = Setting.directo_receipt_payment_term
@prepayment_product_id = Setting.directo_receipt_product_name
@client = DirectoApi::Client.new(api_url, sales_agent, payment_term) @client = new_directo_client
monthly ? send_monthly_invoices : send_receipts monthly ? send_monthly_invoices : send_receipts
end 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 def send_receipts
unsent_invoices = Invoice.where(in_directo: false).non_cancelled unsent_invoices = Invoice.where(in_directo: false).non_cancelled
@ -28,19 +29,18 @@ class DirectoInvoiceForwardJob < Que::Job
def send_monthly_invoices def send_monthly_invoices
Registrar.where.not(test_registrar: true).find_each do |registrar| Registrar.where.not(test_registrar: true).find_each do |registrar|
fetch_monthly_summary(registrar: registrar) next unless registrar.cash_account
@client = new_directo_client
send_invoice_for_registrar(registrar)
end end
return unless @client.invoices.count.positive?
sync_with_directo
end end
def fetch_monthly_summary(registrar:) def send_invoice_for_registrar(registrar)
return unless registrar.cash_account
summary = registrar.monthly_summary(month: @month) summary = registrar.monthly_summary(month: @month)
@client.invoices.add_with_schema(invoice: summary, schema: 'summary') unless summary.nil? @client.invoices.add_with_schema(invoice: summary, schema: 'summary') unless summary.nil?
sync_with_directo if @client.invoices.count.positive?
end end
def assign_monthly_numbers def assign_monthly_numbers

View file

@ -1,8 +1,8 @@
class SendEInvoiceJob < Que::Job class SendEInvoiceJob < Que::Job
def run(invoice_id) def run(invoice_id, payable = true)
invoice = run_condition(Invoice.find_by(id: invoice_id)) invoice = run_condition(Invoice.find_by(id: invoice_id), payable: payable)
invoice.to_e_invoice.deliver invoice.to_e_invoice(payable: payable).deliver
ActiveRecord::Base.transaction do ActiveRecord::Base.transaction do
invoice.update(e_invoice_sent_at: Time.zone.now) invoice.update(e_invoice_sent_at: Time.zone.now)
log_success(invoice) log_success(invoice)
@ -15,9 +15,9 @@ class SendEInvoiceJob < Que::Job
private private
def run_condition(invoice) def run_condition(invoice, payable: true)
destroy unless invoice destroy unless invoice
destroy if invoice.do_not_send_e_invoice? destroy if invoice.do_not_send_e_invoice? && payable
invoice invoice
end end

View file

@ -32,12 +32,14 @@ class Ability
def epp # Registrar/api_user dynamic role def epp # Registrar/api_user dynamic role
if @user.registrar.api_ip_white?(@ip) if @user.registrar.api_ip_white?(@ip)
can :manage, :poll
can :manage, Depp::Contact can :manage, Depp::Contact
can :manage, :xml_console can :manage, :xml_console
can :manage, Depp::Domain can :manage, Depp::Domain
end end
# Poll
can :manage, :poll
# REPP # REPP
can(:manage, :repp) can(:manage, :repp)

View file

@ -4,70 +4,17 @@ class BankStatement < ApplicationRecord
accepts_nested_attributes_for :bank_transactions accepts_nested_attributes_for :bank_transactions
attr_accessor :th6_file
validates :bank_code, :iban, presence: true validates :bank_code, :iban, presence: true
FULLY_BINDED = 'fully_binded' FULLY_BINDED = 'fully_binded'.freeze
PARTIALLY_BINDED = 'partially_binded' PARTIALLY_BINDED = 'partially_binded'.freeze
NOT_BINDED = 'not_binded' NOT_BINDED = 'not_binded'.freeze
def import
import_th6_file && save
end
def import_th6_file
return false unless th6_file
th6_file.open.each_line do |row|
bt_params = parse_th6_row(row)
next unless bt_params
bank_transactions.build(bt_params)
end
prepare_dir
self.import_file_path = "#{ENV['bank_statement_import_dir']}/#{Time.zone.now.to_formatted_s(:number)}.txt"
File.open(import_file_path, 'w') { |f| f.write(th6_file.open.read) }
end
def prepare_dir
dirname = ENV['bank_statement_import_dir']
FileUtils.mkdir_p(dirname) unless File.directory?(dirname)
end
def parse_th6_row(row)
return parse_th6_header(row) if row[4, 3].strip == '000'
return if row[4, 3].strip == '999' # skip footer
return unless row[4, 1].strip == '1' # import only transactions
return unless row[266, 2].strip == 'C' # import only Credit transactions
{
paid_at: DateTime.strptime(row[5, 8].strip, '%Y%m%d'),
bank_reference: row[5, 16].strip,
iban: row[25, 20].strip,
currency: row[45, 3].strip,
buyer_bank_code: row[48, 3].strip,
buyer_iban: row[51, 32].strip,
buyer_name: row[83, 35].strip,
document_no: row[118, 8].strip,
description: row[126, 140].strip,
sum: BigDecimal(row[268, 12].strip) / BigDecimal('100.0'),
reference_no: row[280, 35].strip
}
end
def parse_th6_header(row)
self.bank_code = row[7, 3].strip
self.iban = row[10, 20].strip
self.queried_at = DateTime.strptime(row[30, 10].strip, '%y%m%d%H%M')
nil
end
# TODO: Cache this to database so it can be used for searching # TODO: Cache this to database so it can be used for searching
def status def status
if bank_transactions.unbinded.count == bank_transactions.count if bank_transactions.unbinded.count == bank_transactions.count
NOT_BINDED NOT_BINDED
elsif bank_transactions.unbinded.count == 0 elsif bank_transactions.unbinded.count.zero?
FULLY_BINDED FULLY_BINDED
else else
PARTIALLY_BINDED PARTIALLY_BINDED

View file

@ -31,20 +31,18 @@ class BankTransaction < ApplicationRecord
@registrar ||= Invoice.find_by(reference_no: parsed_ref_number)&.buyer @registrar ||= Invoice.find_by(reference_no: parsed_ref_number)&.buyer
end end
def autobindable?
!binded? && registrar && invoice.payable? ? true : false
rescue NoMethodError
false
end
# For successful binding, reference number, invoice id and sum must match with the invoice # For successful binding, reference number, invoice id and sum must match with the invoice
def autobind_invoice(manual: false) def autobind_invoice(manual: false)
return if binded? return unless autobindable?
return unless registrar
return unless invoice
return unless invoice.payable?
channel = if manual channel = manual ? 'admin_payment' : 'system_payment'
'admin_payment' create_internal_payment_record(channel: channel, invoice: invoice, registrar: registrar)
else
'system_payment'
end
create_internal_payment_record(channel: channel, invoice: invoice,
registrar: registrar)
end end
def create_internal_payment_record(channel: nil, invoice:, registrar:) def create_internal_payment_record(channel: nil, invoice:, registrar:)
@ -93,12 +91,11 @@ class BankTransaction < ApplicationRecord
end end
def create_activity(registrar, invoice) def create_activity(registrar, invoice)
activity = AccountActivity.new( activity = AccountActivity.new(account: registrar.cash_account, bank_transaction: self,
account: registrar.cash_account, bank_transaction: self, invoice: invoice, sum: invoice.subtotal,
invoice: invoice, sum: invoice.subtotal, currency: currency, description: description,
currency: currency, description: description, activity_type: AccountActivity::ADD_CREDIT)
activity_type: AccountActivity::ADD_CREDIT
)
if activity.save if activity.save
reset_pending_registrar_balance_reload reset_pending_registrar_balance_reload
true true
@ -107,6 +104,10 @@ class BankTransaction < ApplicationRecord
end end
end end
def parsed_ref_number
reference_no || ref_number_from_description
end
private private
def reset_pending_registrar_balance_reload def reset_pending_registrar_balance_reload
@ -116,11 +117,12 @@ class BankTransaction < ApplicationRecord
registrar.save! registrar.save!
end end
def parsed_ref_number def ref_number_from_description
reference_no || ref_number_from_description matches = description.to_s.scan(Billing::ReferenceNo::MULTI_REGEXP).flatten
matches.detect { |m| break m if m.length == 7 || valid_ref_no?(m) }
end end
def ref_number_from_description def valid_ref_no?(match)
/(\d{7})/.match(description)[0] return true if Billing::ReferenceNo.valid?(match) && Registrar.find_by(reference_no: match)
end end
end end

View file

@ -1,6 +1,7 @@
module Billing module Billing
class Price < ApplicationRecord class Price < ApplicationRecord
include Concerns::Billing::Price::Expirable include Concerns::Billing::Price::Expirable
include Versions
belongs_to :zone, class_name: 'DNS::Zone', required: true belongs_to :zone, class_name: 'DNS::Zone', required: true
has_many :account_activities has_many :account_activities

View file

@ -1,10 +1,16 @@
module Billing module Billing
class ReferenceNo class ReferenceNo
REGEXP = /\A\d{2,20}\z/ REGEXP = /\A\d{2,20}\z/.freeze
MULTI_REGEXP = /(\d{2,20})/.freeze
def self.generate def self.generate
base = Base.generate base = Base.generate
"#{base}#{base.check_digit}" "#{base}#{base.check_digit}"
end end
def self.valid?(ref)
base = Base.new(ref.to_s[0...-1])
ref.to_s == "#{base}#{base.check_digit}"
end
end end
end end

View file

@ -2,7 +2,7 @@ module Billing
class ReferenceNo class ReferenceNo
class Base class Base
def self.generate def self.generate
new(SecureRandom.random_number(1..1_000_000)) new((SecureRandom.random_number(9e5) + 1e5).to_i)
end end
def initialize(base) def initialize(base)

View file

@ -127,77 +127,20 @@ class Certificate < ApplicationRecord
return false return false
end end
self.class.update_registry_crl self.class.update_crl
self.class.reload_apache
self self
end end
class << self class << self
def tostdout(message)
time = Time.zone.now.utc
STDOUT << "#{time} - #{message}\n" unless Rails.env.test?
end
def update_crl def update_crl
update_id_crl tostdout('Running crlupdater')
update_registry_crl system('/bin/bash', ENV['crl_updater_path'].to_s)
reload_apache tostdout('Finished running crlupdater')
end
def update_id_crl
STDOUT << "#{Time.zone.now.utc} - Updating ID CRL\n" unless Rails.env.test?
_out, _err, _st = Open3.capture3("
mkdir -p #{ENV['crl_dir']}/crl-id-temp
cd #{ENV['crl_dir']}/crl-id-temp
wget https://sk.ee/crls/esteid/esteid2007.crl
wget https://sk.ee/crls/juur/crl.crl
wget https://sk.ee/crls/eeccrca/eeccrca.crl
wget https://sk.ee/repository/crls/esteid2011.crl
openssl crl -in esteid2007.crl -out esteid2007.crl -inform DER
openssl crl -in crl.crl -out crl.crl -inform DER
openssl crl -in eeccrca.crl -out eeccrca.crl -inform DER
openssl crl -in esteid2011.crl -out esteid2011.crl -inform DER
ln -s crl.crl `openssl crl -hash -noout -in crl.crl`.r0
ln -s esteid2007.crl `openssl crl -hash -noout -in esteid2007.crl`.r0
ln -s eeccrca.crl `openssl crl -hash -noout -in eeccrca.crl`.r0
ln -s esteid2011.crl `openssl crl -hash -noout -in esteid2011.crl`.r0
rm -rf #{ENV['crl_dir']}/*.crl #{ENV['crl_dir']}/*.r0
mv #{ENV['crl_dir']}/crl-id-temp/* #{ENV['crl_dir']}
rm -rf #{ENV['crl_dir']}/crl-id-temp
")
STDOUT << "#{Time.zone.now.utc} - ID CRL updated\n" unless Rails.env.test?
end
def update_registry_crl
STDOUT << "#{Time.zone.now.utc} - Updating registry CRL\n" unless Rails.env.test?
_out, _err, _st = Open3.capture3("
mkdir -p #{ENV['crl_dir']}/crl-temp
cd #{ENV['crl_dir']}/crl-temp
openssl ca -config #{ENV['openssl_config_path']} -keyfile #{ENV['ca_key_path']} -cert \
#{ENV['ca_cert_path']} -gencrl -out #{ENV['crl_dir']}/crl-temp/crl.pem -key \
'#{ENV['ca_key_password']}' -batch
ln -s crl.pem `openssl crl -hash -noout -in crl.pem`.r1
rm -rf #{ENV['crl_dir']}/*.pem #{ENV['crl_dir']}/*.r1
mv #{ENV['crl_dir']}/crl-temp/* #{ENV['crl_dir']}
rm -rf #{ENV['crl_dir']}/crl-temp
")
STDOUT << "#{Time.zone.now.utc} - Registry CRL updated\n" unless Rails.env.test?
end
def reload_apache
STDOUT << "#{Time.zone.now.utc} - Reloading apache\n" unless Rails.env.test?
_out, _err, _st = Open3.capture3("sudo /etc/init.d/apache2 reload")
STDOUT << "#{Time.zone.now.utc} - Apache reloaded\n" unless Rails.env.test?
end end
def parse_md_from_string(crt) def parse_md_from_string(crt)

View file

@ -18,6 +18,7 @@ class Domain < ApplicationRecord
alias_attribute :on_hold_time, :outzone_at alias_attribute :on_hold_time, :outzone_at
alias_attribute :outzone_time, :outzone_at alias_attribute :outzone_time, :outzone_at
alias_attribute :auth_info, :transfer_code # Old attribute name; for PaperTrail alias_attribute :auth_info, :transfer_code # Old attribute name; for PaperTrail
alias_attribute :registered_at, :created_at
# TODO: whois requests ip whitelist for full info for own domains and partial info for other domains # TODO: whois requests ip whitelist for full info for own domains and partial info for other domains
# TODO: most inputs should be trimmed before validatation, probably some global logic? # TODO: most inputs should be trimmed before validatation, probably some global logic?
@ -627,7 +628,7 @@ class Domain < ApplicationRecord
def as_json(_options) def as_json(_options)
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['registered_at'] # API v1 requirement hash['valid_from'] = hash['created_at'] # API v1 requirement
hash.delete('statuses_before_force_delete') hash.delete('statuses_before_force_delete')
hash hash
end end

View file

@ -41,7 +41,6 @@ class Epp::Domain < Domain
domain = Epp::Domain.new domain = Epp::Domain.new
domain.attributes = domain.attrs_from(frame, current_user) domain.attributes = domain.attrs_from(frame, current_user)
domain.attach_default_contacts domain.attach_default_contacts
domain.registered_at = Time.zone.now
period = domain.period.to_i period = domain.period.to_i
plural_period_unit_name = (domain.period_unit == 'm' ? 'months' : 'years').to_sym plural_period_unit_name = (domain.period_unit == 'm' ? 'months' : 'years').to_sym
@ -150,7 +149,6 @@ class Epp::Domain < Domain
at[:name] = frame.css('name').text if new_record? at[:name] = frame.css('name').text if new_record?
at[:registrar_id] = current_user.registrar.try(:id) at[:registrar_id] = current_user.registrar.try(:id)
at[:registered_at] = Time.zone.now if new_record?
period = frame.css('period').text period = frame.css('period').text
at[:period] = (period.to_i == 0) ? 1 : period.to_i at[:period] = (period.to_i == 0) ? 1 : period.to_i
@ -502,7 +500,7 @@ class Epp::Domain < Domain
frame.css('registrant').attr('verified').to_s.downcase != 'yes' frame.css('registrant').attr('verified').to_s.downcase != 'yes'
if registrant_verification_needed && errors.empty? && verify && if registrant_verification_needed && errors.empty? && verify &&
Setting.request_confrimation_on_registrant_change_enabled && Setting.request_confirmation_on_registrant_change_enabled &&
unverified_registrant_params unverified_registrant_params
registrant_verification_asked!(frame.to_s, current_user.id) unless disputed? registrant_verification_asked!(frame.to_s, current_user.id) unless disputed?
end end

View file

@ -99,8 +99,8 @@ class Invoice < ApplicationRecord
generator.as_pdf generator.as_pdf
end end
def to_e_invoice def to_e_invoice(payable: true)
generator = Invoice::EInvoiceGenerator.new(self) generator = Invoice::EInvoiceGenerator.new(self, payable)
generator.generate generator.generate
end end
@ -112,6 +112,15 @@ class Invoice < ApplicationRecord
e_invoice_sent_at.present? e_invoice_sent_at.present?
end end
def self.create_from_transaction!(transaction)
registrar_user = Registrar.find_by(reference_no: transaction.parsed_ref_number)
return unless registrar_user
vat = VatRateCalculator.new(registrar: registrar_user).calculate
net = (transaction.sum / (1 + (vat / 100)))
registrar_user.issue_prepayment_invoice(net, 'Direct top-up via bank transfer', payable: false)
end
private private
def apply_default_buyer_vat_no def apply_default_buyer_vat_no
@ -119,6 +128,6 @@ class Invoice < ApplicationRecord
end end
def calculate_total def calculate_total
self.total = subtotal + vat_amount self.total = (subtotal + vat_amount).round(3)
end end
end end

View file

@ -1,9 +1,11 @@
class Invoice class Invoice
class EInvoiceGenerator class EInvoiceGenerator
attr_reader :invoice attr_reader :invoice
attr_reader :payable
def initialize(invoice) def initialize(invoice, payable)
@invoice = invoice @invoice = invoice
@payable = payable
end end
def generate def generate
@ -70,6 +72,7 @@ class Invoice
i.total = invoice.total i.total = invoice.total
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
end end
EInvoice::EInvoice.new(date: Time.zone.today, invoice: e_invoice_invoice) EInvoice::EInvoice.new(date: Time.zone.today, invoice: e_invoice_invoice)

View file

@ -5,7 +5,7 @@ class InvoiceItem < ApplicationRecord
delegate :vat_rate, to: :invoice delegate :vat_rate, to: :invoice
def item_sum_without_vat def item_sum_without_vat
(price * quantity).round(2) (price * quantity).round(3)
end end
alias_method :subtotal, :item_sum_without_vat alias_method :subtotal, :item_sum_without_vat
@ -14,6 +14,6 @@ class InvoiceItem < ApplicationRecord
end end
def total def total
subtotal + vat_amount (subtotal + vat_amount)
end end
end end

View file

@ -54,7 +54,7 @@ class Registrar < ApplicationRecord
end end
end end
def issue_prepayment_invoice(amount, description = nil) def issue_prepayment_invoice(amount, description = nil, payable: true)
vat_rate = ::Invoice::VatRateCalculator.new(registrar: self).calculate vat_rate = ::Invoice::VatRateCalculator.new(registrar: self).calculate
invoice = invoices.create!( invoice = invoices.create!(
@ -99,7 +99,12 @@ class Registrar < ApplicationRecord
} }
] ]
) )
SendEInvoiceJob.enqueue(invoice.id)
unless payable
InvoiceMailer.invoice_email(invoice: invoice, recipient: billing_email).deliver_now
end
SendEInvoiceJob.enqueue(invoice.id, payable)
invoice invoice
end end

View file

@ -0,0 +1,7 @@
module Billing
class PriceVersion < PaperTrail::Version
self.table_name = :log_prices
self.sequence_name = :log_prices_id_seq
end
end

View file

@ -36,7 +36,7 @@ class WhoisRecord < ApplicationRecord
h[:disclaimer] = disclaimer_text if disclaimer_text.present? h[:disclaimer] = disclaimer_text if disclaimer_text.present?
h[:name] = domain.name h[:name] = domain.name
h[:status] = domain.statuses.map { |x| status_map[x] || x } h[:status] = domain.statuses.map { |x| status_map[x] || x }
h[:registered] = domain.registered_at.try(:to_s, :iso8601) h[:registered] = domain.registered_at.iso8601
h[:changed] = domain.updated_at.try(:to_s, :iso8601) h[:changed] = domain.updated_at.try(:to_s, :iso8601)
h[:expire] = domain.valid_to.to_date.to_s h[:expire] = domain.valid_to.to_date.to_s
h[:outzone] = domain.outzone_at.try(:to_date).try(:to_s) h[:outzone] = domain.outzone_at.try(:to_date).try(:to_s)

View file

@ -1,20 +0,0 @@
- content_for :actions do
= link_to(t(:back_to_bank_statements), admin_bank_statements_path, class: 'btn btn-default')
= render 'shared/title', name: t(:import_th6_bank_statement)
= form_for(@bank_statement, url: { action: :create_from_import }, multipart: true) do |f|
= render 'shared/full_errors', object: @bank_statement
.row
.col-md-8
.form-group
.col-md-4.control-label
= f.label :th6_file
.col-md-8
= f.file_field :th6_file
.col-md-4
%p= t(:bank_statement_desc).html_safe
%hr
.row
.col-md-8.text-right
= button_tag(t(:save), class: 'btn btn-primary')

View file

@ -1,6 +1,5 @@
- content_for :actions do - content_for :actions do
= link_to(t(:add), new_admin_bank_statement_path, class: 'btn btn-primary') = link_to(t(:add), new_admin_bank_statement_path, class: 'btn btn-primary')
= link_to(t('.import_btn'), import_admin_bank_statements_path, class: 'btn btn-primary')
= render 'shared/title', name: t(:bank_statements) = render 'shared/title', name: t(:bank_statements)
.row .row

View file

@ -30,10 +30,6 @@
%dt= t(:created_at) %dt= t(:created_at)
%dd= l(@bank_statement.created_at) %dd= l(@bank_statement.created_at)
- if @bank_statement.import_file_path
%dt= t(:import_file)
%dd= link_to(t(:download), download_import_file_admin_bank_statement_path(@bank_statement))
.row .row
.col-sm-6 .col-sm-6
%h3.text-center-xs %h3.text-center-xs

View file

@ -10,7 +10,7 @@
<dt><%= t(:name) %></dt> <dt><%= t(:name) %></dt>
<dd><%= @domain.name %></dd> <dd><%= @domain.name %></dd>
<dt><%= t(:registered_at) %></dt> <dt><%= Domain.human_attribute_name :registered_at %></dt>
<dd><%= l(@domain.registered_at) %></dd> <dd><%= l(@domain.registered_at) %></dd>
<dt><%= t(:registrar_name) %></dt> <dt><%= t(:registrar_name) %></dt>

View file

@ -10,7 +10,7 @@
<dt><%= t(:name) %></dt> <dt><%= t(:name) %></dt>
<dd><%= @domain.name %></dd> <dd><%= @domain.name %></dd>
<dt><%= t(:registered_at) %></dt> <dt><%= Domain.human_attribute_name :registered_at %></dt>
<dd><%= l(@domain.registered_at) %></dd> <dd><%= l(@domain.registered_at) %></dd>
<dt><%= Registrar.model_name.human %></dt> <dt><%= Registrar.model_name.human %></dt>

View file

@ -27,13 +27,13 @@ smtp_authentication: 'plain' # 'plain', 'login', 'cram_md5'
# #
app_name: '.EE Registry' app_name: '.EE Registry'
zonefile_export_dir: 'export/zonefiles' zonefile_export_dir: 'export/zonefiles'
bank_statement_import_dir: 'import/bank_statements'
legal_documents_dir: 'import/legal_documents' legal_documents_dir: 'import/legal_documents'
time_zone: 'Tallinn' # more zones by rake time:zones:all time_zone: 'Tallinn' # more zones by rake time:zones:all
openssl_config_path: '/etc/ssl/openssl.cnf' openssl_config_path: '/etc/ssl/openssl.cnf'
crl_dir: '/home/registry/registry/shared/ca/crl' crl_dir: '/home/registry/registry/shared/ca/crl'
crl_path: '/home/registry/registry/shared/ca/crl/crl.pem' crl_path: '/home/registry/registry/shared/ca/crl/crl.pem'
crl_updater_path: '/home/registry/registry/shared/ca/crl/crlupdater.sh'
ca_cert_path: '/home/registry/registry/shared/ca/certs/ca.crt.pem' ca_cert_path: '/home/registry/registry/shared/ca/certs/ca.crt.pem'
ca_key_path: '/home/registry/registry/shared/ca/private/ca.key.pem' ca_key_path: '/home/registry/registry/shared/ca/private/ca.key.pem'
ca_key_password: 'your-root-key-password' ca_key_password: 'your-root-key-password'

View file

@ -195,7 +195,6 @@ en:
registrar_name: 'Registrar' registrar_name: 'Registrar'
owner: 'Registrant' owner: 'Registrant'
domain_details: 'Domain details' domain_details: 'Domain details'
registered_at: 'Registered at'
password: 'Password' password: 'Password'
valid_from: 'Valid from' valid_from: 'Valid from'
general: 'General' general: 'General'
@ -467,7 +466,6 @@ en:
paid_at: 'Paid at' paid_at: 'Paid at'
invoice: 'Invoice' invoice: 'Invoice'
bank_statements: 'Bank statements' bank_statements: 'Bank statements'
import_th6_bank_statement: 'Import TH6 bank statement'
back_to_bank_statements: 'Back to bank statements' back_to_bank_statements: 'Back to bank statements'
back_to_bank_statement: 'Back to bank statement' back_to_bank_statement: 'Back to bank statement'
back_to_billing: 'Back to billing' back_to_billing: 'Back to billing'
@ -584,7 +582,6 @@ en:
valid: Valid valid: Valid
object_is_not_eligible_for_renewal: 'Object is not eligible for renewal' object_is_not_eligible_for_renewal: 'Object is not eligible for renewal'
object_is_not_holded: 'Object is not holded' object_is_not_holded: 'Object is not holded'
bank_statement_desc: 'Import file row will match only when matching following attributes: <b><br>ref number<br>payment amount<br>invoice number (the first numerical value in comment field)</b>.'
create_bank_statement: 'Create bank statement' create_bank_statement: 'Create bank statement'
create_bank_transaction: 'Create bank transaction' create_bank_transaction: 'Create bank transaction'
create_new_invoice: 'Create new invoice' create_new_invoice: 'Create new invoice'

View file

@ -213,13 +213,7 @@ Rails.application.routes.draw do
resources :bank_statements do resources :bank_statements do
resources :bank_transactions resources :bank_transactions
collection do
get 'import'
post 'create_from_import'
end
post 'bind_invoices', on: :member post 'bind_invoices', on: :member
get 'download_import_file', on: :member
end end
resources :bank_transactions do resources :bank_transactions do

View file

@ -0,0 +1,11 @@
class FixTypoInSettingName < ActiveRecord::Migration[6.0]
def up
setting = Setting.find_by(code: 'request_confrimation_on_registrant_change_enabled')
setting.update(code: 'request_confirmation_on_registrant_change_enabled')
end
def down
setting = Setting.find_by(code: 'request_confirmation_on_registrant_change_enabled')
setting.update(code: 'request_confrimation_on_registrant_change_enabled')
end
end

View file

@ -0,0 +1,5 @@
class RemoveDomainsRegisteredAt < ActiveRecord::Migration[5.0]
def change
remove_column :domains, :registered_at
end
end

View file

@ -0,0 +1,9 @@
class RemoveImportFilePathFromBankStatements < ActiveRecord::Migration[6.0]
def up
remove_column :bank_statements, :import_file_path
end
def down
add_column :bank_statements, :import_file_path, :string
end
end

View file

@ -0,0 +1,5 @@
class ChangeInvoiceItemPriceScaleToThreePlaces < ActiveRecord::Migration[6.0]
def change
change_column :invoice_items, :price, :decimal, precision: 10, scale: 3
end
end

View file

@ -0,0 +1,26 @@
class CreateVersionForPrices < ActiveRecord::Migration[6.0]
def up
create_table :log_prices, force: :cascade do |t|
t.string :item_type, null: false
t.integer :item_id, null: false
t.string :event, null: false
t.string :whodunnit
t.json :object
t.json :object_changes
t.datetime :created_at
t.string :session
t.json :children
t.string :uuid
end
add_index 'log_prices', ['item_type', 'item_id'], name: 'index_log_prices_on_item_type_and_item_id', using: :btree
add_index 'log_prices', ['whodunnit'], name: 'index_log_prices_on_whodunnit', using: :btree
end
def down
remove_index :log_prices, name: 'index_log_prices_on_item_type_and_item_id'
remove_index :log_prices, name: 'index_log_prices_on_whodunnit'
drop_table :log_prices
end
end

View file

@ -26,7 +26,7 @@ ActiveRecord::Base.transaction do
SettingEntry.create(code: 'client_side_status_editing_enabled', value: 'false', format: 'boolean', group: 'other') SettingEntry.create(code: 'client_side_status_editing_enabled', value: 'false', format: 'boolean', group: 'other')
SettingEntry.create(code: 'api_ip_whitelist_enabled', value: 'false', format: 'boolean', group: 'other') SettingEntry.create(code: 'api_ip_whitelist_enabled', value: 'false', format: 'boolean', group: 'other')
SettingEntry.create(code: 'registrar_ip_whitelist_enabled', value: 'false', format: 'boolean', group: 'other') SettingEntry.create(code: 'registrar_ip_whitelist_enabled', value: 'false', format: 'boolean', group: 'other')
SettingEntry.create(code: 'request_confrimation_on_registrant_change_enabled', value: 'true', format: 'boolean', group: 'other') SettingEntry.create(code: 'request_confirmation_on_registrant_change_enabled', value: 'true', format: 'boolean', group: 'other')
SettingEntry.create(code: 'request_confirmation_on_domain_deletion_enabled', value: 'true', format: 'boolean', group: 'other') SettingEntry.create(code: 'request_confirmation_on_domain_deletion_enabled', value: 'true', format: 'boolean', group: 'other')
SettingEntry.create(code: 'default_language', value: 'en', format: 'string', group: 'other') SettingEntry.create(code: 'default_language', value: 'en', format: 'string', group: 'other')
SettingEntry.create(code: 'invoice_number_min', value: '131050', format: 'integer', group: 'billing') SettingEntry.create(code: 'invoice_number_min', value: '131050', format: 'integer', group: 'billing')

View file

@ -371,7 +371,6 @@ CREATE TABLE public.bank_statements (
id integer NOT NULL, id integer NOT NULL,
bank_code character varying, bank_code character varying,
iban character varying, iban character varying,
import_file_path character varying,
queried_at timestamp without time zone, queried_at timestamp without time zone,
created_at timestamp without time zone, created_at timestamp without time zone,
updated_at timestamp without time zone, updated_at timestamp without time zone,
@ -778,7 +777,6 @@ CREATE TABLE public.domains (
id integer NOT NULL, id integer NOT NULL,
name character varying NOT NULL, name character varying NOT NULL,
registrar_id integer NOT NULL, registrar_id integer NOT NULL,
registered_at timestamp without time zone,
valid_to timestamp without time zone NOT NULL, valid_to timestamp without time zone NOT NULL,
registrant_id integer NOT NULL, registrant_id integer NOT NULL,
transfer_code character varying NOT NULL, transfer_code character varying NOT NULL,
@ -964,7 +962,7 @@ CREATE TABLE public.invoice_items (
description character varying NOT NULL, description character varying NOT NULL,
unit character varying NOT NULL, unit character varying NOT NULL,
quantity integer NOT NULL, quantity integer NOT NULL,
price numeric(10,2) NOT NULL, price numeric(10,3) NOT NULL,
created_at timestamp without time zone, created_at timestamp without time zone,
updated_at timestamp without time zone, updated_at timestamp without time zone,
creator_str character varying, creator_str character varying,
@ -1708,7 +1706,45 @@ ALTER SEQUENCE public.log_payment_orders_id_seq OWNED BY public.log_payment_orde
-- --
-- Name: log_registrant_verifications; Type: TABLE; Schema: public; Owner: -; Tablespace: -- Name: log_prices; Type: TABLE; Schema: public; Owner: -
--
CREATE TABLE public.log_prices (
id bigint NOT NULL,
item_type character varying NOT NULL,
item_id integer NOT NULL,
event character varying NOT NULL,
whodunnit character varying,
object json,
object_changes json,
created_at timestamp without time zone,
session character varying,
children json,
uuid character varying
);
--
-- Name: log_prices_id_seq; Type: SEQUENCE; Schema: public; Owner: -
--
CREATE SEQUENCE public.log_prices_id_seq
START WITH 1
INCREMENT BY 1
NO MINVALUE
NO MAXVALUE
CACHE 1;
--
-- Name: log_prices_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: -
--
ALTER SEQUENCE public.log_prices_id_seq OWNED BY public.log_prices.id;
--
-- Name: log_registrant_verifications; Type: TABLE; Schema: public; Owner: -
-- --
CREATE TABLE public.log_registrant_verifications ( CREATE TABLE public.log_registrant_verifications (
@ -2094,8 +2130,8 @@ CREATE TABLE public.prices (
price_cents integer NOT NULL, price_cents integer NOT NULL,
valid_from timestamp without time zone, valid_from timestamp without time zone,
valid_to timestamp without time zone, valid_to timestamp without time zone,
creator_str character varying,
updator_str character varying, updator_str character varying,
creator_str character varying,
created_at timestamp without time zone NOT NULL, created_at timestamp without time zone NOT NULL,
updated_at timestamp without time zone NOT NULL, updated_at timestamp without time zone NOT NULL,
duration interval, duration interval,
@ -2840,7 +2876,14 @@ ALTER TABLE ONLY public.log_payment_orders ALTER COLUMN id SET DEFAULT nextval('
-- --
-- Name: id; Type: DEFAULT; Schema: public; Owner: - -- Name: log_prices id; Type: DEFAULT; Schema: public; Owner: -
--
ALTER TABLE ONLY public.log_prices ALTER COLUMN id SET DEFAULT nextval('public.log_prices_id_seq'::regclass);
--
-- Name: log_registrant_verifications id; Type: DEFAULT; Schema: public; Owner: -
-- --
ALTER TABLE ONLY public.log_registrant_verifications ALTER COLUMN id SET DEFAULT nextval('public.log_registrant_verifications_id_seq'::regclass); ALTER TABLE ONLY public.log_registrant_verifications ALTER COLUMN id SET DEFAULT nextval('public.log_registrant_verifications_id_seq'::regclass);
@ -3306,7 +3349,15 @@ ALTER TABLE ONLY public.log_payment_orders
-- --
-- Name: log_registrant_verifications_pkey; Type: CONSTRAINT; Schema: public; Owner: -; Tablespace: -- Name: log_prices log_prices_pkey; Type: CONSTRAINT; Schema: public; Owner: -
--
ALTER TABLE ONLY public.log_prices
ADD CONSTRAINT log_prices_pkey PRIMARY KEY (id);
--
-- Name: log_registrant_verifications log_registrant_verifications_pkey; Type: CONSTRAINT; Schema: public; Owner: -
-- --
ALTER TABLE ONLY public.log_registrant_verifications ALTER TABLE ONLY public.log_registrant_verifications
@ -4828,6 +4879,7 @@ INSERT INTO "schema_migrations" (version) VALUES
('20191203083643'), ('20191203083643'),
('20191206183853'), ('20191206183853'),
('20191212133136'), ('20191212133136'),
('20191217013225'),
('20191219112434'), ('20191219112434'),
('20191219124429'), ('20191219124429'),
('20191227110904'), ('20191227110904'),
@ -4851,5 +4903,8 @@ INSERT INTO "schema_migrations" (version) VALUES
('20200811074839'), ('20200811074839'),
('20200812090409'), ('20200812090409'),
('20200812125810'), ('20200812125810'),
('20200902131603'); ('20200902131603'),
('20200908131554'),
('20200910085157'),
('20200910102028');

View file

@ -36,6 +36,8 @@ namespace :invoices do
reference_no: incoming_transaction.payment_reference_number, reference_no: incoming_transaction.payment_reference_number,
description: incoming_transaction.payment_description } description: incoming_transaction.payment_description }
transaction = bank_statement.bank_transactions.create!(transaction_attributes) transaction = bank_statement.bank_transactions.create!(transaction_attributes)
Invoice.create_from_transaction!(transaction) unless transaction.autobindable?
transaction.autobind_invoice transaction.autobind_invoice
end end
end end

View file

@ -5,7 +5,6 @@ shop:
registrar: bestnames registrar: bestnames
registrant: john registrant: john
transfer_code: 65078d5 transfer_code: 65078d5
registered_at: <%= Time.zone.parse('2010-07-04').to_s(:db) %>
valid_to: <%= Time.zone.parse('2010-07-05').to_s(:db) %> valid_to: <%= Time.zone.parse('2010-07-05').to_s(:db) %>
outzone_at: <%= Time.zone.parse('2010-07-06').to_s(:db) %> outzone_at: <%= Time.zone.parse('2010-07-06').to_s(:db) %>
delete_date: 2010-07-07 delete_date: 2010-07-07

View file

@ -182,8 +182,8 @@ registrar_ip_whitelist_enabled:
created_at: <%= Time.zone.parse('2010-07-05') %> created_at: <%= Time.zone.parse('2010-07-05') %>
updated_at: <%= Time.zone.parse('2010-07-05') %> updated_at: <%= Time.zone.parse('2010-07-05') %>
request_confrimation_on_registrant_change_enabled: request_confirmation_on_registrant_change_enabled:
code: request_confrimation_on_registrant_change_enabled code: request_confirmation_on_registrant_change_enabled
value: 'true' value: 'true'
group: other group: other
format: boolean format: boolean

View file

@ -6,12 +6,12 @@ class EppDomainUpdateBaseTest < EppTestCase
setup do setup do
@domain = domains(:shop) @domain = domains(:shop)
@original_registrant_change_verification = @original_registrant_change_verification =
Setting.request_confrimation_on_registrant_change_enabled Setting.request_confirmation_on_registrant_change_enabled
ActionMailer::Base.deliveries.clear ActionMailer::Base.deliveries.clear
end end
teardown do teardown do
Setting.request_confrimation_on_registrant_change_enabled = Setting.request_confirmation_on_registrant_change_enabled =
@original_registrant_change_verification @original_registrant_change_verification
end end
@ -87,7 +87,7 @@ class EppDomainUpdateBaseTest < EppTestCase
end end
def test_requires_verification_from_current_registrant_when_provided_registrant_is_a_new_one def test_requires_verification_from_current_registrant_when_provided_registrant_is_a_new_one
Setting.request_confrimation_on_registrant_change_enabled = true Setting.request_confirmation_on_registrant_change_enabled = true
new_registrant = contacts(:william).becomes(Registrant) new_registrant = contacts(:william).becomes(Registrant)
assert_not_equal new_registrant, @domain.registrant assert_not_equal new_registrant, @domain.registrant
@ -124,7 +124,7 @@ class EppDomainUpdateBaseTest < EppTestCase
end end
def test_requires_verification_from_current_registrant_when_not_yet_verified_by_registrar def test_requires_verification_from_current_registrant_when_not_yet_verified_by_registrar
Setting.request_confrimation_on_registrant_change_enabled = true Setting.request_confirmation_on_registrant_change_enabled = true
new_registrant = contacts(:william) new_registrant = contacts(:william)
assert_not_equal new_registrant, @domain.registrant assert_not_equal new_registrant, @domain.registrant
@ -161,7 +161,7 @@ class EppDomainUpdateBaseTest < EppTestCase
end end
def test_updates_registrant_when_legaldoc_is_not_mandatory def test_updates_registrant_when_legaldoc_is_not_mandatory
Setting.request_confrimation_on_registrant_change_enabled = true Setting.request_confirmation_on_registrant_change_enabled = true
new_registrant = contacts(:william) new_registrant = contacts(:william)
assert_not_equal new_registrant, @domain.registrant assert_not_equal new_registrant, @domain.registrant
@ -197,7 +197,7 @@ class EppDomainUpdateBaseTest < EppTestCase
end end
def test_dows_not_update_registrant_when_legaldoc_is_mandatory def test_dows_not_update_registrant_when_legaldoc_is_mandatory
Setting.request_confrimation_on_registrant_change_enabled = true Setting.request_confirmation_on_registrant_change_enabled = true
old_value = Setting.legal_document_is_mandatory old_value = Setting.legal_document_is_mandatory
Setting.legal_document_is_mandatory = true Setting.legal_document_is_mandatory = true
new_registrant = contacts(:william) new_registrant = contacts(:william)
@ -226,7 +226,7 @@ class EppDomainUpdateBaseTest < EppTestCase
end end
def test_skips_verification_when_provided_registrant_is_the_same_as_current_one def test_skips_verification_when_provided_registrant_is_the_same_as_current_one
Setting.request_confrimation_on_registrant_change_enabled = true Setting.request_confirmation_on_registrant_change_enabled = true
request_xml = <<-XML request_xml = <<-XML
<?xml version="1.0" encoding="UTF-8" standalone="no"?> <?xml version="1.0" encoding="UTF-8" standalone="no"?>
@ -260,7 +260,7 @@ class EppDomainUpdateBaseTest < EppTestCase
end end
def test_skips_verification_when_registrant_changed_with_dispute_password def test_skips_verification_when_registrant_changed_with_dispute_password
Setting.request_confrimation_on_registrant_change_enabled = true Setting.request_confirmation_on_registrant_change_enabled = true
dispute = disputes(:expired) dispute = disputes(:expired)
dispute.update!(starts_at: Time.zone.now, expires_at: Time.zone.now + 5.days, closed: nil) dispute.update!(starts_at: Time.zone.now, expires_at: Time.zone.now + 5.days, closed: nil)
new_registrant = contacts(:william) new_registrant = contacts(:william)
@ -303,7 +303,7 @@ class EppDomainUpdateBaseTest < EppTestCase
end end
def test_skips_verification_when_disabled def test_skips_verification_when_disabled
Setting.request_confrimation_on_registrant_change_enabled = false Setting.request_confirmation_on_registrant_change_enabled = false
new_registrant = contacts(:william).becomes(Registrant) new_registrant = contacts(:william).becomes(Registrant)
assert_not_equal new_registrant, @domain.registrant assert_not_equal new_registrant, @domain.registrant
@ -340,7 +340,7 @@ class EppDomainUpdateBaseTest < EppTestCase
end end
def test_skips_verification_from_current_registrant_when_already_verified_by_registrar def test_skips_verification_from_current_registrant_when_already_verified_by_registrar
Setting.request_confrimation_on_registrant_change_enabled = true Setting.request_confirmation_on_registrant_change_enabled = true
new_registrant = contacts(:william).becomes(Registrant) new_registrant = contacts(:william).becomes(Registrant)
assert_not_equal new_registrant, @domain.registrant assert_not_equal new_registrant, @domain.registrant
@ -377,7 +377,7 @@ class EppDomainUpdateBaseTest < EppTestCase
end end
def test_clears_force_delete_when_registrar_changed def test_clears_force_delete_when_registrar_changed
Setting.request_confrimation_on_registrant_change_enabled = true Setting.request_confirmation_on_registrant_change_enabled = true
new_registrant = contacts(:william).becomes(Registrant) new_registrant = contacts(:william).becomes(Registrant)
@domain.schedule_force_delete(type: :fast_track) @domain.schedule_force_delete(type: :fast_track)
assert_not_equal new_registrant, @domain.registrant assert_not_equal new_registrant, @domain.registrant

View file

@ -151,4 +151,44 @@ class DirectoInvoiceForwardJobTest < ActiveSupport::TestCase
DirectoInvoiceForwardJob.run(monthly: true, dry: false) DirectoInvoiceForwardJob.run(monthly: true, dry: false)
end end
end end
def test_sends_each_monthly_invoice_separately
WebMock.reset!
activity = account_activities(:one)
price = billing_prices(:create_one_year)
price.update(duration: '3 years')
activity.update(activity_type: 'create', price: price)
# Creating account activity for second action
another_activity = activity.dup
another_activity.account = accounts(:two)
AccountActivity.skip_callback(:create, :after, :update_balance)
another_activity.created_at = Time.zone.parse('2010-07-05 10:00')
another_activity.save
AccountActivity.set_callback(:create, :after, :update_balance)
response = <<-XML
<?xml version="1.0" encoding="UTF-8"?>
<results>
<Result Type="0" Desc="OK" docid="309902" doctype="ARVE" submit="Invoices"/>
</results>
XML
first_registrar_stub = stub_request(:post, ENV['directo_invoice_url']).with do |request|
body = CGI.unescape(request.body)
(body.include? 'StartDate') && (body.include? 'EndDate') && (body.include? 'bestnames')
end.to_return(status: 200, body: response)
second_registrar_stub = stub_request(:post, ENV['directo_invoice_url']).with do |request|
body = CGI.unescape(request.body)
(body.include? 'StartDate') && (body.include? 'EndDate') && (body.include? 'goodnames')
end.to_return(status: 200, body: response)
DirectoInvoiceForwardJob.run(monthly: true, dry: false)
assert_requested first_registrar_stub
assert_requested second_registrar_stub
end
end end

View file

@ -13,7 +13,7 @@ class SendEInvoiceJobTest < ActiveSupport::TestCase
EInvoice::Providers::TestProvider.deliveries.clear EInvoice::Providers::TestProvider.deliveries.clear
assert_nothing_raised do assert_nothing_raised do
SendEInvoiceJob.enqueue(@invoice.id) SendEInvoiceJob.enqueue(@invoice.id, true)
end end
@invoice.reload @invoice.reload
@ -29,7 +29,7 @@ class SendEInvoiceJobTest < ActiveSupport::TestCase
stub_request(:get, "https://testfinance.post.ee/finance/erp/erpServices.wsdl").to_timeout stub_request(:get, "https://testfinance.post.ee/finance/erp/erpServices.wsdl").to_timeout
assert_raise HTTPClient::TimeoutError do assert_raise HTTPClient::TimeoutError do
SendEInvoiceJob.enqueue(@invoice.id) SendEInvoiceJob.enqueue(@invoice.id, true)
end end
assert @invoicee_invoice_sent_at.blank? assert @invoicee_invoice_sent_at.blank?
@ -37,7 +37,7 @@ class SendEInvoiceJobTest < ActiveSupport::TestCase
EInvoice::Providers::TestProvider.deliveries.clear EInvoice::Providers::TestProvider.deliveries.clear
assert_nothing_raised do assert_nothing_raised do
SendEInvoiceJob.enqueue(@invoice.id) SendEInvoiceJob.enqueue(@invoice.id, true)
end end
@invoice.reload @invoice.reload

View file

@ -26,14 +26,12 @@ class BankTransactionTest < ActiveSupport::TestCase
another_item.save another_item.save
another_invoice.reload another_invoice.reload
first_transaction = BankTransaction.new(description: 'invoice #2221', first_transaction = BankTransaction.new(sum: 10,
sum: 10,
description: 'Order nr 1 from registrar 1234567 second number 2345678') description: 'Order nr 1 from registrar 1234567 second number 2345678')
first_transaction.create_activity(another_invoice.buyer, another_invoice) first_transaction.create_activity(another_invoice.buyer, another_invoice)
transaction = BankTransaction.new(description: 'invoice #2222', transaction = BankTransaction.new(sum: 10,
sum: 10,
description: 'Order nr 1 from registrar 1234567 second number 2345678') description: 'Order nr 1 from registrar 1234567 second number 2345678')
assert_difference 'AccountActivity.count' do assert_difference 'AccountActivity.count' do
@ -54,8 +52,7 @@ class BankTransactionTest < ActiveSupport::TestCase
another_invoice.reload another_invoice.reload
another_invoice.update(reference_no: '1234567', number: '2221', cancelled_at: Time.zone.now) another_invoice.update(reference_no: '1234567', number: '2221', cancelled_at: Time.zone.now)
transaction = BankTransaction.new(description: 'invoice #2222', transaction = BankTransaction.new(sum: 10,
sum: 10,
description: 'Order nr 1 from registrar 1234567 second number 2345678') description: 'Order nr 1 from registrar 1234567 second number 2345678')
assert_difference 'AccountActivity.count' do assert_difference 'AccountActivity.count' do
@ -74,8 +71,7 @@ class BankTransactionTest < ActiveSupport::TestCase
another_item.save another_item.save
another_invoice.reload another_invoice.reload
transaction = BankTransaction.new(description: 'invoice #2222', transaction = BankTransaction.new(sum: 10,
sum: 10,
description: 'Order nr 1 from registrar 1234567 second number 2345678') description: 'Order nr 1 from registrar 1234567 second number 2345678')
assert_difference 'AccountActivity.count' do assert_difference 'AccountActivity.count' do
@ -90,8 +86,7 @@ class BankTransactionTest < ActiveSupport::TestCase
def test_matches_against_invoice_nubmber_and_reference_number_in_description def test_matches_against_invoice_nubmber_and_reference_number_in_description
create_payable_invoice(number: '2222', total: 10, reference_no: '1234567') create_payable_invoice(number: '2222', total: 10, reference_no: '1234567')
transaction = BankTransaction.new(description: 'invoice #2222', transaction = BankTransaction.new(sum: 10,
sum: 10,
description: 'Order nr 1 from registrar 1234567 second number 2345678') description: 'Order nr 1 from registrar 1234567 second number 2345678')
assert_difference 'AccountActivity.count' do assert_difference 'AccountActivity.count' do
@ -99,6 +94,18 @@ class BankTransactionTest < ActiveSupport::TestCase
end end
end end
def test_no_errors_if_no_valid_refnumber_in_description
create_payable_invoice(number: '2222', total: 10, reference_no: '1234567')
transaction = BankTransaction.new(sum: 10,
description: 'Order nr 1 from registrar 123456')
assert_no_difference 'AccountActivity.count' do
assert_nothing_raised do
transaction.autobind_invoice
end
end
end
def test_resets_pending_registrar_balance_reload def test_resets_pending_registrar_balance_reload
registrar = registrar_with_pending_balance_auto_reload registrar = registrar_with_pending_balance_auto_reload
create_payable_invoice(number: '2222', total: 10, reference_no: '1111') create_payable_invoice(number: '2222', total: 10, reference_no: '1111')
@ -149,6 +156,24 @@ class BankTransactionTest < ActiveSupport::TestCase
assert transaction.errors.full_messages.include?('Cannot bind cancelled invoice') assert transaction.errors.full_messages.include?('Cannot bind cancelled invoice')
end end
def test_assumes_7_digit_number_is_reference_no_in_desc
statement = BankTransaction.new
statement.description = 'number 1234567 defo valid'
assert_equal '1234567', statement.parsed_ref_number
end
def test_determines_correct_ref_no_from_description
statement = BankTransaction.new
ref_no = registrars(:bestnames).reference_no
statement.description = "invoice 123 125 55 4521 #{ref_no} 7541 defo valid"
assert_equal ref_no.to_s, statement.parsed_ref_number
end
def test_parsed_ref_no_returns_nil_if_ref_not_found
statement = BankTransaction.new
statement.description = "all invalid 12 123 55 77777 --"
assert_nil statement.parsed_ref_number
end
private private
def create_payable_invoice(attributes) def create_payable_invoice(attributes)

View file

@ -425,6 +425,12 @@ class DomainTest < ActiveSupport::TestCase
assert_not(@domain.force_delete_scheduled?) assert_not(@domain.force_delete_scheduled?)
end end
def test_aliases_registered_at_to_created_at
created_at = Time.zone.parse('2010-07-05 10:00')
domain = Domain.new(created_at: created_at)
assert_equal created_at, domain.registered_at
end
private private
def valid_domain def valid_domain

View file

@ -1,6 +1,8 @@
require 'test_helper' require 'test_helper'
class InvoiceTest < ActiveSupport::TestCase class InvoiceTest < ActiveSupport::TestCase
include ActionMailer::TestHelper
setup do setup do
@invoice = invoices(:one) @invoice = invoices(:one)
end end
@ -109,4 +111,33 @@ class InvoiceTest < ActiveSupport::TestCase
seller_zip: nil) seller_zip: nil)
assert_equal 'street, city, state', invoice.seller_address assert_equal 'street, city, state', invoice.seller_address
end end
def test_creates_invoice_with_bank_transaction_total
registrar = registrars(:bestnames)
transaction = bank_transactions(:one).dup
transaction.reference_no = registrar.reference_no
transaction.sum = 250
invoice = Invoice.create_from_transaction!(transaction)
assert_equal 250, invoice.total
transaction.sum = 146.88
invoice = Invoice.create_from_transaction!(transaction)
assert_equal 146.88, invoice.total
transaction.sum = 0.99
invoice = Invoice.create_from_transaction!(transaction)
assert_equal 0.99, invoice.total
end
def test_emails_invoice_after_creating_topup_invoice
registrar = registrars(:bestnames)
transaction = bank_transactions(:one).dup
transaction.reference_no = registrar.reference_no
transaction.sum = 250
assert_emails 1 do
Invoice.create_from_transaction!(transaction)
end
end
end end

View file

@ -6,11 +6,48 @@ class AdminAreaBankStatementTest < ApplicationSystemTestCase
travel_to Time.zone.parse('2010-07-05 00:30:00') travel_to Time.zone.parse('2010-07-05 00:30:00')
end end
def test_import_statement def test_can_create_statement_manually
assert_difference 'BankStatement.count', 1 do create_bank_statement
visit import_admin_bank_statements_path assert_text 'Record created'
attach_file 'Th6 file', Rails.root.join('test', 'fixtures', 'files', 'bank_statement_test.txt').to_s end
click_link_or_button 'Save'
end def test_can_add_transaction_to_statement_manually
create_bank_statement
click_link_or_button 'Add'
assert_text 'Create bank transaction'
fill_in 'Description', with: 'Invoice with id 123'
fill_in 'Reference number', with: '1232'
fill_in 'Sum', with: '500'
fill_in 'Paid at', with: Time.zone.today.to_s
click_link_or_button 'Save'
assert_text 'Record created'
end
def test_can_bind_statement_transactions
registrar = registrars(:bestnames)
registrar.issue_prepayment_invoice(amount: 500)
invoice = registrar.invoices.last
create_bank_statement
click_link_or_button 'Add'
assert_text 'Create bank transaction'
fill_in 'Description', with: "Invoice with id #{invoice.number}"
fill_in 'Reference number', with: invoice.reference_no
fill_in 'Sum', with: invoice.total
fill_in 'Paid at', with: Time.zone.today.to_s
click_link_or_button 'Save'
click_link_or_button 'Back to bank statement'
click_link_or_button 'Bind invoices'
assert_text 'Invoices were fully binded'
end
def create_bank_statement
visit admin_bank_statements_path
click_link_or_button 'Add'
click_link_or_button 'Save'
end end
end end

View file

@ -12,7 +12,7 @@ class RegistrantAreaDomainDetailsTest < ApplicationSystemTestCase
visit registrant_domain_url(@domain) visit registrant_domain_url(@domain)
assert_text 'Name shop.test' assert_text 'Name shop.test'
assert_text "Registered at #{l Time.zone.parse('2010-07-04')}" assert_text "Registered at #{l @domain.registered_at}"
assert_link 'Best Names', href: registrant_registrar_path(@domain.registrar) assert_link 'Best Names', href: registrant_registrar_path(@domain.registrar)
assert_text 'Transfer code' assert_text 'Transfer code'

View file

@ -82,6 +82,25 @@ class ProcessPaymentsTaskTest < ActiveSupport::TestCase
assert payment_order.failed? assert payment_order.failed?
end end
def test_credits_registrar_account_without_invoice_beforehand
registrar = registrars(:bestnames)
assert_changes -> { registrar.accounts.first.balance } do
run_task
end
assert_changes -> { registrar.invoices.count } do
run_task
end
end
def test_topup_creates_invoice_with_total_of_transactioned_amount
registrar = registrars(:bestnames)
run_task
assert_equal 0.1, registrar.invoices.last.total
end
def test_output def test_output
assert_output "Transactions processed: 1\n" do assert_output "Transactions processed: 1\n" do
run_task run_task