mirror of
https://github.com/internetee/registry.git
synced 2025-07-27 21:16:12 +02:00
Created job for sending monthly invoices
This commit is contained in:
parent
a5f803b57a
commit
d589aa1681
18 changed files with 1103 additions and 43 deletions
10
app/jobs/delete_monthly_invoices_job.rb
Normal file
10
app/jobs/delete_monthly_invoices_job.rb
Normal file
|
@ -0,0 +1,10 @@
|
|||
class DeleteMonthlyInvoicesJob < ApplicationJob
|
||||
queue_as :default
|
||||
|
||||
def perform
|
||||
@month = Time.zone.now - 1.month
|
||||
invoices = Invoice.where(monthly_invoice: true, issue_date: @month.end_of_month.to_date,
|
||||
in_directo: false, e_invoice_sent_at: nil)
|
||||
invoices.delete_all
|
||||
end
|
||||
end
|
|
@ -17,7 +17,7 @@ class SendEInvoiceJob < ApplicationJob
|
|||
def need_to_process_invoice?(invoice:, payable:)
|
||||
logger.info "Checking if need to process e-invoice #{invoice}, payable: #{payable}"
|
||||
return false if invoice.blank?
|
||||
return false if invoice.do_not_send_e_invoice? && payable
|
||||
return false if invoice.do_not_send_e_invoice? && (invoice.monthly_invoice ? true : payable)
|
||||
|
||||
true
|
||||
end
|
||||
|
|
155
app/jobs/send_monthly_invoices_job.rb
Normal file
155
app/jobs/send_monthly_invoices_job.rb
Normal file
|
@ -0,0 +1,155 @@
|
|||
class SendMonthlyInvoicesJob < ApplicationJob
|
||||
queue_as :default
|
||||
|
||||
def perform(dry: false)
|
||||
@dry = dry
|
||||
@month = Time.zone.now - 1.month
|
||||
@directo_client = new_directo_client
|
||||
@min_directo_num = Setting.directo_monthly_number_min.presence.try(:to_i)
|
||||
@max_directo_num = Setting.directo_monthly_number_max.presence.try(:to_i)
|
||||
|
||||
send_monthly_invoices
|
||||
end
|
||||
|
||||
def new_directo_client
|
||||
DirectoApi::Client.new(ENV['directo_invoice_url'], Setting.directo_sales_agent,
|
||||
Setting.directo_receipt_payment_term)
|
||||
end
|
||||
|
||||
def send_monthly_invoices
|
||||
Registrar.where.not(test_registrar: true).find_each do |registrar|
|
||||
next unless registrar.cash_account
|
||||
|
||||
summary = registrar.monthly_summary(month: @month)
|
||||
next if summary.nil?
|
||||
|
||||
invoice = registrar.monthly_invoice(month: @month) || create_invoice(summary, registrar)
|
||||
next if invoice.nil? || @dry
|
||||
|
||||
InvoiceMailer.invoice_email(invoice: invoice,
|
||||
recipient: registrar.billing_email)
|
||||
.deliver_now
|
||||
|
||||
SendEInvoiceJob.set(wait: 1.minute).perform_now(invoice.id, payable: false)
|
||||
|
||||
next if invoice.in_directo
|
||||
|
||||
Rails.logger.info("[DIRECTO] Trying to send monthly invoice #{invoice.number}")
|
||||
@directo_client = new_directo_client
|
||||
directo_invoices = @directo_client.invoices.add_with_schema(invoice: summary,
|
||||
schema: 'summary')
|
||||
next unless directo_invoices.size.positive?
|
||||
|
||||
directo_invoices.last.number = invoice.number
|
||||
sync_with_directo
|
||||
end
|
||||
end
|
||||
|
||||
def create_invoice(summary, registrar)
|
||||
vat_rate = ::Invoice::VatRateCalculator.new(registrar: registrar).calculate
|
||||
invoice = Invoice.new(
|
||||
number: assign_monthly_number,
|
||||
issue_date: summary['date'].to_date,
|
||||
due_date: summary['date'].to_date,
|
||||
currency: 'EUR',
|
||||
description: I18n.t('invoice.monthly_invoice_description'),
|
||||
seller_name: Setting.registry_juridical_name,
|
||||
seller_reg_no: Setting.registry_reg_no,
|
||||
seller_iban: Setting.registry_iban,
|
||||
seller_bank: Setting.registry_bank,
|
||||
seller_swift: Setting.registry_swift,
|
||||
seller_vat_no: Setting.registry_vat_no,
|
||||
seller_country_code: Setting.registry_country_code,
|
||||
seller_state: Setting.registry_state,
|
||||
seller_street: Setting.registry_street,
|
||||
seller_city: Setting.registry_city,
|
||||
seller_zip: Setting.registry_zip,
|
||||
seller_phone: Setting.registry_phone,
|
||||
seller_url: Setting.registry_url,
|
||||
seller_email: Setting.registry_email,
|
||||
seller_contact_name: Setting.registry_invoice_contact,
|
||||
buyer: registrar,
|
||||
buyer_name: registrar.name,
|
||||
buyer_reg_no: registrar.reg_no,
|
||||
buyer_country_code: registrar.address_country_code,
|
||||
buyer_state: registrar.address_state,
|
||||
buyer_street: registrar.address_street,
|
||||
buyer_city: registrar.address_city,
|
||||
buyer_zip: registrar.address_zip,
|
||||
buyer_phone: registrar.phone,
|
||||
buyer_url: registrar.website,
|
||||
buyer_email: registrar.email,
|
||||
reference_no: registrar.reference_no,
|
||||
vat_rate: vat_rate,
|
||||
monthly_invoice: true,
|
||||
metadata: { items: summary['invoice_lines'] },
|
||||
total: 0
|
||||
)
|
||||
return unless invoice.save!
|
||||
|
||||
update_directo_number(num: invoice.number)
|
||||
invoice
|
||||
end
|
||||
|
||||
def sync_with_directo
|
||||
invoices_xml = @directo_client.invoices.as_xml
|
||||
|
||||
Rails.logger.info("[Directo] - attempting to send following XML:\n #{invoices_xml}")
|
||||
|
||||
res = @directo_client.invoices.deliver(ssl_verify: false)
|
||||
process_directo_response(res.body, invoices_xml)
|
||||
rescue SocketError, Errno::ECONNREFUSED, Timeout::Error, Errno::EINVAL, Errno::ECONNRESET,
|
||||
EOFError, Net::HTTPBadResponse, Net::HTTPHeaderSyntaxError, Net::ProtocolError
|
||||
Rails.logger.info('[Directo] Failed to communicate via API')
|
||||
end
|
||||
|
||||
def assign_monthly_numbers
|
||||
invoices_count = @directo_client.invoices.count
|
||||
last_directo_num = [Setting.directo_monthly_number_last.presence.try(:to_i),
|
||||
@min_directo_num].compact.max || 0
|
||||
raise 'Directo Counter is out of period!' if directo_counter_exceedable?(invoices_count,
|
||||
last_directo_num)
|
||||
|
||||
@directo_client.invoices.each do |inv|
|
||||
last_directo_num += 1
|
||||
inv.number = last_directo_num
|
||||
end
|
||||
end
|
||||
|
||||
def assign_monthly_number
|
||||
last_directo_num = [Setting.directo_monthly_number_last.presence.try(:to_i),
|
||||
@min_directo_num].compact.max || 0
|
||||
raise 'Directo Counter is out of period!' if directo_counter_exceedable?(1, last_directo_num)
|
||||
|
||||
last_directo_num + 1
|
||||
end
|
||||
|
||||
def directo_counter_exceedable?(invoices_count, last_directo_num)
|
||||
return true if @max_directo_num && @max_directo_num < (last_directo_num + invoices_count)
|
||||
|
||||
false
|
||||
end
|
||||
|
||||
def process_directo_response(body, req)
|
||||
Rails.logger.info "[Directo] - Responded with body: #{body}"
|
||||
Nokogiri::XML(body).css('Result').each do |res|
|
||||
inv = Invoice.find_by(number: res.attributes['docid'].value.to_i)
|
||||
mark_invoice_as_sent(res: res, req: req, invoice: inv)
|
||||
end
|
||||
end
|
||||
|
||||
def mark_invoice_as_sent(res:, req:, invoice: nil)
|
||||
directo_record = Directo.new(response: res.as_json.to_h,
|
||||
request: req, invoice_number: res.attributes['docid'].value.to_i)
|
||||
directo_record.item = invoice
|
||||
invoice.update(in_directo: true)
|
||||
|
||||
directo_record.save!
|
||||
end
|
||||
|
||||
def update_directo_number(num:)
|
||||
return unless num.to_i > Setting.directo_monthly_number_last.to_i
|
||||
|
||||
Setting.directo_monthly_number_last = num.to_i
|
||||
end
|
||||
end
|
|
@ -4,6 +4,7 @@ class InvoiceMailer < ApplicationMailer
|
|||
|
||||
subject = default_i18n_subject(invoice_number: invoice.number)
|
||||
subject << I18n.t('invoice.already_paid') if paid
|
||||
subject << I18n.t('invoice.monthly_invoice') if invoice.monthly_invoice
|
||||
attachments["invoice-#{invoice.number}.pdf"] = invoice.as_pdf
|
||||
mail(to: recipient, subject: subject)
|
||||
end
|
||||
|
|
|
@ -55,6 +55,11 @@ module Registrar::BookKeeping
|
|||
.where(activity_type: [AccountActivity::CREATE, AccountActivity::RENEW])
|
||||
end
|
||||
|
||||
def monthly_invoice(month:)
|
||||
invoices.where(monthly_invoice: true, issue_date: month.end_of_month.to_date,
|
||||
cancelled_at: nil).first
|
||||
end
|
||||
|
||||
def new_monthly_invoice_line(activity:, duration: nil)
|
||||
price = load_price(activity)
|
||||
line = {
|
||||
|
@ -68,7 +73,7 @@ module Registrar::BookKeeping
|
|||
|
||||
def finalize_invoice_line(line, price:, activity:, duration:)
|
||||
yearly = price.duration.in_years.to_i >= 1
|
||||
line['price'] = yearly ? (price.price.amount / price.duration.in_years.to_i) : price.price.amount
|
||||
line['price'] = yearly ? (price.price.amount / price.duration.in_years.to_i).to_f : price.price.amount.to_f
|
||||
line['description'] = description_in_language(price: price, yearly: yearly)
|
||||
|
||||
add_product_timeframe(line: line, activity: activity, duration: duration) if duration.present? && (duration > 1)
|
||||
|
|
|
@ -32,11 +32,14 @@ class Invoice < ApplicationRecord
|
|||
# rubocop:enable Layout/LineLength
|
||||
# rubocop:enable Style/MultilineBlockLayout
|
||||
validates :due_date, :currency, :seller_name,
|
||||
:seller_iban, :buyer_name, :items, presence: true
|
||||
:seller_iban, :buyer_name, presence: true
|
||||
validates :items, presence: true, unless: -> { monthly_invoice }
|
||||
|
||||
before_create :set_invoice_number
|
||||
before_create :calculate_total, unless: :total?
|
||||
before_create :apply_default_buyer_vat_no, unless: :buyer_vat_no?
|
||||
skip_callback :create, :before, :set_invoice_number, if: -> { monthly_invoice }
|
||||
skip_callback :create, :before, :calculate_total, if: -> { monthly_invoice }
|
||||
|
||||
attribute :vat_rate, ::Type::VatRate.new
|
||||
|
||||
|
@ -118,7 +121,7 @@ class Invoice < ApplicationRecord
|
|||
end
|
||||
|
||||
def subtotal
|
||||
items.map(&:item_sum_without_vat).reduce(:+)
|
||||
items.map(&:item_sum_without_vat).reduce(:+) || 0
|
||||
end
|
||||
|
||||
def vat_amount
|
||||
|
@ -131,8 +134,12 @@ class Invoice < ApplicationRecord
|
|||
end
|
||||
|
||||
def each(&block)
|
||||
if monthly_invoice
|
||||
metadata['items'].map { |el| OpenStruct.new(el) }.each(&block)
|
||||
else
|
||||
items.each(&block)
|
||||
end
|
||||
end
|
||||
|
||||
def as_pdf
|
||||
generator = PdfGenerator.new(self)
|
||||
|
|
|
@ -46,11 +46,18 @@ class Invoice
|
|||
i.price = invoice_item.price
|
||||
i.quantity = invoice_item.quantity
|
||||
i.unit = invoice_item.unit
|
||||
if invoice.monthly_invoice
|
||||
i.subtotal = 0
|
||||
i.vat_rate = 0
|
||||
i.vat_amount = 0
|
||||
i.total = 0
|
||||
else
|
||||
i.subtotal = invoice_item.subtotal
|
||||
i.vat_rate = invoice_item.vat_rate
|
||||
i.vat_amount = invoice_item.vat_amount
|
||||
i.total = invoice_item.total
|
||||
end
|
||||
end
|
||||
e_invoice_invoice_items << e_invoice_invoice_item
|
||||
end
|
||||
|
||||
|
@ -66,9 +73,15 @@ class Invoice
|
|||
i.beneficiary_name = invoice.seller_name
|
||||
i.beneficiary_account_number = invoice.seller_iban
|
||||
i.payer_name = invoice.buyer_name
|
||||
if invoice.monthly_invoice
|
||||
i.subtotal = 0
|
||||
i.vat_amount = 0
|
||||
i.total = 0
|
||||
else
|
||||
i.subtotal = invoice.subtotal
|
||||
i.vat_amount = invoice.vat_amount
|
||||
i.total = invoice.total
|
||||
end
|
||||
i.currency = invoice.currency
|
||||
i.delivery_channel = %i[internet_bank portal]
|
||||
i.payable = payable
|
||||
|
|
|
@ -14,7 +14,8 @@ class Invoice
|
|||
private
|
||||
|
||||
def invoice_html
|
||||
ApplicationController.render(template: 'invoice/pdf', assigns: { invoice: invoice })
|
||||
template = invoice.monthly_invoice ? 'invoice/monthly_pdf' : 'invoice/pdf'
|
||||
ApplicationController.render(template: template, assigns: { invoice: invoice })
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -4,10 +4,11 @@
|
|||
= @invoice
|
||||
.col-sm-8
|
||||
%h1.text-right.text-center-xs
|
||||
- unless @invoice.monthly_invoice
|
||||
- if @invoice.unpaid?
|
||||
= link_to(t(:payment_received), new_admin_bank_statement_path(invoice_id: @invoice.id), class: 'btn btn-default')
|
||||
|
||||
- if @invoice.paid? and !@invoice.cancelled?
|
||||
- if @invoice.paid? && !@invoice.cancelled?
|
||||
= link_to(t(:cancel_payment), cancel_paid_admin_invoices_path(invoice_id: @invoice.id), method: 'post', data: { confirm: t(:are_you_sure) }, class: 'btn btn-warning')
|
||||
|
||||
= link_to(t('.download_btn'), download_admin_invoice_path(@invoice), class: 'btn btn-default')
|
||||
|
|
277
app/views/invoice/monthly_pdf.haml
Normal file
277
app/views/invoice/monthly_pdf.haml
Normal file
|
@ -0,0 +1,277 @@
|
|||
%html{lang: I18n.locale.to_s}
|
||||
%head
|
||||
%meta{charset: "utf-8"}
|
||||
:css
|
||||
.container {
|
||||
margin: auto;
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
.col-md-12 {
|
||||
|
||||
}
|
||||
|
||||
.col-md-6 {
|
||||
width: 49%;
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
.col-xs-4 {
|
||||
width: 33%;
|
||||
}
|
||||
|
||||
.col-xs-2 {
|
||||
width: 16%;
|
||||
}
|
||||
|
||||
.col-md-3 {
|
||||
width: 24%;
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
.left {
|
||||
float: left;
|
||||
}
|
||||
|
||||
.left {
|
||||
padding-right: 5px;
|
||||
}
|
||||
|
||||
.right {
|
||||
float: right;
|
||||
}
|
||||
|
||||
.text-right {
|
||||
text-align: right;
|
||||
}
|
||||
|
||||
dt {
|
||||
float: left;
|
||||
width: 100px;
|
||||
clear: left;
|
||||
text-align: right;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
font-weight: bold;
|
||||
line-height: 1.42857;
|
||||
}
|
||||
|
||||
dd {
|
||||
margin-left: 120px;
|
||||
line-height: 1.42857;
|
||||
}
|
||||
|
||||
table {
|
||||
width: 100%;
|
||||
border-collapse: collapse;
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
th {
|
||||
text-align: left;
|
||||
border: 0px;
|
||||
border-top: 1px solid #DDD;
|
||||
padding: 6px;
|
||||
}
|
||||
|
||||
thead th {
|
||||
border-bottom: 2px solid #DDD;
|
||||
border-top: 0px;
|
||||
}
|
||||
|
||||
td {
|
||||
border-top: 1px solid #DDD;
|
||||
}
|
||||
|
||||
td {
|
||||
padding: 6px;
|
||||
}
|
||||
|
||||
.no-border {
|
||||
border: 0px;
|
||||
}
|
||||
|
||||
hr {
|
||||
height: 1px;
|
||||
border: 0;
|
||||
color: #DDD;
|
||||
background-color: #DDD;
|
||||
}
|
||||
|
||||
.clear {
|
||||
clear: both;
|
||||
}
|
||||
|
||||
.pull-down {
|
||||
margin-top: 50px;
|
||||
}
|
||||
|
||||
#header {
|
||||
position: relative;
|
||||
min-height: 100px;
|
||||
}
|
||||
|
||||
img {
|
||||
width: 106px;
|
||||
height: 102px;
|
||||
}
|
||||
|
||||
#header-content {
|
||||
position: absolute;
|
||||
bottom: 0;
|
||||
}
|
||||
|
||||
#footer {
|
||||
position: absolute;
|
||||
bottom: 0px;
|
||||
width: 99%;
|
||||
}
|
||||
|
||||
h1 {
|
||||
margin-bottom: 5px;
|
||||
}
|
||||
%body
|
||||
.container
|
||||
#header.row
|
||||
.col-sm-6.left
|
||||
#header-content
|
||||
%h1
|
||||
= @invoice
|
||||
.col-sm-6.right
|
||||
%img{src: "#{Rails.root}/public/eis-logo-black-et.png"}
|
||||
.clear
|
||||
%hr
|
||||
.row
|
||||
.col-md-6.left
|
||||
%h4
|
||||
Details
|
||||
%hr
|
||||
%dl.dl-horizontal
|
||||
%dt= t(:issue_date)
|
||||
%dd= l @invoice.issue_date
|
||||
|
||||
- if @invoice.cancelled?
|
||||
%dt= Invoice.human_attribute_name :cancelled_at
|
||||
%dd= l @invoice.cancelled_at
|
||||
|
||||
%dt= t(:due_date)
|
||||
- if @invoice.cancelled?
|
||||
%dd= t(:cancelled)
|
||||
- else
|
||||
%dd= l @invoice.due_date
|
||||
|
||||
%dt= t(:issuer)
|
||||
%dd= @invoice.seller_contact_name
|
||||
|
||||
- if @invoice.description.present?
|
||||
%dt= t(:description)
|
||||
%dd=@invoice.description
|
||||
|
||||
%dt= Invoice.human_attribute_name :reference_no
|
||||
%dd= @invoice.reference_no
|
||||
|
||||
.col-md-6.right
|
||||
%h4= t(:client)
|
||||
%hr
|
||||
%dl.dl-horizontal
|
||||
%dt= t(:name)
|
||||
%dd= @invoice.buyer_name
|
||||
|
||||
%dt= t(:reg_no)
|
||||
%dd= @invoice.buyer_reg_no
|
||||
|
||||
- if @invoice.buyer_address.present?
|
||||
%dt= Invoice.human_attribute_name :address
|
||||
%dd= @invoice.buyer_address
|
||||
|
||||
- if @invoice.buyer_country.present?
|
||||
%dt= t(:country)
|
||||
%dd= @invoice.buyer_country
|
||||
|
||||
- if @invoice.buyer_phone.present?
|
||||
%dt= t(:phone)
|
||||
%dd= @invoice.buyer_phone
|
||||
|
||||
- if @invoice.buyer_url.present?
|
||||
%dt= t(:url)
|
||||
%dd= @invoice.buyer_url
|
||||
|
||||
- if @invoice.buyer_email.present?
|
||||
%dt= t(:email)
|
||||
%dd= @invoice.buyer_email
|
||||
|
||||
.clear
|
||||
.row.pull-down
|
||||
.col-md-12
|
||||
.table-responsive
|
||||
%table.table.table-hover.table-condensed
|
||||
%thead
|
||||
%tr
|
||||
%th{class: 'col-xs-1'}= t(:code)
|
||||
%th{class: 'col-xs-1'}= InvoiceItem.human_attribute_name :quantity
|
||||
%th{class: 'col-xs-1'}= t(:unit)
|
||||
%th{class: 'col-xs-5'}= t(:description)
|
||||
%th{class: 'col-xs-2'}= t(:price)
|
||||
%th{class: 'col-xs-2'}= t(:total)
|
||||
%tbody
|
||||
- @invoice.each do |invoice_item|
|
||||
%tr
|
||||
%td= invoice_item.product_id
|
||||
%td= invoice_item.quantity
|
||||
%td= invoice_item.unit
|
||||
%td= invoice_item.description
|
||||
- if invoice_item.price && invoice_item.quantity
|
||||
%td= currency(invoice_item.price)
|
||||
%td= "#{currency((invoice_item.price * invoice_item.quantity).round(3))} #{@invoice.currency}"
|
||||
- else
|
||||
%td= ''
|
||||
%td= ''
|
||||
%tfoot
|
||||
%tr
|
||||
%th{colspan: 4}
|
||||
%th= Invoice.human_attribute_name :subtotal
|
||||
%td= number_to_currency(0)
|
||||
%tr
|
||||
%th.no-border{colspan: 4}
|
||||
%th= "VAT #{number_to_percentage(@invoice.vat_rate, precision: 1)}"
|
||||
%td= number_to_currency(0)
|
||||
%tr
|
||||
%th.no-border{colspan: 4}
|
||||
%th= t(:total)
|
||||
%td= number_to_currency(0)
|
||||
|
||||
#footer
|
||||
%hr
|
||||
.row
|
||||
.col-md-3.left
|
||||
= @invoice.seller_name
|
||||
%br
|
||||
= @invoice.seller_address
|
||||
%br
|
||||
= @invoice.seller_country
|
||||
%br
|
||||
= "#{t('reg_no')} #{@invoice.seller_reg_no}"
|
||||
%br
|
||||
= "#{Registrar.human_attribute_name :vat_no} #{@invoice.seller_vat_no}"
|
||||
|
||||
.col-md-3.left
|
||||
= @invoice.seller_phone
|
||||
%br
|
||||
= @invoice.seller_email
|
||||
%br
|
||||
= @invoice.seller_url
|
||||
|
||||
.col-md-3.text-right.left
|
||||
= t(:bank)
|
||||
%br
|
||||
= t(:iban)
|
||||
%br
|
||||
= t(:swift)
|
||||
|
||||
.col-md-3.left
|
||||
= @invoice.seller_bank
|
||||
%br
|
||||
= @invoice.seller_iban
|
||||
%br
|
||||
= @invoice.seller_swift
|
|
@ -484,6 +484,8 @@ en:
|
|||
invoice:
|
||||
title: 'Invoice'
|
||||
already_paid: " (already paid)"
|
||||
monthly_invoice: " (monthly invoice)"
|
||||
monthly_invoice_description: 'Monthly invoice'
|
||||
bank_statements: 'Bank statements'
|
||||
back_to_bank_statements: 'Back to bank statements'
|
||||
back_to_bank_statement: 'Back to bank statement'
|
||||
|
|
|
@ -9,3 +9,5 @@ et:
|
|||
invoice:
|
||||
title: 'Arve'
|
||||
already_paid: " (juba makstud)"
|
||||
monthly_invoice: " (kuuaruanne)"
|
||||
monthly_invoice_description: 'Kuuaruanne'
|
||||
|
|
|
@ -0,0 +1,6 @@
|
|||
class AddMonthlyInvoiceTypeColumns < ActiveRecord::Migration[6.1]
|
||||
def change
|
||||
add_column :invoices, :monthly_invoice, :boolean, default: false
|
||||
add_column :invoices, :metadata, :jsonb
|
||||
end
|
||||
end
|
339
db/structure.sql
339
db/structure.sql
|
@ -955,14 +955,14 @@ CREATE TABLE public.domains (
|
|||
pending_json jsonb,
|
||||
force_delete_date date,
|
||||
statuses character varying[],
|
||||
status_notes public.hstore,
|
||||
upid integer,
|
||||
up_date timestamp without time zone,
|
||||
uuid uuid DEFAULT public.gen_random_uuid() NOT NULL,
|
||||
locked_by_registrant_at timestamp without time zone,
|
||||
force_delete_start timestamp without time zone,
|
||||
force_delete_data public.hstore,
|
||||
json_statuses_history jsonb,
|
||||
status_notes public.hstore
|
||||
json_statuses_history jsonb
|
||||
);
|
||||
|
||||
|
||||
|
@ -985,6 +985,98 @@ CREATE SEQUENCE public.domains_id_seq
|
|||
ALTER SEQUENCE public.domains_id_seq OWNED BY public.domains.id;
|
||||
|
||||
|
||||
--
|
||||
-- Name: email_address_verifications; Type: TABLE; Schema: public; Owner: -
|
||||
--
|
||||
|
||||
CREATE TABLE public.email_address_verifications (
|
||||
id bigint NOT NULL,
|
||||
email public.citext NOT NULL,
|
||||
verified_at timestamp without time zone,
|
||||
success boolean DEFAULT false NOT NULL,
|
||||
domain public.citext NOT NULL
|
||||
);
|
||||
|
||||
|
||||
--
|
||||
-- Name: email_address_verifications_id_seq; Type: SEQUENCE; Schema: public; Owner: -
|
||||
--
|
||||
|
||||
CREATE SEQUENCE public.email_address_verifications_id_seq
|
||||
START WITH 1
|
||||
INCREMENT BY 1
|
||||
NO MINVALUE
|
||||
NO MAXVALUE
|
||||
CACHE 1;
|
||||
|
||||
|
||||
--
|
||||
-- Name: email_address_verifications_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: -
|
||||
--
|
||||
|
||||
ALTER SEQUENCE public.email_address_verifications_id_seq OWNED BY public.email_address_verifications.id;
|
||||
|
||||
|
||||
--
|
||||
-- Name: email_addresses_validations; Type: TABLE; Schema: public; Owner: -
|
||||
--
|
||||
|
||||
CREATE TABLE public.email_addresses_validations (
|
||||
id bigint NOT NULL,
|
||||
email character varying NOT NULL,
|
||||
validated_at timestamp without time zone
|
||||
);
|
||||
|
||||
|
||||
--
|
||||
-- Name: email_addresses_validations_id_seq; Type: SEQUENCE; Schema: public; Owner: -
|
||||
--
|
||||
|
||||
CREATE SEQUENCE public.email_addresses_validations_id_seq
|
||||
START WITH 1
|
||||
INCREMENT BY 1
|
||||
NO MINVALUE
|
||||
NO MAXVALUE
|
||||
CACHE 1;
|
||||
|
||||
|
||||
--
|
||||
-- Name: email_addresses_validations_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: -
|
||||
--
|
||||
|
||||
ALTER SEQUENCE public.email_addresses_validations_id_seq OWNED BY public.email_addresses_validations.id;
|
||||
|
||||
|
||||
--
|
||||
-- Name: email_addresses_verifications; Type: TABLE; Schema: public; Owner: -
|
||||
--
|
||||
|
||||
CREATE TABLE public.email_addresses_verifications (
|
||||
id bigint NOT NULL,
|
||||
email character varying NOT NULL,
|
||||
validated_at timestamp without time zone
|
||||
);
|
||||
|
||||
|
||||
--
|
||||
-- Name: email_addresses_verifications_id_seq; Type: SEQUENCE; Schema: public; Owner: -
|
||||
--
|
||||
|
||||
CREATE SEQUENCE public.email_addresses_verifications_id_seq
|
||||
START WITH 1
|
||||
INCREMENT BY 1
|
||||
NO MINVALUE
|
||||
NO MAXVALUE
|
||||
CACHE 1;
|
||||
|
||||
|
||||
--
|
||||
-- Name: email_addresses_verifications_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: -
|
||||
--
|
||||
|
||||
ALTER SEQUENCE public.email_addresses_verifications_id_seq OWNED BY public.email_addresses_verifications.id;
|
||||
|
||||
|
||||
--
|
||||
-- Name: epp_sessions; Type: TABLE; Schema: public; Owner: -
|
||||
--
|
||||
|
@ -1104,6 +1196,8 @@ CREATE TABLE public.invoices (
|
|||
issue_date date NOT NULL,
|
||||
e_invoice_sent_at timestamp without time zone,
|
||||
payment_link character varying,
|
||||
monthly_invoice boolean DEFAULT false,
|
||||
metadata jsonb,
|
||||
CONSTRAINT invoices_due_date_is_not_before_issue_date CHECK ((due_date >= issue_date))
|
||||
);
|
||||
|
||||
|
@ -2190,6 +2284,74 @@ CREATE SEQUENCE public.payment_orders_id_seq
|
|||
ALTER SEQUENCE public.payment_orders_id_seq OWNED BY public.payment_orders.id;
|
||||
|
||||
|
||||
--
|
||||
-- Name: pghero_query_stats; Type: TABLE; Schema: public; Owner: -
|
||||
--
|
||||
|
||||
CREATE TABLE public.pghero_query_stats (
|
||||
id bigint NOT NULL,
|
||||
database text,
|
||||
"user" text,
|
||||
query text,
|
||||
query_hash bigint,
|
||||
total_time double precision,
|
||||
calls bigint,
|
||||
captured_at timestamp without time zone
|
||||
);
|
||||
|
||||
|
||||
--
|
||||
-- Name: pghero_query_stats_id_seq; Type: SEQUENCE; Schema: public; Owner: -
|
||||
--
|
||||
|
||||
CREATE SEQUENCE public.pghero_query_stats_id_seq
|
||||
START WITH 1
|
||||
INCREMENT BY 1
|
||||
NO MINVALUE
|
||||
NO MAXVALUE
|
||||
CACHE 1;
|
||||
|
||||
|
||||
--
|
||||
-- Name: pghero_query_stats_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: -
|
||||
--
|
||||
|
||||
ALTER SEQUENCE public.pghero_query_stats_id_seq OWNED BY public.pghero_query_stats.id;
|
||||
|
||||
|
||||
--
|
||||
-- Name: pghero_space_stats; Type: TABLE; Schema: public; Owner: -
|
||||
--
|
||||
|
||||
CREATE TABLE public.pghero_space_stats (
|
||||
id bigint NOT NULL,
|
||||
database text,
|
||||
schema text,
|
||||
relation text,
|
||||
size bigint,
|
||||
captured_at timestamp without time zone
|
||||
);
|
||||
|
||||
|
||||
--
|
||||
-- Name: pghero_space_stats_id_seq; Type: SEQUENCE; Schema: public; Owner: -
|
||||
--
|
||||
|
||||
CREATE SEQUENCE public.pghero_space_stats_id_seq
|
||||
START WITH 1
|
||||
INCREMENT BY 1
|
||||
NO MINVALUE
|
||||
NO MAXVALUE
|
||||
CACHE 1;
|
||||
|
||||
|
||||
--
|
||||
-- Name: pghero_space_stats_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: -
|
||||
--
|
||||
|
||||
ALTER SEQUENCE public.pghero_space_stats_id_seq OWNED BY public.pghero_space_stats.id;
|
||||
|
||||
|
||||
--
|
||||
-- Name: prices; Type: TABLE; Schema: public; Owner: -
|
||||
--
|
||||
|
@ -2228,6 +2390,48 @@ CREATE SEQUENCE public.prices_id_seq
|
|||
ALTER SEQUENCE public.prices_id_seq OWNED BY public.prices.id;
|
||||
|
||||
|
||||
--
|
||||
-- Name: que_jobs; Type: TABLE; Schema: public; Owner: -
|
||||
--
|
||||
|
||||
CREATE TABLE public.que_jobs (
|
||||
priority smallint DEFAULT 100 NOT NULL,
|
||||
run_at timestamp with time zone DEFAULT now() NOT NULL,
|
||||
job_id bigint NOT NULL,
|
||||
job_class text NOT NULL,
|
||||
args json DEFAULT '[]'::json NOT NULL,
|
||||
error_count integer DEFAULT 0 NOT NULL,
|
||||
last_error text,
|
||||
queue text DEFAULT ''::text NOT NULL
|
||||
);
|
||||
|
||||
|
||||
--
|
||||
-- Name: TABLE que_jobs; Type: COMMENT; Schema: public; Owner: -
|
||||
--
|
||||
|
||||
COMMENT ON TABLE public.que_jobs IS '3';
|
||||
|
||||
|
||||
--
|
||||
-- Name: que_jobs_job_id_seq; Type: SEQUENCE; Schema: public; Owner: -
|
||||
--
|
||||
|
||||
CREATE SEQUENCE public.que_jobs_job_id_seq
|
||||
START WITH 1
|
||||
INCREMENT BY 1
|
||||
NO MINVALUE
|
||||
NO MAXVALUE
|
||||
CACHE 1;
|
||||
|
||||
|
||||
--
|
||||
-- Name: que_jobs_job_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: -
|
||||
--
|
||||
|
||||
ALTER SEQUENCE public.que_jobs_job_id_seq OWNED BY public.que_jobs.job_id;
|
||||
|
||||
|
||||
--
|
||||
-- Name: registrant_verifications; Type: TABLE; Schema: public; Owner: -
|
||||
--
|
||||
|
@ -2508,8 +2712,7 @@ CREATE TABLE public.validation_events (
|
|||
validation_eventable_type character varying,
|
||||
validation_eventable_id bigint,
|
||||
created_at timestamp(6) without time zone NOT NULL,
|
||||
updated_at timestamp(6) without time zone NOT NULL,
|
||||
event_type public.validation_type
|
||||
updated_at timestamp(6) without time zone NOT NULL
|
||||
);
|
||||
|
||||
|
||||
|
@ -2813,6 +3016,27 @@ ALTER TABLE ONLY public.domain_transfers ALTER COLUMN id SET DEFAULT nextval('pu
|
|||
ALTER TABLE ONLY public.domains ALTER COLUMN id SET DEFAULT nextval('public.domains_id_seq'::regclass);
|
||||
|
||||
|
||||
--
|
||||
-- Name: email_address_verifications id; Type: DEFAULT; Schema: public; Owner: -
|
||||
--
|
||||
|
||||
ALTER TABLE ONLY public.email_address_verifications ALTER COLUMN id SET DEFAULT nextval('public.email_address_verifications_id_seq'::regclass);
|
||||
|
||||
|
||||
--
|
||||
-- Name: email_addresses_validations id; Type: DEFAULT; Schema: public; Owner: -
|
||||
--
|
||||
|
||||
ALTER TABLE ONLY public.email_addresses_validations ALTER COLUMN id SET DEFAULT nextval('public.email_addresses_validations_id_seq'::regclass);
|
||||
|
||||
|
||||
--
|
||||
-- Name: email_addresses_verifications id; Type: DEFAULT; Schema: public; Owner: -
|
||||
--
|
||||
|
||||
ALTER TABLE ONLY public.email_addresses_verifications ALTER COLUMN id SET DEFAULT nextval('public.email_addresses_verifications_id_seq'::regclass);
|
||||
|
||||
|
||||
--
|
||||
-- Name: epp_sessions id; Type: DEFAULT; Schema: public; Owner: -
|
||||
--
|
||||
|
@ -3030,6 +3254,20 @@ ALTER TABLE ONLY public.notifications ALTER COLUMN id SET DEFAULT nextval('publi
|
|||
ALTER TABLE ONLY public.payment_orders ALTER COLUMN id SET DEFAULT nextval('public.payment_orders_id_seq'::regclass);
|
||||
|
||||
|
||||
--
|
||||
-- Name: pghero_query_stats id; Type: DEFAULT; Schema: public; Owner: -
|
||||
--
|
||||
|
||||
ALTER TABLE ONLY public.pghero_query_stats ALTER COLUMN id SET DEFAULT nextval('public.pghero_query_stats_id_seq'::regclass);
|
||||
|
||||
|
||||
--
|
||||
-- Name: pghero_space_stats id; Type: DEFAULT; Schema: public; Owner: -
|
||||
--
|
||||
|
||||
ALTER TABLE ONLY public.pghero_space_stats ALTER COLUMN id SET DEFAULT nextval('public.pghero_space_stats_id_seq'::regclass);
|
||||
|
||||
|
||||
--
|
||||
-- Name: prices id; Type: DEFAULT; Schema: public; Owner: -
|
||||
--
|
||||
|
@ -3037,6 +3275,13 @@ ALTER TABLE ONLY public.payment_orders ALTER COLUMN id SET DEFAULT nextval('publ
|
|||
ALTER TABLE ONLY public.prices ALTER COLUMN id SET DEFAULT nextval('public.prices_id_seq'::regclass);
|
||||
|
||||
|
||||
--
|
||||
-- Name: que_jobs job_id; Type: DEFAULT; Schema: public; Owner: -
|
||||
--
|
||||
|
||||
ALTER TABLE ONLY public.que_jobs ALTER COLUMN job_id SET DEFAULT nextval('public.que_jobs_job_id_seq'::regclass);
|
||||
|
||||
|
||||
--
|
||||
-- Name: registrant_verifications id; Type: DEFAULT; Schema: public; Owner: -
|
||||
--
|
||||
|
@ -3274,6 +3519,30 @@ ALTER TABLE ONLY public.domains
|
|||
ADD CONSTRAINT domains_pkey PRIMARY KEY (id);
|
||||
|
||||
|
||||
--
|
||||
-- Name: email_address_verifications email_address_verifications_pkey; Type: CONSTRAINT; Schema: public; Owner: -
|
||||
--
|
||||
|
||||
ALTER TABLE ONLY public.email_address_verifications
|
||||
ADD CONSTRAINT email_address_verifications_pkey PRIMARY KEY (id);
|
||||
|
||||
|
||||
--
|
||||
-- Name: email_addresses_validations email_addresses_validations_pkey; Type: CONSTRAINT; Schema: public; Owner: -
|
||||
--
|
||||
|
||||
ALTER TABLE ONLY public.email_addresses_validations
|
||||
ADD CONSTRAINT email_addresses_validations_pkey PRIMARY KEY (id);
|
||||
|
||||
|
||||
--
|
||||
-- Name: email_addresses_verifications email_addresses_verifications_pkey; Type: CONSTRAINT; Schema: public; Owner: -
|
||||
--
|
||||
|
||||
ALTER TABLE ONLY public.email_addresses_verifications
|
||||
ADD CONSTRAINT email_addresses_verifications_pkey PRIMARY KEY (id);
|
||||
|
||||
|
||||
--
|
||||
-- Name: epp_sessions epp_sessions_pkey; Type: CONSTRAINT; Schema: public; Owner: -
|
||||
--
|
||||
|
@ -3522,6 +3791,22 @@ ALTER TABLE ONLY public.payment_orders
|
|||
ADD CONSTRAINT payment_orders_pkey PRIMARY KEY (id);
|
||||
|
||||
|
||||
--
|
||||
-- Name: pghero_query_stats pghero_query_stats_pkey; Type: CONSTRAINT; Schema: public; Owner: -
|
||||
--
|
||||
|
||||
ALTER TABLE ONLY public.pghero_query_stats
|
||||
ADD CONSTRAINT pghero_query_stats_pkey PRIMARY KEY (id);
|
||||
|
||||
|
||||
--
|
||||
-- Name: pghero_space_stats pghero_space_stats_pkey; Type: CONSTRAINT; Schema: public; Owner: -
|
||||
--
|
||||
|
||||
ALTER TABLE ONLY public.pghero_space_stats
|
||||
ADD CONSTRAINT pghero_space_stats_pkey PRIMARY KEY (id);
|
||||
|
||||
|
||||
--
|
||||
-- Name: prices prices_pkey; Type: CONSTRAINT; Schema: public; Owner: -
|
||||
--
|
||||
|
@ -3530,6 +3815,14 @@ ALTER TABLE ONLY public.prices
|
|||
ADD CONSTRAINT prices_pkey PRIMARY KEY (id);
|
||||
|
||||
|
||||
--
|
||||
-- Name: que_jobs que_jobs_pkey; Type: CONSTRAINT; Schema: public; Owner: -
|
||||
--
|
||||
|
||||
ALTER TABLE ONLY public.que_jobs
|
||||
ADD CONSTRAINT que_jobs_pkey PRIMARY KEY (queue, priority, run_at, job_id);
|
||||
|
||||
|
||||
--
|
||||
-- Name: registrant_verifications registrant_verifications_pkey; Type: CONSTRAINT; Schema: public; Owner: -
|
||||
--
|
||||
|
@ -3941,6 +4234,13 @@ CREATE INDEX index_domains_on_registrar_id ON public.domains USING btree (regist
|
|||
CREATE INDEX index_domains_on_statuses ON public.domains USING gin (statuses);
|
||||
|
||||
|
||||
--
|
||||
-- Name: index_email_address_verifications_on_domain; Type: INDEX; Schema: public; Owner: -
|
||||
--
|
||||
|
||||
CREATE INDEX index_email_address_verifications_on_domain ON public.email_address_verifications USING btree (domain);
|
||||
|
||||
|
||||
--
|
||||
-- Name: index_epp_sessions_on_updated_at; Type: INDEX; Schema: public; Owner: -
|
||||
--
|
||||
|
@ -4277,6 +4577,20 @@ CREATE INDEX index_notifications_on_registrar_id ON public.notifications USING b
|
|||
CREATE INDEX index_payment_orders_on_invoice_id ON public.payment_orders USING btree (invoice_id);
|
||||
|
||||
|
||||
--
|
||||
-- Name: index_pghero_query_stats_on_database_and_captured_at; Type: INDEX; Schema: public; Owner: -
|
||||
--
|
||||
|
||||
CREATE INDEX index_pghero_query_stats_on_database_and_captured_at ON public.pghero_query_stats USING btree (database, captured_at);
|
||||
|
||||
|
||||
--
|
||||
-- Name: index_pghero_space_stats_on_database_and_captured_at; Type: INDEX; Schema: public; Owner: -
|
||||
--
|
||||
|
||||
CREATE INDEX index_pghero_space_stats_on_database_and_captured_at ON public.pghero_space_stats USING btree (database, captured_at);
|
||||
|
||||
|
||||
--
|
||||
-- Name: index_prices_on_zone_id; Type: INDEX; Schema: public; Owner: -
|
||||
--
|
||||
|
@ -4333,13 +4647,6 @@ CREATE INDEX index_users_on_registrar_id ON public.users USING btree (registrar_
|
|||
CREATE INDEX index_validation_events_on_event_data ON public.validation_events USING gin (event_data);
|
||||
|
||||
|
||||
--
|
||||
-- Name: index_validation_events_on_event_type; Type: INDEX; Schema: public; Owner: -
|
||||
--
|
||||
|
||||
CREATE INDEX index_validation_events_on_event_type ON public.validation_events USING btree (event_type);
|
||||
|
||||
|
||||
--
|
||||
-- Name: index_validation_events_on_validation_eventable; Type: INDEX; Schema: public; Owner: -
|
||||
--
|
||||
|
@ -5085,9 +5392,11 @@ INSERT INTO "schema_migrations" (version) VALUES
|
|||
('20210708131814'),
|
||||
('20210729131100'),
|
||||
('20210729134625'),
|
||||
('20210827185249'),
|
||||
('20211029073644'),
|
||||
('20211028122103'),
|
||||
('20211028125245'),
|
||||
('20211029082225'),
|
||||
('20211124071418'),
|
||||
('20211124084308'),
|
||||
('20211125181033'),
|
||||
('20211125184334'),
|
||||
('20211126085139'),
|
||||
|
@ -5098,12 +5407,12 @@ INSERT INTO "schema_migrations" (version) VALUES
|
|||
('20220124105717'),
|
||||
('20220228093211'),
|
||||
('20220316140727'),
|
||||
('20220406085500'),
|
||||
('20220412130856'),
|
||||
('20220413073315'),
|
||||
('20220413084536'),
|
||||
('20220413084748'),
|
||||
('20220504090512'),
|
||||
('20220524130709');
|
||||
('20220524130709'),
|
||||
('20220818075833');
|
||||
|
||||
|
||||
|
|
|
@ -23,7 +23,8 @@ module Serializers
|
|||
created_at: obj.created_at, updated_at: obj.updated_at,
|
||||
due_date: obj.due_date, currency: obj.currency,
|
||||
seller: seller, buyer: buyer, items: items,
|
||||
recipient: obj.buyer.billing_email
|
||||
recipient: obj.buyer.billing_email,
|
||||
monthly_invoice: obj.monthly_invoice
|
||||
}
|
||||
end
|
||||
|
||||
|
@ -54,6 +55,9 @@ module Serializers
|
|||
end
|
||||
|
||||
def items
|
||||
if invoice.monthly_invoice
|
||||
invoice.metadata['items']
|
||||
else
|
||||
invoice.items.map do |item|
|
||||
{ description: item.description, unit: item.unit,
|
||||
quantity: item.quantity, price: item.price,
|
||||
|
@ -61,6 +65,7 @@ module Serializers
|
|||
vat_amount: item.vat_amount, total: item.total }
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def simple_object
|
||||
{
|
||||
|
@ -75,6 +80,7 @@ module Serializers
|
|||
due_date: invoice.due_date,
|
||||
total: invoice.total,
|
||||
recipient: invoice.buyer.billing_email,
|
||||
monthly_invoice: invoice.monthly_invoice,
|
||||
}
|
||||
end
|
||||
# rubocop:enable Metrics/MethodLength
|
||||
|
|
|
@ -8,9 +8,9 @@ class DirectoInvoiceForwardJobTest < ActiveSupport::TestCase
|
|||
end
|
||||
|
||||
def teardown
|
||||
Setting.directo_monthly_number_min = 309901
|
||||
Setting.directo_monthly_number_max = 309999
|
||||
Setting.directo_monthly_number_last = 309901
|
||||
Setting.directo_monthly_number_min = 309_901
|
||||
Setting.directo_monthly_number_max = 309_999
|
||||
Setting.directo_monthly_number_last = 309_901
|
||||
end
|
||||
|
||||
def test_directo_json_sends_customer_as_hash
|
||||
|
@ -49,7 +49,7 @@ class DirectoInvoiceForwardJobTest < ActiveSupport::TestCase
|
|||
price = billing_prices(:create_one_year)
|
||||
activity.update!(activity_type: 'create', price: price)
|
||||
|
||||
Setting.directo_monthly_number_max = 30991
|
||||
Setting.directo_monthly_number_max = 30_991
|
||||
|
||||
assert_raises 'RuntimeError' do
|
||||
DirectoInvoiceForwardJob.perform_now(monthly: true, dry: false)
|
||||
|
|
265
test/jobs/send_monthly_invoices_job_test.rb
Normal file
265
test/jobs/send_monthly_invoices_job_test.rb
Normal file
|
@ -0,0 +1,265 @@
|
|||
require 'test_helper'
|
||||
|
||||
class SendMonthlyInvoicesJobTest < ActiveSupport::TestCase
|
||||
include ActionMailer::TestHelper
|
||||
|
||||
setup do
|
||||
@user = registrars(:bestnames)
|
||||
@date = Time.zone.parse('2010-08-06')
|
||||
travel_to @date
|
||||
ActionMailer::Base.deliveries.clear
|
||||
EInvoice.provider = EInvoice::Providers::TestProvider.new
|
||||
EInvoice::Providers::TestProvider.deliveries.clear
|
||||
end
|
||||
|
||||
def teardown
|
||||
Setting.directo_monthly_number_min = 309_901
|
||||
Setting.directo_monthly_number_max = 309_999
|
||||
Setting.directo_monthly_number_last = 309_901
|
||||
EInvoice.provider = EInvoice::Providers::TestProvider.new
|
||||
EInvoice::Providers::TestProvider.deliveries.clear
|
||||
end
|
||||
|
||||
def test_fails_if_directo_bounds_exceedable
|
||||
activity = account_activities(:one)
|
||||
price = billing_prices(:create_one_year)
|
||||
activity.update!(activity_type: 'create', price: price)
|
||||
|
||||
Setting.directo_monthly_number_max = 30_991
|
||||
|
||||
assert_no_difference 'Directo.count' do
|
||||
assert_raises 'RuntimeError' do
|
||||
SendMonthlyInvoicesJob.perform_now
|
||||
end
|
||||
end
|
||||
|
||||
assert_nil Invoice.find_by_monthly_invoice(true)
|
||||
assert_emails 0
|
||||
assert_equal 0, EInvoice::Providers::TestProvider.deliveries.count
|
||||
end
|
||||
|
||||
def test_monthly_summary_is_not_delivered_if_dry
|
||||
activity = account_activities(:one)
|
||||
price = billing_prices(:create_one_year)
|
||||
activity.update!(activity_type: 'create', price: price)
|
||||
@user.update(language: 'et')
|
||||
|
||||
assert_difference 'Setting.directo_monthly_number_last' do
|
||||
assert_no_difference 'Directo.count' do
|
||||
SendMonthlyInvoicesJob.perform_now(dry: true)
|
||||
end
|
||||
end
|
||||
|
||||
invoice = Invoice.last
|
||||
assert_equal 309_902, invoice.number
|
||||
refute invoice.in_directo
|
||||
assert invoice.e_invoice_sent_at.blank?
|
||||
|
||||
assert_emails 0
|
||||
assert_equal 0, EInvoice::Providers::TestProvider.deliveries.count
|
||||
end
|
||||
|
||||
def test_monthly_summary_is_delivered_if_invoice_already_exists
|
||||
@monthly_invoice = invoices(:one)
|
||||
@monthly_invoice.update(number: 309_902, monthly_invoice: true,
|
||||
issue_date: @date.last_month.end_of_month,
|
||||
due_date: @date.last_month.end_of_month,
|
||||
metadata: metadata,
|
||||
in_directo: false,
|
||||
e_invoice_sent_at: nil)
|
||||
|
||||
activity = account_activities(:one)
|
||||
price = billing_prices(:create_one_year)
|
||||
activity.update!(activity_type: 'create', price: price)
|
||||
@user.update(language: 'et')
|
||||
|
||||
response = <<-XML
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<results>
|
||||
<Result Type="0" Desc="OK" docid="309902" doctype="ARVE" submit="Invoices"/>
|
||||
</results>
|
||||
XML
|
||||
|
||||
stub_request(:post, ENV['directo_invoice_url']).with do |request|
|
||||
body = CGI.unescape(request.body)
|
||||
|
||||
(body.include? '.test registreerimine: 1 aasta(t)') &&
|
||||
(body.include? 'Domeenide ettemaks') &&
|
||||
(body.include? '309902')
|
||||
end.to_return(status: 200, body: response)
|
||||
|
||||
assert_no_difference 'Setting.directo_monthly_number_last' do
|
||||
assert_difference('Directo.count', 1) do
|
||||
SendMonthlyInvoicesJob.perform_now
|
||||
end
|
||||
end
|
||||
|
||||
invoice = Invoice.last
|
||||
assert_equal 309_902, invoice.number
|
||||
assert invoice.in_directo
|
||||
assert_not invoice.e_invoice_sent_at.blank?
|
||||
|
||||
assert_emails 1
|
||||
email = ActionMailer::Base.deliveries.last
|
||||
assert_equal ['billing@bestnames.test'], email.to
|
||||
assert_equal 'Invoice no. 309902 (monthly invoice)', email.subject
|
||||
assert email.attachments['invoice-309902.pdf']
|
||||
|
||||
assert_equal 1, EInvoice::Providers::TestProvider.deliveries.count
|
||||
end
|
||||
|
||||
def test_monthly_summary_is_delivered_in_estonian
|
||||
activity = account_activities(:one)
|
||||
price = billing_prices(:create_one_year)
|
||||
activity.update!(activity_type: 'create', price: price)
|
||||
@user.update(language: 'et')
|
||||
|
||||
response = <<-XML
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<results>
|
||||
<Result Type="0" Desc="OK" docid="309902" doctype="ARVE" submit="Invoices"/>
|
||||
</results>
|
||||
XML
|
||||
|
||||
stub_request(:post, ENV['directo_invoice_url']).with do |request|
|
||||
body = CGI.unescape(request.body)
|
||||
|
||||
(body.include? '.test registreerimine: 1 aasta(t)') &&
|
||||
(body.include? 'Domeenide ettemaks') &&
|
||||
(body.include? '309902')
|
||||
end.to_return(status: 200, body: response)
|
||||
|
||||
assert_difference 'Setting.directo_monthly_number_last' do
|
||||
assert_difference('Directo.count', 1) do
|
||||
SendMonthlyInvoicesJob.perform_now
|
||||
end
|
||||
end
|
||||
|
||||
invoice = Invoice.last
|
||||
assert_equal 309_902, invoice.number
|
||||
assert invoice.in_directo
|
||||
assert_not invoice.e_invoice_sent_at.blank?
|
||||
|
||||
assert_emails 1
|
||||
email = ActionMailer::Base.deliveries.last
|
||||
assert_equal ['billing@bestnames.test'], email.to
|
||||
assert_equal 'Invoice no. 309902 (monthly invoice)', email.subject
|
||||
assert email.attachments['invoice-309902.pdf']
|
||||
|
||||
assert_equal 1, EInvoice::Providers::TestProvider.deliveries.count
|
||||
end
|
||||
|
||||
def test_multi_year_purchases_have_duration_assigned
|
||||
activity = account_activities(:one)
|
||||
price = billing_prices(:create_one_year)
|
||||
price.update(duration: 3.years)
|
||||
activity.update(activity_type: 'create', price: price)
|
||||
|
||||
response = <<-XML
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<results>
|
||||
<Result Type="0" Desc="OK" docid="309902" doctype="ARVE" submit="Invoices"/>
|
||||
</results>
|
||||
XML
|
||||
|
||||
stub_request(:post, ENV['directo_invoice_url']).with do |request|
|
||||
body = CGI.unescape(request.body)
|
||||
(body.include? 'StartDate') && (body.include? 'EndDate')
|
||||
end.to_return(status: 200, body: response)
|
||||
|
||||
assert_difference 'Setting.directo_monthly_number_last' do
|
||||
SendMonthlyInvoicesJob.perform_now
|
||||
end
|
||||
|
||||
invoice = Invoice.last
|
||||
assert_equal 309_902, invoice.number
|
||||
assert invoice.in_directo
|
||||
assert_not invoice.e_invoice_sent_at.blank?
|
||||
end
|
||||
|
||||
def test_monthly_duration_products_are_present_in_summary
|
||||
activity = account_activities(:one)
|
||||
price = billing_prices(:create_one_month)
|
||||
activity.update(activity_type: 'create', price: price)
|
||||
|
||||
response = <<-XML
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<results>
|
||||
<Result Type="0" Desc="OK" docid="309902" doctype="ARVE" submit="Invoices"/>
|
||||
</results>
|
||||
XML
|
||||
|
||||
stub_request(:post, ENV['directo_invoice_url']).with do |request|
|
||||
body = CGI.unescape(request.body)
|
||||
body.include? 'month(s)'
|
||||
end.to_return(status: 200, body: response)
|
||||
|
||||
assert_difference 'Setting.directo_monthly_number_last' do
|
||||
SendMonthlyInvoicesJob.perform_now
|
||||
end
|
||||
|
||||
invoice = Invoice.last
|
||||
assert_equal 309_902, invoice.number
|
||||
assert invoice.in_directo
|
||||
assert_not invoice.e_invoice_sent_at.blank?
|
||||
end
|
||||
|
||||
def test_sends_each_monthly_invoice_separately
|
||||
WebMock.reset!
|
||||
|
||||
activity = account_activities(:one)
|
||||
price = billing_prices(:create_one_year)
|
||||
price.update(duration: 3.years)
|
||||
activity.update(activity_type: 'create', price: price)
|
||||
|
||||
# Creating account activity for second action
|
||||
another_activity = activity.dup
|
||||
another_activity.account = accounts(:two)
|
||||
|
||||
AccountActivity.skip_callback(:create, :after, :update_balance)
|
||||
another_activity.created_at = Time.zone.parse('2010-07-05 10:00')
|
||||
another_activity.save
|
||||
AccountActivity.set_callback(:create, :after, :update_balance)
|
||||
|
||||
response = <<-XML
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<results>
|
||||
<Result Type="0" Desc="OK" docid="309902" doctype="ARVE" submit="Invoices"/>
|
||||
</results>
|
||||
XML
|
||||
|
||||
first_registrar_stub = stub_request(:post, ENV['directo_invoice_url']).with do |request|
|
||||
body = CGI.unescape(request.body)
|
||||
(body.include? 'StartDate') && (body.include? 'EndDate') && (body.include? 'bestnames')
|
||||
end.to_return(status: 200, body: response)
|
||||
|
||||
second_registrar_stub = stub_request(:post, ENV['directo_invoice_url']).with do |request|
|
||||
body = CGI.unescape(request.body)
|
||||
(body.include? 'StartDate') && (body.include? 'EndDate') && (body.include? 'goodnames')
|
||||
end.to_return(status: 200, body: response)
|
||||
|
||||
assert_difference('Invoice.count', 2) do
|
||||
assert_difference('Directo.count', 2) do
|
||||
SendMonthlyInvoicesJob.perform_now
|
||||
end
|
||||
end
|
||||
|
||||
assert_requested first_registrar_stub
|
||||
assert_requested second_registrar_stub
|
||||
|
||||
assert_emails 2
|
||||
assert_equal 2, EInvoice::Providers::TestProvider.deliveries.count
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def metadata
|
||||
{
|
||||
"items" => [
|
||||
{ "description" => "Domeenide registreerimine - Juuli 2010" },
|
||||
{ "product_id" => nil, "quantity" => 1, "unit" => "tk", "price" => 10.0, "description" => ".test registreerimine: 1 aasta(t)" },
|
||||
{ "product_id" => "ETTEM06", "description" => "Domeenide ettemaks", "quantity" => -1, "price" => 10.0, "unit" => "tk" },
|
||||
],
|
||||
}
|
||||
end
|
||||
end
|
Loading…
Add table
Add a link
Reference in a new issue