Class: StatementOfAccount

Inherits:
ApplicationRecord show all
Includes:
Models::AccountingDocumentTransmittable, Models::Auditable
Defined in:
app/models/statement_of_account.rb

Overview

== Schema Information

Table name: statement_of_accounts
Database name: primary

id :integer not null, primary key
currency :string(255)
open_amount :decimal(12, 2)
transmission_error :text
transmission_state :string(255)
uploads_count :integer
created_at :datetime
updated_at :datetime
customer_id :integer

Indexes

index_statement_of_accounts_on_customer_id (customer_id)
index_statement_of_accounts_on_transmission_state (transmission_state)

Constant Summary

Constants included from Models::Auditable

Models::Auditable::ALWAYS_IGNORED

Instance Attribute Summary collapse

Belongs to collapse

Methods included from Models::Auditable

#creator, #updater

Has many collapse

Class Method Summary collapse

Instance Method Summary collapse

Methods included from Models::AccountingDocumentTransmittable

#can_be_transmitted?, #fallback_notification_channel_type, #notification_channel_sort_order, #notification_channel_types, #notification_channels, #own_notification_channel_type, #post_communication_exception_hook, #post_communication_sent_hook, #primary_transmission_contact, #primary_transmission_contact_point_id, #transmission_contact_points

Methods included from Models::Auditable

#all_skipped_columns, #audit_reference_data, #should_not_save_version, #stamp_record

Methods inherited from ApplicationRecord

ransackable_associations, ransackable_attributes, ransackable_scopes, ransortable_attributes, #to_relation

Methods included from Models::EventPublishable

#publish_event

Instance Attribute Details

#customer_idObject (readonly)



30
# File 'app/models/statement_of_account.rb', line 30

validates :customer_id, presence: true

Class Method Details

.generate_monthly_statementsObject



104
105
106
107
108
109
# File 'app/models/statement_of_account.rb', line 104

def self.generate_monthly_statements
  customer_ids = Customer.where(send_statement: true).pluck(:id)
  customer_ids.each do |customer_id|
    StatementOfAccountGenerationWorker.perform_async(customer_id)
  end
end

.generate_pdf(customer, split_by_currency = false) ⇒ Object



62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
# File 'app/models/statement_of_account.rb', line 62

def self.generate_pdf(customer, split_by_currency = false)
  results = StatementOfAccount.results(customer, include_ship_to = true)
  uploads = []
  if split_by_currency == true
    # need to generate a statement for each currency
    results.each do |currency, res|
      if res.empty?
        soa = nil
      else
        soa = StatementOfAccount.create(currency:, customer_id: customer.id, open_amount: res.sum { |r| BigDecimal(r.open_amount) })
        soa.transmit
        pdf = Statement::PdfGenerator.new.process(soa, { currency => res }).pdf
        path = Upload.temp_location(soa.file_name)
        File.open(path, 'wb') do |file|
          file.write pdf
          file.flush
          file.fsync
        end
        upload = Upload.uploadify(path, 'statement_of_account_pdf', soa, soa.file_name(true))
        uploads << upload
      end
    end
  elsif results.empty?
    # need to combine into one statement
    soa = nil
  else
    soa = StatementOfAccount.create(currency: 'ALL', customer_id: customer.id, open_amount: results.sum { |currency, res| res.sum { |r| BigDecimal(r.open_amount) } })
    soa.transmit
    pdf = Statement::PdfGenerator.new.process(soa, results).pdf
    path = Upload.temp_location(soa.file_name)
    File.open(path, 'wb') do |file|
      file.write pdf
      file.flush
      file.fsync
    end
    upload = Upload.uploadify(path, 'statement_of_account_pdf', soa, soa.file_name(true))
    uploads << upload
  end

  soa
end

.results(customer, include_ship_to = false) ⇒ Object



44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
# File 'app/models/statement_of_account.rb', line 44

def self.results(customer, include_ship_to = false)
  start_date = Date.current - 4.years
  end_date = Date.current + 1.year
  invoices = Invoice.where("state = 'unpaid' and due_date between '#{start_date}' and '#{end_date}' and total != 0") \
                    .select("customer_id, billing_customer_id, 'INVOICE' as doc_type, reference_number, po_number, terms, gl_date, due_date, (invoices.total - coalesce((select sum(rd.amount)+sum(rd.discount)+sum(rd.write_off) as receipts_total from receipt_details rd where rd.state <> 'voided' and rd.invoice_id = invoices.id),0)) as open_amount, currency")
  invoices = include_ship_to == true ? invoices.where("(billing_customer_id = #{customer.id} or customer_id = #{customer.id})") : invoices.where("billing_customer_id = #{customer.id}")
  credit_memos = CreditMemo.where("state in ('printed','partially_offset') and document_date between '#{start_date}' and '#{end_date}' and billing_customer_id = #{customer.id} and total != 0") \
                           .select("customer_id, billing_customer_id, 'CREDIT' as doc_type, reference_number, original_po_number as po_number, (select p.terms from parties p where p.id = credit_memos.customer_id) as terms, gl_date, document_date as due_date, credit_memos.total - (coalesce((select sum(amount) from receipt_details where credit_memo_id = credit_memos.id and state <> 'voided'),0)-coalesce((select sum(amount) from outgoing_payment_items where credit_memo_id = credit_memos.id and state = 'applied'),0)) as open_amount, currency")
  credit_memos = include_ship_to == true ? credit_memos.where("(billing_customer_id = #{customer.id} or customer_id = #{customer.id})") : credit_memos.where("billing_customer_id = #{customer.id}")
  receipts = Receipt.where("state in ('unapplied','partially_applied') and receipt_date between '#{start_date}' and '#{end_date}' and customer_id = #{customer.id} and amount != 0") \
                    .select("customer_id, customer_id as billing_customer_id, 'PAYMENT' as doc_type, reference as reference_number, null as po_number, (select p.terms from parties p where p.id = receipts.customer_id) as terms, gl_date as gl_date, receipt_date as due_date, (receipts.amount - coalesce((select sum(rd.amount)+sum(rd.discount)+sum(rd.write_off) as receipts_total from receipt_details rd where rd.state <> 'voided' and rd.receipt_id = receipts.id),0)) * -1 as open_amount, currency")
  statement_results = invoices + credit_memos + receipts
  statement_results = statement_results.group_by { |a| a.currency }
  sorted_statement_results = {}
  statement_results.each { |currency, results| sorted_statement_results[currency] = results.sort_by { |a| Date.strptime(a.due_date.to_s, '%Y-%m-%d') } }
  sorted_statement_results
end

Instance Method Details

#billing_address_idObject



40
41
42
# File 'app/models/statement_of_account.rb', line 40

def billing_address_id
  customer.billing_address.party_id
end

#billing_customerObject



36
37
38
# File 'app/models/statement_of_account.rb', line 36

def billing_customer
  customer.billing_address.party
end

#communicationsActiveRecord::Relation<Communication>

Returns:

See Also:



28
# File 'app/models/statement_of_account.rb', line 28

has_many :communications, -> { order(:id).reverse_order }, as: :resource, dependent: :nullify

#customerCustomer

Returns:

See Also:



25
# File 'app/models/statement_of_account.rb', line 25

belongs_to :customer, optional: true

#file_name(with_extension = true) ⇒ Object



115
116
117
# File 'app/models/statement_of_account.rb', line 115

def file_name(with_extension = true)
  "Statement_of_Account_#{customer.id}_#{currency}#{'.pdf' if with_extension}"
end

#reference_numberObject



111
112
113
# File 'app/models/statement_of_account.rb', line 111

def reference_number
  "SOA#{id}"
end

#to_sObject



32
33
34
# File 'app/models/statement_of_account.rb', line 32

def to_s
  "Statement Of Account #{id}"
end

#uploadsActiveRecord::Relation<Upload>

Returns:

  • (ActiveRecord::Relation<Upload>)

See Also:



27
# File 'app/models/statement_of_account.rb', line 27

has_many :uploads, as: :resource, dependent: :destroy