lucadeal 0.2.18 → 0.2.24

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: 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