mirror of
https://github.com/internetee/registry.git
synced 2025-06-07 21:25:39 +02:00
Refactor and improve invoices
- `runner 'Invoice.cancel_overdue_invoices'` in `schedule.rb` is changed to `rake 'invoices:cancel_overdue'`. - `invoices.payment_term` database column is removed and its value is hardcoded in UI. - `invoices.paid_at` is removed as unused - `invoices.due_date` column's type is now `date`. - `Invoice#invoice_items` renamed to `Invoice#items` and `Invoice` interface to get a list of items is unified. - Default date format in UI. - Default translations are used. - Tests improved. - Specs converted to tests and removed along with factories. - Database structure improved.
This commit is contained in:
parent
d86ec026e3
commit
a97728c0f3
65 changed files with 758 additions and 341 deletions
|
@ -33,13 +33,8 @@ module Admin
|
||||||
end
|
end
|
||||||
|
|
||||||
def cancel
|
def cancel
|
||||||
if @invoice.cancel
|
@invoice.cancel
|
||||||
flash[:notice] = t(:record_updated)
|
redirect_to [:admin, @invoice], notice: t('.cancelled')
|
||||||
redirect_to([:admin, @invoice])
|
|
||||||
else
|
|
||||||
flash.now[:alert] = t(:failed_to_update_record)
|
|
||||||
render :show
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
|
||||||
def forward
|
def forward
|
||||||
|
|
|
@ -6,8 +6,7 @@ class Registrar
|
||||||
|
|
||||||
def index
|
def index
|
||||||
params[:q] ||= {}
|
params[:q] ||= {}
|
||||||
invoices = current_registrar_user.registrar.invoices
|
invoices = current_registrar_user.registrar.invoices.includes(:items, :account_activity)
|
||||||
.includes(:invoice_items, :account_activity)
|
|
||||||
|
|
||||||
normalize_search_parameters do
|
normalize_search_parameters do
|
||||||
@q = invoices.search(params[:q])
|
@q = invoices.search(params[:q])
|
||||||
|
@ -35,13 +34,8 @@ class Registrar
|
||||||
end
|
end
|
||||||
|
|
||||||
def cancel
|
def cancel
|
||||||
if @invoice.cancel
|
@invoice.cancel
|
||||||
flash[:notice] = t(:record_updated)
|
redirect_to [:registrar, @invoice], notice: t('.cancelled')
|
||||||
redirect_to([:registrar, @invoice])
|
|
||||||
else
|
|
||||||
flash.now[:alert] = t(:failed_to_update_record)
|
|
||||||
render :show
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
|
||||||
def download_pdf
|
def download_pdf
|
||||||
|
@ -58,18 +52,7 @@ class Registrar
|
||||||
def normalize_search_parameters
|
def normalize_search_parameters
|
||||||
params[:q][:total_gteq].gsub!(',', '.') if params[:q][:total_gteq]
|
params[:q][:total_gteq].gsub!(',', '.') if params[:q][:total_gteq]
|
||||||
params[:q][:total_lteq].gsub!(',', '.') if params[:q][:total_lteq]
|
params[:q][:total_lteq].gsub!(',', '.') if params[:q][:total_lteq]
|
||||||
|
|
||||||
ca_cache = params[:q][:due_date_lteq]
|
|
||||||
begin
|
|
||||||
end_time = params[:q][:due_date_lteq].try(:to_date)
|
|
||||||
params[:q][:due_date_lteq] = end_time.try(:end_of_day)
|
|
||||||
rescue
|
|
||||||
logger.warn('Invalid date')
|
|
||||||
end
|
|
||||||
|
|
||||||
yield
|
yield
|
||||||
|
|
||||||
params[:q][:due_date_lteq] = ca_cache
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -29,7 +29,7 @@ class Registrar
|
||||||
if @payment.valid_response_from_intermediary? && @payment.settled_payment?
|
if @payment.valid_response_from_intermediary? && @payment.settled_payment?
|
||||||
@payment.complete_transaction
|
@payment.complete_transaction
|
||||||
|
|
||||||
if invoice.binded?
|
if invoice.paid?
|
||||||
flash[:notice] = t(:pending_applied)
|
flash[:notice] = t(:pending_applied)
|
||||||
else
|
else
|
||||||
flash[:alert] = t(:something_wrong)
|
flash[:alert] = t(:something_wrong)
|
||||||
|
|
|
@ -41,9 +41,7 @@ class BankTransaction < ActiveRecord::Base
|
||||||
return unless registrar
|
return unless registrar
|
||||||
return unless invoice_num
|
return unless invoice_num
|
||||||
return unless invoice
|
return unless invoice
|
||||||
|
return unless invoice.payable?
|
||||||
return if invoice.binded?
|
|
||||||
return if invoice.cancelled?
|
|
||||||
|
|
||||||
return if invoice.total != sum
|
return if invoice.total != sum
|
||||||
create_activity(registrar, invoice)
|
create_activity(registrar, invoice)
|
||||||
|
@ -62,7 +60,7 @@ class BankTransaction < ActiveRecord::Base
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
|
|
||||||
if invoice.binded?
|
if invoice.paid?
|
||||||
errors.add(:base, I18n.t('invoice_is_already_binded'))
|
errors.add(:base, I18n.t('invoice_is_already_binded'))
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
|
|
28
app/models/concerns/invoice/cancellable.rb
Normal file
28
app/models/concerns/invoice/cancellable.rb
Normal file
|
@ -0,0 +1,28 @@
|
||||||
|
module Concerns
|
||||||
|
module Invoice
|
||||||
|
module Cancellable
|
||||||
|
extend ActiveSupport::Concern
|
||||||
|
|
||||||
|
included do
|
||||||
|
scope :non_cancelled, -> { where(cancelled_at: nil) }
|
||||||
|
end
|
||||||
|
|
||||||
|
def cancellable?
|
||||||
|
unpaid? && not_cancelled?
|
||||||
|
end
|
||||||
|
|
||||||
|
def cancel
|
||||||
|
raise 'Invoice cannot be cancelled' unless cancellable?
|
||||||
|
update!(cancelled_at: Time.zone.now)
|
||||||
|
end
|
||||||
|
|
||||||
|
def cancelled?
|
||||||
|
cancelled_at
|
||||||
|
end
|
||||||
|
|
||||||
|
def not_cancelled?
|
||||||
|
!cancelled?
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
28
app/models/concerns/invoice/payable.rb
Normal file
28
app/models/concerns/invoice/payable.rb
Normal file
|
@ -0,0 +1,28 @@
|
||||||
|
module Concerns
|
||||||
|
module Invoice
|
||||||
|
module Payable
|
||||||
|
extend ActiveSupport::Concern
|
||||||
|
|
||||||
|
included do
|
||||||
|
scope :unpaid, -> { where('id NOT IN (SELECT invoice_id FROM account_activities WHERE' \
|
||||||
|
' invoice_id IS NOT NULL)') }
|
||||||
|
end
|
||||||
|
|
||||||
|
def payable?
|
||||||
|
unpaid? && not_cancelled?
|
||||||
|
end
|
||||||
|
|
||||||
|
def paid?
|
||||||
|
account_activity
|
||||||
|
end
|
||||||
|
|
||||||
|
def receipt_date
|
||||||
|
account_activity.created_at.to_date
|
||||||
|
end
|
||||||
|
|
||||||
|
def unpaid?
|
||||||
|
!paid?
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
|
@ -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(in_directo: false).where(cancelled_at: nil)
|
new_trans = Invoice.where(in_directo: false).non_cancelled
|
||||||
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")
|
||||||
|
@ -26,7 +26,7 @@ class Directo < ActiveRecord::Base
|
||||||
xml.invoice(
|
xml.invoice(
|
||||||
"SalesAgent" => Setting.directo_sales_agent,
|
"SalesAgent" => Setting.directo_sales_agent,
|
||||||
"Number" => num,
|
"Number" => num,
|
||||||
"InvoiceDate" => invoice.created_at.strftime("%Y-%m-%d"),
|
"InvoiceDate" => invoice.issue_date.strftime("%Y-%m-%d"),
|
||||||
"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
|
||||||
|
|
|
@ -1,16 +1,16 @@
|
||||||
class Invoice < ActiveRecord::Base
|
class Invoice < ActiveRecord::Base
|
||||||
include Versions
|
include Versions
|
||||||
|
include Concerns::Invoice::Cancellable
|
||||||
|
include Concerns::Invoice::Payable
|
||||||
|
|
||||||
belongs_to :seller, class_name: 'Registrar'
|
belongs_to :seller, class_name: 'Registrar'
|
||||||
belongs_to :buyer, class_name: 'Registrar'
|
belongs_to :buyer, class_name: 'Registrar'
|
||||||
has_one :account_activity
|
has_one :account_activity
|
||||||
has_many :invoice_items
|
has_many :items, class_name: 'InvoiceItem', dependent: :destroy
|
||||||
has_many :directo_records, as: :item, class_name: 'Directo'
|
has_many :directo_records, as: :item, class_name: 'Directo'
|
||||||
|
|
||||||
accepts_nested_attributes_for :invoice_items
|
accepts_nested_attributes_for :items
|
||||||
|
|
||||||
scope :unbinded, lambda {
|
|
||||||
where('id NOT IN (SELECT invoice_id FROM account_activities where invoice_id IS NOT NULL)')
|
|
||||||
}
|
|
||||||
scope :all_columns, ->{select("invoices.*")}
|
scope :all_columns, ->{select("invoices.*")}
|
||||||
scope :sort_due_date_column, ->{all_columns.select("CASE WHEN invoices.cancelled_at is not null THEN
|
scope :sort_due_date_column, ->{all_columns.select("CASE WHEN invoices.cancelled_at is not null THEN
|
||||||
(invoices.cancelled_at + interval '100 year') ELSE
|
(invoices.cancelled_at + interval '100 year') ELSE
|
||||||
|
@ -24,11 +24,14 @@ class Invoice < ActiveRecord::Base
|
||||||
scope :sort_by_sort_receipt_date_asc, ->{sort_receipt_date_column.order("sort_receipt_date ASC")}
|
scope :sort_by_sort_receipt_date_asc, ->{sort_receipt_date_column.order("sort_receipt_date ASC")}
|
||||||
scope :sort_by_sort_receipt_date_desc, ->{sort_receipt_date_column.order("sort_receipt_date DESC")}
|
scope :sort_by_sort_receipt_date_desc, ->{sort_receipt_date_column.order("sort_receipt_date DESC")}
|
||||||
|
|
||||||
|
scope :overdue, -> { unpaid.non_cancelled.where('due_date < ?', Time.zone.today) }
|
||||||
|
|
||||||
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 :issue_date, presence: true
|
||||||
validates :due_date, :currency, :seller_name,
|
validates :due_date, :currency, :seller_name,
|
||||||
:seller_iban, :buyer_name, :invoice_items, presence: true
|
:seller_iban, :buyer_name, :items, presence: true
|
||||||
validates :vat_rate, numericality: { greater_than_or_equal_to: 0, less_than: 100 },
|
validates :vat_rate, numericality: { greater_than_or_equal_to: 0, less_than: 100 },
|
||||||
allow_nil: true
|
allow_nil: true
|
||||||
|
|
||||||
|
@ -56,35 +59,6 @@ class Invoice < ActiveRecord::Base
|
||||||
false
|
false
|
||||||
end
|
end
|
||||||
|
|
||||||
class << self
|
|
||||||
def cancel_overdue_invoices
|
|
||||||
STDOUT << "#{Time.zone.now.utc} - Cancelling overdue invoices\n" unless Rails.env.test?
|
|
||||||
|
|
||||||
cr_at = Time.zone.now - Setting.days_to_keep_overdue_invoices_active.days
|
|
||||||
invoices = Invoice.unbinded.where(
|
|
||||||
'due_date < ? AND cancelled_at IS NULL', cr_at
|
|
||||||
)
|
|
||||||
|
|
||||||
unless Rails.env.test?
|
|
||||||
invoices.each do |m|
|
|
||||||
STDOUT << "#{Time.zone.now.utc} Invoice.cancel_overdue_invoices: ##{m.id}\n"
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
count = invoices.update_all(cancelled_at: Time.zone.now)
|
|
||||||
|
|
||||||
STDOUT << "#{Time.zone.now.utc} - Successfully cancelled #{count} overdue invoices\n" unless Rails.env.test?
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
def binded?
|
|
||||||
account_activity.present?
|
|
||||||
end
|
|
||||||
|
|
||||||
def receipt_date
|
|
||||||
account_activity.try(:created_at)
|
|
||||||
end
|
|
||||||
|
|
||||||
def to_s
|
def to_s
|
||||||
I18n.t('invoice_no', no: number)
|
I18n.t('invoice_no', no: number)
|
||||||
end
|
end
|
||||||
|
@ -119,25 +93,6 @@ class Invoice < ActiveRecord::Base
|
||||||
"invoice-#{number}.pdf"
|
"invoice-#{number}.pdf"
|
||||||
end
|
end
|
||||||
|
|
||||||
def cancel
|
|
||||||
if binded?
|
|
||||||
errors.add(:base, I18n.t('cannot_cancel_paid_invoice'))
|
|
||||||
return false
|
|
||||||
end
|
|
||||||
|
|
||||||
if cancelled?
|
|
||||||
errors.add(:base, I18n.t('cannot_cancel_cancelled_invoice'))
|
|
||||||
return false
|
|
||||||
end
|
|
||||||
|
|
||||||
self.cancelled_at = Time.zone.now
|
|
||||||
save
|
|
||||||
end
|
|
||||||
|
|
||||||
def cancelled?
|
|
||||||
cancelled_at.present?
|
|
||||||
end
|
|
||||||
|
|
||||||
def forward(html)
|
def forward(html)
|
||||||
return false unless valid?
|
return false unless valid?
|
||||||
return false unless billing_email.present?
|
return false unless billing_email.present?
|
||||||
|
@ -146,12 +101,8 @@ class Invoice < ActiveRecord::Base
|
||||||
true
|
true
|
||||||
end
|
end
|
||||||
|
|
||||||
def items
|
|
||||||
invoice_items
|
|
||||||
end
|
|
||||||
|
|
||||||
def subtotal
|
def subtotal
|
||||||
invoice_items.map(&:item_sum_without_vat).reduce(:+)
|
items.map(&:item_sum_without_vat).reduce(:+)
|
||||||
end
|
end
|
||||||
|
|
||||||
def vat_amount
|
def vat_amount
|
||||||
|
@ -164,6 +115,10 @@ class Invoice < ActiveRecord::Base
|
||||||
read_attribute(:total)
|
read_attribute(:total)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def each
|
||||||
|
items.each { |item| yield item }
|
||||||
|
end
|
||||||
|
|
||||||
private
|
private
|
||||||
|
|
||||||
def apply_default_vat_rate
|
def apply_default_vat_rate
|
||||||
|
|
|
@ -3,6 +3,6 @@ class InvoiceItem < ActiveRecord::Base
|
||||||
belongs_to :invoice
|
belongs_to :invoice
|
||||||
|
|
||||||
def item_sum_without_vat
|
def item_sum_without_vat
|
||||||
(amount * price).round(2)
|
(price * quantity).round(2)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -51,8 +51,8 @@ class Registrar < ActiveRecord::Base
|
||||||
|
|
||||||
def issue_prepayment_invoice(amount, description = nil)
|
def issue_prepayment_invoice(amount, description = nil)
|
||||||
invoices.create(
|
invoices.create(
|
||||||
due_date: (Time.zone.now.to_date + Setting.days_to_keep_invoices_active.days).end_of_day,
|
issue_date: Time.zone.today,
|
||||||
payment_term: 'prepayment',
|
due_date: (Time.zone.now + Setting.days_to_keep_invoices_active.days).to_date,
|
||||||
description: description,
|
description: description,
|
||||||
currency: 'EUR',
|
currency: 'EUR',
|
||||||
seller_name: Setting.registry_juridical_name,
|
seller_name: Setting.registry_juridical_name,
|
||||||
|
@ -82,11 +82,11 @@ class Registrar < ActiveRecord::Base
|
||||||
buyer_url: website,
|
buyer_url: website,
|
||||||
buyer_email: email,
|
buyer_email: email,
|
||||||
reference_no: reference_no,
|
reference_no: reference_no,
|
||||||
invoice_items_attributes: [
|
items_attributes: [
|
||||||
{
|
{
|
||||||
description: 'prepayment',
|
description: 'prepayment',
|
||||||
unit: 'piece',
|
unit: 'piece',
|
||||||
amount: 1,
|
quantity: 1,
|
||||||
price: amount
|
price: amount
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
|
33
app/services/overdue_invoice_canceller.rb
Normal file
33
app/services/overdue_invoice_canceller.rb
Normal file
|
@ -0,0 +1,33 @@
|
||||||
|
class OverdueInvoiceCanceller
|
||||||
|
attr_reader :invoices
|
||||||
|
attr_reader :delay
|
||||||
|
|
||||||
|
def initialize(invoices: Invoice.overdue, delay: self.class.delay)
|
||||||
|
@invoices = invoices
|
||||||
|
@delay = delay
|
||||||
|
end
|
||||||
|
|
||||||
|
def self.default_delay
|
||||||
|
30.days
|
||||||
|
end
|
||||||
|
|
||||||
|
def self.delay
|
||||||
|
Setting.days_to_keep_overdue_invoices_active&.days || default_delay
|
||||||
|
end
|
||||||
|
|
||||||
|
def cancel
|
||||||
|
invoices.each do |invoice|
|
||||||
|
next unless cancellable?(invoice)
|
||||||
|
|
||||||
|
invoice.cancel
|
||||||
|
yield invoice if block_given?
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
private
|
||||||
|
|
||||||
|
def cancellable?(invoice)
|
||||||
|
due_date_with_delay = invoice.due_date + delay
|
||||||
|
due_date_with_delay.past?
|
||||||
|
end
|
||||||
|
end
|
|
@ -61,7 +61,7 @@
|
||||||
%th{class: 'col-xs-2'}
|
%th{class: 'col-xs-2'}
|
||||||
= sort_link(@q, 'activity_type')
|
= sort_link(@q, 'activity_type')
|
||||||
%th{class: 'col-xs-3'}
|
%th{class: 'col-xs-3'}
|
||||||
= sort_link(@q, 'created_at', t(:receipt_date))
|
= sort_link(@q, 'created_at', AccountActivity.human_attribute_name(:created_at))
|
||||||
%th{class: 'col-xs-2'}
|
%th{class: 'col-xs-2'}
|
||||||
= sort_link(@q, 'sum')
|
= sort_link(@q, 'sum')
|
||||||
%tbody
|
%tbody
|
||||||
|
|
|
@ -16,18 +16,18 @@
|
||||||
%th{class: 'col-xs-3'}
|
%th{class: 'col-xs-3'}
|
||||||
= sort_link(@q, :sort_receipt_date, "Receipt date")
|
= sort_link(@q, :sort_receipt_date, "Receipt date")
|
||||||
%tbody
|
%tbody
|
||||||
- @invoices.each do |x|
|
- @invoices.each do |invoice|
|
||||||
%tr
|
%tr
|
||||||
%td= link_to(x, [:admin, x])
|
%td= link_to(invoice, [:admin, invoice])
|
||||||
%td= link_to(x.buyer_name, admin_registrar_path(x.buyer_id))
|
%td= link_to(invoice.buyer_name, admin_registrar_path(invoice.buyer_id))
|
||||||
- if x.cancelled?
|
- if invoice.cancelled?
|
||||||
%td.text-grey= t(:cancelled)
|
%td.text-grey= t(:cancelled)
|
||||||
- else
|
- else
|
||||||
%td= l(x.due_date, format: :date_long)
|
%td= l invoice.due_date
|
||||||
|
|
||||||
- if x.binded?
|
- if invoice.paid?
|
||||||
%td= l(x.receipt_date, format: :date_long)
|
%td= l invoice.receipt_date
|
||||||
- elsif x.cancelled?
|
- elsif invoice.cancelled?
|
||||||
%td.text-grey= t(:cancelled)
|
%td.text-grey= t(:cancelled)
|
||||||
- else
|
- else
|
||||||
%td.text-danger= t(:unpaid)
|
%td.text-danger= t(:unpaid)
|
||||||
|
|
|
@ -4,11 +4,11 @@
|
||||||
= @invoice
|
= @invoice
|
||||||
.col-sm-8
|
.col-sm-8
|
||||||
%h1.text-right.text-center-xs
|
%h1.text-right.text-center-xs
|
||||||
- unless @invoice.binded?
|
- if @invoice.unpaid?
|
||||||
= link_to(t(:payment_received), new_admin_bank_statement_path(invoice_id: @invoice.id), class: 'btn btn-default')
|
= link_to(t(:payment_received), new_admin_bank_statement_path(invoice_id: @invoice.id), class: 'btn btn-default')
|
||||||
= link_to(t(:download), admin_invoice_download_pdf_path(@invoice), class: 'btn btn-default')
|
= link_to(t(:download), admin_invoice_download_pdf_path(@invoice), class: 'btn btn-default')
|
||||||
= link_to(t(:forward), admin_invoice_forward_path(@invoice), class: 'btn btn-default')
|
= link_to(t(:forward), admin_invoice_forward_path(@invoice), class: 'btn btn-default')
|
||||||
- if !@invoice.cancelled? && !@invoice.binded?
|
- if @invoice.cancellable?
|
||||||
= link_to(t(:cancel), cancel_admin_invoice_path(@invoice), method: :patch, class: 'btn btn-warning')
|
= link_to(t(:cancel), cancel_admin_invoice_path(@invoice), method: :patch, class: 'btn btn-warning')
|
||||||
= link_to(t(:back), admin_invoices_path, class: 'btn btn-default')
|
= link_to(t(:back), admin_invoices_path, class: 'btn btn-default')
|
||||||
%hr
|
%hr
|
||||||
|
|
|
@ -44,7 +44,7 @@
|
||||||
%th{class: 'col-xs-2'}
|
%th{class: 'col-xs-2'}
|
||||||
= sort_link(@q, 'activity_type')
|
= sort_link(@q, 'activity_type')
|
||||||
%th{class: 'col-xs-3'}
|
%th{class: 'col-xs-3'}
|
||||||
= sort_link(@q, 'created_at', t(:receipt_date))
|
= sort_link(@q, 'created_at', AccountActivity.human_attribute_name(:created_at))
|
||||||
%th{class: 'col-xs-2'}
|
%th{class: 'col-xs-2'}
|
||||||
= sort_link(@q, 'sum')
|
= sort_link(@q, 'sum')
|
||||||
%tbody
|
%tbody
|
||||||
|
|
|
@ -52,22 +52,22 @@
|
||||||
%thead
|
%thead
|
||||||
%tr
|
%tr
|
||||||
%th{class: 'col-xs-3'}= t(:invoice)
|
%th{class: 'col-xs-3'}= t(:invoice)
|
||||||
%th{class: 'col-xs-3'}= t(:receipt_date)
|
%th{class: 'col-xs-3'}= Invoice.human_attribute_name :receipt_date
|
||||||
%th{class: 'col-xs-3'}= t(:due_date)
|
%th{class: 'col-xs-3'}= t(:due_date)
|
||||||
%th{class: 'col-xs-3'}= t(:total)
|
%th{class: 'col-xs-3'}= t(:total)
|
||||||
%tbody
|
%tbody
|
||||||
- @invoices.each do |x|
|
- @invoices.each do |invoice|
|
||||||
%tr
|
%tr.invoice
|
||||||
%td= link_to(x, [:registrar, x])
|
%td= link_to(invoice, [:registrar, invoice])
|
||||||
- if x.receipt_date
|
- if invoice.paid?
|
||||||
%td= l(x.receipt_date, format: :date_long)
|
%td= l invoice.receipt_date
|
||||||
- elsif x.cancelled?
|
- elsif invoice.cancelled?
|
||||||
%td.text-grey= t(:cancelled)
|
%td.text-grey= t(:cancelled)
|
||||||
- else
|
- else
|
||||||
%td{class: 'text-danger'}= t(:unpaid)
|
%td{class: 'text-danger'}= t(:unpaid)
|
||||||
|
|
||||||
%td= l(x.due_date, format: :date_long)
|
%td= l invoice.due_date
|
||||||
%td= currency(x.total)
|
%td= currency(invoice.total)
|
||||||
.row
|
.row
|
||||||
.col-md-12
|
.col-md-12
|
||||||
= paginate @invoices
|
= paginate @invoices
|
||||||
|
|
|
@ -2,28 +2,28 @@
|
||||||
%hr
|
%hr
|
||||||
%dl.dl-horizontal
|
%dl.dl-horizontal
|
||||||
%dt= t(:issue_date)
|
%dt= t(:issue_date)
|
||||||
%dd= l(@invoice.created_at, format: :date_long)
|
%dd= l @invoice.issue_date
|
||||||
|
|
||||||
- if @invoice.cancelled?
|
- if @invoice.cancelled?
|
||||||
%dt= t(:cancel_date)
|
%dt= Invoice.human_attribute_name :cancelled_at
|
||||||
%dd= l(@invoice.cancelled_at, format: :date_long)
|
%dd= l @invoice.cancelled_at
|
||||||
|
|
||||||
%dt= t(:due_date)
|
%dt= t(:due_date)
|
||||||
- if @invoice.cancelled?
|
- if @invoice.cancelled?
|
||||||
%dd.text-grey= t(:cancelled)
|
%dd.text-grey= t(:cancelled)
|
||||||
- else
|
- else
|
||||||
%dd= l(@invoice.due_date, format: :date_long)
|
%dd= l @invoice.due_date
|
||||||
|
|
||||||
%dt= t(:receipt_date)
|
%dt= Invoice.human_attribute_name :receipt_date
|
||||||
- if @invoice.binded?
|
- if @invoice.paid?
|
||||||
%dd= l(@invoice.receipt_date, format: :date_long)
|
%dd= l @invoice.receipt_date
|
||||||
- elsif @invoice.cancelled?
|
- elsif @invoice.cancelled?
|
||||||
%dd.text-grey= t(:cancelled)
|
%dd.text-grey= t(:cancelled)
|
||||||
- else
|
- else
|
||||||
%dd{class: 'text-danger'}= t(:unpaid)
|
%dd{class: 'text-danger'}= t(:unpaid)
|
||||||
|
|
||||||
%dt= t(:payment_term)
|
%dt= t(:payment_term)
|
||||||
%dd= t(@invoice.payment_term)
|
%dd Prepayment
|
||||||
|
|
||||||
%dt= t(:invoice_number)
|
%dt= t(:invoice_number)
|
||||||
%dd= @invoice.number
|
%dd= @invoice.number
|
||||||
|
|
|
@ -6,17 +6,17 @@
|
||||||
%tr
|
%tr
|
||||||
%th{class: 'col-xs-4'}= t(:description)
|
%th{class: 'col-xs-4'}= t(:description)
|
||||||
%th{class: 'col-xs-2'}= t(:unit)
|
%th{class: 'col-xs-2'}= t(:unit)
|
||||||
%th{class: 'col-xs-2'}= t(:amount)
|
%th{class: 'col-xs-2'}= InvoiceItem.human_attribute_name :quantity
|
||||||
%th{class: 'col-xs-2'}= t(:price)
|
%th{class: 'col-xs-2'}= t(:price)
|
||||||
%th{class: 'col-xs-2'}= t(:total)
|
%th{class: 'col-xs-2'}= t(:total)
|
||||||
%tbody
|
%tbody
|
||||||
- @invoice.items.each do |x|
|
- @invoice.each do |invoice_item|
|
||||||
%tr
|
%tr
|
||||||
%td= t(x.description)
|
%td= invoice_item.description
|
||||||
%td= x.unit
|
%td= invoice_item.unit
|
||||||
%td= currency(x.amount)
|
%td= invoice_item.quantity
|
||||||
%td= currency(x.price)
|
%td= currency(invoice_item.price)
|
||||||
%td= currency(x.item_sum_without_vat)
|
%td= currency(invoice_item.item_sum_without_vat)
|
||||||
%tfoot
|
%tfoot
|
||||||
%tr
|
%tr
|
||||||
%th{colspan: 3}
|
%th{colspan: 3}
|
||||||
|
|
|
@ -5,7 +5,7 @@
|
||||||
/ %dd= t(@invoice.document_name)
|
/ %dd= t(@invoice.document_name)
|
||||||
|
|
||||||
%dt= t(:issue_date)
|
%dt= t(:issue_date)
|
||||||
%dd= l(@invoice.created_at)
|
%dd= l(@invoice.date)
|
||||||
|
|
||||||
%dt= t(:due_date)
|
%dt= t(:due_date)
|
||||||
%dd= l(@invoice.due_date)
|
%dd= l(@invoice.due_date)
|
||||||
|
|
|
@ -149,21 +149,21 @@
|
||||||
%hr
|
%hr
|
||||||
%dl.dl-horizontal
|
%dl.dl-horizontal
|
||||||
%dt= t(:issue_date)
|
%dt= t(:issue_date)
|
||||||
%dd= l(@invoice.created_at, format: :date_long)
|
%dd= l @invoice.issue_date
|
||||||
|
|
||||||
- if @invoice.cancelled?
|
- if @invoice.cancelled?
|
||||||
%dt= t(:cancel_date)
|
%dt= Invoice.human_attribute_name :cancelled_at
|
||||||
%dd= l(@invoice.cancelled_at, format: :date_long)
|
%dd= l @invoice.cancelled_at,
|
||||||
|
|
||||||
%dt= t(:due_date)
|
%dt= t(:due_date)
|
||||||
- if @invoice.cancelled?
|
- if @invoice.cancelled?
|
||||||
%dd= t(:cancelled)
|
%dd= t(:cancelled)
|
||||||
- else
|
- else
|
||||||
%dd= l(@invoice.due_date, format: :date_long)
|
%dd= l @invoice.due_date
|
||||||
|
|
||||||
%dt= t(:receipt_date)
|
%dt= Invoice.human_attribute_name :receipt_date
|
||||||
- if @invoice.binded?
|
- if @invoice.paid?
|
||||||
%dd= l(@invoice.receipt_date, format: :date_long)
|
%dd= l @invoice.receipt_date
|
||||||
- elsif @invoice.cancelled?
|
- elsif @invoice.cancelled?
|
||||||
%dd= t(:cancelled)
|
%dd= t(:cancelled)
|
||||||
- else
|
- else
|
||||||
|
@ -173,7 +173,7 @@
|
||||||
%dd= @invoice.seller_contact_name
|
%dd= @invoice.seller_contact_name
|
||||||
|
|
||||||
%dt= t(:payment_term)
|
%dt= t(:payment_term)
|
||||||
%dd= t(@invoice.payment_term)
|
%dd Prepayment
|
||||||
|
|
||||||
%dt= t(:invoice_number)
|
%dt= t(:invoice_number)
|
||||||
%dd= @invoice.number
|
%dd= @invoice.number
|
||||||
|
@ -224,17 +224,17 @@
|
||||||
%tr
|
%tr
|
||||||
%th{class: 'col-xs-4'}= t(:description)
|
%th{class: 'col-xs-4'}= t(:description)
|
||||||
%th{class: 'col-xs-2'}= t(:unit)
|
%th{class: 'col-xs-2'}= t(:unit)
|
||||||
%th{class: 'col-xs-1'}= t(:amount)
|
%th{class: 'col-xs-1'}= InvoiceItem.human_attribute_name :quantity
|
||||||
%th{class: 'col-xs-3'}= t(:price)
|
%th{class: 'col-xs-3'}= t(:price)
|
||||||
%th{class: 'col-xs-2'}= t(:total)
|
%th{class: 'col-xs-2'}= t(:total)
|
||||||
%tbody
|
%tbody
|
||||||
- @invoice.items.each do |x|
|
- @invoice.each do |invoice_item|
|
||||||
%tr
|
%tr
|
||||||
%td= t(x.description)
|
%td= invoice_item.description
|
||||||
%td= x.unit
|
%td= invoice_item.unit
|
||||||
%td= currency(x.amount)
|
%td= invoice_item.quantity
|
||||||
%td= currency(x.price)
|
%td= currency(invoice_item.price)
|
||||||
%td= "#{currency(x.item_sum_without_vat)} #{@invoice.currency}"
|
%td= "#{currency(invoice_item.item_sum_without_vat)} #{@invoice.currency}"
|
||||||
%tfoot
|
%tfoot
|
||||||
%tr
|
%tr
|
||||||
%th{colspan: 3}
|
%th{colspan: 3}
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
- content_for :actions do
|
- content_for :actions do
|
||||||
= link_to(t(:download), download_pdf_registrar_invoice_path(@invoice), class: 'btn btn-default')
|
= link_to(t(:download), download_pdf_registrar_invoice_path(@invoice), class: 'btn btn-default')
|
||||||
= link_to(t(:forward), forward_registrar_invoice_path(@invoice), class: 'btn btn-default')
|
= link_to(t(:forward), forward_registrar_invoice_path(@invoice), class: 'btn btn-default')
|
||||||
- if !@invoice.cancelled? && !@invoice.binded?
|
- if @invoice.cancellable?
|
||||||
= link_to(t(:cancel), cancel_registrar_invoice_path(@invoice), method: :patch, class: 'btn btn-warning')
|
= link_to(t(:cancel), cancel_registrar_invoice_path(@invoice), method: :patch, class: 'btn btn-warning')
|
||||||
= link_to(t(:back), registrar_invoices_path, class: 'btn btn-default')
|
= link_to(t(:back), registrar_invoices_path, class: 'btn btn-default')
|
||||||
= render 'shared/title', name: @invoice.to_s
|
= render 'shared/title', name: @invoice.to_s
|
||||||
|
@ -15,6 +15,6 @@
|
||||||
.row
|
.row
|
||||||
.col-md-12= render 'registrar/invoices/partials/items'
|
.col-md-12= render 'registrar/invoices/partials/items'
|
||||||
|
|
||||||
- if !@invoice.cancelled? && !@invoice.binded?
|
- if @invoice.payable?
|
||||||
.row.semifooter
|
.row.semifooter
|
||||||
.col-md-6-offset-6.text-right= render 'registrar/invoices/partials/banklinks', locals: { payment_channels: PaymentOrders::PAYMENT_METHODS }
|
.col-md-6-offset-6.text-right= render 'registrar/invoices/partials/banklinks', locals: { payment_channels: PaymentOrders::PAYMENT_METHODS }
|
||||||
|
|
|
@ -40,7 +40,6 @@ if con.present? && con.table_exists?('settings')
|
||||||
Setting.save_default(:directo_monthly_number_max, 309999)
|
Setting.save_default(:directo_monthly_number_max, 309999)
|
||||||
Setting.save_default(:directo_monthly_number_last, 309901)
|
Setting.save_default(:directo_monthly_number_last, 309901)
|
||||||
Setting.save_default(:days_to_keep_invoices_active, 30)
|
Setting.save_default(:days_to_keep_invoices_active, 30)
|
||||||
Setting.save_default(:days_to_keep_overdue_invoices_active, 30)
|
|
||||||
Setting.save_default(:minimum_deposit, 0.0)
|
Setting.save_default(:minimum_deposit, 0.0)
|
||||||
Setting.save_default(:directo_receipt_payment_term, "R")
|
Setting.save_default(:directo_receipt_payment_term, "R")
|
||||||
Setting.save_default(:directo_receipt_product_name, "ETTEM06")
|
Setting.save_default(:directo_receipt_product_name, "ETTEM06")
|
||||||
|
|
5
config/locales/account_activities.en.yml
Normal file
5
config/locales/account_activities.en.yml
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
en:
|
||||||
|
activerecord:
|
||||||
|
attributes:
|
||||||
|
account_activity:
|
||||||
|
created_at: Receipt date
|
5
config/locales/admin/invoices.en.yml
Normal file
5
config/locales/admin/invoices.en.yml
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
en:
|
||||||
|
admin:
|
||||||
|
invoices:
|
||||||
|
cancel:
|
||||||
|
cancelled: Invoice has been cancelled
|
|
@ -523,12 +523,10 @@ en:
|
||||||
domain_not_found: 'Domain was not found'
|
domain_not_found: 'Domain was not found'
|
||||||
new_contact: 'New contact'
|
new_contact: 'New contact'
|
||||||
add_deposit: 'Add deposit'
|
add_deposit: 'Add deposit'
|
||||||
amount: 'Amount'
|
|
||||||
please_pay_the_following_invoice: 'Please pay the following invoice'
|
please_pay_the_following_invoice: 'Please pay the following invoice'
|
||||||
invoice_no: 'Invoice no. %{no}'
|
invoice_no: 'Invoice no. %{no}'
|
||||||
invoice_number: Invoice no.
|
invoice_number: Invoice no.
|
||||||
seller: 'Seller'
|
seller: 'Seller'
|
||||||
prepayment: 'Prepayment'
|
|
||||||
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'
|
||||||
|
@ -588,7 +586,6 @@ en:
|
||||||
refers to the computer that saves and forwards notices related to the Domain Names and their corresponding IP addresses in the Internet.
|
refers to the computer that saves and forwards notices related to the Domain Names and their corresponding IP addresses in the Internet.
|
||||||
account_activity: 'Account activity'
|
account_activity: 'Account activity'
|
||||||
account_activities: 'Account activities'
|
account_activities: 'Account activities'
|
||||||
receipt_date: 'Receipt date'
|
|
||||||
manual_binding: 'Manual binding'
|
manual_binding: 'Manual binding'
|
||||||
transaction_is_already_binded: 'Transaction is already binded'
|
transaction_is_already_binded: 'Transaction is already binded'
|
||||||
invoice_was_not_found: 'Invoice was not found'
|
invoice_was_not_found: 'Invoice was not found'
|
||||||
|
@ -614,9 +611,6 @@ en:
|
||||||
certificates: 'Certificates'
|
certificates: 'Certificates'
|
||||||
cancel: 'Cancel'
|
cancel: 'Cancel'
|
||||||
cancelled: 'Cancelled'
|
cancelled: 'Cancelled'
|
||||||
cancel_date: 'Cancel date'
|
|
||||||
cannot_cancel_paid_invoice: 'Cannot cancel paid invoice'
|
|
||||||
cannot_cancel_cancelled_invoice: 'Cannot cancel cancelled invoice'
|
|
||||||
cannot_bind_cancelled_invoice: 'Cannot bind cancelled invoice'
|
cannot_bind_cancelled_invoice: 'Cannot bind cancelled invoice'
|
||||||
minimum_invoice_no: 'Miminum invoice no'
|
minimum_invoice_no: 'Miminum invoice no'
|
||||||
maximum_invoice_no: 'Maximum invoice no'
|
maximum_invoice_no: 'Maximum invoice no'
|
||||||
|
|
|
@ -9,3 +9,6 @@ en:
|
||||||
payment_complete: Credit Card payment Complete
|
payment_complete: Credit Card payment Complete
|
||||||
index:
|
index:
|
||||||
reset_btn: Reset
|
reset_btn: Reset
|
||||||
|
|
||||||
|
cancel:
|
||||||
|
cancelled: Invoice has been cancelled
|
|
@ -22,7 +22,7 @@ if @cron_group == 'registry'
|
||||||
end
|
end
|
||||||
|
|
||||||
every :day, at: '12:10am' do
|
every :day, at: '12:10am' do
|
||||||
runner 'Invoice.cancel_overdue_invoices'
|
rake 'invoices:cancel_overdue'
|
||||||
end
|
end
|
||||||
|
|
||||||
# TODO
|
# TODO
|
||||||
|
|
|
@ -0,0 +1,5 @@
|
||||||
|
class RenameInvoiceItemsAmountToQuantity < ActiveRecord::Migration
|
||||||
|
def change
|
||||||
|
rename_column :invoice_items, :amount, :quantity
|
||||||
|
end
|
||||||
|
end
|
|
@ -0,0 +1,5 @@
|
||||||
|
class AddInvoiceItemsInvoiceIdFk < ActiveRecord::Migration
|
||||||
|
def change
|
||||||
|
add_foreign_key :invoice_items, :invoices, name: 'invoice_items_invoice_id_fk'
|
||||||
|
end
|
||||||
|
end
|
|
@ -0,0 +1,5 @@
|
||||||
|
class ChangeInvoiceItemsInvoiceIdToNotNull < ActiveRecord::Migration
|
||||||
|
def change
|
||||||
|
change_column_null :invoice_items, :invoice_id, false
|
||||||
|
end
|
||||||
|
end
|
|
@ -0,0 +1,5 @@
|
||||||
|
class ChangeInvoiceItemsQuantityToNotNull < ActiveRecord::Migration
|
||||||
|
def change
|
||||||
|
change_column_null :invoice_items, :quantity, false
|
||||||
|
end
|
||||||
|
end
|
|
@ -0,0 +1,5 @@
|
||||||
|
class ChangeInvoiceItemsUnitToNotNull < ActiveRecord::Migration
|
||||||
|
def change
|
||||||
|
change_column_null :invoice_items, :unit, false
|
||||||
|
end
|
||||||
|
end
|
|
@ -0,0 +1,5 @@
|
||||||
|
class ChangeInvoiceItemsPriceToNotNull < ActiveRecord::Migration
|
||||||
|
def change
|
||||||
|
change_column_null :invoice_items, :price, false
|
||||||
|
end
|
||||||
|
end
|
|
@ -0,0 +1,5 @@
|
||||||
|
class ChangeInvoicesDueDateToDate < ActiveRecord::Migration
|
||||||
|
def change
|
||||||
|
change_column :invoices, :due_date, :date, null: false
|
||||||
|
end
|
||||||
|
end
|
5
db/migrate/20181022100114_add_invoices_issue_date.rb
Normal file
5
db/migrate/20181022100114_add_invoices_issue_date.rb
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
class AddInvoicesIssueDate < ActiveRecord::Migration
|
||||||
|
def change
|
||||||
|
add_column :invoices, :issue_date, :date
|
||||||
|
end
|
||||||
|
end
|
5
db/migrate/20190311111718_remove_invoices_paid_at.rb
Normal file
5
db/migrate/20190311111718_remove_invoices_paid_at.rb
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
class RemoveInvoicesPaidAt < ActiveRecord::Migration
|
||||||
|
def change
|
||||||
|
remove_column :invoices, :paid_at
|
||||||
|
end
|
||||||
|
end
|
|
@ -0,0 +1,5 @@
|
||||||
|
class RemoveInvoicesPaymentTerm < ActiveRecord::Migration
|
||||||
|
def change
|
||||||
|
remove_column :invoices, :payment_term
|
||||||
|
end
|
||||||
|
end
|
|
@ -1039,11 +1039,11 @@ ALTER SEQUENCE public.epp_sessions_id_seq OWNED BY public.epp_sessions.id;
|
||||||
|
|
||||||
CREATE TABLE public.invoice_items (
|
CREATE TABLE public.invoice_items (
|
||||||
id integer NOT NULL,
|
id integer NOT NULL,
|
||||||
invoice_id integer,
|
invoice_id integer NOT NULL,
|
||||||
description character varying NOT NULL,
|
description character varying NOT NULL,
|
||||||
unit character varying,
|
unit character varying NOT NULL,
|
||||||
amount integer,
|
quantity integer NOT NULL,
|
||||||
price numeric(10,2),
|
price numeric(10,2) 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,
|
||||||
|
@ -1078,13 +1078,11 @@ CREATE TABLE public.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,
|
||||||
due_date timestamp without time zone NOT NULL,
|
due_date date NOT NULL,
|
||||||
payment_term character varying,
|
|
||||||
currency character varying NOT NULL,
|
currency character varying NOT NULL,
|
||||||
description character varying,
|
description character varying,
|
||||||
reference_no character varying NOT NULL,
|
reference_no character varying NOT NULL,
|
||||||
vat_rate numeric(4,3),
|
vat_rate numeric(4,3),
|
||||||
paid_at timestamp without time zone,
|
|
||||||
seller_id integer,
|
seller_id integer,
|
||||||
seller_name character varying NOT NULL,
|
seller_name character varying NOT NULL,
|
||||||
seller_reg_no character varying,
|
seller_reg_no character varying,
|
||||||
|
@ -1118,7 +1116,8 @@ CREATE TABLE public.invoices (
|
||||||
cancelled_at timestamp without time zone,
|
cancelled_at timestamp without time zone,
|
||||||
total numeric(10,2) NOT NULL,
|
total numeric(10,2) NOT NULL,
|
||||||
in_directo boolean DEFAULT false,
|
in_directo boolean DEFAULT false,
|
||||||
buyer_vat_no character varying
|
buyer_vat_no character varying,
|
||||||
|
issue_date date
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
||||||
|
@ -4234,6 +4233,14 @@ ALTER TABLE ONLY public.account_activities
|
||||||
ADD CONSTRAINT fk_rails_d2cc3c2fa9 FOREIGN KEY (price_id) REFERENCES public.prices(id);
|
ADD CONSTRAINT fk_rails_d2cc3c2fa9 FOREIGN KEY (price_id) REFERENCES public.prices(id);
|
||||||
|
|
||||||
|
|
||||||
|
--
|
||||||
|
-- Name: invoice_items_invoice_id_fk; Type: FK CONSTRAINT; Schema: public; Owner: -
|
||||||
|
--
|
||||||
|
|
||||||
|
ALTER TABLE ONLY public.invoice_items
|
||||||
|
ADD CONSTRAINT invoice_items_invoice_id_fk FOREIGN KEY (invoice_id) REFERENCES public.invoices(id);
|
||||||
|
|
||||||
|
|
||||||
--
|
--
|
||||||
-- Name: messages_registrar_id_fk; Type: FK CONSTRAINT; Schema: public; Owner: -
|
-- Name: messages_registrar_id_fk; Type: FK CONSTRAINT; Schema: public; Owner: -
|
||||||
--
|
--
|
||||||
|
@ -4926,6 +4933,22 @@ INSERT INTO schema_migrations (version) VALUES ('20181001090536');
|
||||||
|
|
||||||
INSERT INTO schema_migrations (version) VALUES ('20181002090319');
|
INSERT INTO schema_migrations (version) VALUES ('20181002090319');
|
||||||
|
|
||||||
|
INSERT INTO schema_migrations (version) VALUES ('20181017092829');
|
||||||
|
|
||||||
|
INSERT INTO schema_migrations (version) VALUES ('20181017153658');
|
||||||
|
|
||||||
|
INSERT INTO schema_migrations (version) VALUES ('20181017153812');
|
||||||
|
|
||||||
|
INSERT INTO schema_migrations (version) VALUES ('20181017153935');
|
||||||
|
|
||||||
|
INSERT INTO schema_migrations (version) VALUES ('20181017154038');
|
||||||
|
|
||||||
|
INSERT INTO schema_migrations (version) VALUES ('20181017154143');
|
||||||
|
|
||||||
|
INSERT INTO schema_migrations (version) VALUES ('20181017205123');
|
||||||
|
|
||||||
|
INSERT INTO schema_migrations (version) VALUES ('20181022100114');
|
||||||
|
|
||||||
INSERT INTO schema_migrations (version) VALUES ('20181108154921');
|
INSERT INTO schema_migrations (version) VALUES ('20181108154921');
|
||||||
|
|
||||||
INSERT INTO schema_migrations (version) VALUES ('20181129150515');
|
INSERT INTO schema_migrations (version) VALUES ('20181129150515');
|
||||||
|
@ -4962,3 +4985,7 @@ INSERT INTO schema_migrations (version) VALUES ('20190102115333');
|
||||||
|
|
||||||
INSERT INTO schema_migrations (version) VALUES ('20190102144032');
|
INSERT INTO schema_migrations (version) VALUES ('20190102144032');
|
||||||
|
|
||||||
|
INSERT INTO schema_migrations (version) VALUES ('20190311111718');
|
||||||
|
|
||||||
|
INSERT INTO schema_migrations (version) VALUES ('20190312211614');
|
||||||
|
|
||||||
|
|
16
lib/tasks/data_migrations/populate_invoice_issue_date.rake
Normal file
16
lib/tasks/data_migrations/populate_invoice_issue_date.rake
Normal file
|
@ -0,0 +1,16 @@
|
||||||
|
namespace :data_migrations do
|
||||||
|
task populate_invoice_issue_date: [:environment] do
|
||||||
|
processed_invoice_count = 0
|
||||||
|
|
||||||
|
Invoice.transaction do
|
||||||
|
Invoice.find_each do |invoice|
|
||||||
|
invoice_issue_date = invoice.created_at.to_date
|
||||||
|
invoice.update!(issue_date: invoice_issue_date)
|
||||||
|
|
||||||
|
processed_invoice_count += 1
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
puts "Invoices processed: #{processed_invoice_count}"
|
||||||
|
end
|
||||||
|
end
|
13
lib/tasks/invoices/cancel_overdue.rake
Normal file
13
lib/tasks/invoices/cancel_overdue.rake
Normal file
|
@ -0,0 +1,13 @@
|
||||||
|
namespace :invoices do
|
||||||
|
task cancel_overdue: :environment do
|
||||||
|
cancelled_invoice_count = 0
|
||||||
|
|
||||||
|
canceller = OverdueInvoiceCanceller.new
|
||||||
|
canceller.cancel do |invoice|
|
||||||
|
puts "Invoice ##{invoice.id} is cancelled"
|
||||||
|
cancelled_invoice_count += 1
|
||||||
|
end
|
||||||
|
|
||||||
|
puts "Cancelled total: #{cancelled_invoice_count}"
|
||||||
|
end
|
||||||
|
end
|
|
@ -1,18 +0,0 @@
|
||||||
FactoryBot.define do
|
|
||||||
factory :invoice do
|
|
||||||
buyer_name 'Registrar 1'
|
|
||||||
currency { 'EUR' }
|
|
||||||
due_date { Time.zone.now.to_date + 1.day }
|
|
||||||
seller_iban { '123' }
|
|
||||||
seller_name { 'EIS' }
|
|
||||||
seller_city { 'Tallinn' }
|
|
||||||
seller_street { 'Paldiski mnt. 123' }
|
|
||||||
vat_rate 0.2
|
|
||||||
buyer { FactoryBot.create(:registrar) }
|
|
||||||
sequence(:reference_no) { |n| "1234#{n}" }
|
|
||||||
|
|
||||||
after :build do |invoice|
|
|
||||||
invoice.invoice_items << FactoryBot.create_pair(:invoice_item)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
|
@ -1,8 +0,0 @@
|
||||||
FactoryBot.define do
|
|
||||||
factory :invoice_item do
|
|
||||||
description { 'add money' }
|
|
||||||
unit 1
|
|
||||||
amount 1
|
|
||||||
price 150
|
|
||||||
end
|
|
||||||
end
|
|
|
@ -1,69 +0,0 @@
|
||||||
require 'rails_helper'
|
|
||||||
|
|
||||||
describe Invoice do
|
|
||||||
context 'with invalid attribute' do
|
|
||||||
before :all do
|
|
||||||
@invoice = Invoice.new
|
|
||||||
end
|
|
||||||
|
|
||||||
it 'should not be valid' do
|
|
||||||
@invoice.valid?
|
|
||||||
@invoice.errors.full_messages.should match_array([
|
|
||||||
"Buyer name is missing",
|
|
||||||
"Currency is missing",
|
|
||||||
"Due date is missing",
|
|
||||||
"Invoice items is missing",
|
|
||||||
"Seller iban is missing",
|
|
||||||
"Seller name is missing",
|
|
||||||
])
|
|
||||||
end
|
|
||||||
|
|
||||||
it 'should not have any versions' do
|
|
||||||
@invoice.versions.should == []
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
context 'with valid attributes' do
|
|
||||||
before :all do
|
|
||||||
@invoice = create(:invoice)
|
|
||||||
end
|
|
||||||
|
|
||||||
it 'should be valid' do
|
|
||||||
@invoice.valid?
|
|
||||||
@invoice.errors.full_messages.should match_array([])
|
|
||||||
end
|
|
||||||
|
|
||||||
it 'should be valid twice' do
|
|
||||||
@invoice = create(:invoice)
|
|
||||||
@invoice.valid?
|
|
||||||
@invoice.errors.full_messages.should match_array([])
|
|
||||||
end
|
|
||||||
|
|
||||||
it 'should be valid twice' do
|
|
||||||
@invoice = create(:invoice)
|
|
||||||
@invoice.valid?
|
|
||||||
@invoice.errors.full_messages.should match_array([])
|
|
||||||
end
|
|
||||||
|
|
||||||
it 'should return correct addresses' do
|
|
||||||
@invoice = create(:invoice)
|
|
||||||
@invoice.seller_address.should == 'Paldiski mnt. 123, Tallinn'
|
|
||||||
end
|
|
||||||
|
|
||||||
it 'should cancel overdue invoices' do
|
|
||||||
create(:invoice, created_at: Time.zone.now - 35.days, due_date: Time.zone.now - 30.days)
|
|
||||||
Invoice.cancel_overdue_invoices
|
|
||||||
Invoice.where(cancelled_at: nil).count.should == 1
|
|
||||||
end
|
|
||||||
|
|
||||||
it 'should have one version' do
|
|
||||||
with_versioning do
|
|
||||||
@invoice.versions.should == []
|
|
||||||
@invoice.buyer_name = 'New name'
|
|
||||||
@invoice.save
|
|
||||||
@invoice.errors.full_messages.should match_array([])
|
|
||||||
@invoice.versions.size.should == 1
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
8
test/fixtures/account_activities.yml
vendored
8
test/fixtures/account_activities.yml
vendored
|
@ -1,7 +1,5 @@
|
||||||
DEFAULTS: &DEFAULTS
|
|
||||||
account_id: 1
|
|
||||||
|
|
||||||
one:
|
one:
|
||||||
<<: *DEFAULTS
|
account: cash
|
||||||
invoice: paid
|
invoice: one
|
||||||
bank_transaction: one
|
bank_transaction: one
|
||||||
|
created_at: <%= Time.zone.parse('2010-07-05 10:00') %>
|
6
test/fixtures/accounts.yml
vendored
6
test/fixtures/accounts.yml
vendored
|
@ -4,6 +4,12 @@ cash:
|
||||||
currency: EUR
|
currency: EUR
|
||||||
registrar: bestnames
|
registrar: bestnames
|
||||||
|
|
||||||
|
two:
|
||||||
|
account_type: cash
|
||||||
|
balance: 100
|
||||||
|
currency: EUR
|
||||||
|
registrar: goodnames
|
||||||
|
|
||||||
not_in_use_cash:
|
not_in_use_cash:
|
||||||
account_type: cash
|
account_type: cash
|
||||||
balance: 0
|
balance: 0
|
||||||
|
|
11
test/fixtures/invoice_items.yml
vendored
11
test/fixtures/invoice_items.yml
vendored
|
@ -1,13 +1,6 @@
|
||||||
one:
|
one:
|
||||||
description: Acme services
|
description: Acme services
|
||||||
price: 5
|
price: 5
|
||||||
amount: 1
|
quantity: 1
|
||||||
unit: pc
|
unit: pc
|
||||||
invoice: valid
|
invoice: one
|
||||||
|
|
||||||
two:
|
|
||||||
description: Acme services
|
|
||||||
price: 5
|
|
||||||
amount: 2
|
|
||||||
unit: pc
|
|
||||||
invoice: valid
|
|
||||||
|
|
39
test/fixtures/invoices.yml
vendored
39
test/fixtures/invoices.yml
vendored
|
@ -1,5 +1,5 @@
|
||||||
DEFAULTS: &DEFAULTS
|
one:
|
||||||
created_at: <%= Date.parse '2010-07-05' %>
|
issue_date: <%= Date.parse '2010-07-05' %>
|
||||||
due_date: <%= Date.parse '2010-07-06' %>
|
due_date: <%= Date.parse '2010-07-06' %>
|
||||||
currency: EUR
|
currency: EUR
|
||||||
seller_name: John Doe
|
seller_name: John Doe
|
||||||
|
@ -10,30 +10,15 @@ DEFAULTS: &DEFAULTS
|
||||||
total: 16.50
|
total: 16.50
|
||||||
reference_no: 13
|
reference_no: 13
|
||||||
|
|
||||||
valid:
|
|
||||||
<<: *DEFAULTS
|
|
||||||
|
|
||||||
exported:
|
|
||||||
<<: *DEFAULTS
|
|
||||||
in_directo: true
|
|
||||||
|
|
||||||
cancelled:
|
|
||||||
<<: *DEFAULTS
|
|
||||||
cancelled_at: <%= Date.parse '2010-07-05' %>
|
|
||||||
|
|
||||||
paid:
|
|
||||||
<<: *DEFAULTS
|
|
||||||
total: 1
|
|
||||||
|
|
||||||
outstanding:
|
|
||||||
<<: *DEFAULTS
|
|
||||||
due_date: <%= Date.parse '2010-07-04' %>
|
|
||||||
|
|
||||||
overdue:
|
|
||||||
<<: *DEFAULTS
|
|
||||||
due_date: <%= Date.parse '2010-07-03' %>
|
|
||||||
|
|
||||||
for_payments_test:
|
for_payments_test:
|
||||||
<<: *DEFAULTS
|
|
||||||
total: 12.00
|
|
||||||
number: 1
|
number: 1
|
||||||
|
issue_date: <%= Date.parse '2010-07-05' %>
|
||||||
|
due_date: <%= Date.parse '2010-07-06' %>
|
||||||
|
currency: EUR
|
||||||
|
seller_name: John Doe
|
||||||
|
seller_iban: 1234
|
||||||
|
buyer: bestnames
|
||||||
|
buyer_name: Jane Doe
|
||||||
|
vat_rate: 0.1
|
||||||
|
reference_no: 13
|
||||||
|
total: 12.00
|
|
@ -35,7 +35,7 @@ class RegenerateRegistrarReferenceNumbersTaskTest < ActiveSupport::TestCase
|
||||||
def test_keeps_iso_reference_number_on_the_invoice_unchanged
|
def test_keeps_iso_reference_number_on_the_invoice_unchanged
|
||||||
registrar = registrars(:bestnames)
|
registrar = registrars(:bestnames)
|
||||||
registrar.update_column(:reference_no, 'RF1111')
|
registrar.update_column(:reference_no, 'RF1111')
|
||||||
invoice = registrar.invoices.first
|
invoice = invoices(:one)
|
||||||
invoice.update!(reference_no: 'RF2222')
|
invoice.update!(reference_no: 'RF2222')
|
||||||
|
|
||||||
capture_io { run_task }
|
capture_io { run_task }
|
||||||
|
|
11
test/models/account_activity_test.rb
Normal file
11
test/models/account_activity_test.rb
Normal file
|
@ -0,0 +1,11 @@
|
||||||
|
require 'test_helper'
|
||||||
|
|
||||||
|
class AccountActivityTest < ActiveSupport::TestCase
|
||||||
|
setup do
|
||||||
|
@account_activity = account_activities(:one)
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_fixture_is_valid
|
||||||
|
assert @account_activity.valid?
|
||||||
|
end
|
||||||
|
end
|
|
@ -2,7 +2,7 @@ require 'test_helper'
|
||||||
|
|
||||||
class BankTransactionTest < ActiveSupport::TestCase
|
class BankTransactionTest < ActiveSupport::TestCase
|
||||||
def test_matches_against_invoice_reference_number
|
def test_matches_against_invoice_reference_number
|
||||||
invoices(:valid).update!(number: '2222', total: 10, reference_no: '1111')
|
invoices(:one).update!(account_activity: nil, number: '2222', total: 10, reference_no: '1111')
|
||||||
transaction = BankTransaction.new(description: 'invoice #2222', sum: 10, reference_no: '1111')
|
transaction = BankTransaction.new(description: 'invoice #2222', sum: 10, reference_no: '1111')
|
||||||
|
|
||||||
assert_difference 'AccountActivity.count' do
|
assert_difference 'AccountActivity.count' do
|
||||||
|
@ -20,7 +20,7 @@ class BankTransactionTest < ActiveSupport::TestCase
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_underpayment_is_not_matched_with_invoice
|
def test_underpayment_is_not_matched_with_invoice
|
||||||
invoices(:valid).update!(number: '2222', total: 10)
|
invoices(:one).update!(account_activity: nil, number: '2222', total: 10)
|
||||||
transaction = BankTransaction.new(sum: 9)
|
transaction = BankTransaction.new(sum: 9)
|
||||||
|
|
||||||
assert_no_difference 'AccountActivity.count' do
|
assert_no_difference 'AccountActivity.count' do
|
||||||
|
@ -30,7 +30,7 @@ class BankTransactionTest < ActiveSupport::TestCase
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_overpayment_is_not_matched_with_invoice
|
def test_overpayment_is_not_matched_with_invoice
|
||||||
invoices(:valid).update!(number: '2222', total: 10)
|
invoices(:one).update!(account_activity: nil, number: '2222', total: 10)
|
||||||
transaction = BankTransaction.new(sum: 11)
|
transaction = BankTransaction.new(sum: 11)
|
||||||
|
|
||||||
assert_no_difference 'AccountActivity.count' do
|
assert_no_difference 'AccountActivity.count' do
|
||||||
|
@ -40,7 +40,7 @@ class BankTransactionTest < ActiveSupport::TestCase
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_cancelled_invoice_is_not_matched
|
def test_cancelled_invoice_is_not_matched
|
||||||
invoices(:valid).update!(number: '2222', total: 10, cancelled_at: '2010-07-05')
|
invoices(:one).update!(account_activity: nil, number: '2222', total: 10, cancelled_at: '2010-07-05')
|
||||||
transaction = BankTransaction.new(sum: 10)
|
transaction = BankTransaction.new(sum: 10)
|
||||||
|
|
||||||
assert_no_difference 'AccountActivity.count' do
|
assert_no_difference 'AccountActivity.count' do
|
||||||
|
|
69
test/models/invoice/cancellable_test.rb
Normal file
69
test/models/invoice/cancellable_test.rb
Normal file
|
@ -0,0 +1,69 @@
|
||||||
|
require 'test_helper'
|
||||||
|
|
||||||
|
class CancellableInvoiceTest < ActiveSupport::TestCase
|
||||||
|
setup do
|
||||||
|
@invoice = invoices(:one)
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_non_cancelled_scope_returns_non_cancelled_invoices
|
||||||
|
@invoice.update!(cancelled_at: nil)
|
||||||
|
assert Invoice.non_cancelled.include?(@invoice), 'Should return cancelled invoice'
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_non_cancelled_scope_does_not_return_cancelled_invoices
|
||||||
|
@invoice.update!(cancelled_at: '2010-07-05')
|
||||||
|
assert_not Invoice.non_cancelled.include?(@invoice), 'Should not return cancelled invoice'
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_cancellable_when_unpaid_and_not_yet_cancelled
|
||||||
|
@invoice.account_activity = nil
|
||||||
|
@invoice.cancelled_at = nil
|
||||||
|
assert @invoice.cancellable?
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_not_cancellable_when_paid
|
||||||
|
assert @invoice.paid?
|
||||||
|
assert_not @invoice.cancellable?
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_not_cancellable_when_already_cancelled
|
||||||
|
@invoice.cancelled_at = '2010-07-05'
|
||||||
|
assert_not @invoice.cancellable?
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_cancels_an_invoice
|
||||||
|
travel_to Time.zone.parse('2010-07-05 08:00')
|
||||||
|
@invoice.account_activity = nil
|
||||||
|
assert @invoice.cancellable?
|
||||||
|
assert_nil @invoice.cancelled_at
|
||||||
|
|
||||||
|
@invoice.cancel
|
||||||
|
@invoice.reload
|
||||||
|
|
||||||
|
assert @invoice.cancelled?
|
||||||
|
assert_equal Time.zone.parse('2010-07-05 08:00'), @invoice.cancelled_at
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_throws_an_exception_when_trying_to_cancel_already_cancelled_invoice
|
||||||
|
@invoice.cancelled_at = '2010-07-05'
|
||||||
|
|
||||||
|
e = assert_raise do
|
||||||
|
@invoice.cancel
|
||||||
|
end
|
||||||
|
assert_equal 'Invoice cannot be cancelled', e.message
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_not_cancelled
|
||||||
|
@invoice.cancelled_at = nil
|
||||||
|
|
||||||
|
assert @invoice.not_cancelled?
|
||||||
|
assert_not @invoice.cancelled?
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_cancelled
|
||||||
|
@invoice.cancelled_at = '2010-07-05'
|
||||||
|
|
||||||
|
assert @invoice.cancelled?
|
||||||
|
assert_not @invoice.not_cancelled?
|
||||||
|
end
|
||||||
|
end
|
53
test/models/invoice/payable_test.rb
Normal file
53
test/models/invoice/payable_test.rb
Normal file
|
@ -0,0 +1,53 @@
|
||||||
|
require 'test_helper'
|
||||||
|
|
||||||
|
class InvoiceTest < ActiveSupport::TestCase
|
||||||
|
setup do
|
||||||
|
@invoice = invoices(:one)
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_unpaid_scope_returns_unpaid_invoices
|
||||||
|
@invoice.account_activity = nil
|
||||||
|
assert Invoice.unpaid.include?(@invoice), 'Should return unpaid invoice'
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_unpaid_scope_does_not_return_paid_invoices
|
||||||
|
assert @invoice.paid?
|
||||||
|
assert_not Invoice.unpaid.include?(@invoice), 'Should not return paid invoice'
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_paid_when_there_is_an_account_activity
|
||||||
|
assert @invoice.account_activity
|
||||||
|
|
||||||
|
assert @invoice.paid?
|
||||||
|
assert_not @invoice.unpaid?
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_unpaid_when_there_is_no_account_activity
|
||||||
|
@invoice.account_activity = nil
|
||||||
|
|
||||||
|
assert @invoice.unpaid?
|
||||||
|
assert_not @invoice.paid?
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_payable_when_unpaid_and_not_cancelled
|
||||||
|
@invoice.account_activity = nil
|
||||||
|
@invoice.cancelled_at = nil
|
||||||
|
|
||||||
|
assert @invoice.payable?
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_not_payable_when_already_paid
|
||||||
|
assert @invoice.paid?
|
||||||
|
assert_not @invoice.payable?
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_not_payable_when_cancelled
|
||||||
|
@invoice.cancelled_at = '2010-07-05'
|
||||||
|
assert_not @invoice.payable?
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_returns_receipt_date
|
||||||
|
assert_equal Time.zone.parse('2010-07-05 10:00'), @invoice.account_activity.created_at
|
||||||
|
assert_equal Date.parse('2010-07-05'), @invoice.receipt_date
|
||||||
|
end
|
||||||
|
end
|
8
test/models/invoice_item_test.rb
Normal file
8
test/models/invoice_item_test.rb
Normal file
|
@ -0,0 +1,8 @@
|
||||||
|
require 'test_helper'
|
||||||
|
|
||||||
|
class InvoiceItemTest < ActiveSupport::TestCase
|
||||||
|
def test_calculates_sum_without_vat
|
||||||
|
invoice_item = InvoiceItem.new(price: 5, quantity: 2)
|
||||||
|
assert_equal 10, invoice_item.item_sum_without_vat
|
||||||
|
end
|
||||||
|
end
|
|
@ -2,11 +2,40 @@ require 'test_helper'
|
||||||
|
|
||||||
class InvoiceTest < ActiveSupport::TestCase
|
class InvoiceTest < ActiveSupport::TestCase
|
||||||
setup do
|
setup do
|
||||||
@invoice = invoices(:valid)
|
@invoice = invoices(:one)
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_valid
|
def test_fixture_is_valid
|
||||||
assert @invoice.valid?
|
assert @invoice.valid?, proc { @invoice.errors.full_messages }
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_overdue_scope_returns_unpaid_uncancelled_invoices_with_past_due_date
|
||||||
|
travel_to Time.zone.parse('2010-07-05')
|
||||||
|
@invoice.update!(account_activity: nil, cancelled_at: nil, due_date: '2010-07-04')
|
||||||
|
|
||||||
|
assert Invoice.overdue.include?(@invoice), 'Should return overdue invoice'
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_overdue_scope_does_not_return_paid_invoices
|
||||||
|
assert @invoice.paid?
|
||||||
|
assert_not Invoice.overdue.include?(@invoice), 'Should not return paid invoice'
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_overdue_scope_does_not_return_cancelled_invoices
|
||||||
|
@invoice.update!(cancelled_at: '2010-07-05')
|
||||||
|
assert_not Invoice.overdue.include?(@invoice), 'Should not return cancelled invoice'
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_overdue_scope_does_not_return_invoices_with_due_due_of_today_or_in_the_future
|
||||||
|
travel_to Time.zone.parse('2010-07-05')
|
||||||
|
@invoice.update!(due_date: '2010-07-05')
|
||||||
|
|
||||||
|
assert_not Invoice.overdue.include?(@invoice), 'Should not return non-overdue invoice'
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_invalid_without_issue_date
|
||||||
|
@invoice.issue_date = nil
|
||||||
|
assert @invoice.invalid?
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_optional_vat_rate
|
def test_optional_vat_rate
|
||||||
|
@ -30,7 +59,7 @@ class InvoiceTest < ActiveSupport::TestCase
|
||||||
|
|
||||||
def test_serializes_and_deserializes_vat_rate
|
def test_serializes_and_deserializes_vat_rate
|
||||||
invoice = @invoice.dup
|
invoice = @invoice.dup
|
||||||
invoice.invoice_items = @invoice.invoice_items
|
invoice.items = @invoice.items
|
||||||
invoice.vat_rate = BigDecimal('25.5')
|
invoice.vat_rate = BigDecimal('25.5')
|
||||||
invoice.save!
|
invoice.save!
|
||||||
invoice.reload
|
invoice.reload
|
||||||
|
@ -42,7 +71,7 @@ class InvoiceTest < ActiveSupport::TestCase
|
||||||
invoice = @invoice.dup
|
invoice = @invoice.dup
|
||||||
invoice.vat_rate = nil
|
invoice.vat_rate = nil
|
||||||
invoice.buyer = registrar
|
invoice.buyer = registrar
|
||||||
invoice.invoice_items = @invoice.invoice_items
|
invoice.items = @invoice.items
|
||||||
|
|
||||||
registrar.stub(:effective_vat_rate, BigDecimal(55)) do
|
registrar.stub(:effective_vat_rate, BigDecimal(55)) do
|
||||||
invoice.save!
|
invoice.save!
|
||||||
|
@ -59,7 +88,9 @@ class InvoiceTest < ActiveSupport::TestCase
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_calculates_vat_amount
|
def test_calculates_vat_amount
|
||||||
assert_equal BigDecimal('1.5'), @invoice.vat_amount
|
invoice_item = InvoiceItem.new(price: 25, quantity: 2)
|
||||||
|
invoice = Invoice.new(vat_rate: 10, items: [invoice_item, invoice_item.dup])
|
||||||
|
assert_equal 10, invoice.vat_amount
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_vat_amount_is_zero_when_vat_rate_is_blank
|
def test_vat_amount_is_zero_when_vat_rate_is_blank
|
||||||
|
@ -69,7 +100,7 @@ class InvoiceTest < ActiveSupport::TestCase
|
||||||
|
|
||||||
def test_calculates_subtotal
|
def test_calculates_subtotal
|
||||||
line_item = InvoiceItem.new
|
line_item = InvoiceItem.new
|
||||||
invoice = Invoice.new(invoice_items: [line_item, line_item])
|
invoice = Invoice.new(items: [line_item, line_item])
|
||||||
|
|
||||||
line_item.stub(:item_sum_without_vat, BigDecimal('2.5')) do
|
line_item.stub(:item_sum_without_vat, BigDecimal('2.5')) do
|
||||||
assert_equal BigDecimal(5), invoice.subtotal
|
assert_equal BigDecimal(5), invoice.subtotal
|
||||||
|
@ -84,7 +115,7 @@ class InvoiceTest < ActiveSupport::TestCase
|
||||||
line_item = InvoiceItem.new
|
line_item = InvoiceItem.new
|
||||||
invoice = Invoice.new
|
invoice = Invoice.new
|
||||||
invoice.vat_rate = 10
|
invoice.vat_rate = 10
|
||||||
invoice.invoice_items = [line_item, line_item]
|
invoice.items = [line_item, line_item]
|
||||||
|
|
||||||
line_item.stub(:item_sum_without_vat, BigDecimal('2.5')) do
|
line_item.stub(:item_sum_without_vat, BigDecimal('2.5')) do
|
||||||
assert_equal BigDecimal('5.50'), invoice.total
|
assert_equal BigDecimal('5.50'), invoice.total
|
||||||
|
@ -102,8 +133,25 @@ class InvoiceTest < ActiveSupport::TestCase
|
||||||
invoice = @invoice.dup
|
invoice = @invoice.dup
|
||||||
invoice.buyer_vat_no = nil
|
invoice.buyer_vat_no = nil
|
||||||
invoice.buyer = registrar
|
invoice.buyer = registrar
|
||||||
invoice.invoice_items = @invoice.invoice_items
|
invoice.items = @invoice.items
|
||||||
invoice.save!
|
invoice.save!
|
||||||
assert_equal 'US1234', invoice.buyer_vat_no
|
assert_equal 'US1234', invoice.buyer_vat_no
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def test_invalid_without_invoice_items
|
||||||
|
@invoice.items.clear
|
||||||
|
assert @invoice.invalid?
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_iterates_over_invoice_items
|
||||||
|
invoice = Invoice.new(items: [InvoiceItem.new(description: 'test')])
|
||||||
|
|
||||||
|
iteration_count = 0
|
||||||
|
invoice.each do |invoice_item|
|
||||||
|
assert_equal 'test', invoice_item.description
|
||||||
|
iteration_count += 1
|
||||||
|
end
|
||||||
|
|
||||||
|
assert_equal 1, iteration_count
|
||||||
|
end
|
||||||
end
|
end
|
|
@ -10,8 +10,8 @@ class BankLinkTest < ActiveSupport::TestCase
|
||||||
@invoice = invoices(:for_payments_test)
|
@invoice = invoices(:for_payments_test)
|
||||||
invoice_item = invoice_items(:one)
|
invoice_item = invoice_items(:one)
|
||||||
|
|
||||||
@invoice.invoice_items << invoice_item
|
@invoice.items << invoice_item
|
||||||
@invoice.invoice_items << invoice_item
|
@invoice.items << invoice_item
|
||||||
|
|
||||||
travel_to '2018-04-01 00:30 +0300'
|
travel_to '2018-04-01 00:30 +0300'
|
||||||
create_new_bank_link
|
create_new_bank_link
|
||||||
|
|
|
@ -7,8 +7,8 @@ class EveryPayTest < ActiveSupport::TestCase
|
||||||
@invoice = invoices(:for_payments_test)
|
@invoice = invoices(:for_payments_test)
|
||||||
invoice_item = invoice_items(:one)
|
invoice_item = invoice_items(:one)
|
||||||
|
|
||||||
@invoice.invoice_items << invoice_item
|
@invoice.items << invoice_item
|
||||||
@invoice.invoice_items << invoice_item
|
@invoice.items << invoice_item
|
||||||
|
|
||||||
params = {
|
params = {
|
||||||
response:
|
response:
|
||||||
|
|
|
@ -83,4 +83,17 @@ class RegistrarTest < ActiveSupport::TestCase
|
||||||
registrars(:goodnames).update!(reference_no: '1234')
|
registrars(:goodnames).update!(reference_no: '1234')
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def test_issues_new_invoice
|
||||||
|
travel_to Time.zone.parse('2010-07-05')
|
||||||
|
@original_days_to_keep_invoices_active_setting = Setting.days_to_keep_invoices_active
|
||||||
|
Setting.days_to_keep_invoices_active = 10
|
||||||
|
|
||||||
|
invoice = @registrar.issue_prepayment_invoice(100)
|
||||||
|
|
||||||
|
assert_equal Date.parse('2010-07-05'), invoice.issue_date
|
||||||
|
assert_equal Date.parse('2010-07-15'), invoice.due_date
|
||||||
|
|
||||||
|
Setting.days_to_keep_invoices_active = @original_days_to_keep_invoices_active_setting
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
62
test/services/overdue_invoice_canceller_test.rb
Normal file
62
test/services/overdue_invoice_canceller_test.rb
Normal file
|
@ -0,0 +1,62 @@
|
||||||
|
require 'test_helper'
|
||||||
|
|
||||||
|
class OverdueInvoiceCancellerTest < ActiveSupport::TestCase
|
||||||
|
setup do
|
||||||
|
@invoice = invoices(:one)
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_default_delay
|
||||||
|
assert_equal 30.days, OverdueInvoiceCanceller.default_delay
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_uses_default_delay_when_not_configured
|
||||||
|
Setting.days_to_keep_overdue_invoices_active = nil
|
||||||
|
canceller = OverdueInvoiceCanceller.new
|
||||||
|
assert_equal OverdueInvoiceCanceller.default_delay, canceller.delay
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_uses_configured_delay
|
||||||
|
Setting.days_to_keep_overdue_invoices_active = 1
|
||||||
|
canceller = OverdueInvoiceCanceller.new
|
||||||
|
assert_equal 1.day, canceller.delay
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_cancels_overdue_invoices
|
||||||
|
travel_to Time.zone.parse('2010-07-05')
|
||||||
|
@invoice.update!(account_activity: nil, cancelled_at: nil, due_date: '2010-07-03')
|
||||||
|
assert @invoice.cancellable?
|
||||||
|
|
||||||
|
canceller = OverdueInvoiceCanceller.new(delay: 1.day)
|
||||||
|
canceller.cancel
|
||||||
|
@invoice.reload
|
||||||
|
|
||||||
|
assert @invoice.cancelled?
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_yields_cancelled_invoices
|
||||||
|
travel_to Time.zone.parse('2010-07-05')
|
||||||
|
@invoice.update!(account_activity: nil, cancelled_at: nil, due_date: '2010-07-03')
|
||||||
|
assert @invoice.cancellable?
|
||||||
|
|
||||||
|
canceller = OverdueInvoiceCanceller.new(delay: 1.day)
|
||||||
|
|
||||||
|
iteration_count = 0
|
||||||
|
canceller.cancel do |invoice|
|
||||||
|
assert_equal @invoice, invoice
|
||||||
|
iteration_count += 1
|
||||||
|
end
|
||||||
|
assert_equal 1, iteration_count
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_keeps_not_overdue_invoices_intact
|
||||||
|
travel_to Time.zone.parse('2010-07-05')
|
||||||
|
@invoice.update!(account_activity: nil, cancelled_at: nil, due_date: '2010-07-04')
|
||||||
|
assert @invoice.cancellable?
|
||||||
|
|
||||||
|
canceller = OverdueInvoiceCanceller.new(delay: 1.day)
|
||||||
|
canceller.cancel
|
||||||
|
@invoice.reload
|
||||||
|
|
||||||
|
assert @invoice.not_cancelled?
|
||||||
|
end
|
||||||
|
end
|
20
test/system/admin_area/invoices_test.rb
Normal file
20
test/system/admin_area/invoices_test.rb
Normal file
|
@ -0,0 +1,20 @@
|
||||||
|
require 'test_helper'
|
||||||
|
|
||||||
|
class AdminAreaInvoicesTest < ApplicationSystemTestCase
|
||||||
|
setup do
|
||||||
|
sign_in users(:admin)
|
||||||
|
@invoice = invoices(:one)
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_cancels_an_invoice
|
||||||
|
@invoice.account_activity = nil
|
||||||
|
assert @invoice.cancellable?
|
||||||
|
|
||||||
|
visit admin_invoice_url(@invoice)
|
||||||
|
click_on 'Cancel'
|
||||||
|
@invoice.reload
|
||||||
|
|
||||||
|
assert @invoice.cancelled?
|
||||||
|
assert_text 'Invoice has been cancelled'
|
||||||
|
end
|
||||||
|
end
|
|
@ -1,12 +1,12 @@
|
||||||
require 'test_helper'
|
require 'test_helper'
|
||||||
|
|
||||||
class ListInvoicesTest < ApplicationSystemTestCase
|
class ListInvoicesTest < ApplicationSystemTestCase
|
||||||
def setup
|
setup do
|
||||||
super
|
|
||||||
|
|
||||||
@user = users(:api_bestnames)
|
@user = users(:api_bestnames)
|
||||||
@registrar_invoices = @user.registrar.invoices
|
|
||||||
sign_in @user
|
sign_in @user
|
||||||
|
|
||||||
|
@invoice = invoices(:one)
|
||||||
|
eliminate_effect_of_other_invoices
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_show_balance
|
def test_show_balance
|
||||||
|
@ -14,15 +14,31 @@ class ListInvoicesTest < ApplicationSystemTestCase
|
||||||
assert_text "Your current account balance is 100,00 EUR"
|
assert_text "Your current account balance is 100,00 EUR"
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_show_multiple_invoices
|
def test_show_invoices_of_current_registrar
|
||||||
@invoices = invoices
|
registrar = registrars(:bestnames)
|
||||||
@registrar_invoices = []
|
@user.update!(registrar: registrar)
|
||||||
@invoices.each do |invoice|
|
@invoice.update!(seller: registrar)
|
||||||
@registrar_invoices << invoice
|
|
||||||
|
visit registrar_invoices_url
|
||||||
|
|
||||||
|
assert_css '.invoice'
|
||||||
end
|
end
|
||||||
|
|
||||||
visit registrar_invoices_path
|
def test_do_not_show_invoices_of_other_registrars
|
||||||
assert_text "Unpaid", count: 5
|
registrar = registrars(:goodnames)
|
||||||
assert_text "Invoice no.", count: 7
|
@user.update!(registrar: registrar)
|
||||||
|
@invoice.update!(seller: registrar)
|
||||||
|
|
||||||
|
visit registrar_invoices_url
|
||||||
|
|
||||||
|
assert_no_css '.invoice'
|
||||||
|
end
|
||||||
|
|
||||||
|
private
|
||||||
|
|
||||||
|
def eliminate_effect_of_other_invoices
|
||||||
|
Invoice.connection.disable_referential_integrity do
|
||||||
|
Invoice.delete_all("id != #{@invoice.id}")
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
|
@ -12,8 +12,8 @@ class PaymentCallbackTest < ApplicationSystemTestCase
|
||||||
@invoice = invoices(:for_payments_test)
|
@invoice = invoices(:for_payments_test)
|
||||||
invoice_item = invoice_items(:one)
|
invoice_item = invoice_items(:one)
|
||||||
|
|
||||||
@invoice.invoice_items << invoice_item
|
@invoice.items << invoice_item
|
||||||
@invoice.invoice_items << invoice_item
|
@invoice.items << invoice_item
|
||||||
@user.registrar.invoices << @invoice
|
@user.registrar.invoices << @invoice
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
@ -12,8 +12,8 @@ class PaymentReturnTest < ApplicationSystemTestCase
|
||||||
@invoice = invoices(:for_payments_test)
|
@invoice = invoices(:for_payments_test)
|
||||||
invoice_item = invoice_items(:one)
|
invoice_item = invoice_items(:one)
|
||||||
|
|
||||||
@invoice.invoice_items << invoice_item
|
@invoice.items << invoice_item
|
||||||
@invoice.invoice_items << invoice_item
|
@invoice.items << invoice_item
|
||||||
@user.registrar.invoices << @invoice
|
@user.registrar.invoices << @invoice
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
20
test/system/registrar_area/invoices_test.rb
Normal file
20
test/system/registrar_area/invoices_test.rb
Normal file
|
@ -0,0 +1,20 @@
|
||||||
|
require 'test_helper'
|
||||||
|
|
||||||
|
class RegistrarAreaInvoicesTest < ApplicationSystemTestCase
|
||||||
|
setup do
|
||||||
|
sign_in users(:api_bestnames)
|
||||||
|
@invoice = invoices(:one)
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_cancels_an_invoice
|
||||||
|
@invoice.account_activity = nil
|
||||||
|
assert @invoice.cancellable?
|
||||||
|
|
||||||
|
visit registrar_invoice_url(@invoice)
|
||||||
|
click_on 'Cancel'
|
||||||
|
@invoice.reload
|
||||||
|
|
||||||
|
assert @invoice.cancelled?
|
||||||
|
assert_text 'Invoice has been cancelled'
|
||||||
|
end
|
||||||
|
end
|
|
@ -0,0 +1,37 @@
|
||||||
|
require 'test_helper'
|
||||||
|
|
||||||
|
class PopulateInvoiceIssueDateTaskTest < ActiveSupport::TestCase
|
||||||
|
setup do
|
||||||
|
@invoice = invoices(:one)
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_populates_invoice_issue_date
|
||||||
|
eliminate_effect_of_other_invoices
|
||||||
|
@invoice.update_columns(issue_date: nil, created_at: Time.zone.parse('2010-07-05'))
|
||||||
|
assert_nil @invoice.read_attribute(:issue_date)
|
||||||
|
|
||||||
|
capture_io { run_task }
|
||||||
|
@invoice.reload
|
||||||
|
|
||||||
|
assert_equal Date.parse('2010-07-05'), @invoice.issue_date
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_outputs_results
|
||||||
|
eliminate_effect_of_other_invoices
|
||||||
|
@invoice.update_columns(issue_date: nil, created_at: Time.zone.parse('2010-07-05'))
|
||||||
|
|
||||||
|
assert_output("Invoices processed: 1\n") { run_task }
|
||||||
|
end
|
||||||
|
|
||||||
|
private
|
||||||
|
|
||||||
|
def eliminate_effect_of_other_invoices
|
||||||
|
Invoice.connection.disable_referential_integrity do
|
||||||
|
Invoice.delete_all("id != #{@invoice.id}")
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def run_task
|
||||||
|
Rake::Task['data_migrations:populate_invoice_issue_date'].execute
|
||||||
|
end
|
||||||
|
end
|
41
test/tasks/invoices/cancel_overdue_test.rb
Normal file
41
test/tasks/invoices/cancel_overdue_test.rb
Normal file
|
@ -0,0 +1,41 @@
|
||||||
|
require 'test_helper'
|
||||||
|
|
||||||
|
class CancelOverdueInvoicesTaskTest < ActiveSupport::TestCase
|
||||||
|
setup do
|
||||||
|
@invoice = invoices(:one)
|
||||||
|
eliminate_effect_of_other_invoices
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_cancels_overdue_invoices
|
||||||
|
@invoice.update!(account_activity: nil, cancelled_at: nil, due_date: '2010-07-05')
|
||||||
|
assert @invoice.cancellable?
|
||||||
|
|
||||||
|
capture_io do
|
||||||
|
run_task
|
||||||
|
end
|
||||||
|
@invoice.reload
|
||||||
|
|
||||||
|
assert @invoice.cancelled?
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_output
|
||||||
|
@invoice.update!(account_activity: nil, cancelled_at: nil, due_date: '2010-07-05')
|
||||||
|
assert @invoice.cancellable?
|
||||||
|
|
||||||
|
assert_output "Invoice ##{@invoice.id} is cancelled\nCancelled total: 1\n" do
|
||||||
|
run_task
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
private
|
||||||
|
|
||||||
|
def eliminate_effect_of_other_invoices
|
||||||
|
Invoice.connection.disable_referential_integrity do
|
||||||
|
Invoice.delete_all("id != #{@invoice.id}")
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def run_task
|
||||||
|
Rake::Task['invoices:cancel_overdue'].execute
|
||||||
|
end
|
||||||
|
end
|
Loading…
Add table
Add a link
Reference in a new issue