From d5662f42b8617d0dd5b25e1e06257045db71143a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Karl=20Erik=20=C3=95unapuu?= Date: Wed, 12 Feb 2020 17:14:18 +0200 Subject: [PATCH] Fully implemented prepayment Directo invoice forwarding, WIP on proformas --- Gemfile.lock | 12 +- app/controllers/concerns/book_keeping.rb | 99 +++++++++ app/jobs/directo_invoice_forward_job.rb | 101 +++++++++ app/jobs/directo_invoice_forward_job_job.rb | 100 --------- app/models/counter.rb | 24 --- app/models/directo.rb | 195 ------------------ app/models/invoice.rb | 18 +- app/models/registrar.rb | 1 + test/jobs/directo_invoice_forward_job_test.rb | 20 ++ test/models/directo_test.rb | 16 -- 10 files changed, 249 insertions(+), 337 deletions(-) create mode 100644 app/controllers/concerns/book_keeping.rb create mode 100644 app/jobs/directo_invoice_forward_job.rb delete mode 100644 app/jobs/directo_invoice_forward_job_job.rb delete mode 100644 app/models/counter.rb create mode 100644 test/jobs/directo_invoice_forward_job_test.rb diff --git a/Gemfile.lock b/Gemfile.lock index 23aa90a51..71abcf70d 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -7,6 +7,15 @@ GIT activesupport savon +GIT + remote: https://github.com/internetee/directo.git + revision: 6ac71939da589fcceb5ef3989ba982134679ec97 + branch: directo-api + specs: + directo (0.1.0) + money (~> 6.13) + nokogiri (~> 1.10) + GIT remote: https://github.com/internetee/e_invoice.git revision: 3a754974ed25569aa85d99a87ae9e131b7c10a24 @@ -457,6 +466,7 @@ DEPENDENCIES database_cleaner devise (~> 4.7) digidoc_client! + directo! domain_name e_invoice! epp! @@ -500,4 +510,4 @@ DEPENDENCIES wkhtmltopdf-binary BUNDLED WITH - 2.0.2 + 2.1.4 diff --git a/app/controllers/concerns/book_keeping.rb b/app/controllers/concerns/book_keeping.rb new file mode 100644 index 000000000..4e25a466f --- /dev/null +++ b/app/controllers/concerns/book_keeping.rb @@ -0,0 +1,99 @@ +module BookKeeping + extend ActiveSupport::Concern + + DOMAIN_TO_PRODUCT = { 'ee': '01EE', 'com.ee': '02COM', 'pri.ee': '03PRI', + 'fie.ee': '04FIE', 'med.ee': '05MED' }.freeze + + def monthly_summary(month:) + activities = monthly_activites(month) + inv = { + 'number': 1, + 'customer_code': accounting_customer_code, + 'language': language, + 'currency': activities.first.currency, + 'date': month.end_of_month.strftime('%Y-%m-%d'), + }.as_json + + lines = [] + activities.each do |activity| + fetch_invoice_lines(activity, lines) + end + lines << prepayment_for_all(lines) + + inv['invoice_lines'] = lines.as_json + + inv + end + + def fetch_invoice_lines(activity, lines) + price = load_price(activity) + if price.duration.include? 'year' + price.duration.to_i.times do |duration| + lines << new_montly_invoice_line(activity: activity, duration: duration + 1).as_json + end + else + lines << new_monthly_invoice_line(activity: activity).as_json + end + end + + def monthly_activites(month) + AccountActivity.where(account_id: account_ids) + .where(created_at: month.beginning_of_month..month.end_of_month) + .where(activity_type: [AccountActivity::CREATE, AccountActivity::RENEW]) + end + + def new_montly_invoice_line(activity:, duration: nil) + price = DirectoInvoiceForwardJob.load_price(activity) + yearly = price.duration.include?('year') + line = { + 'product_id': DOMAIN_TO_PRODUCT[price.zone_name.to_sym], + 'quantity': 1, + 'price': yearly ? (price.price.amount / price.duration.to_i) : price.amount, + } + + line['description'] = description_in_language(price: price, yearly: yearly) + add_product_timeframe(line: line, activity: activity, duration: duration) if duration > 1 + + line + end + + def add_product_timeframe(line:, activity:, duration:) + create_time = activity.created_at + line['start_date'] = (create_time + (duration - 1).year).end_of_month.strftime('%Y-%m-%d') + line['end_date'] = (create_time + (duration - 1).year + 1).end_of_month.strftime('%Y-%m-%d') + end + + def description_in_language(price:, yearly:) + if language == 'en' + registration_length = yearly ? 'year' : 'month' + prefix = ".#{price.zone_name} registration: #{price.duration.to_i} #{registration_length}" + suffix = 's' + else + registration_length = yearly ? 'aasta' : 'kuu' + prefix = ".#{price.zone_name} registreerimine: #{price.duration.to_i} #{registration_length}" + suffix = yearly ? 't' : 'd' + end + + return "#{prefix}#{suffix}" if price.duration.to_i > 1 + + prefix + end + + def prepayment_for_all(lines) + total = 0 + lines.each { |l| total += l['quantity'].to_f * l['price'].to_f } + { + 'product_id': Setting.directo_receipt_product_name, + 'description': 'Domeenide ettemaks', + 'quantity': -1, + 'price': total + } + end + + def load_price(account_activity) + @pricelists ||= {} + return @pricelists[account_activity.price_id] if @pricelists.key? account_activity.price_id + + @pricelists[account_activity.price_id] = account_activity.price + end +end diff --git a/app/jobs/directo_invoice_forward_job.rb b/app/jobs/directo_invoice_forward_job.rb new file mode 100644 index 000000000..6eca4c73c --- /dev/null +++ b/app/jobs/directo_invoice_forward_job.rb @@ -0,0 +1,101 @@ +class DirectoInvoiceForwardJob < Que::Job + def run(monthly: false, dry: false) + @dry = dry + api_url = ENV['directo_invoice_url'] + sales_agent = Setting.directo_sales_agent + payment_term = Setting.directo_receipt_payment_term + @prepayment_product_id = Setting.directo_receipt_product_name + + @client = DirectoApi::Client.new(api_url, sales_agent, payment_term) + monthly ? send_monthly_invoices : send_receipts + end + + def send_receipts + unsent_invoices = Invoice.where(in_directo: false).non_cancelled + + Rails.logger.info("[DIRECTO] Trying to send #{unsent_invoices.count} prepayment invoices") + unsent_invoices.each do |invoice| + unless valid_invoice_conditions?(invoice) + Rails.logger.info "[DIRECTO] Invoice #{invoice.number} has been skipped" + next + end + @client.invoices.add_with_schema(invoice: invoice.as_directo_json, schema: 'prepayment') + end + + sync_with_directo + end + + def send_monthly_invoices + month = Time.now - 1.month + + Registrar.where.not(test_registrar: true).find_each do |registrar| + next unless registrar.cash_account + + invoice = registrar.monthly_summary(month: month) + @client.invoices.add_with_schema(invoice: invoice, schema: 'summary') + end + + # TODO: Invoice number + sync_with_directo + end + + def valid_invoice_conditions?(invoice) + if invoice.account_activity.nil? || invoice.account_activity.bank_transaction.nil? || + invoice.account_activity.bank_transaction.sum.nil? || + invoice.account_activity.bank_transaction.sum != invoice.total + return false + + end + + true + end + + def sync_with_directo + Rails.logger.info('[Directo] - attempting to send following XML:') + puts @client.invoices.as_xml + + return if @dry + + res = @client.invoices.deliver(ssl_verify: false) + + update_invoice_directo_state(res.body) if res.code == '200' + rescue SocketError, Errno::ECONNREFUSED, Timeout::Error, Errno::EINVAL, Errno::ECONNRESET, + EOFError, Net::HTTPBadResponse, Net::HTTPHeaderSyntaxError, Net::ProtocolError + Rails.logger.info("[Directo] Failed. Responded with code: #{res.code}, body: #{res.body}") + end + + def update_invoice_directo_state(xml) + Nokogiri::XML(xml).css('Result').each do |res| + inv = Invoice.find_by(number: res.attributes['docid'].value.to_i) + mark_invoice_as_sent(invoice: inv, data: res) + end + end + + def mark_invoice_as_sent(invoice:, data:) + invoice.directo_records.create!(response: data.as_json.to_h, invoice_number: invoice.number) + invoice.update_columns(in_directo: true) + Rails.logger.info("[DIRECTO] Invoice #{invoice.number} was pushed and return is #{data.as_json.to_h.inspect}") + end + + def self.load_price(account_activity) + @pricelists ||= {} + if @pricelists.key? account_activity.price_id + return @pricelists[account_activity.price_id] + end + + @pricelists[account_activity.price_id] = account_activity.price + end + + def last_directo_monthly_number + min_directo = Setting.directo_monthly_number_min.presence.try(:to_i) + max_directo = Setting.directo_monthly_number_max.presence.try(:to_i) + last_directo = [Setting.directo_monthly_number_last.presence.try(:to_i), min_directo] + .compact.max || 0 + + if max_directo && max_directo <= last_directo + raise 'Directo counter is out of period' + end + + last_directo + end +end diff --git a/app/jobs/directo_invoice_forward_job_job.rb b/app/jobs/directo_invoice_forward_job_job.rb deleted file mode 100644 index 4c95bb366..000000000 --- a/app/jobs/directo_invoice_forward_job_job.rb +++ /dev/null @@ -1,100 +0,0 @@ -class DirectoInvoiceForwardJobJob < ApplicationJob - queue_as :default - - def perform(monthly: false, dry: false) - api_url = ENV['directo_invoice_url'] - sales_agent = Setting.directo_sales_agent - payment_term = Setting.directo_receipt_payment_term - @prepayment_product_id = Setting.directo_receipt_product_name - - @client = DirectoApi::Client.new(api_url, sales_agent, payment_term) - monthly ? send_monthly_invoices(dry: dry) : send_receipts(dry: dry) - end - - def send_receipts - unsent_invoices = Invoice.where(in_directo: false).non_cancelled - - Rails.logger.info("[DIRECTO] Trying to send #{unsent_invoices.count} prepayment invoices") - unsent_invoices.each do |invoice| - unless valid_invoice_conditions?(invoice) - Rails.logger.info("[DIRECTO] Invoice #{invoice.number} has been skipped") && next - end - - @client.invoices.add(generate_directo_invoice(invoice: invoice, client: @client, - product_id: @prepayment_product_id)) - end - sync_with_directo - end - - def send_monthly_invoices; end - - def valid_invoice_conditions?(invoice) - if invoice.account_activity.nil? || invoice.account_activity.bank_transaction.nil? || - invoice.account_activity.bank_transaction.sum.nil? || - invoice.account_activity.bank_transaction.sum != invoice.total - false - end - true - end - - def generate_directo_invoice(invoice:, client:, product_id:) - inv = client.invoices.new - inv = create_invoice_meta(directo_invoice: inv, invoice: invoice) - inv = create_invoice_line(invoice: invoice, directo_invoice: inv, product_id: product_id) - - inv - end - - def create_invoice_meta(directo_invoice:, invoice:) - directo_invoice.customer = create_invoice_customer(invoice: invoice) - directo_invoice.date = invoice.issue_date.strftime('%Y-%m-%d') # Mapped - directo_invoice.transaction_date = - invoice.account_activity.bank_transaction&.paid_at&.strftime('%Y-%m-%d') # Mapped - directo_invoice.number = invoice.number # Mapped - directo_invoice.currency = invoice.currency # Mapped - directo_invoice.language = 'ENG' # Hardcoded - - directo_invoice - end - - def create_invoice_line(invoice:, directo_invoice:, product_id:) - line = directo_invoice.lines.new - line.code = product_id # MAPPED - line.description = invoice.result.auction.domain_name # MAPPED - line.quantity = 1 # MAPPED - line.price = ActionController::Base.helpers. - number_with_precision(invoice.subtotal, precision: 2, separator: ".") # MAPPED - directo_invoice.lines.add(line) - - directo_invoice - end - - def create_invoice_customer(invoice:) - customer = Directo::Customer.new - customer.code = invoice.buyer.accounting_customer_code # MAPPED - - customer - end - - def sync_with_directo - res = @client.invoices.deliver(ssl_verify: false) - Rails.logger.info("[Directo] Directo responded with code: #{res.code}, body: #{res.body}") - update_invoice_directo_state(res.body) if res.code == '200' - rescue SocketError, Errno::ECONNREFUSED, Timeout::Error, Errno::EINVAL, Errno::ECONNRESET, - EOFError, Net::HTTPBadResponse, Net::HTTPHeaderSyntaxError, Net::ProtocolError - Rails.logger.info("[Directo] Failed. Responded with code: #{res.code}, body: #{res.body}") - end - - def update_invoice_directo_state(xml) - Nokogiri::XML(xml).css('Result').each do |res| - inv = Invoice.find_by(number: res.attributes['docid'].value.to_i) - mark_invoice_as_sent(invoice: inv, data: res) - end - end - - def mark_invoice_as_sent(invoice:, data:) - invoice.directo_records.create!(response: data.as_json.to_h, invoice_number: invoice.number) - invoice.update_columns(in_directo: true) - Rails.logger.info("[DIRECTO] Invoice #{invoice.number} was pushed and return is #{data.as_json.to_h.inspect}") - end -end diff --git a/app/models/counter.rb b/app/models/counter.rb deleted file mode 100644 index 7d1c2b926..000000000 --- a/app/models/counter.rb +++ /dev/null @@ -1,24 +0,0 @@ -class Counter - def initialize value = 0 - @value = value - end - attr_accessor :value - def method_missing *args, &blk - @value.send(*args, &blk) - end - def to_s - @value.to_s - end - - def now - @value - end - - # pre-increment ".+" when x not present - def next(x = 1) - @value += x - end - def prev(x = 1) - @value -= x - end -end \ No newline at end of file diff --git a/app/models/directo.rb b/app/models/directo.rb index 789db64b2..a4af6c134 100644 --- a/app/models/directo.rb +++ b/app/models/directo.rb @@ -1,198 +1,3 @@ class Directo < ApplicationRecord - DOMAIN_TO_PRODUCT = {"ee" => "01EE", "com.ee" => "02COM", "pri.ee" => "03PRI", "fie.ee"=>"04FIE", "med.ee" => "05MED"}.freeze belongs_to :item, polymorphic: true - - def self.send_receipts - new_trans = Invoice.where(in_directo: false).non_cancelled - total = new_trans.count - counter = 0 - Rails.logger.info("[DIRECTO] Will try to send #{total} invoices") - - new_trans.find_in_batches(batch_size: 10).each do |group| - mappers = {} # need them as no direct connection between invoice - builder = Nokogiri::XML::Builder.new(encoding: "UTF-8") do |xml| - xml.invoices { - group.each do |invoice| - - if invoice.account_activity.nil? || invoice.account_activity.bank_transaction.nil? || - invoice.account_activity.bank_transaction.sum.nil? || invoice.account_activity.bank_transaction.sum != invoice.total - Rails.logger.info("[DIRECTO] Invoice #{invoice.number} has been skipped") - next - end - counter += 1 - - num = invoice.number - paid_at = invoice.account_activity.bank_transaction&.paid_at&.strftime("%Y-%m-%d") - mappers[num] = invoice - xml.invoice( - "SalesAgent" => Setting.directo_sales_agent, - "Number" => num, - "InvoiceDate" => invoice.issue_date.strftime("%Y-%m-%d"), - 'TransactionDate' => paid_at, - "PaymentTerm" => Setting.directo_receipt_payment_term, - "Currency" => invoice.currency, - "CustomerCode"=> invoice.buyer.accounting_customer_code - ){ - xml.line( - "ProductID" => Setting.directo_receipt_product_name, - "Quantity" => 1, - "UnitPriceWoVAT" => ActionController::Base.helpers.number_with_precision(invoice.subtotal, precision: 2, separator: "."), - "ProductName" => invoice.order - ) - } - end - } - end - - data = builder.to_xml.gsub("\n",'') - Rails.logger.info("[Directo] XML request: #{data}") - response = RestClient::Request.execute(url: ENV['directo_invoice_url'], method: :post, payload: {put: "1", what: "invoice", xmldata: data}, verify_ssl: false) - Rails.logger.info("[Directo] Directo responded with code: #{response.code}, body: #{response.body}") - dump_result_to_db(mappers, response.to_s) - end - - STDOUT << "#{Time.zone.now.utc} - Directo receipts sending finished. #{counter} of #{total} are sent\n" - end - - def self.dump_result_to_db mappers, xml - Nokogiri::XML(xml).css("Result").each do |res| - obj = mappers[res.attributes["docid"].value.to_i] - obj.directo_records.create!(response: res.as_json.to_h, invoice_number: obj.number) - obj.update_columns(in_directo: true) - Rails.logger.info("[DIRECTO] Invoice #{res.attributes["docid"].value} was pushed and return is #{res.as_json.to_h.inspect}") - end - end - - - def self.send_monthly_invoices(debug: false) - I18n.locale = :et - month = Time.now - 1.month - invoices_until = month.end_of_month - date_format = "%Y-%m-%d" - invoice_counter= Counter.new - - min_directo = Setting.directo_monthly_number_min.presence.try(:to_i) - max_directo = Setting.directo_monthly_number_max.presence.try(:to_i) - last_directo = [Setting.directo_monthly_number_last.presence.try(:to_i), min_directo].compact.max || 0 - if max_directo && max_directo <= last_directo - raise "Directo counter is out of period (max allowed number is smaller than last counter number)" - end - - directo_next = last_directo - Registrar.where.not(test_registrar: true).find_each do |registrar| - unless registrar.cash_account - Rails.logger.info("[DIRECTO] Monthly invoice for registrar #{registrar.id} has been skipped as it doesn't has cash_account") - next - end - counter = Counter.new(1) - items = {} - registrar_activities = AccountActivity.where(account_id: registrar.account_ids).where("created_at BETWEEN ? AND ?",month.beginning_of_month, month.end_of_month) - - # adding domains items - registrar_activities.where(activity_type: [AccountActivity::CREATE, AccountActivity::RENEW]).each do |activity| - price = load_price(activity) - - if price.duration.include?('year') - price.duration.to_i.times do |i| - year = i+1 - hash = { - "ProductID" => DOMAIN_TO_PRODUCT[price.zone_name], - "Unit" => "tk", - "ProductName" => ".#{price.zone_name} registreerimine: #{price.duration.to_i} aasta#{price.duration.to_i > 1 ? 't' : ''}", - "UnitPriceWoVAT" => price.price.amount / price.duration.to_i - } - hash["StartDate"] = (activity.created_at + (year-1).year).end_of_month.strftime(date_format) if year > 1 - hash["EndDate"] = (activity.created_at + (year-1).year + 1).end_of_month.strftime(date_format) if year > 1 - - if items.has_key?(hash) - items[hash]["Quantity"] += 1 - else - items[hash] = { "RN" => counter.next, "RR" => counter.now - i, "Quantity" => 1 } - end - end - else - 1.times do |i| - quantity = price.account_activities - .where(account_id: registrar.account_ids) - .where(created_at: month.beginning_of_month..month.end_of_month) - .where(activity_type: [AccountActivity::CREATE, AccountActivity::RENEW]) - .count - - hash = { - "ProductID" => DOMAIN_TO_PRODUCT[price.zone_name], - "Unit" => "tk", - "ProductName" => ".#{price.zone_name} registreerimine: #{price.duration.to_i} kuud", - "UnitPriceWoVAT" => price.price.amount, - } - - if items.has_key?(hash) - #items[hash]["Quantity"] += 1 - else - items[hash] = { "RN" => counter.next, "RR" => counter.now - i, "Quantity" => quantity } - end - end - end - - - end - - #adding prepaiments - if items.any? - total = 0 - items.each{ |key, val| total += val["Quantity"] * key["UnitPriceWoVAT"] } - hash = {"ProductID" => Setting.directo_receipt_product_name, "Unit" => "tk", "ProductName" => "Domeenide ettemaks", "UnitPriceWoVAT"=>total} - items[hash] = {"RN"=>counter.next, "RR" => counter.now, "Quantity"=> -1} - end - - # generating XML - if items.any? - directo_next += 1 - invoice_counter.next - - builder = Nokogiri::XML::Builder.new(encoding: "UTF-8") do |xml| - xml.invoices{ - xml.invoice("Number" =>directo_next, - "InvoiceDate" =>invoices_until.strftime(date_format), - "PaymentTerm" =>Setting.directo_receipt_payment_term, - "CustomerCode"=>registrar.accounting_customer_code, - "Language" =>"", - "Currency" =>registrar_activities.first.currency, - "SalesAgent" =>Setting.directo_sales_agent){ - xml.line("RN" => 1, "RR"=>1, "ProductName"=> "Domeenide registreerimine - #{I18n.l(invoices_until, format: "%B %Y").titleize}") - items.each do |line, val| - xml.line(val.merge(line)) - end - } - } - end - - data = builder.to_xml.gsub("\n",'') - Rails.logger.info("[Directo] XML request: #{data}") - - if debug - STDOUT << "#{Time.zone.now.utc} - Directo xml had to be sent #{data}\n" - else - response = RestClient::Request.execute(url: ENV['directo_invoice_url'], method: :post, payload: {put: "1", what: "invoice", xmldata: data}, verify_ssl: false) - Rails.logger.info("[Directo] Directo responded with code: #{response.code}, body: #{response.body}") - response = response.to_s - - Setting.directo_monthly_number_last = directo_next - Nokogiri::XML(response).css("Result").each do |res| - Directo.create!(request: data, response: res.as_json.to_h, invoice_number: directo_next) - Rails.logger.info("[DIRECTO] Invoice #{res.attributes["docid"].value} was pushed and return is #{res.as_json.to_h.inspect}") - end - end - else - Rails.logger.info("[DIRECTO] Registrar #{registrar.id} has nothing to be sent to Directo") - end - - end - STDOUT << "#{Time.zone.now.utc} - Directo invoices sending finished. #{invoice_counter.now} are sent\n" - end - - def self.load_price(account_activity) - @pricelists ||= {} - return @pricelists[account_activity.price_id] if @pricelists.has_key?(account_activity.price_id) - @pricelists[account_activity.price_id] = account_activity.price - end end diff --git a/app/models/invoice.rb b/app/models/invoice.rb index 7f1dea825..20d0c5091 100644 --- a/app/models/invoice.rb +++ b/app/models/invoice.rb @@ -102,6 +102,22 @@ class Invoice < ApplicationRecord generator.generate end + def as_directo_json + inv = ActiveSupport::JSON.decode(ActiveSupport::JSON.encode(self)) + inv['customer_code'] = buyer.accounting_customer_code + inv['issue_date'] = issue_date.strftime('%Y-%m-%d') + inv['transaction_date'] = account_activity.bank_transaction&.paid_at&.strftime('%Y-%m-%d') + inv['language'] = buyer.language + inv['invoice_lines'] = [{ + 'product_id': Setting.directo_receipt_product_name, + 'description': order, + 'quantity': 1, + 'price': ActionController::Base.helpers.number_with_precision(subtotal, precision: 2, separator: ".") + }].as_json + + inv + end + private def apply_default_buyer_vat_no @@ -111,4 +127,4 @@ class Invoice < ApplicationRecord def calculate_total self.total = subtotal + vat_amount end -end \ No newline at end of file +end diff --git a/app/models/registrar.rb b/app/models/registrar.rb index 8f41d62ca..788d7857a 100644 --- a/app/models/registrar.rb +++ b/app/models/registrar.rb @@ -1,5 +1,6 @@ class Registrar < ApplicationRecord include Versions # version/registrar_version.rb + include BookKeeping has_many :domains, dependent: :restrict_with_error has_many :contacts, dependent: :restrict_with_error diff --git a/test/jobs/directo_invoice_forward_job_test.rb b/test/jobs/directo_invoice_forward_job_test.rb new file mode 100644 index 000000000..47cf9e6fb --- /dev/null +++ b/test/jobs/directo_invoice_forward_job_test.rb @@ -0,0 +1,20 @@ +require "test_helper" + +class DirectoInvoiceForwardJobTest < ActiveSupport::TestCase + setup do + @invoice = invoices(:one) + end + + def test_xml_is_include_transaction_date + @invoice.update(total: @invoice.account_activity.bank_transaction.sum) + @invoice.account_activity.bank_transaction.update(paid_at: Time.zone.now) + + stub_request(:post, ENV['directo_invoice_url']).with do |request| + request.body.include? 'TransactionDate' + end + + assert_nothing_raised do + DirectoInvoiceForwardJob.run(monthly: false) + end + end +end diff --git a/test/models/directo_test.rb b/test/models/directo_test.rb index 9dbbf64d4..603a38d15 100644 --- a/test/models/directo_test.rb +++ b/test/models/directo_test.rb @@ -1,20 +1,4 @@ require 'test_helper' class DirectoTest < ActiveSupport::TestCase - setup do - @invoice = invoices(:one) - end - - def test_xml_is_include_transaction_date - @invoice.update(total: @invoice.account_activity.bank_transaction.sum) - @invoice.account_activity.bank_transaction.update(paid_at: Time.zone.now) - - stub_request(:post, ENV['directo_invoice_url']).with do |request| - request.body.include? 'TransactionDate' - end - - assert_nothing_raised do - Directo.send_receipts - end - end end