lucadeal 0.4.1 → 0.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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