mirror of
https://github.com/internetee/registry.git
synced 2025-06-06 04:37:30 +02:00
Merge pull request #1260 from internetee/process-invoice-payments-automatically
Process invoice payments automatically
This commit is contained in:
commit
70860d76a2
9 changed files with 269 additions and 0 deletions
1
Gemfile
1
Gemfile
|
@ -92,6 +92,7 @@ gem 'airbrake'
|
|||
|
||||
gem 'company_register', github: 'internetee/company_register', branch: :master
|
||||
gem 'e_invoice', github: 'internetee/e_invoice', branch: :master
|
||||
gem 'lhv', github: 'internetee/lhv', tag: 'v0.1.0'
|
||||
|
||||
group :development do
|
||||
# deploy
|
||||
|
|
11
Gemfile.lock
11
Gemfile.lock
|
@ -41,6 +41,15 @@ GIT
|
|||
hpricot
|
||||
libxml-ruby
|
||||
|
||||
GIT
|
||||
remote: https://github.com/internetee/lhv.git
|
||||
revision: e211516bc5fff2139584d4da41c17511863c229d
|
||||
tag: v0.1.0
|
||||
specs:
|
||||
lhv (0.1.0)
|
||||
keystores
|
||||
nokogiri
|
||||
|
||||
GIT
|
||||
remote: https://github.com/tarmotalu/digidoc_client.git
|
||||
revision: 1645e83a5a548addce383f75703b0275c5310c32
|
||||
|
@ -231,6 +240,7 @@ GEM
|
|||
kaminari (0.16.3)
|
||||
actionpack (>= 3.0.0)
|
||||
activesupport (>= 3.0.0)
|
||||
keystores (0.4.0)
|
||||
libxml-ruby (3.0.0)
|
||||
loofah (2.2.3)
|
||||
crass (~> 1.0.2)
|
||||
|
@ -479,6 +489,7 @@ DEPENDENCIES
|
|||
jquery-rails (= 4.0.4)
|
||||
jquery-ui-rails (= 5.0.5)
|
||||
kaminari (= 0.16.3)
|
||||
lhv!
|
||||
mina (= 0.3.1)
|
||||
money-rails
|
||||
nokogiri
|
||||
|
|
|
@ -152,6 +152,12 @@ action_mailer_default_port: # default: no port (80)
|
|||
action_mailer_default_from: # no-reply@example.com
|
||||
action_mailer_force_delete_from: # `From` header for `DomainDeleteMailer#forced` email
|
||||
|
||||
lhv_keystore:
|
||||
lhv_keystore_password:
|
||||
lhv_keystore_alias:
|
||||
lhv_ca_file: # Needed only in dev mode
|
||||
lhv_dev_mode: 'false'
|
||||
|
||||
# Since the keys for staging are absent from the repo, we need to supply them separate for testing.
|
||||
test:
|
||||
payments_seb_bank_certificate: 'test/fixtures/files/seb_bank_cert.pem'
|
||||
|
@ -161,6 +167,9 @@ test:
|
|||
action_mailer_default_host: 'registry.test'
|
||||
action_mailer_default_from: 'no-reply@registry.test'
|
||||
action_mailer_force_delete_from: 'legal@registry.test'
|
||||
lhv_keystore: 'test/fixtures/files/keystore.jks'
|
||||
lhv_keystore_password: 'testtest'
|
||||
lhv_keystore_alias: 'testtest'
|
||||
|
||||
# Airbrake // Errbit:
|
||||
airbrake_host: "https://your-errbit-host.ee"
|
||||
|
|
|
@ -57,6 +57,13 @@ if @cron_group == 'registry'
|
|||
every 42.minutes do
|
||||
rake 'domain:discard'
|
||||
end
|
||||
|
||||
# Should be at least once every 4 days, since according to LHV specs:
|
||||
# "Unread messages older than 5 days are automatically scheduled for deletion"
|
||||
# https://partners.lhv.ee/en/connect/#messaging
|
||||
every :day, at: '12:01am' do
|
||||
rake 'invoices:process_payments'
|
||||
end
|
||||
end
|
||||
|
||||
every 10.minutes do
|
||||
|
|
73
lib/tasks/dev/create_bank_transactions/bank_transactions.xml
Normal file
73
lib/tasks/dev/create_bank_transactions/bank_transactions.xml
Normal file
|
@ -0,0 +1,73 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<Document xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="urn:iso:std:iso:20022:tech:xsd:pain.001.001.03">
|
||||
<CstmrCdtTrfInitn>
|
||||
<GrpHdr>
|
||||
<MsgId>populated by rake task</MsgId>
|
||||
<CreDtTm>2019-07-28T10:00:00</CreDtTm>
|
||||
<NbOfTxs>1</NbOfTxs>
|
||||
<!-- Amount of all transactions; acts as a checksum -->
|
||||
<CtrlSum>0.1</CtrlSum>
|
||||
<InitgPty>
|
||||
<Nm>ABC Corporation</Nm>
|
||||
</InitgPty>
|
||||
</GrpHdr>
|
||||
<PmtInf>
|
||||
<PmtInfId>test3</PmtInfId>
|
||||
<PmtMtd>TRF</PmtMtd>
|
||||
<BtchBookg>false</BtchBookg>
|
||||
<NbOfTxs>1</NbOfTxs>
|
||||
<ReqdExctnDt>2019-07-28</ReqdExctnDt>
|
||||
<Dbtr>
|
||||
<Nm>test</Nm>
|
||||
</Dbtr>
|
||||
<DbtrAcct>
|
||||
<Id>
|
||||
<IBAN>populated by rake task</IBAN>
|
||||
</Id>
|
||||
<Ccy>EUR</Ccy>
|
||||
</DbtrAcct>
|
||||
<DbtrAgt>
|
||||
<FinInstnId>
|
||||
<BIC>LHVBEE22</BIC>
|
||||
</FinInstnId>
|
||||
</DbtrAgt>
|
||||
<CdtTrfTxInf>
|
||||
<PmtId>
|
||||
<InstrId>ABC/090928/CCT001/01</InstrId>
|
||||
<EndToEndId>ABC/4562/2009-09-08</EndToEndId>
|
||||
</PmtId>
|
||||
<Amt>
|
||||
<!-- Transaction amount. Use the smallest amount possible in dev mode, since account balance is not infinite -->
|
||||
<InstdAmt Ccy="EUR">0.1</InstdAmt>
|
||||
</Amt>
|
||||
<ChrgBr>SHAR</ChrgBr>
|
||||
<CdtrAgt>
|
||||
<FinInstnId>
|
||||
<BIC>LHVBEE22</BIC>
|
||||
</FinInstnId>
|
||||
</CdtrAgt>
|
||||
<Cdtr>
|
||||
<Nm>DEF Electronics</Nm>
|
||||
<PstlAdr>
|
||||
<AdrLine>Corn Exchange 5th Floor</AdrLine>
|
||||
</PstlAdr>
|
||||
</Cdtr>
|
||||
<CdtrAcct>
|
||||
<Id>
|
||||
<IBAN>populated by rake task</IBAN>
|
||||
</Id>
|
||||
</CdtrAcct>
|
||||
<RmtInf>
|
||||
<!-- payment description -->
|
||||
<Ustrd>1</Ustrd>
|
||||
<Strd>
|
||||
<CdtrRefInf>
|
||||
<!-- payment reference number -->
|
||||
<Ref>13</Ref>
|
||||
</CdtrRefInf>
|
||||
</Strd>
|
||||
</RmtInf>
|
||||
</CdtTrfTxInf>
|
||||
</PmtInf>
|
||||
</CstmrCdtTrfInitn>
|
||||
</Document>
|
|
@ -0,0 +1,41 @@
|
|||
namespace :dev do
|
||||
task create_bank_transactions: :environment do
|
||||
remitter_iban = ENV['remitter_iban']
|
||||
beneficiary_iban = Setting.registry_iban
|
||||
|
||||
keystore_password = ENV['lhv_keystore_password']
|
||||
keystore_alias = ENV['lhv_keystore_alias']
|
||||
keystore = Keystores::JavaKeystore.new
|
||||
keystore.load(ENV['lhv_keystore'], keystore_password)
|
||||
cert = keystore.get_certificate(keystore_alias)
|
||||
key = keystore.get_key(keystore_alias, keystore_password)
|
||||
|
||||
api_base_uri = URI.parse('https://testconnect.lhv.eu/connect-prelive')
|
||||
request_headers = { 'content-type' => 'application/xml' }
|
||||
|
||||
request_xml = File.binread(File.join(__dir__, 'bank_transactions.xml'))
|
||||
request_xml_doc = Nokogiri::XML(request_xml)
|
||||
request_xml_doc.at_css('CstmrCdtTrfInitn > GrpHdr > MsgId').content = SecureRandom.hex
|
||||
request_xml_doc.at_css('CstmrCdtTrfInitn > PmtInf > DbtrAcct > Id > IBAN')
|
||||
.content = remitter_iban
|
||||
request_xml_doc.at_css('CstmrCdtTrfInitn > PmtInf > CdtTrfTxInf > CdtrAcct > Id > IBAN')
|
||||
.content = beneficiary_iban
|
||||
request_body = request_xml_doc.to_xml
|
||||
|
||||
http = Net::HTTP.new(api_base_uri.host, api_base_uri.port)
|
||||
http.use_ssl = api_base_uri.is_a?(URI::HTTPS)
|
||||
http.cert = cert
|
||||
http.key = key
|
||||
http.ca_file = ENV['lhv_ca_file']
|
||||
|
||||
http.start do
|
||||
response = http.post(api_base_uri.path + '/payment', request_body, request_headers)
|
||||
|
||||
if response.is_a?(Net::HTTPSuccess)
|
||||
puts 'Success'
|
||||
else
|
||||
puts 'Failure'
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
49
lib/tasks/invoices/process_payments.rake
Normal file
49
lib/tasks/invoices/process_payments.rake
Normal file
|
@ -0,0 +1,49 @@
|
|||
namespace :invoices do
|
||||
task process_payments: :environment do
|
||||
registry_bank_account_iban = Setting.registry_iban
|
||||
|
||||
keystore_password = ENV['lhv_keystore_password']
|
||||
keystore_alias = ENV['lhv_keystore_alias']
|
||||
keystore = Keystores::JavaKeystore.new
|
||||
keystore.load(ENV['lhv_keystore'], keystore_password)
|
||||
cert = keystore.get_certificate(keystore_alias)
|
||||
key = keystore.get_key(keystore_alias, keystore_password)
|
||||
|
||||
api = Lhv::ConnectApi.new
|
||||
api.cert = cert
|
||||
api.key = key
|
||||
api.ca_file = ENV['lhv_ca_file']
|
||||
api.dev_mode = ENV['lhv_dev_mode'] == 'true'
|
||||
|
||||
incoming_transactions = []
|
||||
|
||||
api.credit_debit_notification_messages.each do |message|
|
||||
next unless message.bank_account_iban == registry_bank_account_iban
|
||||
|
||||
message.credit_transactions.each do |credit_transaction|
|
||||
incoming_transactions << credit_transaction
|
||||
end
|
||||
end
|
||||
|
||||
if incoming_transactions.any?
|
||||
bank_statement = BankStatement.new(bank_code: Setting.registry_bank_code,
|
||||
iban: Setting.registry_iban)
|
||||
|
||||
ActiveRecord::Base.transaction do
|
||||
bank_statement.save!
|
||||
|
||||
incoming_transactions.each do |incoming_transaction|
|
||||
transaction_attributes = { sum: incoming_transaction.amount,
|
||||
currency: incoming_transaction.currency,
|
||||
paid_at: incoming_transaction.date,
|
||||
reference_no: incoming_transaction.payment_reference_number,
|
||||
description: incoming_transaction.payment_description }
|
||||
transaction = bank_statement.bank_transactions.create!(transaction_attributes)
|
||||
transaction.autobind_invoice
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
puts "Transactions processed: #{incoming_transactions.size}"
|
||||
end
|
||||
end
|
BIN
test/fixtures/files/keystore.jks
vendored
Normal file
BIN
test/fixtures/files/keystore.jks
vendored
Normal file
Binary file not shown.
78
test/tasks/invoices/process_payments_test.rb
Normal file
78
test/tasks/invoices/process_payments_test.rb
Normal file
|
@ -0,0 +1,78 @@
|
|||
require 'test_helper'
|
||||
|
||||
class ProcessPaymentsTaskTest < ActiveSupport::TestCase
|
||||
setup do
|
||||
@payment_amount = payment_amount = 0.1
|
||||
@payment_currency = payment_currency = 'EUR'
|
||||
@payment_date = payment_date = Date.parse('2010-07-05')
|
||||
@payment_reference_number = payment_reference_number = '13'
|
||||
@payment_description = payment_description = @invoice_number = '1234'
|
||||
beneficiary_iban = 'GB33BUKB20201555555555'
|
||||
|
||||
@invoice = create_payable_invoice(number: @invoice_number,
|
||||
total: payment_amount,
|
||||
currency: @payment_currency,
|
||||
reference_no: @payment_reference_number)
|
||||
Setting.registry_iban = beneficiary_iban
|
||||
|
||||
Lhv::ConnectApi.class_eval do
|
||||
define_method :credit_debit_notification_messages do
|
||||
transaction = OpenStruct.new(amount: payment_amount,
|
||||
currency: payment_currency,
|
||||
date: payment_date,
|
||||
payment_reference_number: payment_reference_number,
|
||||
payment_description: payment_description)
|
||||
message = OpenStruct.new(bank_account_iban: beneficiary_iban,
|
||||
credit_transactions: [transaction])
|
||||
[message]
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def test_doubles_are_valid
|
||||
assert Lhv::ConnectApi.method_defined?(:credit_debit_notification_messages)
|
||||
assert Lhv::ConnectApi::Messages::CreditDebitNotification.method_defined?(:bank_account_iban)
|
||||
assert Lhv::ConnectApi::Messages::CreditDebitNotification.method_defined?(:credit_transactions)
|
||||
end
|
||||
|
||||
def test_saves_transactions
|
||||
assert_difference 'BankStatement.count' do
|
||||
assert_difference 'BankTransaction.count' do
|
||||
capture_io { run_task }
|
||||
end
|
||||
end
|
||||
transaction = BankTransaction.last
|
||||
assert_equal @payment_amount, transaction.sum
|
||||
assert_equal @payment_currency, transaction.currency
|
||||
assert_equal @payment_date, transaction.paid_at.to_date
|
||||
assert_equal @payment_reference_number, transaction.reference_no
|
||||
assert_equal @payment_description, transaction.description
|
||||
end
|
||||
|
||||
def test_marks_matched_invoice_as_paid
|
||||
assert @invoice.unpaid?
|
||||
|
||||
capture_io { run_task }
|
||||
@invoice.reload
|
||||
|
||||
assert @invoice.paid?
|
||||
end
|
||||
|
||||
def test_output
|
||||
assert_output "Transactions processed: 1\n" do
|
||||
run_task
|
||||
end
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def run_task
|
||||
Rake::Task['invoices:process_payments'].execute
|
||||
end
|
||||
|
||||
def create_payable_invoice(attributes = {})
|
||||
invoice = invoices(:one)
|
||||
invoice.update!({ account_activity: nil, cancelled_at: nil }.merge(attributes))
|
||||
invoice
|
||||
end
|
||||
end
|
Loading…
Add table
Add a link
Reference in a new issue