Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

23.12.2 #288

Merged
merged 4 commits into from
Dec 28, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,14 @@

## Unreleased

## Version 23.12.2

Released on 28.12.2023

- Feature: Add column_config for data digests
- Feature: Improve deposit detection
- Bugfixes

## Version 23.12.1

Released on 19.12.2023
Expand Down
2 changes: 1 addition & 1 deletion VERSION
Original file line number Diff line number Diff line change
@@ -1 +1 @@
V23.12.1
V23.12.2
2 changes: 1 addition & 1 deletion app/controllers/manage/payments_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ def new_import
@bookings = bookings_for_import
@invoices = invoices_for_import
@payments = params[:camt_file].presence &&
Payment::Factory.new(current_organisation).from_camt_file(params[:camt_file])
CamtService.new(current_organisation).payments_from_file(params[:camt_file])

render 'import' if @payments.present?
rescue CamtParser::Errors::BaseError, Nokogiri::SyntaxError => e
Expand Down
2 changes: 1 addition & 1 deletion app/models/invoice/factory.rb
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@ def payable_until(invoice)
settings = invoice.booking.organisation.settings
if invoice.is_a?(Invoices::Deposit)
return [settings.deposit_payment_deadline.from_now,
invoice.booking.begins_at]
invoice.booking.begins_at].min
end

settings.invoice_payment_deadline.from_now
Expand Down
12 changes: 12 additions & 0 deletions app/models/invoice_part/factory.rb
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ def initialize(invoice)
def call
I18n.with_locale(invoice.locale || I18n.locale) do
[
from_payments.presence,
from_deposits.presence,
from_supersede_invoice.presence,
from_usages.presence
Expand All @@ -32,6 +33,17 @@ def from_usages(usages = booking.usages.ordered.where.not(id: invoice.invoice_pa
end.flatten
end

def from_payments
payed_amount = @invoice.booking.payments.where(invoice: nil, write_off: false).sum(:amount)
return [] unless payed_amount.positive? && @invoice.new_record?

[
InvoiceParts::Text.new(apply: suggest?, label: Invoices::Deposit.model_name.human),
InvoiceParts::Add.new(apply: suggest?, label: I18n.t('invoice_parts.deposited_amount'),
amount: - payed_amount)
]
end

def from_deposits
deposits = Invoices::Deposit.of(@invoice.booking).kept
deposited_amount = deposits.sum(&:amount_paid)
Expand Down
38 changes: 0 additions & 38 deletions app/models/payment/factory.rb
Original file line number Diff line number Diff line change
Expand Up @@ -6,44 +6,6 @@ def initialize(organisation)
@organisation = organisation
end

def from_camt_file(file)
camt = CamtParser::String.parse file.read
camt.notifications.map do |notification|
notification.entries.flat_map { |entry| from_camt_entry(entry) }
end.flatten.compact
end

def from_camt_entry(entry)
return unless entry.booked? && entry.credit? && entry.currency.upcase == @organisation.currency.upcase

entry.transactions.map do |transaction|
from_camt_transaction(transaction, entry)
end
end

def find_invoice_by_ref(ref)
@organisation.invoice_ref_strategy.find_invoice_by_ref(ref, scope: @organisation.invoices.kept)
end

def from_camt_transaction(transaction, entry)
ref = transaction.creditor_reference
invoice = find_invoice_by_ref(ref)
remarks = [transaction.name, entry.description].compact_blank.join("\n\n")

Payment.new(
invoice:, booking: invoice&.booking, applies: invoice.present?, ref:,
paid_at: entry.value_date, amount: transaction.amount, data: camt_transaction_to_h(transaction),
camt_instr_id: transaction.reference, remarks:
)
end

def camt_transaction_to_h(transaction)
fields = %i[amount amount_in_cents currency name iban bic debit sign
remittance_information swift_code reference bank_reference end_to_end_reference mandate_reference
creditor_reference transaction_id creditor_identifier payment_information additional_information]
fields.index_with { |field| transaction.try(field) }
end

def from_import(payments_params)
payments = payments_params.values.filter_map { |payment_params| Payment.new(payment_params) }
payments = payments.select(&:applies)
Expand Down
50 changes: 50 additions & 0 deletions app/services/camt_service.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
# frozen_string_literal: true

class CamtService
def initialize(organisation)
@organisation = organisation
end

def payments_from_file(file) # rubocop:disable Metrics/CyclomaticComplexity
camt = CamtParser::String.parse file.read
entries = case camt
when CamtParser::Format053::Base
camt.statements.flat_map(&:entries)
when CamtParser::Format054::Base
camt.notifications.flat_map(&:entries)
end

entries&.flat_map { |entry| payments_from_entry(entry) }&.compact
end

def payments_from_entry(entry)
return unless entry.booked? && entry.credit? && entry.currency.upcase == @organisation.currency.upcase

entry.transactions.map do |transaction|
payment_from_transaction(transaction, entry)
end
end

def payment_from_transaction(transaction, entry)
ref = transaction.creditor_reference
invoice = find_invoice_by_ref(ref)
remarks = [transaction.name, entry.description].compact_blank.join("\n\n")

Payment.new(
invoice:, booking: invoice&.booking, applies: invoice.present?, ref:,
paid_at: entry.value_date, amount: transaction.amount, data: transaction_to_h(transaction),
camt_instr_id: transaction.reference, remarks:
)
end

def find_invoice_by_ref(ref)
@organisation.invoice_ref_strategy.find_invoice_by_ref(ref, scope: @organisation.invoices.kept)
end

def transaction_to_h(transaction)
fields = %i[amount amount_in_cents currency name iban bic debit sign
remittance_information swift_code reference bank_reference end_to_end_reference mandate_reference
creditor_reference transaction_id creditor_identifier payment_information additional_information]
fields.index_with { |field| transaction.try(field) }
end
end
3 changes: 3 additions & 0 deletions config/initializers/camt_parser.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
# frozen_string_literal: true

CamtParser::Xml.register('urn:iso:std:iso:20022:tech:xsd:camt.054.001.08', :camt054)