-
Notifications
You must be signed in to change notification settings - Fork 19
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #2456 from internetee/modify-monthly-invoice-gener…
…ation Refactored monthly invoice generation job
- Loading branch information
Showing
21 changed files
with
390 additions
and
512 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,147 +1,67 @@ | ||
class SendMonthlyInvoicesJob < ApplicationJob # rubocop:disable Metrics/ClassLength | ||
queue_as :default | ||
discard_on StandardError | ||
|
||
def perform(dry: false) | ||
def perform(dry: false, months_ago: 1) | ||
@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) | ||
@month = Time.zone.now - months_ago.month | ||
@directo_data = [] | ||
|
||
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 | ||
|
||
# rubocop:disable Metrics/MethodLength | ||
def send_monthly_invoices | ||
Registrar.with_cash_accounts.find_each do |registrar| | ||
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 | ||
|
||
send_email_to_registrar(invoice: invoice, registrar: registrar) | ||
send_e_invoice(invoice.id) | ||
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 | ||
invoices = find_or_init_monthly_invoices | ||
assign_invoice_numbers(invoices) | ||
return if invoices.empty? || @dry | ||
|
||
invoices.each do |inv| | ||
inv.send_to_registrar! unless inv.sent? | ||
send_e_invoice(inv.id) | ||
@directo_data << inv.as_monthly_directo_json unless inv.in_directo | ||
end | ||
end | ||
|
||
# rubocop:enable Metrics/MethodLength | ||
|
||
def send_email_to_registrar(invoice:, registrar:) | ||
InvoiceMailer.invoice_email(invoice: invoice, | ||
recipient: registrar.billing_email) | ||
.deliver_now | ||
end | ||
|
||
def send_e_invoice(invoice_id) | ||
SendEInvoiceLegacyJob.set(wait: 1.minute).perform_later(invoice_id, payable: false) | ||
end | ||
|
||
def create_invoice(summary, registrar) | ||
invoice = registrar.init_monthly_invoice(normalize(summary)) | ||
invoice.number = assign_monthly_number | ||
return unless invoice.save! | ||
|
||
update_monthly_invoice_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}") | ||
return if @directo_data.empty? | ||
|
||
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') | ||
EisBilling::SendDataToDirecto.send_request(object_data: @directo_data, | ||
monthly: true) | ||
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) | ||
def assign_invoice_numbers(invoices) | ||
invoice_without_numbers = invoices.select { |i| i.number.nil? } | ||
return if invoice_without_numbers.empty? | ||
|
||
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) | ||
result = EisBilling::GetMonthlyInvoiceNumbers.send_request(invoice_without_numbers.size) | ||
response = JSON.parse(result.body) | ||
handle_assign_numbers_response_errors(response) | ||
|
||
false | ||
end | ||
numbers = response['invoice_numbers'] | ||
invoice_without_numbers.each_with_index do |inv, index| | ||
inv.number = numbers[index] | ||
next if inv.save | ||
|
||
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_to_directo(res: res, req: req, invoice: inv) | ||
Rails.logger.info 'There was an error creating monthly ' \ | ||
"invoice #{inv.number}: #{inv.errors.full_messages.first}" | ||
end | ||
end | ||
# rubocop:enable Metrics/MethodLength | ||
|
||
def mark_invoice_as_sent_to_directo(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! | ||
def find_or_init_monthly_invoices(invoices: []) | ||
Registrar.with_cash_accounts.find_each do |registrar| | ||
invoice = registrar.find_or_init_monthly_invoice(month: @month) | ||
invoices << invoice unless invoice.nil? | ||
end | ||
invoices | ||
end | ||
|
||
def update_monthly_invoice_number(num:) | ||
return unless num.to_i > Setting.directo_monthly_number_last.to_i | ||
|
||
Setting.directo_monthly_number_last = num.to_i | ||
def send_e_invoice(invoice_id) | ||
SendEInvoiceJob.set(wait: 30.seconds).perform_later(invoice_id, payable: false) | ||
end | ||
|
||
private | ||
|
||
# rubocop:disable Metrics/MethodLength | ||
def normalize(summary, lines: []) | ||
sum = summary.dup | ||
line_map = Hash.new 0 | ||
sum['invoice_lines'].each { |l| line_map[l] += 1 } | ||
|
||
line_map.each_key do |count| | ||
count['quantity'] = line_map[count] unless count['unit'].nil? | ||
regex = /Domeenide ettemaks|Domains prepayment/ | ||
count['quantity'] = -1 if count['description'].match?(regex) | ||
lines << count | ||
end | ||
|
||
sum['invoice_lines'] = summarize_lines(lines) | ||
sum | ||
end | ||
# rubocop:enable Metrics/MethodLength | ||
|
||
def summarize_lines(invoice_lines, lines: []) | ||
line_map = Hash.new 0 | ||
invoice_lines.each do |l| | ||
hash = l.with_indifferent_access.except(:start_date, :end_date) | ||
line_map[hash] += 1 | ||
end | ||
|
||
line_map.each_key do |count| | ||
count['price'] = (line_map[count] * count['price'].to_f).round(3) unless count['price'].nil? | ||
lines << count | ||
end | ||
|
||
lines | ||
def handle_assign_numbers_response_errors(response) | ||
raise 'INVOICE NUMBER LIMIT REACHED, COULD NOT GENERATE INVOICE' if response['code'] == '403' | ||
raise 'PROBLEM WITH TOKEN' if response['error'] == 'out of range' | ||
end | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.