lucadeal 0.4.1 → 0.5.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 560b745f485f42d80938858af2ff4cdbe1b2cc9aef27898ca0801430c6d638cd
4
- data.tar.gz: f800500cc78a51ca0cb574856493ae43660d659a463f741b442d0887da9027a9
3
+ metadata.gz: fa7bf6bd03335ca54d5bf0a1bf2b3e525677ef21e0ea20b009530ba73b310fc9
4
+ data.tar.gz: 7791dbb5b32566b52ae2bc4209382ca59f1eb95b3f284990f16bd0427f7302ae
5
5
  SHA512:
6
- metadata.gz: 1c1d0abdf72851ceb10a18cf64538aee7ef1c9313d0ab4fc86bcbebf090824e4002670225208b7ddf30c38eb6e064062e15ba15c858f411895c17ce674ca1612
7
- data.tar.gz: 1d9f8d246ddd47196860e350662dc34989e810e0f5e9951b380e1028962ce4a0c9a2c926592991d5a8a39036a8ab38fbc38c22b6580bec8372f50ab02753e2f7
6
+ metadata.gz: a1b16a74bfdb56bdbda22f1f5003e24f9f5361d361b38c0875a6d8289607328f670a0f10756dc41af7df92b12c1d3b162f15bf9fa68069d175815e13af70bd74
7
+ data.tar.gz: fce3bf80a9cf60ac5b904e7c51bd7fa83911cd1b5d59377cfb5cdfcaa49adc63fef2d6fdc2fbb8c8d6f0443cd9434ce0dd9eddd8012694439bc0554c818771f2
data/CHANGELOG.md CHANGED
@@ -1,3 +1,14 @@
1
+ ## LucaDeal 0.5.0
2
+
3
+ * `luca-deal` command now searches valid sub directory.
4
+ * `luca-deal invoices list` has `--full` option with additional settlement info.
5
+ * `--mail --full` lists unsettled table.
6
+
7
+ ## LucaDeal 0.4.2
8
+
9
+ * `luca-deal custoer|invoice|fee list`, `luca-deal reports balance` supports interactive `--explore` w/nushell.
10
+ * `luca-deal invoices settle` checks already settled invoices and renamed customer.
11
+
1
12
  ## LucaDeal 0.4.1
2
13
 
3
14
  * Limit LucaRecord dependency '>= 0.5.4'
data/exe/luca-deal CHANGED
@@ -1,6 +1,16 @@
1
1
  #!/usr/bin/ruby
2
2
  # frozen_string_literal: true
3
3
 
4
+ unless Dir.exist?('data') || ARGV[0] == 'new'
5
+ target = 'customers'
6
+ Dir.glob('*').reject { |f| File.symlink?(f) }
7
+ .find { |f| File.directory?("#{f}/data/#{target}") }.tap do |d|
8
+ abort "No valid data directory, exit..." if d.nil?
9
+
10
+ Dir.chdir(d)
11
+ end
12
+ end
13
+
4
14
  require 'date'
5
15
  require 'optparse'
6
16
  require 'luca_deal'
@@ -131,7 +141,7 @@ class LucaCmd
131
141
  LucaDeal::NoInvoice.new(date).monthly_invoice
132
142
  LucaDeal::Fee.new(date).monthly_fee if params[:fee]
133
143
  if params[:mail]
134
- LucaDeal::Invoice.new(date).stats_email
144
+ LucaDeal::Invoice.new(date).stats_email(3, mode: 'full')
135
145
  end
136
146
  else
137
147
  date = "#{args[1]}-#{args[2]}-#{args[3] || '1'}" if !args.empty?
@@ -178,9 +188,9 @@ class LucaCmd
178
188
  count = 3
179
189
  end
180
190
  if params[:mail]
181
- LucaDeal::Invoice.new(date).stats_email
191
+ LucaDeal::Invoice.new(date).stats_email(3, mode: params[:mode])
182
192
  else
183
- render(LucaDeal::Invoice.new(date).stats(count || 1), params)
193
+ render(LucaDeal::Invoice.new(date).stats(count || 1, mode: params[:mode]), params)
184
194
  end
185
195
  end
186
196
 
@@ -274,7 +284,9 @@ class LucaCmd
274
284
  when 'json'
275
285
  puts JSON.dump(dat)
276
286
  when 'nu'
277
- LucaSupport::View.nushell(dat)
287
+ LucaSupport::View.nushell(dat, :expand)
288
+ when 'explore'
289
+ LucaSupport::View.nushell(dat, :explore)
278
290
  when 'csv'
279
291
  str = CSV.generate(String.new, col_sep: "\t") do |row|
280
292
  row << dat.first.keys
@@ -309,6 +321,7 @@ when /customers?/
309
321
  OptionParser.new do |opt|
310
322
  opt.banner = 'Usage: luca-deal customers list [options]'
311
323
  opt.on('--nu', 'show table in nushell') { |_v| params[:output] = 'nu' }
324
+ opt.on('--explore', 'explore table in nushell') { |_v| params[:output] = 'explore' }
312
325
  opt.on('-o', '--output VAL', 'output serialized data') { |v| params[:output] = v }
313
326
  args = opt.parse(ARGV)
314
327
  LucaCmd::Customer.list(args, params)
@@ -384,8 +397,10 @@ when /invoices?/, 'i'
384
397
  OptionParser.new do |opt|
385
398
  opt.banner = 'Usage: luca-deal invoices list [options] year month [date]'
386
399
  opt.on('--nu', 'show table in nushell') { |_v| params[:output] = 'nu' }
400
+ opt.on('--explore', 'explore table in nushell') { |_v| params[:output] = 'explore' }
387
401
  opt.on('-o', '--output VAL', 'output serialized data') { |v| params[:output] = v }
388
402
  opt.on('--mail', 'send payment list by email') { |_v| params[:mail] = true }
403
+ opt.on('--full', 'add settlement info') { |_v| params[:mode] = 'full' }
389
404
  args = opt.parse(ARGV)
390
405
  LucaCmd::Invoice.list(args, params)
391
406
  end
@@ -432,6 +447,7 @@ when /reports?/, 'r'
432
447
  OptionParser.new do |opt|
433
448
  opt.banner = 'Usage: luca-deal r[eports] balance [options] [year month]'
434
449
  opt.on('--nu', 'show table in nushell') { |_v| params[:output] = 'nu' }
450
+ opt.on('--explore', 'explore table in nushell') { |_v| params[:output] = 'explore' }
435
451
  opt.on('-o', '--output VAL', 'output serialized data') { |v| params[:output] = v }
436
452
  opt.on('--detail', 'show detail info') { |_v| params[:detail] = true }
437
453
  opt.on('--force-due', 'respect due date over actual payment') { |_v| params[:due] = true }
@@ -470,6 +486,7 @@ when /fee/
470
486
  OptionParser.new do |opt|
471
487
  opt.banner = 'Usage: luca-deal fee list [options] year month [date]'
472
488
  opt.on('--nu', 'show table in nushell') { |_v| params[:output] = 'nu' }
489
+ opt.on('--explore', 'explore table in nushell') { |_v| params[:output] = 'explore' }
473
490
  opt.on('-o', '--output VAL', 'output serialized data') { |v| params[:output] = v }
474
491
  opt.on('--html', 'output html invoices') { |_v| params[:html] = 'monthly' }
475
492
  args = opt.parse(ARGV)
@@ -150,7 +150,11 @@ module LucaDeal
150
150
  #
151
151
  def self.settle(io, payment_terms = 1)
152
152
  customers = {}.tap do |h|
153
- Customer.all.each { |c| h[c['name']] = c }
153
+ Customer.all.each do |c|
154
+ LucaSupport::Code.take_history(c, 'name').each do |name|
155
+ h[name] = c
156
+ end
157
+ end
154
158
  end
155
159
  contracts = {}.tap do |h|
156
160
  Contract.all.each { |c| h[c['customer_id']] ||= []; h[c['customer_id']] << c }
@@ -181,6 +185,11 @@ module LucaDeal
181
185
  if Regexp.new("^LucaBook/#{j['id']}").match invoice.dig('settled', 'id')||''
182
186
  break
183
187
  end
188
+ next if 0 >= [
189
+ invoice.dig('subtotal', 0, 'items'),
190
+ invoice.dig('subtotal', 0, 'tax'),
191
+ invoice.dig('settled', 'amount')
192
+ ].compact.sum
184
193
 
185
194
  invoice['settled'] = {
186
195
  'id' => "LucaBook/#{j['id']}",
@@ -212,7 +221,7 @@ module LucaDeal
212
221
  # total: 100000
213
222
  # tax: 10000
214
223
  #
215
- def stats(count = 1)
224
+ def stats(count = 1, mode: nil)
216
225
  [].tap do |collection|
217
226
  scan_date = @date.next_month
218
227
  count.times do
@@ -226,8 +235,13 @@ module LucaDeal
226
235
  'subtotal' => amount,
227
236
  'tax' => tax,
228
237
  'due' => invoice.dig('due_date'),
229
- 'mail' => invoice.dig('status')&.select { |a| a.keys.include?('mail_delivered') }&.first
230
- }
238
+ 'mail' => invoice.dig('status')&.select { |a| a.keys.include?('mail_delivered') }&.first,
239
+ }.tap do |r|
240
+ if mode == 'full'
241
+ r['settled'] = invoice.dig('settled', 'amount')
242
+ r['settle_date'] = invoice.dig('settled', 'date')
243
+ end
244
+ end
231
245
  end
232
246
  stat['issue_date'] = scan_date.to_s
233
247
  stat['count'] = stat['records'].count
@@ -241,14 +255,25 @@ module LucaDeal
241
255
 
242
256
  # send payment list to preview address or from address.
243
257
  #
244
- def stats_email
258
+ def stats_email(count = 3, mode: nil)
245
259
  {}.tap do |res|
246
- stats(3).each.with_index(1) do |stat, i|
260
+ stats(count, mode: mode).each.with_index(1) do |stat, i|
247
261
  stat['records'].each do |record|
248
262
  res[record['customer']] ||= {}
249
263
  res[record['customer']]['customer_name'] ||= record['customer']
250
- res[record['customer']]["amount#{i}"] ||= record['subtotal']
264
+ res[record['customer']]["amount#{i}"] ||= record['subtotal'].to_s
251
265
  res[record['customer']]["tax#{i}"] ||= record['tax']
266
+ next if mode != 'full' || ! record['settled']
267
+
268
+ diff = ['subtotal', 'tax', 'settled'].map { |k| record[k] }.compact.sum
269
+ mark = if diff == 0
270
+ '[S]'
271
+ elsif diff > 0
272
+ '[P]'
273
+ else
274
+ '[O]'
275
+ end
276
+ res[record['customer']]["amount#{i}"].insert(0, mark)
252
277
  end
253
278
  if i == 1
254
279
  @issue_date = stat['issue_date']
@@ -260,6 +285,16 @@ module LucaDeal
260
285
  @invoices = res.values
261
286
  end
262
287
  @company = CONFIG.dig('company', 'name')
288
+ @legend = if mode == 'full'
289
+ '[S] Settled, [P] Partially settled, [O] Overpaid'
290
+ else
291
+ ''
292
+ end
293
+ @unsettled = if mode == 'full'
294
+ self.class.report(@date)
295
+ else
296
+ []
297
+ end
263
298
 
264
299
  mail = Mail.new
265
300
  mail.to = CONFIG.dig('mail', 'preview') || CONFIG.dig('mail', 'from')
@@ -50,5 +50,28 @@
50
50
  </tr>
51
51
  </tbody>
52
52
  </table>
53
+ <div style="margin: 1em 0"><%= @legend %></div>
54
+
55
+ <% if ! @unsettled.empty? %>
56
+ <h3 style="margin: 1em 0">Unsettled</h3>
57
+ <table>
58
+ <thead>
59
+ <tr>
60
+ <th>#</th>
61
+ <th>Customer</th>
62
+ <th>Balance</th>
63
+ </tr>
64
+ </thead>
65
+ <tbody>
66
+ <% @unsettled.each.with_index(1) do |record, i| %>
67
+ <tr>
68
+ <th><%= i %></th>
69
+ <td><%= record['customer'] %></td>
70
+ <td><%= record['unsettled'] %></td>
71
+ </tr>
72
+ <% end %>
73
+ </tbody>
74
+ </table>
75
+ <% end %>
53
76
  </body>
54
77
  </html>
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module LucaDeal
4
- VERSION = '0.4.1'
4
+ VERSION = '0.5.0'
5
5
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: lucadeal
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.4.1
4
+ version: 0.5.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Chuma Takahiro
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2023-04-11 00:00:00.000000000 Z
11
+ date: 2023-04-20 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: lucarecord
@@ -16,14 +16,14 @@ dependencies:
16
16
  requirements:
17
17
  - - ">="
18
18
  - !ruby/object:Gem::Version
19
- version: 0.5.4
19
+ version: 0.6.0
20
20
  type: :runtime
21
21
  prerelease: false
22
22
  version_requirements: !ruby/object:Gem::Requirement
23
23
  requirements:
24
24
  - - ">="
25
25
  - !ruby/object:Gem::Version
26
- version: 0.5.4
26
+ version: 0.6.0
27
27
  - !ruby/object:Gem::Dependency
28
28
  name: bundler
29
29
  requirement: !ruby/object:Gem::Requirement
@@ -111,14 +111,14 @@ required_ruby_version: !ruby/object:Gem::Requirement
111
111
  requirements:
112
112
  - - ">="
113
113
  - !ruby/object:Gem::Version
114
- version: 2.6.0
114
+ version: 3.0.0
115
115
  required_rubygems_version: !ruby/object:Gem::Requirement
116
116
  requirements:
117
117
  - - ">="
118
118
  - !ruby/object:Gem::Version
119
119
  version: '0'
120
120
  requirements: []
121
- rubygems_version: 3.3.5
121
+ rubygems_version: 3.4.10
122
122
  signing_key:
123
123
  specification_version: 4
124
124
  summary: Deal with contracts