lucadeal 0.2.18 → 0.2.24

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: d8159099446dcdae1b4c928d4eac5861cd35fe13f8d37155cdf28dafb30fc21e
4
- data.tar.gz: 3c086a2ea6c4c9ec6bc9014fa9500ab9fde0a07c1778a5817fbb64e7409b5670
3
+ metadata.gz: 0e4fa52c476838906c3ad849ab1bc4a9bf58926a526034553a90d6c6299d7945
4
+ data.tar.gz: c3e434b8677a0b502cfbef70dc8d936bbc2dd3d7f0be0b6b1e2edea8294baa2c
5
5
  SHA512:
6
- metadata.gz: 0a26cec96f1a0805044470f8710b36b60aacf344bad53527c2a9fd4ff64557a06836e4eefec21f083e0b51bc48a9854dbe2fdd6fed4d4754aba9fe51fa5890ce
7
- data.tar.gz: 8a611e016833673fb1e7fcab747a24d4bfdb4152a60086791a1377d8576feb181255c8b2a0dfeca2f6807a4d11d4d2f579be6353ca62a7996a5f960d8b4f1311
6
+ metadata.gz: ae66f02ef1861eeb9bf217dc5547b05bdd384a9d25bddd8d12dfd62ab2fea63e3f051c699dc267620488949659c98e772799d027dd27101b2d214b8517b55ba2
7
+ data.tar.gz: 5ec46b9f38cb9bfda178896e2319d728cd41df86d6fb389342a4e9759351e64608abe33980a7cf35e5a8f25459223521c9a69bf356dc61fad55d8cb83588cdda
data/CHANGELOG.md CHANGED
@@ -1,3 +1,33 @@
1
+ ## LucaDeal 0.2.24
2
+
3
+ * add `luca-deal invoices create --monthly --mail`, send payment list after monthly invoice creation.
4
+ * add 'other_payments' tracking with no invoices.
5
+ * can have limit on fee calculation.
6
+ * initial implment of `luca-deal fee list`
7
+
8
+ ## LucaDeal 0.2.23
9
+
10
+ * implement `luca-deal invoices list --mail`: payment list via HTML mail
11
+
12
+ ## LucaDeal 0.2.22
13
+
14
+ * Breaking change: export key 'value' -> 'amount'
15
+
16
+ ## LucaDeal 0.2.21
17
+
18
+ * Implement `luca-deal fee` subcommands.
19
+ * single invoice creation with contract id fragment.
20
+
21
+ ## LucaDeal 0.2.20
22
+
23
+ * CLI provides `--nu` option. Add JSON output.
24
+ * `luca-deal invoices list --html`, rendering HTML to stdout.
25
+
26
+ ## LucaDeal 0.2.19
27
+
28
+ * CLI id completion on Customer delete, Contract create/delete
29
+ * add `describe` to Customer / Contract
30
+
1
31
  ## LucaDeal 0.2.18
2
32
 
3
33
  * Breaking change: restructure CLI in sub-sub command format.
data/README.md CHANGED
@@ -61,9 +61,30 @@ Monthly invoices are generated with `invoice create --monthly` sub command. Targ
61
61
  $ luca-deal invoice create --monthly [yyyy m]
62
62
  ```
63
63
 
64
+ Or, any invoice can be created with contract ID. Contract ID is just unique fragment of uuid, listed with `luca-deal invoice create` with no args.
65
+
66
+ ```
67
+ $ luca-deal invoice create 1d3 yyyy m
68
+ ```
69
+
64
70
  Invoice conditions are defined by contracts.
65
71
 
66
72
 
73
+ ### Send Invoice
74
+
75
+ Invoice is implemented with HTML & ERB. Copy [default template](lib/luca_deal/templates/invoice.html.erb) to `templates/` in the data directory, and customize.
76
+ If you want to send invoices in PDF, you need to install `wkhtmltopdf command separately. Send mail command is as bellows:`
77
+
78
+ ```
79
+ $ luca-deal invoice mail yyyy m
80
+ ```
81
+
82
+
83
+ ### Sales Fee
84
+
85
+ You can also manage revenue share program with Fee object. Setup proper contract structure.
86
+
87
+
67
88
  ## Data Structure
68
89
 
69
90
  Records are stored in YAML format. On historical records, see [LucaRecord](../lucarecord/README.md#historical-field).
@@ -114,7 +135,7 @@ Fields for subscription customers are as bellows:
114
135
  | Top level | Second level | | historical | Description |
115
136
  |-----------|---------------|----------|------------|------------------------------------------------------------------------------------------------------|
116
137
  | terms | | | | |
117
- | | billing_cycle | optional | | If 'monthly', invoices are generated on each month. |
138
+ | | billing_cycle | optional | | If 'monthly', invoices are generated on each month. If 'other_payments', no_invoices are generated on each month. `no_invoices` are mostly same as invoices, but not sending email. |
118
139
  | | category | optional | | Default: 'subscription' |
119
140
  | products | | | | Array of products. |
120
141
  | | id | | | reference for Product |
@@ -133,6 +154,7 @@ Fields for sales fee are as bellows:
133
154
  |-----------|--------------|----------|------------|-------------------------------------------------------------------------------------|
134
155
  | terms | | | | |
135
156
  | | category | | | If 'sales_fee', contract is treated as selling commission. |
157
+ | | limit | | | If set, fees are calculated as mas as `limit` months. |
136
158
  | rate | | optional | | |
137
159
  | | default | | | sales fee rate. |
138
160
  | | initial | | | sales fee rate for items of type=initial. |
data/exe/luca-deal CHANGED
@@ -5,8 +5,8 @@ require 'date'
5
5
  require 'optparse'
6
6
  require 'luca_deal'
7
7
 
8
- module LucaCmd
9
- class Customer
8
+ class LucaCmd
9
+ class Customer < LucaCmd
10
10
  def self.create(args = nil, params = {})
11
11
  if args
12
12
  id = LucaDeal::Customer.create(name: args[0])
@@ -18,50 +18,137 @@ module LucaCmd
18
18
  end
19
19
  end
20
20
 
21
- def self.delete(args = nil, params = {})
22
- if args
23
- id = LucaDeal::Customer.delete(args[0])
21
+ def self.describe(args = nil, params = {})
22
+ if args.empty?
23
+ list = LucaDeal::Customer.id_completion('')
24
+ puts 'requires customer\'s id. exit'
25
+ list.each { |item| puts " #{item[:id]} #{item[:label]}" }
26
+ exit 1
24
27
  else
28
+ list = LucaDeal::Customer.id_completion(args[0])
29
+ case list.length
30
+ when 1
31
+ render(LucaDeal::Customer.new.describe(list.first), params)
32
+ else
33
+ puts 'found multiple contract id. exit'
34
+ list.each { |item| puts " #{item[:id]} #{item[:label]}" }
35
+ exit 1
36
+ end
37
+ end
38
+ end
39
+
40
+ def self.delete(args = nil, params = {})
41
+ if args.empty?
42
+ list = LucaDeal::Customer.id_completion('')
25
43
  puts 'requires customer\'s id. exit'
44
+ list.each { |item| puts " #{item[:id]} #{item[:label]}" }
26
45
  exit 1
46
+ else
47
+ list = LucaDeal::Customer.id_completion(args[0])
48
+ case list.length
49
+ when 1
50
+ id = LucaDeal::Customer.delete(list.first)
51
+ else
52
+ puts 'found multiple customer\'s id. exit'
53
+ list.each { |item| puts " #{item[:id]} #{item[:label]}" }
54
+ exit 1
55
+ end
27
56
  end
28
57
  end
29
58
 
30
59
  def self.list(args = nil, params = {})
31
- LucaDeal::Customer.new.list_name
60
+ render(LucaDeal::Customer.new.list_name, params)
32
61
  end
33
62
  end
34
63
 
35
- class Contract
64
+ class Contract < LucaCmd
36
65
  def self.create(args = nil, params = {})
37
- if args
38
- id = LucaDeal::Contract.new.generate!(args[0], params['category'])
39
- puts "Successfully generated Contract #{id}" if id
40
- puts 'Conditions are tentative. Edit contract detail.' if id
41
- else
66
+ if args.empty?
67
+ list = LucaDeal::Customer.id_completion('')
42
68
  puts 'requires customer\'s id. exit'
69
+ list.each { |item| puts " #{item[:id]} #{item[:label]}" }
43
70
  exit 1
71
+ else
72
+ list = LucaDeal::Customer.id_completion(args[0])
73
+ case list.length
74
+ when 1
75
+ id = LucaDeal::Contract.new.generate!(list.first, params['category'])
76
+ puts "Successfully generated Contract #{id}" if id
77
+ puts 'Conditions are tentative. Edit contract detail.' if id
78
+ else
79
+ puts 'found multiple customer\'s id. exit'
80
+ list.each { |item| puts " #{item[:id]} #{item[:label]}" }
81
+ exit 1
82
+ end
44
83
  end
45
84
  end
46
85
 
47
- def self.delete(args = nil, params = {})
48
- if args
49
- id = LucaDeal::Contract.delete(args[0])
86
+ def self.describe(args = nil, params = {})
87
+ if args.empty?
88
+ list = LucaDeal::Contract.id_completion('', label: 'customer_name')
89
+ puts 'requires contract id. exit'
90
+ list.each { |item| puts " #{item[:id]} #{item[:label]}" }
91
+ exit 1
50
92
  else
93
+ list = LucaDeal::Contract.id_completion(args[0])
94
+ case list.length
95
+ when 1
96
+ render(LucaDeal::Contract.new.describe(list.first), params)
97
+ else
98
+ puts 'found multiple contract id. exit'
99
+ list.each { |item| puts " #{item[:id]} #{item[:label]}" }
100
+ exit 1
101
+ end
102
+ end
103
+ end
104
+
105
+ def self.delete(args = nil, params = {})
106
+ if args.empty?
107
+ list = LucaDeal::Contract.id_completion('', label: 'customer_name')
51
108
  puts 'requires contract id. exit'
109
+ list.each { |item| puts " #{item[:id]} #{item[:label]}" }
52
110
  exit 1
111
+ else
112
+ list = LucaDeal::Contract.id_completion(args[0])
113
+ case list.length
114
+ when 1
115
+ id = LucaDeal::Contract.delete(list.first)
116
+ else
117
+ puts 'found multiple contract id. exit'
118
+ list.each { |item| puts " #{item[:id]} #{item[:label]}" }
119
+ exit 1
120
+ end
53
121
  end
54
122
  end
55
123
  end
56
124
 
57
- class Invoice
125
+ class Invoice < LucaCmd
58
126
  def self.create(args = nil, params = {})
59
- date = "#{args[0]}-#{args[1]}-#{args[2] || '1'}" if !args.empty?
60
127
  case params['mode']
61
128
  when 'monthly'
129
+ date = "#{args[0]}-#{args[1]}-#{args[2] || '1'}" if !args.empty?
62
130
  LucaDeal::Invoice.new(date).monthly_invoice
131
+ LucaDeal::NoInvoice.new(date).monthly_invoice
132
+ if params[:mail]
133
+ LucaDeal::Invoice.new(date).stats_email
134
+ end
63
135
  else
64
- puts 'not implemented mode'
136
+ date = "#{args[1]}-#{args[2]}-#{args[3] || '1'}" if !args.empty?
137
+ list = LucaDeal::Contract.id_completion(args[0] || '', label: 'customer_name')
138
+ if args.length != 3
139
+ puts 'requires contract id & year month. exit'
140
+ list.each { |item| puts " #{item[:id]} #{item[:label]}" }
141
+ exit 1
142
+ else
143
+ case list.length
144
+ when 1
145
+ id = LucaDeal::Invoice.new(date).single_invoice(list.first)
146
+ else
147
+ puts 'found multiple contract id. exit'
148
+ list.each { |item| puts " #{item[:id]} #{item[:label]}" }
149
+ exit 1
150
+ end
151
+ end
65
152
  end
66
153
  end
67
154
 
@@ -89,7 +176,13 @@ module LucaCmd
89
176
  date = "#{Date.today.year}-#{Date.today.month}-1"
90
177
  count = 3
91
178
  end
92
- LucaDeal::Invoice.new(date).stats(count || 1)
179
+ if params[:html]
180
+ LucaDeal::Invoice.new(date).preview_stdout
181
+ elsif params[:mail]
182
+ LucaDeal::Invoice.new(date).stats_email
183
+ else
184
+ render(LucaDeal::Invoice.new(date).stats(count || 1), params)
185
+ end
93
186
  end
94
187
 
95
188
  def self.mail(args = nil, params = {})
@@ -102,6 +195,62 @@ module LucaCmd
102
195
  end
103
196
  end
104
197
  end
198
+
199
+ class Fee < LucaCmd
200
+ def self.create(args = nil, params = {})
201
+ case params['mode']
202
+ when 'monthly'
203
+ date = "#{args[0]}-#{args[1]}-#{args[2] || '1'}" if !args.empty?
204
+ LucaDeal::Fee.new(date).monthly_fee
205
+ else
206
+ puts "not implemented yet"
207
+ exit 1
208
+ end
209
+ end
210
+
211
+ def self.delete(args = nil, params = {})
212
+ if args
213
+ id = LucaDeal::Fee.delete(args[0])
214
+ else
215
+ puts 'requires contract id. exit'
216
+ exit 1
217
+ end
218
+ end
219
+
220
+ def self.list(args = nil, params = {})
221
+ date = "#{args[0]}-#{args[1]}-#{args[2] || '1'}" if !args.empty?
222
+ if args.empty?
223
+ date = "#{Date.today.year}-#{Date.today.month}-1"
224
+ count = 3
225
+ end
226
+ if params[:html]
227
+ LucaDeal::Fee.new(date).preview_stdout
228
+ else
229
+ render(LucaDeal::Fee.new(date).stats(count || 1), params)
230
+ end
231
+ end
232
+
233
+ def self.mail(args = nil, params = {})
234
+ date = "#{args[0]}-#{args[1]}-#{args[2] || '1'}" if !args.empty?
235
+ case params['mode']
236
+ when 'preview'
237
+ LucaDeal::Fee.new(date).preview_mail
238
+ else
239
+ LucaDeal::Fee.new(date).deliver_mail
240
+ end
241
+ end
242
+ end
243
+
244
+ def self.render(dat, params)
245
+ case params[:output]
246
+ when 'json'
247
+ puts JSON.dump(dat)
248
+ when 'nu'
249
+ LucaSupport::View.nushell(YAML.dump(dat))
250
+ else
251
+ puts YAML.dump(dat)
252
+ end
253
+ end
105
254
  end
106
255
 
107
256
  def new_pj(args = nil, params = {})
@@ -116,22 +265,39 @@ case cmd
116
265
  when /customers?/
117
266
  subcmd = ARGV.shift
118
267
  case subcmd
268
+ when 'create'
269
+ OptionParser.new do |opt|
270
+ opt.banner = 'Usage: luca-deal customers create CustomerName'
271
+ args = opt.parse(ARGV)
272
+ LucaCmd::Customer.create(args, params)
273
+ end
119
274
  when 'list'
120
275
  OptionParser.new do |opt|
121
276
  opt.banner = 'Usage: luca-deal customers list [options]'
277
+ opt.on('--nu', 'show table in nushell') { |_v| params[:output] = 'nu' }
278
+ opt.on('-o', '--output VAL', 'output serialized data') { |v| params[:output] = v }
122
279
  args = opt.parse(ARGV)
123
280
  LucaCmd::Customer.list(args, params)
124
281
  end
125
- when 'create'
282
+ when 'describe'
126
283
  OptionParser.new do |opt|
127
- opt.banner = 'Usage: luca-deal customers create CustomerName'
284
+ opt.banner = 'Usage: luca-deal customers describe [options] customer_id'
285
+ opt.on('--nu', 'show table in nushell') { |_v| params[:output] = 'nu' }
286
+ opt.on('-o', '--output VAL', 'output serialized data') { |v| params[:output] = v }
128
287
  args = opt.parse(ARGV)
129
- LucaCmd::Customer.create(args, params)
288
+ LucaCmd::Customer.describe(args, params)
130
289
  end
131
290
  when 'delete'
132
291
  LucaCmd::Customer.delete(ARGV)
133
292
  else
134
- puts 'Usage: luca-deal customers sub-commands'
293
+ puts 'Proper subcommand needed.'
294
+ puts
295
+ puts 'Usage: luca-deal customer[s] subcommands [--help|options]'
296
+ puts ' create'
297
+ puts ' list'
298
+ puts ' describe: show customer with contracts info'
299
+ puts ' delete'
300
+ exit 1
135
301
  end
136
302
  when /contracts?/
137
303
  subcmd = ARGV.shift
@@ -145,10 +311,24 @@ when /contracts?/
145
311
  args = opt.parse(ARGV)
146
312
  LucaCmd::Contract.create(args, params)
147
313
  end
314
+ when 'describe'
315
+ OptionParser.new do |opt|
316
+ opt.banner = 'Usage: luca-deal contracts describe [options] customer_id'
317
+ opt.on('--nu', 'show table in nushell') { |_v| params[:output] = 'nu' }
318
+ opt.on('-o', '--output VAL', 'output serialized data') { |v| params[:output] = v }
319
+ args = opt.parse(ARGV)
320
+ LucaCmd::Contract.describe(args, params)
321
+ end
148
322
  when 'delete'
149
323
  LucaCmd::Contract.delete(ARGV)
150
324
  else
151
- puts 'Usage: luca-deal contracts Subcommand'
325
+ puts 'Proper subcommand needed.'
326
+ puts
327
+ puts 'Usage: luca-deal contract[s] subcommand [--help|options]'
328
+ puts ' create'
329
+ puts ' describe: show contract with puroducts or items info'
330
+ puts ' delete'
331
+ exit 1
152
332
  end
153
333
  when 'export'
154
334
  LucaCmd::Invoice.export(ARGV)
@@ -157,8 +337,9 @@ when /invoices?/, 'i'
157
337
  case subcmd
158
338
  when 'create'
159
339
  OptionParser.new do |opt|
160
- opt.banner = 'Usage: luca-deal invoices create [options] year month [date]'
161
- opt.on('--monthly', 'generate monthly data') { |v| params['mode'] = 'monthly' }
340
+ opt.banner = 'Usage: luca-deal invoices create [options] --monthly|contract_id year month [date]'
341
+ opt.on('--monthly', 'generate monthly data') { |_v| params['mode'] = 'monthly' }
342
+ opt.on('--mail', 'send payment list by email. Only works with --monthly') { |_v| params[:mail] = true }
162
343
  args = opt.parse(ARGV)
163
344
  LucaCmd::Invoice.create(args, params)
164
345
  end
@@ -167,29 +348,83 @@ when /invoices?/, 'i'
167
348
  when 'list'
168
349
  OptionParser.new do |opt|
169
350
  opt.banner = 'Usage: luca-deal invoices list [options] year month [date]'
351
+ opt.on('--nu', 'show table in nushell') { |_v| params[:output] = 'nu' }
352
+ opt.on('-o', '--output VAL', 'output serialized data') { |v| params[:output] = v }
353
+ opt.on('--html', 'output html invoices') { |_v| params[:html] = 'monthly' }
354
+ opt.on('--mail', 'send payment list by email') { |_v| params[:mail] = true }
170
355
  args = opt.parse(ARGV)
171
356
  LucaCmd::Invoice.list(args, params)
172
357
  end
173
358
  when 'mail'
174
359
  OptionParser.new do |opt|
175
360
  opt.banner = 'Usage: luca-deal invoices mail [options] year month [date]'
176
- opt.on('--preview', 'send to preview user') { |v| params['mode'] = 'preview' }
361
+ opt.on('--preview', 'send to preview user') { |_v| params['mode'] = 'preview' }
177
362
  args = opt.parse(ARGV)
178
363
  LucaCmd::Invoice.mail(args, params)
179
364
  end
180
365
  else
181
- puts 'Usage: luca-deal invoices SubCommand'
366
+ puts 'Proper subcommand needed.'
367
+ puts
368
+ puts 'Usage: luca-deal invoices subcommand [--help|options]'
369
+ puts ' create'
370
+ puts ' delete'
371
+ puts ' list'
372
+ puts ' mail: send mail with invoice'
373
+ exit 1
182
374
  end
183
375
  when 'new'
184
376
  params = {}
185
377
  OptionParser.new do |opt|
378
+ opt.banner = 'Usage: luca-deal new DIR'
186
379
  args = opt.parse(ARGV)
187
380
  new_pj(args, params)
188
381
  end
382
+ when /fee/
383
+ subcmd = ARGV.shift
384
+ case subcmd
385
+ when 'create'
386
+ OptionParser.new do |opt|
387
+ opt.banner = 'Usage: luca-deal fee create [options] year month [date]'
388
+ opt.on('--monthly', 'generate monthly data') { |_v| params['mode'] = 'monthly' }
389
+ args = opt.parse(ARGV)
390
+ LucaCmd::Fee.create(args, params)
391
+ end
392
+ when 'delete'
393
+ LucaCmd::Fee.delete(ARGV)
394
+ when 'list'
395
+ OptionParser.new do |opt|
396
+ opt.banner = 'Usage: luca-deal fee list [options] year month [date]'
397
+ opt.on('--nu', 'show table in nushell') { |_v| params[:output] = 'nu' }
398
+ opt.on('-o', '--output VAL', 'output serialized data') { |v| params[:output] = v }
399
+ opt.on('--html', 'output html invoices') { |_v| params[:html] = 'monthly' }
400
+ args = opt.parse(ARGV)
401
+ LucaCmd::Fee.list(args, params)
402
+ end
403
+ when 'mail'
404
+ OptionParser.new do |opt|
405
+ opt.banner = 'Usage: luca-deal fee mail [options] year month [date]'
406
+ opt.on('--preview', 'send to preview user') { |_v| params['mode'] = 'preview' }
407
+ args = opt.parse(ARGV)
408
+ LucaCmd::Fee.mail(args, params)
409
+ end
410
+ else
411
+ puts 'Proper subcommand needed.'
412
+ puts
413
+ puts 'Usage: luca-deal fee subcommand [--help|options]'
414
+ puts ' create'
415
+ puts ' delete'
416
+ puts ' list'
417
+ puts ' mail: send mail with report'
418
+ exit 1
419
+ end
189
420
  else
190
- puts 'Usage: luca-deal sub-command [--help|options]'
421
+ puts 'Proper subcommand needed.'
422
+ puts
423
+ puts 'Usage: luca-deal subcommand [options]'
191
424
  puts ' customers'
192
425
  puts ' contracts'
193
426
  puts ' invoices'
194
- puts ' export'
427
+ puts ' new: initialize project dir'
428
+ puts ' export: puts invoice data for LucaBook import'
429
+ exit 1
195
430
  end