From bbd58e9e8ea51d83207b0afdc72f8eec40ccbf49 Mon Sep 17 00:00:00 2001 From: Lars Brillert Date: Fri, 23 Mar 2018 13:34:24 +0100 Subject: [PATCH 1/4] more AZV --- Gemfile | 2 +- Gemfile.lock | 10 ++- box/adapters/fake.rb | 8 ++ box/apis/v1/content.rb | 1 + box/apis/v2/credit_transfers.rb | 31 +++++-- box/business_processes/credit.rb | 6 +- box/business_processes/foreign_credit.rb | 85 +++++++++++++++++++ box/business_processes/import_statements.rb | 8 +- box/entities/v2/credit_transfer.rb | 40 +++++++-- box/jobs/credit.rb | 8 +- box/models/account.rb | 19 +++++ box/validations/unique_transaction_eref.rb | 15 ++++ ...180316144100_add_foreign_credit_support.rb | 6 ++ spec/apis/v2/credit_transfers_spec.rb | 43 +++++++++- 14 files changed, 260 insertions(+), 22 deletions(-) create mode 100644 box/business_processes/foreign_credit.rb create mode 100644 migrations/20180316144100_add_foreign_credit_support.rb diff --git a/Gemfile b/Gemfile index 921f4d86..85f53a40 100644 --- a/Gemfile +++ b/Gemfile @@ -13,6 +13,7 @@ gem 'grape-swagger-entity' gem 'faraday' gem 'nokogiri' gem 'sepa_king' +gem 'king_dtaus', git: 'https://github.com/salesking/king_dtaus.git' gem 'sequel' gem 'puma' gem 'jwt' @@ -28,7 +29,6 @@ else gem 'epics', '~> 1.5.0' end - group :development, :test do gem 'database_cleaner' gem 'dotenv' diff --git a/Gemfile.lock b/Gemfile.lock index 48f678ee..8c7f324d 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -5,6 +5,13 @@ GIT camt_parser (1.0.2) nokogiri +GIT + remote: https://github.com/salesking/king_dtaus.git + revision: 84a72f2f0476b6fae5253aa7a139cfc639eace08 + specs: + king_dtaus (2.0.4) + i18n + GEM remote: https://rubygems.org/ specs: @@ -192,6 +199,7 @@ DEPENDENCIES grape-swagger grape-swagger-entity jwt + king_dtaus! nokogiri pg pry @@ -205,4 +213,4 @@ DEPENDENCIES webmock BUNDLED WITH - 1.15.4 + 1.16.1 diff --git a/box/adapters/fake.rb b/box/adapters/fake.rb index b9404f96..789d0839 100644 --- a/box/adapters/fake.rb +++ b/box/adapters/fake.rb @@ -42,6 +42,10 @@ def HAC(from = nil, to = nil) ::File.open( ::File.expand_path("~/hac_empty.xml")) end + def HTD + ::File.open( ::File.expand_path("~/htd.xml")) + end + def CD1(pain) ["TRX#{SecureRandom.hex(6)}", "N#{SecureRandom.hex(6)}"] end @@ -80,6 +84,10 @@ def CCT(pain) Event.statement_created(statement) ["TRX#{SecureRandom.hex(6)}", "N#{SecureRandom.hex(6)}"] end + + def AZV(dtazv) + ["TRX#{SecureRandom.hex(6)}", "N#{SecureRandom.hex(6)}"] + end end end end diff --git a/box/apis/v1/content.rb b/box/apis/v1/content.rb index 99850e1e..a27543cc 100644 --- a/box/apis/v1/content.rb +++ b/box/apis/v1/content.rb @@ -10,6 +10,7 @@ # Business processes require_relative '../../business_processes/credit' +require_relative '../../business_processes/foreign_credit' require_relative '../../business_processes/direct_debit' require_relative '../../jobs/fetch_statements' diff --git a/box/apis/v2/credit_transfers.rb b/box/apis/v2/credit_transfers.rb index bdb66c72..07af83a2 100644 --- a/box/apis/v2/credit_transfers.rb +++ b/box/apis/v2/credit_transfers.rb @@ -6,7 +6,6 @@ require_relative '../../validations/length' require_relative '../../errors/business_process_failure' - module Box module Apis module V2 @@ -44,7 +43,6 @@ class CreditTransfers < Grape::API present query.paginate(declared(params)).all, with: Entities::V2::CreditTransfer end - ### ### POST /credit_transfers ### @@ -66,22 +64,39 @@ class CreditTransfers < Grape::API params do requires :account, type: String, desc: "the account to use", documentation: { param_type: 'body' } requires :name, type: String, desc: "the customers name" - optional :bic , type: String, desc: "the customers bic", allow_blank: false - requires :iban, type: String, desc: "the customers iban" + + optional :currency, type: String, desc: "currency of the transfer", length: 3, regexp: /[A-Z]{3}/, default: 'EUR' + requires :iban, type: String, desc: "the customers acconut" + + given currency: ->(val) { val != 'EUR' } do + optional :fee_handling, type: Symbol, values: %i[split sender receiver], default: :split + requires :bic, type: String, desc: "the customers bic", allow_blank: false + requires :country_code, type: String, desc: "the customers country", allow_blank: false + end + + given currency: ->(val) { val == 'EUR' } do + optional :urgent, type: Boolean, desc: "requested execution date", default: false + end + + requires :end_to_end_reference, type: String, desc: "unique end to end reference", unique_transaction_eref: true, length_transaction_eref: true + requires :amount_in_cents, type: Integer, desc: "amount to credit (charged in cents)", values: 1..1200000000 - requires :end_to_end_reference, type: String, desc: "unique end to end reference", unique_transaction_eref: true optional :reference, type: String, length: 140, desc: "description of the transaction (max. 140 char)" optional :execution_date, type: Date, desc: "requested execution date", default: -> { Date.today } - optional :urgent, type: Boolean, desc: "requested execution date", default: false end post do account = current_organization.find_account!(params[:account]) - Credit.v2_create!(current_user, account, declared(params)) + + if params[:currency] == "EUR" + Credit.v2_create!(current_user, account, declared(params)) + else + ForeignCredit.v2_create!(current_user, account, declared(params)) + end + { message: 'Credit transfer has been initiated successfully!' } end - ### ### GET /credit_transfers/:id ### diff --git a/box/business_processes/credit.rb b/box/business_processes/credit.rb index 660e65a4..d8ad934e 100644 --- a/box/business_processes/credit.rb +++ b/box/business_processes/credit.rb @@ -29,7 +29,9 @@ def self.create!(account, params, user) user_id: user.id, payload: Base64.strict_encode64(sct.to_xml), eref: params[:eref], - amount: params[:amount] + currency: 'EUR', + amount: params[:amount], + metadata: params.slice(:name, :iban, :bic, :execution_date, :reference) ) else fail(Box::BusinessProcessFailure.new(sct.errors)) @@ -51,9 +53,7 @@ def self.v2_create!(user, account, params) # Set urgent flag or fall back to SEPA params[:service_level] = params[:urgent] ? 'URGP' : 'SEPA' - # Execute v1 method create!(account, params, user) end - end end diff --git a/box/business_processes/foreign_credit.rb b/box/business_processes/foreign_credit.rb new file mode 100644 index 00000000..acddead0 --- /dev/null +++ b/box/business_processes/foreign_credit.rb @@ -0,0 +1,85 @@ +require 'king_dtaus' +require_relative '../errors/business_process_failure' + +module Box + class ForeignCredit + class Payload < OpenStruct + def sender + KingDta::Account.new({ + owner_name: account.name, + bank_number: account.bank_number, + owner_country_code: account.bank_country_code, + bank_account_number: account.bank_account_number + }) + end + + def receiver + KingDta::Account.new({ + bank_bic: params[:bic], + owner_name: params[:name], + owner_country_code: params[:country_code], + ** account_number + }) + end + + def account_number + if params[:iban] =~ /[A-Z]{2}/ + { bank_iban: params[:iban] } + else + { bank_account_number: params[:iban] } + end + end + + def amount + params[:amount] / 100.0 + end + + def fee_handling + { + split: '00', + sender: '01', + receiver: '02', + }[params[:fee_handling]] + end + + def booking + KingDta::Booking.new(receiver, amount, params[:eref], nil, params[:currency]).tap do |booking| + booking.payment_type = '00' + booking.charge_bearer_code = fee_handling + end + end + + def create + azv = KingDta::Dtazv.new(params[:execution_date]) + azv.account = sender + azv.add(booking) + + azv.create + end + end + + def self.v2_create!(user, account, params) + params[:requested_date] = params[:execution_date].to_time.to_i + + # Transform a few params + params[:amount] = params[:amount_in_cents] + params[:eref] = params[:end_to_end_reference] + params[:remittance_information] = params[:reference] + + payload = Payload.new(account: account, params: params) + + Queue.execute_credit( + account_id: account.id, + user_id: user.id, + payload: Base64.strict_encode64(payload.create), + eref: params[:eref], + currency: params[:currency], + amount: params[:amount], + metadata: params.slice(:name, :iban, :bic, :execution_date, :reference, :country_code, :fee_handling) + ) + rescue ArgumentError => e + # TODO: Will be fixed upstream in the sepa_king gem by us + fail Box::BusinessProcessFailure.new({ base: e.message }, 'Invalid data') + end + end +end diff --git a/box/business_processes/import_statements.rb b/box/business_processes/import_statements.rb index a06883d2..bfbaee54 100644 --- a/box/business_processes/import_statements.rb +++ b/box/business_processes/import_statements.rb @@ -46,9 +46,13 @@ def self.create_statement(account, bank_transaction, bank_statement_id, unique_i end def self.link_statement_to_transaction(account, statement) - if transaction = account.transactions_dataset.where(eref: statement.eref).first - transaction.add_statement(statement) + # find transactions via EREF + transaction = account.transactions_dataset.where(eref: statement.eref).first + # fallback to finding via statement information + transaction ||= account.transactions_dataset.exclude(currency: 'EUR', status: ['credit_received', 'debit_received']).where{ created_at > 14.days.ago}.detect{|t| statement.information =~ /#{t.eref}/i } + if transaction + transaction.add_statement(statement) if statement.credit? transaction.update_status("credit_received") elsif statement.debit? diff --git a/box/entities/v2/credit_transfer.rb b/box/entities/v2/credit_transfer.rb index f51081fa..4c89700e 100644 --- a/box/entities/v2/credit_transfer.rb +++ b/box/entities/v2/credit_transfer.rb @@ -7,13 +7,13 @@ module V2 class CreditTransfer < Grape::Entity expose(:public_id, as: "id") expose(:account) { |transaction| transaction.account.iban } - expose(:name) { |trx| trx.parsed_payload[:payments].first[:transactions].first[:name] } - expose(:iban) { |trx| trx.parsed_payload[:payments].first[:transactions].first[:iban] } - expose(:bic) { |trx| trx.parsed_payload[:payments].first[:transactions].first[:bic] } + expose(:name) + expose(:iban) + expose(:bic) expose(:amount, as: "amount_in_cents") expose(:eref, as: 'end_to_end_reference') - expose(:reference) { |trx| trx.parsed_payload[:payments].first[:transactions].first[:remittance_information] } - expose(:executed_on) { |trx| trx.parsed_payload[:payments].first[:execution_date] } + expose(:reference) + expose(:executed_on) expose(:status) expose(:_links) do |transaction| iban = transaction.account.iban @@ -22,6 +22,36 @@ class CreditTransfer < Grape::Entity account: Box.configuration.app_url + "/accounts/#{iban}/", } end + + def name + object.metadata.fetch('name') do + object.parsed_payload[:payments].first[:transactions].first[:name] + end + end + + def iban + object.metadata.fetch('iban') do + object.parsed_payload[:payments].first[:transactions].first[:iban] + end + end + + def bic + object.metadata.fetch('bic') do + object.parsed_payload[:payments].first[:transactions].first[:bic] + end + end + + def reference + object.metadata.fetch('reference') do + object.parsed_payload[:payments].first[:transactions].first[:remittance_information] + end + end + + def executed_on + object.metadata.fetch('execution_date') do + object.parsed_payload[:payments].first[:execution_date] + end + end end end end diff --git a/box/jobs/credit.rb b/box/jobs/credit.rb index 385c6ac2..990de10c 100644 --- a/box/jobs/credit.rb +++ b/box/jobs/credit.rb @@ -7,6 +7,10 @@ module Box module Jobs class Credit + INSTRUMENT_MAPPING = Hash.new('AZV').update({ + "EUR" => :CCT, + }) + def self.process!(message) transaction = Transaction.create( account_id: message[:account_id], @@ -15,8 +19,10 @@ def self.process!(message) type: "credit", payload: Base64.strict_decode64(message[:payload]), eref: message[:eref], + currency: message[:currency], status: "created", - order_type: :CCT + order_type: INSTRUMENT_MAPPING[message[:currency]], + metadata: message[:metadata] ) transaction.execute! diff --git a/box/models/account.rb b/box/models/account.rb index 72f2bbf6..80a33b4d 100644 --- a/box/models/account.rb +++ b/box/models/account.rb @@ -106,6 +106,25 @@ def credit_pain_attributes_hash values.slice(:name, :bic, :iban) end + def bank_account_number + @bank_account_number ||= (bank_account_metadata; @bank_account_number) + end + + def bank_number + @bank_number ||= (bank_account_metadata; @bank_number) + end + + def bank_country_code + iban[0...2] + end + + def bank_account_metadata + Nokogiri::XML(transport_client.HTD).tap do |htd| + @bank_account_number ||= htd.at_xpath("//xmlns:AccountNumber[@international='false']", xmlns: "urn:org:ebics:H004").text + @bank_number ||= htd.at_xpath("//xmlns:BankCode[@international='false']", xmlns: "urn:org:ebics:H004").text + end + end + def last_imported_at DB[:imports].where(account_id: id).order(:date).last.try(:[], :date) end diff --git a/box/validations/unique_transaction_eref.rb b/box/validations/unique_transaction_eref.rb index 54d633b5..59376db2 100644 --- a/box/validations/unique_transaction_eref.rb +++ b/box/validations/unique_transaction_eref.rb @@ -15,4 +15,19 @@ def validate(request) eref_unused or fail(Grape::Exceptions::Validation, params: [@scope.full_name(:end_to_end_reference)], message: "must be unique") end end + + class LengthTransactionEref < Grape::Validations::Base + + def length(currency) + Hash.new(27).update( + 'EUR' => 64 + )[currency] + end + + def validate(request) + return if request.params[:end_to_end_reference].to_s.size <= length(request.params[:currency]) + + fail(Grape::Exceptions::Validation, params: [@scope.full_name(:end_to_end_reference)], message: "must be at the most #{length(request.params[:currency])} characters long") + end + end end diff --git a/migrations/20180316144100_add_foreign_credit_support.rb b/migrations/20180316144100_add_foreign_credit_support.rb new file mode 100644 index 00000000..44363500 --- /dev/null +++ b/migrations/20180316144100_add_foreign_credit_support.rb @@ -0,0 +1,6 @@ +Sequel.migration do + change do + add_column :transactions, :currency, String, default: 'EUR' + add_column :transactions, :metadata, String, type: :json, default: Sequel.pg_json({}) + end +end diff --git a/spec/apis/v2/credit_transfers_spec.rb b/spec/apis/v2/credit_transfers_spec.rb index 9ae3b5ff..61d7e603 100644 --- a/spec/apis/v2/credit_transfers_spec.rb +++ b/spec/apis/v2/credit_transfers_spec.rb @@ -153,6 +153,14 @@ module Box } end + let(:valid_attributes_foreign) do + valid_attributes.merge( + currency: 'CHF', + country_code: 'CH', + end_to_end_reference: 'TEST' + ) + end + context "when no valid access token is provided" do it 'returns a 401' do post '/credit_transfers', {}, INVALID_TOKEN_HEADER @@ -203,6 +211,33 @@ module Box post "/credit_transfers", valid_attributes.merge(bic: 'MYTESTBIC'), VALID_HEADERS expect_json message: "Failed to initiate credit transfer.", errors: { base: "Bic MYTESTBIC is invalid" } end + + it 'fails on too long end_to_end_reference' do + post "/credit_transfers", valid_attributes.merge(end_to_end_reference: 'E'*65), VALID_HEADERS + expect_json 'errors.end_to_end_reference', ["must be at the most 64 characters long"] + end + + context 'foreign currency' do + it 'fails on missing country_code' do + post "/credit_transfers", valid_attributes.merge(currency: 'CHF'), VALID_HEADERS + expect_json 'errors.country_code', ["is missing", "is empty"] + end + + it 'fails on missing bic' do + post "/credit_transfers", valid_attributes.merge(currency: 'CHF', bic: nil), VALID_HEADERS + expect_json 'errors.bic', ["is empty"] + end + + it 'fails on invalid currency' do + post "/credit_transfers", valid_attributes.merge(currency: 'CHF123'), VALID_HEADERS + expect_json 'errors.currency', ["must be at the most 3 characters long"] + end + + it 'fails on too long end_to_end_reference' do + post "/credit_transfers", valid_attributes.merge(currency: 'CHF', end_to_end_reference: 'E'*13), VALID_HEADERS + expect_json 'errors.end_to_end_reference', ["must be at the most 12 characters long"] + end + end end context 'valid data' do @@ -243,6 +278,13 @@ module Box expect_status 201 end + context 'foreign currency' do + it 'returns a 201' do + post "/credit_transfers", valid_attributes_foreign, VALID_HEADERS + expect_status 201 + end + end + context "when sandbox server mode" do before { allow(Box.configuration).to receive(:sandbox?).and_return(true) } @@ -251,7 +293,6 @@ module Box end end - ### ### GET /accounts ### From b35c041c30fa7c4652de70834e2bde3e6cc8d405 Mon Sep 17 00:00:00 2001 From: Lars Brillert Date: Mon, 26 Mar 2018 14:17:43 +0200 Subject: [PATCH 2/4] adjust specs --- spec/apis/v2/credit_transfers_spec.rb | 8 +- spec/fixtures/htd.xml | 213 ++++++++++++++++++++++++++ 2 files changed, 219 insertions(+), 2 deletions(-) create mode 100644 spec/fixtures/htd.xml diff --git a/spec/apis/v2/credit_transfers_spec.rb b/spec/apis/v2/credit_transfers_spec.rb index 61d7e603..fa1030d9 100644 --- a/spec/apis/v2/credit_transfers_spec.rb +++ b/spec/apis/v2/credit_transfers_spec.rb @@ -234,8 +234,8 @@ module Box end it 'fails on too long end_to_end_reference' do - post "/credit_transfers", valid_attributes.merge(currency: 'CHF', end_to_end_reference: 'E'*13), VALID_HEADERS - expect_json 'errors.end_to_end_reference', ["must be at the most 12 characters long"] + post "/credit_transfers", valid_attributes.merge(currency: 'CHF', end_to_end_reference: 'E'*28), VALID_HEADERS + expect_json 'errors.end_to_end_reference', ["must be at the most 27 characters long"] end end end @@ -279,6 +279,10 @@ module Box end context 'foreign currency' do + before do + allow_any_instance_of(Epics::Client).to receive(:HTD).and_return(File.read('spec/fixtures/htd.xml')) + end + it 'returns a 201' do post "/credit_transfers", valid_attributes_foreign, VALID_HEADERS expect_status 201 diff --git a/spec/fixtures/htd.xml b/spec/fixtures/htd.xml new file mode 100644 index 00000000..1286bce7 --- /dev/null +++ b/spec/fixtures/htd.xml @@ -0,0 +1,213 @@ + + + + + Railslove GmbH + Sechzigstr. + 50733 + Köln + + + EBICSSPK + + + 2624334974 + DE45100110012624334974 + 10011001 + NTSBDEB1XXX + Railslove GmbH + + + C52 + Download + CAMT052 + Abholen Vormerkposten + + + C53 + Download + CAMT053 + Abholen Kontoauszuege + + + HAA + Download + MISC + Abrufbare Auftragsarten abholen + + + HAC + Download + HAC + Kundenprotokoll (XML-Format) abholen + + + HKD + Download + MISC + Kunden- und Teilnehmerdaten abholen + + + HPB + Download + MISC + Public Keys der Bank abholen + + + HPD + Download + MISC + Bankparameter abholen + + + HTD + Download + MISC + Kunden- und Teilnehmerdaten abholen + + + HVD + Download + MISC + VEU-Status abrufen + + + HVT + Download + MISC + VEU-Transaktionsdetails abrufen + + + HVU + Download + MISC + VEU-Uebersicht abholen + + + HVZ + Download + MISC + VEU-Uebersicht mit Zusatzinformationen + + + PTK + Download + PTK + Protokolldatei abholen + + + STA + Download + MT940 + Swift-Tagesauszuege abholen + + + AZV + Upload + DTAZVJS + AZV im Diskettenformat senden + 1 + + + CCT + Upload + PN1GOCS + Einreichen von Ueberweisungen + 1 + + + CCU + Upload + P1URGCS + Einreichen von Eilueberweisungen + 1 + + + CD1 + Upload + P8COR1 + Einreichen von Lastschriften D-1-Option + 1 + + + CDD + Upload + PN8GOCS + Einreichen von Lastschriften + 1 + + + HCA + Upload + MISC + Teilnehmerschluessel EBICS aendern + 0 + + + HCS + Upload + MISC + Teilnehmerschluessel EU und EBICS aendern + 0 + + + HIA + Upload + MISC + Teilnehmerschluessel EBICS uebermitteln + 0 + + + HVE + Upload + MISC + VEU-Unterschrift hinzufuegen + 0 + + + HVS + Upload + MISC + VEU-Storno + 0 + + + INI + Upload + MISC + Passwort-Initialisierung + 0 + + + PUB + Upload + MISC + Public-Key senden + 0 + + + SPR + Upload + MISC + Sperrung der Zugangsberechtigung + 0 + + + + 12353901 + Michael Bumann + + C52 C53 HAA HAC HKD HPB HPD HTD HVD HVT HVU HVZ PTK STA + + + + accid000000001 + + + AZV CCT CCU CD1 CDD + + + HCA HCS HIA HVE HVS INI PUB SPR + + + From 5a7690835c5262dbb6f4018f0513ed87e2919f54 Mon Sep 17 00:00:00 2001 From: Maxim Date: Tue, 27 Mar 2018 11:38:04 +0200 Subject: [PATCH 3/4] fixes typo --- box/apis/v2/credit_transfers.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/box/apis/v2/credit_transfers.rb b/box/apis/v2/credit_transfers.rb index 07af83a2..c44e6d46 100644 --- a/box/apis/v2/credit_transfers.rb +++ b/box/apis/v2/credit_transfers.rb @@ -66,7 +66,7 @@ class CreditTransfers < Grape::API requires :name, type: String, desc: "the customers name" optional :currency, type: String, desc: "currency of the transfer", length: 3, regexp: /[A-Z]{3}/, default: 'EUR' - requires :iban, type: String, desc: "the customers acconut" + requires :iban, type: String, desc: "the customers account" given currency: ->(val) { val != 'EUR' } do optional :fee_handling, type: Symbol, values: %i[split sender receiver], default: :split From aeabd55362021c950469a1b5090d830d28b81cfe Mon Sep 17 00:00:00 2001 From: Maxim Date: Mon, 9 Apr 2018 16:49:17 +0200 Subject: [PATCH 4/4] fixes migration not passing when tables already exist --- migrations/20171104144100_merged.rb | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/migrations/20171104144100_merged.rb b/migrations/20171104144100_merged.rb index bb91688b..74803b3f 100644 --- a/migrations/20171104144100_merged.rb +++ b/migrations/20171104144100_merged.rb @@ -21,7 +21,7 @@ String :statements_format, :default=>"mt940", :text=>true String :config, type: :json, default: Sequel.pg_json({}) String :descriptor, :text=>true - end + end unless tables.include?(:accounts) create_table(:bank_statements) do primary_key :id @@ -34,7 +34,7 @@ Date :fetched_on String :content, :text=>true Integer :year - end + end unless tables.include?(:bank_statements) create_table(:events) do primary_key :id @@ -46,7 +46,7 @@ String :signature, :text=>true String :webhook_status, :default=>"pending", :text=>true Integer :webhook_retries, :default=>0 - end + end unless tables.include?(:events) create_table(:imports) do primary_key :id @@ -54,14 +54,14 @@ Integer :duration Integer :transactions_count Integer :account_id - end + end unless tables.include?(:imports) create_table(:organizations) do primary_key :id String :name, :text=>true DateTime :created_at, :default=>Sequel.function(:now) String :webhook_token, :text=>true, :null=>false - end + end unless tables.include?(:organizations) create_table(:statements, :ignore_index_errors=>true) do primary_key :id @@ -91,7 +91,7 @@ String :public_id index [:sha], :name=>:statements_sha_key, :unique=>true - end + end unless tables.include?(:statements) create_table(:subscribers) do primary_key :id @@ -104,7 +104,7 @@ DateTime :activated_at String :ini_letter, :text=>true DateTime :submitted_at - end + end unless tables.include?(:subscribers) create_table(:transactions, :ignore_index_errors=>true) do primary_key :id @@ -123,7 +123,7 @@ String :history, :type=>:json, :default=> Sequel.pg_json([]) index [:eref], :name=>:transactions_eref_key, :unique=>true - end + end unless tables.include?(:transactions) create_table(:users) do primary_key :id @@ -133,7 +133,7 @@ DateTime :created_at, :default=>Sequel.function(:now) TrueClass :admin, :default=>false String :email, :text=>true - end + end unless tables.include?(:users) create_table(:webhook_deliveries) do primary_key :id @@ -143,6 +143,6 @@ String :reponse_headers, type: :json, default: Sequel.pg_json({}) Integer :response_status Integer :response_time - end + end unless tables.include?(:webhook_deliveries) end end