Merge pull request #775 from internetee/registry-623

Registry 623
This commit is contained in:
Timo Võhmar 2018-04-13 14:10:00 +03:00 committed by GitHub
commit b02df5ef02
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
45 changed files with 512 additions and 121 deletions

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -3,7 +3,7 @@ class Directo < ActiveRecord::Base
belongs_to :item, polymorphic: true belongs_to :item, polymorphic: true
def self.send_receipts 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 total = new_trans.count
counter = 0 counter = 0
Rails.logger.info("[DIRECTO] Will try to send #{total} invoices") Rails.logger.info("[DIRECTO] Will try to send #{total} invoices")
@ -15,7 +15,7 @@ class Directo < ActiveRecord::Base
group.each do |invoice| group.each do |invoice|
if invoice.account_activity.nil? || invoice.account_activity.bank_transaction.nil? || 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") Rails.logger.info("[DIRECTO] Invoice #{invoice.number} has been skipped")
next next
end end
@ -29,12 +29,14 @@ class Directo < ActiveRecord::Base
"InvoiceDate" => invoice.created_at.strftime("%Y-%m-%dT%H:%M:%S"), "InvoiceDate" => invoice.created_at.strftime("%Y-%m-%dT%H:%M:%S"),
"PaymentTerm" => Setting.directo_receipt_payment_term, "PaymentTerm" => Setting.directo_receipt_payment_term,
"Currency" => invoice.currency, "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( xml.line(
"ProductID" => Setting.directo_receipt_product_name, "ProductID" => Setting.directo_receipt_product_name,
"Quantity" => 1, "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 "ProductName" => invoice.order
) )
} }

View file

@ -27,12 +27,18 @@ class Invoice < ActiveRecord::Base
attr_accessor :billing_email attr_accessor :billing_email
validates :billing_email, email_format: { message: :invalid }, allow_blank: true validates :billing_email, email_format: { message: :invalid }, allow_blank: true
validates :invoice_type, :due_date, :currency, :seller_name, validates :due_date, :currency, :seller_name,
:seller_iban, :buyer_name, :invoice_items, :vat_prc, presence: true :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 def set_invoice_number
last_no = Invoice.order(number: :desc).where('number IS NOT NULL').limit(1).pluck(:number).first 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 false
end 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 class << self
def cancel_overdue_invoices def cancel_overdue_invoices
STDOUT << "#{Time.zone.now.utc} - Cancelling overdue invoices\n" unless Rails.env.test? STDOUT << "#{Time.zone.now.utc} - Cancelling overdue invoices\n" unless Rails.env.test?
@ -152,15 +150,31 @@ class Invoice < ActiveRecord::Base
invoice_items invoice_items
end end
def sum_without_vat def subtotal
(items.map(&:item_sum_without_vat).sum).round(2) invoice_items.map(&:item_sum_without_vat).reduce(:+)
end end
def vat def vat_amount
(sum_without_vat * vat_prc).round(2) return 0 unless vat_rate
subtotal * vat_rate / 100
end end
def sum def total
(sum_without_vat + vat).round(2) 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
end end

View file

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

@ -7,6 +7,9 @@
<dt><%= Registrar.human_attribute_name :vat_no %></dt> <dt><%= Registrar.human_attribute_name :vat_no %></dt>
<dd><%= registrar.vat_no %></dd> <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> <dt><%= Registrar.human_attribute_name :accounting_customer_code %></dt>
<dd><%= registrar.accounting_customer_code %></dd> <dd><%= registrar.accounting_customer_code %></dd>

View file

@ -17,6 +17,19 @@
</div> </div>
</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="form-group">
<div class="col-md-4 control-label"> <div class="col-md-4 control-label">
<%= f.label :accounting_customer_code %> <%= f.label :accounting_customer_code %>

View file

@ -33,11 +33,11 @@
.col-md-3 .col-md-3
.form-group .form-group
= f.label t(:minimum_total) = 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 .col-md-3
.form-group .form-group
= f.label t(:maximum_total) = 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;'} .col-md-3{style: 'padding-top: 25px;'}
%button.btn.btn-default %button.btn.btn-default
&nbsp; &nbsp;
@ -67,7 +67,7 @@
%td{class: 'text-danger'}= t(:unpaid) %td{class: 'text-danger'}= t(:unpaid)
%td= l(x.due_date, format: :date_long) %td= l(x.due_date, format: :date_long)
%td= currency(x.sum) %td= currency(x.total)
.row .row
.col-md-12 .col-md-12
= paginate @invoices = paginate @invoices

View file

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

View file

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

View file

@ -15,7 +15,7 @@ require 'rails/all'
# you've limited to :test, :development, or :production. # you've limited to :test, :development, or :production.
Bundler.require(*Rails.groups) Bundler.require(*Rails.groups)
module Registry module DomainNameRegistry
class Application < Rails::Application class Application < Rails::Application
# Settings in config/environments/* take precedence over those specified here. # Settings in config/environments/* take precedence over those specified here.
# Application configuration should go into files in config/initializers # Application configuration should go into files in config/initializers

View file

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

View file

@ -538,7 +538,6 @@ en:
invoice_number: Invoice no. invoice_number: Invoice no.
seller: 'Seller' seller: 'Seller'
prepayment: 'Prepayment' prepayment: 'Prepayment'
vat: 'VAT (%{vat_prc}%)'
unpaid: 'Unpaid' unpaid: 'Unpaid'
your_current_account_balance_is: 'Your current account balance is %{balance} %{currency}' your_current_account_balance_is: 'Your current account balance is %{balance} %{currency}'
billing: 'Billing' billing: 'Billing'
@ -556,7 +555,6 @@ en:
unit: 'Unit' unit: 'Unit'
price: 'Price' price: 'Price'
total: 'Total' total: 'Total'
total_without_vat: 'Total without VAT'
paid_at: 'Paid at' paid_at: 'Paid at'
invoice: 'Invoice' invoice: 'Invoice'
bank_statements: 'Bank statements' bank_statements: 'Bank statements'
@ -762,5 +760,6 @@ en:
attributes: attributes:
vat_no: VAT number vat_no: VAT number
vat_rate: VAT rate
ipv4: IPv4 ipv4: IPv4
ipv6: IPv6 ipv6: IPv6

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

@ -998,13 +998,12 @@ CREATE TABLE invoices (
id integer NOT NULL, id integer NOT NULL,
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,
invoice_type character varying NOT NULL,
due_date timestamp without time zone NOT NULL, due_date timestamp without time zone NOT NULL,
payment_term character varying, payment_term character varying,
currency character varying NOT NULL, currency character varying NOT NULL,
description character varying, description character varying,
reference_no character varying, reference_no character varying,
vat_prc numeric(10,2) NOT NULL, vat_rate numeric(4,3),
paid_at timestamp without time zone, paid_at timestamp without time zone,
seller_id integer, seller_id integer,
seller_name character varying NOT NULL, seller_name character varying NOT NULL,
@ -1037,8 +1036,9 @@ CREATE TABLE invoices (
updator_str character varying, updator_str character varying,
number integer, number integer,
cancelled_at timestamp without time zone, cancelled_at timestamp without time zone,
sum_cache numeric(10,2), total numeric(10,2) NOT NULL,
in_directo boolean DEFAULT false in_directo boolean DEFAULT false,
buyer_vat_no character varying
); );
@ -2154,11 +2154,11 @@ CREATE TABLE registrars (
code character varying NOT NULL, code character varying NOT NULL,
website character varying, website character varying,
accounting_customer_code character varying NOT NULL, accounting_customer_code character varying NOT NULL,
vat boolean,
legacy_id integer, legacy_id integer,
reference_no character varying, reference_no character varying,
test_registrar boolean DEFAULT false, test_registrar boolean DEFAULT false,
language character varying NOT NULL language character varying NOT NULL,
vat_rate numeric(4,3)
); );
@ -4669,6 +4669,16 @@ INSERT INTO schema_migrations (version) VALUES ('20180214213743');
INSERT INTO schema_migrations (version) VALUES ('20180218004148'); 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 ('20180306180401');
INSERT INTO schema_migrations (version) VALUES ('20180306181538'); INSERT INTO schema_migrations (version) VALUES ('20180306181538');
@ -4695,3 +4705,11 @@ INSERT INTO schema_migrations (version) VALUES ('20180309053921');
INSERT INTO schema_migrations (version) VALUES ('20180309054510'); 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');

View file

@ -1489,7 +1489,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="-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="-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="-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="-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> <text text-anchor="start" x="1600.5" y="-2309.3" font-family="Times,serif" font-size="14.00">reference_no :string</text>
</g> </g>
@ -1614,13 +1613,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="-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="-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="-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="-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="-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="-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="-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="-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="-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="-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> <text text-anchor="start" x="121.5" y="-1391.3" font-family="Times,serif" font-size="14.00">seller_name :string</text>
@ -1653,7 +1651,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="-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="-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="-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> </g>
<!-- Registrar&#45;&gt;Invoice --> <!-- Registrar&#45;&gt;Invoice -->
<g id="edge64" class="edge"><title>Registrar&#45;&gt;Invoice</title> <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

View file

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

View file

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

View file

@ -13,10 +13,8 @@ describe Invoice do
"Currency is missing", "Currency is missing",
"Due date is missing", "Due date is missing",
"Invoice items is missing", "Invoice items is missing",
"Invoice type is missing",
"Seller iban is missing", "Seller iban is missing",
"Seller name is missing", "Seller name is missing",
"Vat prc is missing"
]) ])
end end
@ -52,20 +50,6 @@ describe Invoice do
@invoice.seller_address.should == 'Paldiski mnt. 123, Tallinn' @invoice.seller_address.should == 'Paldiski mnt. 123, Tallinn'
end 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 it 'should cancel overdue invoices' do
create(:invoice, created_at: Time.zone.now - 35.days, due_date: Time.zone.now - 30.days) create(:invoice, created_at: Time.zone.now - 35.days, due_date: Time.zone.now - 30.days)
Invoice.cancel_overdue_invoices Invoice.cancel_overdue_invoices

View file

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

View file

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

View file

@ -17,7 +17,8 @@ goodnames:
reg_no: 12345 reg_no: 12345
code: goodnames code: goodnames
email: info@goodnames.test email: info@goodnames.test
country_code: US country_code: DE
vat_no: DE123456789
accounting_customer_code: goodnames accounting_customer_code: goodnames
language: en language: en
@ -29,3 +30,23 @@ not_in_use:
country_code: US country_code: US
accounting_customer_code: any accounting_customer_code: any
language: en 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

@ -1,7 +1,7 @@
require 'test_helper' require 'test_helper'
class AdminAreaNewMailTemplateTest < ActionDispatch::IntegrationTest class AdminAreaNewMailTemplateTest < ActionDispatch::IntegrationTest
def setup setup do
login_as users(:admin) login_as users(:admin)
end 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

@ -12,6 +12,7 @@ class AdminAreaNewRegistrarTest < ActionDispatch::IntegrationTest
fill_in 'Name', with: 'Brand new names' fill_in 'Name', with: 'Brand new names'
fill_in 'Reg no', with: '55555555' fill_in 'Reg no', with: '55555555'
fill_in 'Contact e-mail', with: 'test@example.com' fill_in 'Contact e-mail', with: 'test@example.com'
select 'United States', from: 'Country'
fill_in 'Accounting customer code', with: 'test' fill_in 'Accounting customer code', with: 'test'
fill_in '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
setup do
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

@ -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

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

@ -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

@ -29,7 +29,7 @@ class RegistrarTest < ActiveSupport::TestCase
assert @registrar.invalid? assert @registrar.invalid?
end end
def test_requires_country_code def test_invalid_without_country_code
@registrar.country_code = '' @registrar.country_code = ''
assert @registrar.invalid? assert @registrar.invalid?
end 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

@ -14,6 +14,7 @@ require 'webmock/minitest'
require 'support/rails5_assetions' # Remove once upgraded to Rails 5 require 'support/rails5_assetions' # Remove once upgraded to Rails 5
Setting.address_processing = false Setting.address_processing = false
Setting.registry_country_code = 'US'
class ActiveSupport::TestCase class ActiveSupport::TestCase
include FactoryBot::Syntax::Methods include FactoryBot::Syntax::Methods