Class: LucaDeal::Fee

Inherits:
LucaRecord::Base
  • Object
show all
Defined in:
lib/luca_deal/fee.rb

Instance Method Summary collapse

Constructor Details

#initialize(date = nil) ⇒ Fee

Returns a new instance of Fee.



15
16
17
# File 'lib/luca_deal/fee.rb', line 15

def initialize(date = nil)
  @date = issue_date(date)
end

Instance Method Details

#compose_mail(dat, mode: nil, attachment: :html) ⇒ Object



97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
# File 'lib/luca_deal/fee.rb', line 97

def compose_mail(dat, mode: nil, attachment: :html)
  @company = set_company
  fee_vars(dat)

  mail = Mail.new
  mail.to = dat.dig('customer', 'to') if mode.nil?
  mail.subject = LucaRecord::CONST.config.dig('fee', 'mail_subject') || 'Your Report is available'
  if mode == :preview
    mail.cc = LucaRecord::CONST.config.dig('mail', 'preview') || LucaRecord::CONST.config.dig('mail', 'from')
    mail.subject = '[preview] ' + mail.subject
  end
  mail.text_part = Mail::Part.new(body: render_erb(search_template('fee-report-mail.txt.erb')), charset: 'UTF-8')
  mail.attachments[attachment_name(dat, attachment)] = render_report(attachment)
  mail
end

#deliver_mail(attachment_type = nil, mode: nil, skip_no_item: true) ⇒ Object



68
69
70
71
72
73
74
75
76
77
78
79
80
81
# File 'lib/luca_deal/fee.rb', line 68

def deliver_mail(attachment_type = nil, mode: nil, skip_no_item: true)
  attachment_type = LucaRecord::CONST.config.dig('fee', 'attachment') || :html
  fees = self.class.asof(@date.year, @date.month)
  raise "No report for #{@date.year}/#{@date.month}" if fees.count.zero?

  fees.each do |dat, path|
    next if has_status?(dat, 'mail_delivered')
    next if skip_no_item && dat['items'].empty?

    mail = compose_mail(dat, mode: mode, attachment: attachment_type.to_sym)
    LucaSupport::Mail.new(mail, LucaRecord::CONST.pjdir).deliver
    self.class.add_status!(path, 'mail_delivered') if mode.nil?
  end
end

#export_jsonObject



154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
# File 'lib/luca_deal/fee.rb', line 154

def export_json
  labels = export_labels
  [].tap do |res|
    self.class.asof(@date.year, @date.month) do |dat|
      sub = dat['sales_fee']
      next if readable(sub['fee']) == 0 and readable(sub['deduction']) == 0

      item = {
        'date' => dat['issue_date'],
        'debit' => [],
        'credit' => []
      }
      if readable(sub['fee']) != 0
        item['debit'] << { 'label' => labels[:debit][:fee], 'amount' => readable(sub['fee']) }
        item['credit'] << { 'label' => labels[:credit][:fee], 'amount' => readable(sub['fee']) }
      end
      if readable(sub['tax']) != 0
        item['debit'] << { 'label' => labels[:debit][:tax], 'amount' => readable(sub['tax']) }
        item['credit'] << { 'label' => labels[:credit][:tax], 'amount' => readable(sub['tax']) }
      end
      if readable(sub['deduction']) != 0
        item['debit'] << { 'label' => labels[:debit][:deduction], 'amount' => readable(sub['deduction'] * -1) }
        item['credit'] << { 'label' => sub['deduction_label'] || labels[:credit][:deduction], 'amount' => readable(sub['deduction'] * -1) }
      end
      item['x-customer'] = dat['customer']['name'] if dat.dig('customer', 'name')
      item['x-editor'] = 'LucaDeal'
      res << item
    end
    puts JSON.dump(res)
  end
end

#get_customer(id) ⇒ Object



197
198
199
200
201
202
203
204
205
206
207
208
# File 'lib/luca_deal/fee.rb', line 197

def get_customer(id)
  {}.tap do |res|
    Customer.find(id) do |dat|
      customer = parse_current(dat)
      res['id'] = customer['id']
      res['name'] = customer.dig('name')
      res['address'] = customer.dig('address')
      res['address2'] = customer.dig('address2')
      res['to'] = customer.dig('contacts').map { |h| take_current(h, 'mail') }.compact
    end
  end
end

#monthly_feeObject

calculate fee, based on invoices



21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
# File 'lib/luca_deal/fee.rb', line 21

def monthly_fee
  Contract.asof(@date.year, @date.month, @date.day) do |contract|
    next if contract.dig('terms', 'category') != 'sales_fee'
    next if duplicated_contract? contract['id']

    @rate = { 'default' => BigDecimal(contract.dig('rate', 'default')) }
    @rate['initial'] = contract.dig('rate', 'initial') ? BigDecimal(contract.dig('rate', 'initial')) : @rate['default']
    limit = contract.dig('terms', 'limit')

    fee = {
      'contract_id' => contract['id'],
      'items' => [],
      'sales_fee' => {
        'fee' => 0,
        'tax' => 0,
        'deduction' => 0,
        'deduction_label' => contract.dig('terms', 'deduction_label')
      }
    }
    fee['customer'] = get_customer(contract['customer_id'])
    fee['issue_date'] = @date
    Invoice.asof(@date.year, @date.month) do |invoice|
      next if invoice.dig('sales_fee', 'id') != contract['id']
      next if exceed_limit?(invoice, limit)

      invoice['items'].each do |item|
        rate = item['type'] == 'initial' ? @rate['initial'] : @rate['default']
        fee['items'] << fee_record(invoice, item, rate)
      end
      subtotal(fee['items']).each{ |k, v| fee['sales_fee'][k] += v }
    end
    NoInvoice.asof(@date.year, @date.month) do |no_invoice|
      next if no_invoice.dig('sales_fee', 'id') != contract['id']
      next if exceed_limit?(no_invoice, limit)

      no_invoice['items'].each do |item|
        rate = item['type'] == 'initial' ? @rate['initial'] : @rate['default']
        fee['items'] << fee_record(no_invoice, item, rate)
      end
      subtotal(fee['items']).each{ |k, v| fee['sales_fee'][k] += v }
    end
    deduction_rate = contract.dig('rate', 'deduction')
    fee['sales_fee']['deduction'] = -1 * (fee['sales_fee']['fee'] * deduction_rate).floor if deduction_rate
    self.class.create(fee, date: @date, codes: Array(contract['id']))
  end
end

#preview_mail(attachment_type = nil) ⇒ Object



83
84
85
# File 'lib/luca_deal/fee.rb', line 83

def preview_mail(attachment_type = nil)
  deliver_mail(attachment_type, mode: :preview)
end

#preview_stdoutObject

Render HTML to console



89
90
91
92
93
94
95
# File 'lib/luca_deal/fee.rb', line 89

def preview_stdout
  self.class.asof(@date.year, @date.month) do |dat, _|
    @company = set_company
    fee_vars(dat)
    puts render_report
  end
end

#render_report(file_type = :html) ⇒ Object



186
187
188
189
190
191
192
193
194
195
# File 'lib/luca_deal/fee.rb', line 186

def render_report(file_type = :html)
  case file_type
  when :html
    render_erb(search_template('fee-report.html.erb'))
  when :pdf
    erb2pdf(search_template('fee-report.html.erb'))
  else
    raise 'This filetype is not supported.'
  end
end

#stats(count = 1) ⇒ Object

Output seriarized fee data to stdout. Returns previous N months on multiple count

Example YAML output

---
- records:
  - customer: Example Co.
    subtotal: 100000
    tax: 10000
    due: 2020-10-31
    issue_date: '2020-09-30'
  count: 1
  total: 100000
  tax: 10000


128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
# File 'lib/luca_deal/fee.rb', line 128

def stats(count = 1)
  [].tap do |collection|
    scan_date = @date.next_month
    count.times do
      scan_date = scan_date.prev_month
      {}.tap do |stat|
        stat['records'] = self.class.asof(scan_date.year, scan_date.month).map do |fee|
          {
            'customer' => fee.dig('customer', 'name'),
            'client' => fee['items'].map{ |item| item.dig('customer_name') }.join(' / '),
            'subtotal' => fee.dig('sales_fee', 'fee'),
            'tax' => fee.dig('sales_fee', 'tax'),
            'due' => fee.dig('due_date'),
            'mail' => fee.dig('status')&.select { |a| a.keys.include?('mail_delivered') }&.first
          }
        end
        stat['issue_date'] = scan_date.to_s
        stat['count'] = stat['records'].count
        stat['total'] = stat['records'].inject(0) { |sum, rec| sum + rec.dig('subtotal') }
        stat['tax'] = stat['records'].inject(0) { |sum, rec| sum + rec.dig('tax') }
        collection << readable(stat)
      end
    end
  end
end