Class: Cash

Inherits:
Ekylibre::Record::Base show all
Includes:
Attachable, Customizable
Defined in:
app/models/cash.rb

Overview

Informations

License

Ekylibre - Simple agricultural ERP Copyright (C) 2008-2009 Brice Texier, Thibaud Merigon Copyright (C) 2010-2012 Brice Texier Copyright (C) 2012-2019 Brice Texier, David Joulin

This program is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or any later version.

This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details.

You should have received a copy of the GNU Affero General Public License along with this program. If not, see www.gnu.org/licenses.

Table: cashes

bank_account_holder_name     :string
bank_account_key             :string
bank_account_number          :string
bank_agency_address          :text
bank_agency_code             :string
bank_code                    :string
bank_identifier_code         :string
bank_name                    :string
container_id                 :integer
country                      :string
created_at                   :datetime         not null
creator_id                   :integer
currency                     :string           not null
custom_fields                :jsonb
iban                         :string
id                           :integer          not null, primary key
journal_id                   :integer          not null
last_number                  :integer
lock_version                 :integer          default(0), not null
main_account_id              :integer          not null
mode                         :string           default("iban"), not null
name                         :string           not null
nature                       :string           default("bank_account"), not null
owner_id                     :integer
spaced_iban                  :string
suspend_until_reconciliation :boolean          default(FALSE), not null
suspense_account_id          :integer
updated_at                   :datetime         not null
updater_id                   :integer

Constant Summary collapse

BBAN_TRANSLATIONS =
{
  fr: %w[abcdefghijklmonpqrstuvwxyz 12345678912345678923456789]
}.freeze

Class Method Summary collapse

Instance Method Summary collapse

Methods included from Customizable

#custom_value, #set_custom_value, #validate_custom_fields

Methods inherited from Ekylibre::Record::Base

#already_updated?, #check_if_destroyable?, #check_if_updateable?, columns_definition, #customizable?, customizable?, #customized?, #destroyable?, #editable?, has_picture, #human_attribute_name, nomenclature_reflections, #old_record, #others, refers_to, #unsuppress, #updateable?

Methods included from Userstamp::Stampable

included

Methods included from Userstamp::Stamper

included

Class Method Details

.generate_iban(country_code, bban) ⇒ Object

Generates the IBAN key.


217
218
219
220
221
222
223
# File 'app/models/cash.rb', line 217

def self.generate_iban(country_code, bban)
  iban = bban + country_code.upcase + '00'
  iban.each_char do |c|
    iban.gsub!(c, c.to_i(36).to_s) if c =~ /\D/
  end
  country_code + (98 - (iban.to_i.modulo 97)).to_s + bban
end

.load_defaultsObject

Load default cashes (1 bank account and 1 cash box)


226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
# File 'app/models/cash.rb', line 226

def self.load_defaults
  [
    %i[bank_account bank banks],
    %i[cash_box cash cashes]
  ].each do |nature, journal_nature, |
    next if find_by(nature: nature)
    journal = Journal.find_by(nature: journal_nature)
     = Account.find_or_import_from_nomenclature()
    next unless journal && 
    create!(
      name: "enumerize.cash.nature.#{nature}".t,
      nature: nature.to_s,
      main_account: ,
      journal: journal
    )
  end
end

.valid_bban?(country_code, options = {}) ⇒ Boolean

Checks if the BBAN is valid.

Returns:

  • (Boolean)

206
207
208
209
210
211
212
213
214
# File 'app/models/cash.rb', line 206

def self.valid_bban?(country_code, options = {})
  case cc = country_code.lower.to_sym
  when :fr
    ban = (options['bank_code'].to_s.lower.tr(*BBAN_TRANSLATIONS[cc]).to_i * 89 + options['bank_agency_code'].to_s.lower.tr(*BBAN_TRANSLATIONS[cc]).to_i * 15 + options['bank_account_number'].to_s.lower.tr(*BBAN_TRANSLATIONS[cc]).to_i * 3)
    (options['bank_account_key'].to_i + ban.modulo(97) - 97).zero?
  else
    raise ArgumentError, "Unknown country code #{country_code.inspect}"
  end
end

Instance Method Details

#accountObject


185
186
187
# File 'app/models/cash.rb', line 185

def 
  suspend_until_reconciliation ?  : 
end

#account=(record) ⇒ Object


189
190
191
192
193
194
195
# File 'app/models/cash.rb', line 189

def account=(record)
  if suspend_until_reconciliation
    self. = record
  else
    self. = record
  end
end

#account_idObject


173
174
175
# File 'app/models/cash.rb', line 173

def 
  suspend_until_reconciliation ?  : 
end

#account_id=(id) ⇒ Object


177
178
179
180
181
182
183
# File 'app/models/cash.rb', line 177

def (id)
  if suspend_until_reconciliation
    self. = id
  else
    self. = id
  end
end

#balance(at = Time.zone.now) ⇒ Object

Returns (real) main account cash balance in the global currency


283
284
285
286
287
288
289
290
291
# File 'app/models/cash.rb', line 283

def balance(at = Time.zone.now)
  if at == Time.zone.now
    main_journal_entry_items.sum('real_debit - real_credit') || 0.0
  else
    closure = FinancialYear.last_closure || Date.civil(-1, 12, 31)
    closure += 1
    main_journal_entry_items.where(printed_on: closure..at.to_date).sum('real_debit - real_credit') || 0.0
  end
end

#formatted_bban(separator = ' ') ⇒ Object


201
202
203
# File 'app/models/cash.rb', line 201

def formatted_bban(separator = ' ')
  [bank_code, bank_agency_code, , ].join(separator)
end

#journal_entry_itemsObject


165
166
167
# File 'app/models/cash.rb', line 165

def journal_entry_items
  suspend_until_reconciliation ? suspended_journal_entry_items : main_journal_entry_items
end

#last_journal_entryObject

Return last entry date


278
279
280
# File 'app/models/cash.rb', line 278

def last_journal_entry
  main_journal_entry_items.reorder(printed_on: :desc).first
end

#letter_items(statement_items, journal_entry_items) ⇒ Object


298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
# File 'app/models/cash.rb', line 298

def letter_items(statement_items, journal_entry_items)
  new_letter = next_reconciliation_letter
  return false if (journal_entry_items + statement_items).length.zero?

  statement_entries = JournalEntryItem.where(resource: statement_items)
  to_letter = journal_entry_items + statement_entries
  .mark(to_letter) if suspend_until_reconciliation

  saved = true
  saved &&= statement_items.update_all(letter: new_letter)
  saved &&= journal_entry_items.update_all(
    bank_statement_letter: new_letter
  )

  saved && new_letter
end

#monthly_sums(started_at, stopped_at, expr = 'debit - credit') ⇒ Object


252
253
254
255
256
257
# File 'app/models/cash.rb', line 252

def monthly_sums(started_at, stopped_at, expr = 'debit - credit')
  .journal_entry_items.between(started_at, stopped_at).group('EXTRACT(YEAR FROM printed_on)*100 + EXTRACT(MONTH FROM printed_on)').sum(expr).sort.each_with_object({}) do |pair, hash|
    hash[pair[0].to_i.to_s] = pair[1].to_d
    hash
  end
end

#next_reconciliation_letterObject


259
260
261
262
# File 'app/models/cash.rb', line 259

def next_reconciliation_letter
  item = BankStatementItem.where('LENGTH(TRIM(letter)) > 0').order('LENGTH(letter) DESC, letter DESC').first
  item ? item.letter.succ : 'A'
end

#next_reconciliation_lettersObject


264
265
266
267
268
269
270
271
272
273
274
275
# File 'app/models/cash.rb', line 264

def next_reconciliation_letters
  Enumerator.new do |yielder|
    letter_column = "#{BankStatementItem.table_name}.letter"
    letter = 'A'
    loop do
      if bank_statements.joins(:items).where(letter_column => letter).blank?
        yielder << letter
      end
      letter = letter.succ
    end
  end
end

#pointable?Boolean

Returns:

  • (Boolean)

244
245
246
# File 'app/models/cash.rb', line 244

def pointable?
  bank_account? || associate_account?
end

#suspended_balance(_at = Time.zone.now) ⇒ Object

Returns (theoric) suspense account cash balance in the global currency


294
295
296
# File 'app/models/cash.rb', line 294

def suspended_balance(_at = Time.zone.now)
  suspended_journal_entry_items.sum('real_debit - real_credit') || 0.0
end

#unpointed_journal_entry_itemsObject


169
170
171
# File 'app/models/cash.rb', line 169

def unpointed_journal_entry_items
  suspend_until_reconciliation ? unpointed_suspended_journal_entry_items : unpointed_main_journal_entry_items
end

#unpointed_journal_entry_items?Boolean

Returns:

  • (Boolean)

248
249
250
# File 'app/models/cash.rb', line 248

def unpointed_journal_entry_items?
  pointable? && unpointed_journal_entry_items.any?
end

#used?Boolean

Returns:

  • (Boolean)

197
198
199
# File 'app/models/cash.rb', line 197

def used?
  deposits.any? || bank_statements.any? || outgoing_payment_modes.any? || incoming_payment_modes.any?
end