lucadeal 0.2.16 → 0.2.23

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: 5f17d75af6f101c60eced0ecfb770e39ac66b0f35725a6976f135216a0c75099
4
- data.tar.gz: d3e60d51908e78ab72e177f29affc26864744afb584d1c5dadd507b18ff888f6
3
+ metadata.gz: 5f3d23a1f082ee44833db42f3cf4dbdecc0d078ea3ca6499d5cf77e6d235580a
4
+ data.tar.gz: c2ea468ea064bb865d0b481d9717a03f11afe212f0bfd3b58ac43722116a95e7
5
5
  SHA512:
6
- metadata.gz: bd534c31a33405478cdeba88777481f5c17af6337cf743e2d16a8e5027209a65d1efb8329cf7f6e72318dfea8c3daa1965d9cf1e833ce93b85d24925c17638f6
7
- data.tar.gz: f1d809de08ce94cf7da913c5bc733515f95bba596dc155596880cb4776837113c36f93ee4247c35fe34990f2a45fd758df1bddec3d2e587d182062cdb5893c60
6
+ metadata.gz: 545d6acb5b7837497c30d17a42c6a32611186f2e12f9821d116c9aa3ed9735dc1c8bc2c072d1439c9e21e1fd38d7398de770ffd9fd835352f4565f96a18a19ca
7
+ data.tar.gz: c8cf01067781332a241138ab9b253d282902a3838a19d2f9623d9eb29c6c4a3432e7d0e6818bc67a3e3b3e682e5ba3c4c5c128a90f93b3f91dcadca0285ea2f4
@@ -1,3 +1,35 @@
1
+ ## LucaDeal 0.2.23
2
+
3
+ * implement `luca-deal invoices list --mail`: payment list via HTML mail
4
+
5
+ ## LucaDeal 0.2.22
6
+
7
+ * Breaking change: export key 'value' -> 'amount'
8
+
9
+ ## LucaDeal 0.2.21
10
+
11
+ * Implement `luca-deal fee` subcommands.
12
+ * single invoice creation with contract id fragment.
13
+
14
+ ## LucaDeal 0.2.20
15
+
16
+ * CLI provides `--nu` option. Add JSON output.
17
+ * `luca-deal invoices list --html`, rendering HTML to stdout.
18
+
19
+ ## LucaDeal 0.2.19
20
+
21
+ * CLI id completion on Customer delete, Contract create/delete
22
+ * add `describe` to Customer / Contract
23
+
24
+ ## LucaDeal 0.2.18
25
+
26
+ * Breaking change: restructure CLI in sub-sub command format.
27
+ * Add 'x-customer', 'x-editor' on export to LucaBook
28
+
29
+ ## LucaDeal 0.2.17
30
+
31
+ * `luca-deal export` export JSON for LucaBook
32
+
1
33
  ## LucaDeal 0.2.14
2
34
 
3
35
  * Introduce Product for selling items template.
data/README.md CHANGED
@@ -22,7 +22,67 @@ Or install it yourself as:
22
22
 
23
23
  ## Usage
24
24
 
25
- TODO: Write usage instructions here
25
+ You can create project skelton with `new` sub command.
26
+
27
+ ```
28
+ $ luca-deal new Dir
29
+ ```
30
+
31
+ Example assumes setup with bundler shim. `bundle exec` prefix may be needed in most cases.
32
+
33
+
34
+ ### Manage Contract
35
+
36
+ Customer object can be created by `customer create` subcommand with name.
37
+
38
+ ```
39
+ $ luca-deal customer create CustomerName
40
+ Successfully generated Customer 5976652cc2d9c0ebf4a8646f7a28aa8d6bd2d606
41
+ Edit customer detail.
42
+ ```
43
+
44
+ Customer is filed under `data/customers` as YAML. Detail need to be editted.
45
+ Then, Contract object is created by `contract create` sub command with customer id.
46
+
47
+ ```
48
+ $ luca-deal contract create 5976652cc2d9c0ebf4a8646f7a28aa8d6bd2d606
49
+ uccessfully generated Contract 814c6fc9fffe5566fe8e7ef683b439b355d612dc
50
+ Conditions are tentative. Edit contract detail.
51
+ ```
52
+
53
+ Contract is filed under `data/contracts` as YAML. Detail need to be editted.
54
+
55
+
56
+ ### Issue invoice
57
+
58
+ Monthly invoices are generated with `invoice create --monthly` sub command. Target month is optional. Without month, this month including today is the target.
59
+
60
+ ```
61
+ $ luca-deal invoice create --monthly [yyyy m]
62
+ ```
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
+
70
+ Invoice conditions are defined by contracts.
71
+
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.
26
86
 
27
87
 
28
88
  ## Data Structure
@@ -5,57 +5,247 @@ require 'date'
5
5
  require 'optparse'
6
6
  require 'luca_deal'
7
7
 
8
- def customer(args = nil, params = {})
9
- case params['mode']
10
- when 'list'
11
- LucaDeal::Customer.new.list_name
12
- when 'create'
13
- if params['name']
14
- id = LucaDeal::Customer.create(name: params['name'])
15
- puts "Successfully generated Customer #{id}" if id
16
- puts 'Edit customer detail.' if id
17
- else
18
- puts 'requires customer\'s name. exit'
19
- exit 1
8
+ class LucaCmd
9
+ class Customer < LucaCmd
10
+ def self.create(args = nil, params = {})
11
+ if args
12
+ id = LucaDeal::Customer.create(name: args[0])
13
+ puts "Successfully generated Customer #{id}" if id
14
+ puts 'Edit customer detail.' if id
15
+ else
16
+ puts 'requires customer\'s name. exit'
17
+ exit 1
18
+ end
19
+ end
20
+
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
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('')
43
+ puts 'requires customer\'s id. exit'
44
+ list.each { |item| puts " #{item[:id]} #{item[:label]}" }
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
56
+ end
57
+ end
58
+
59
+ def self.list(args = nil, params = {})
60
+ render(LucaDeal::Customer.new.list_name, params)
20
61
  end
21
- else
22
- puts 'invalid option. --help for usage'
23
- exit 1
24
62
  end
25
- end
26
63
 
27
- def contract(args = nil, params = {})
28
- case params['mode']
29
- when 'create'
30
- if params['customer_id']
31
- id = LucaDeal::Contract.new.generate!(params['customer_id'], params['category'])
32
- puts "Successfully generated Contract #{id}" if id
33
- puts 'Conditions are tentative. Edit contract detail.' if id
34
- else
35
- puts 'requires customer\'s id. exit'
36
- exit 1
64
+ class Contract < LucaCmd
65
+ def self.create(args = nil, params = {})
66
+ if args.empty?
67
+ list = LucaDeal::Customer.id_completion('')
68
+ puts 'requires customer\'s id. exit'
69
+ list.each { |item| puts " #{item[:id]} #{item[:label]}" }
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
83
+ end
84
+ end
85
+
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
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')
108
+ puts 'requires contract id. exit'
109
+ list.each { |item| puts " #{item[:id]} #{item[:label]}" }
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
121
+ end
37
122
  end
38
- else
39
123
  end
40
- end
41
124
 
42
- def invoice(args = nil, params = {})
43
- date = "#{args[0]}-#{args[1]}-#{args[2] || '1'}" if !args.empty?
44
- case params['mode']
45
- when 'monthly'
46
- LucaDeal::Invoice.new(date).monthly_invoice
47
- when 'mail'
48
- LucaDeal::Invoice.new(date).deliver_mail
49
- when 'preview'
50
- LucaDeal::Invoice.new(date).preview_mail
51
- when 'stats'
52
- if args.empty?
53
- date = "#{Date.today.year}-#{Date.today.month}-1"
54
- count = 3
55
- end
56
- LucaDeal::Invoice.new(date).stats(count || 1)
57
- else
58
- puts 'not implemented mode'
125
+ class Invoice < LucaCmd
126
+ def self.create(args = nil, params = {})
127
+ case params['mode']
128
+ when 'monthly'
129
+ date = "#{args[0]}-#{args[1]}-#{args[2] || '1'}" if !args.empty?
130
+ LucaDeal::Invoice.new(date).monthly_invoice
131
+ else
132
+ date = "#{args[1]}-#{args[2]}-#{args[3] || '1'}" if !args.empty?
133
+ list = LucaDeal::Contract.id_completion(args[0] || '', label: 'customer_name')
134
+ if args.length != 3
135
+ puts 'requires contract id & year month. exit'
136
+ list.each { |item| puts " #{item[:id]} #{item[:label]}" }
137
+ exit 1
138
+ else
139
+ case list.length
140
+ when 1
141
+ id = LucaDeal::Invoice.new(date).single_invoice(list.first)
142
+ else
143
+ puts 'found multiple contract id. exit'
144
+ list.each { |item| puts " #{item[:id]} #{item[:label]}" }
145
+ exit 1
146
+ end
147
+ end
148
+ end
149
+ end
150
+
151
+ def self.delete(args = nil, params = {})
152
+ if args
153
+ id = LucaDeal::Invoice.delete(args[0])
154
+ else
155
+ puts 'requires contract id. exit'
156
+ exit 1
157
+ end
158
+ end
159
+
160
+ def self.export(args = nil, _params = nil)
161
+ if args
162
+ args << 28 if args.length == 2 # specify safe last day
163
+ LucaDeal::Invoice.new(args.join('-')).export_json
164
+ else
165
+ LucaDeal::Invoice.new.export_json
166
+ end
167
+ end
168
+
169
+ def self.list(args = nil, params = {})
170
+ date = "#{args[0]}-#{args[1]}-#{args[2] || '1'}" if !args.empty?
171
+ if args.empty?
172
+ date = "#{Date.today.year}-#{Date.today.month}-1"
173
+ count = 3
174
+ end
175
+ if params[:html]
176
+ LucaDeal::Invoice.new(date).preview_stdout
177
+ elsif params[:mail]
178
+ LucaDeal::Invoice.new(date).stats_email
179
+ else
180
+ render(LucaDeal::Invoice.new(date).stats(count || 1), params)
181
+ end
182
+ end
183
+
184
+ def self.mail(args = nil, params = {})
185
+ date = "#{args[0]}-#{args[1]}-#{args[2] || '1'}" if !args.empty?
186
+ case params['mode']
187
+ when 'preview'
188
+ LucaDeal::Invoice.new(date).preview_mail
189
+ else
190
+ LucaDeal::Invoice.new(date).deliver_mail
191
+ end
192
+ end
193
+ end
194
+
195
+ class Fee < LucaCmd
196
+ def self.create(args = nil, params = {})
197
+ case params['mode']
198
+ when 'monthly'
199
+ date = "#{args[0]}-#{args[1]}-#{args[2] || '1'}" if !args.empty?
200
+ LucaDeal::Fee.new(date).monthly_fee
201
+ else
202
+ puts "not implemented yet"
203
+ exit 1
204
+ end
205
+ end
206
+
207
+ def self.delete(args = nil, params = {})
208
+ if args
209
+ id = LucaDeal::Fee.delete(args[0])
210
+ else
211
+ puts 'requires contract id. exit'
212
+ exit 1
213
+ end
214
+ end
215
+
216
+ def self.list(args = nil, params = {})
217
+ date = "#{args[0]}-#{args[1]}-#{args[2] || '1'}" if !args.empty?
218
+ if args.empty?
219
+ date = "#{Date.today.year}-#{Date.today.month}-1"
220
+ count = 3
221
+ end
222
+ if params[:html]
223
+ LucaDeal::Fee.new(date).preview_stdout
224
+ else
225
+ render(LucaDeal::Fee.new(date).stats(count || 1), params)
226
+ end
227
+ end
228
+
229
+ def self.mail(args = nil, params = {})
230
+ date = "#{args[0]}-#{args[1]}-#{args[2] || '1'}" if !args.empty?
231
+ case params['mode']
232
+ when 'preview'
233
+ LucaDeal::Fee.new(date).preview_mail
234
+ else
235
+ LucaDeal::Fee.new(date).deliver_mail
236
+ end
237
+ end
238
+ end
239
+
240
+ def self.render(dat, params)
241
+ case params[:output]
242
+ when 'json'
243
+ puts JSON.dump(dat)
244
+ when 'nu'
245
+ LucaSupport::View.nushell(YAML.dump(dat))
246
+ else
247
+ puts YAML.dump(dat)
248
+ end
59
249
  end
60
250
  end
61
251
 
@@ -65,54 +255,171 @@ end
65
255
 
66
256
  LucaRecord::Base.valid_project?
67
257
  cmd = ARGV.shift
258
+ params = {}
68
259
 
69
260
  case cmd
70
- when 'customer'
71
- params = {}
72
- OptionParser.new do |opt|
73
- opt.banner = 'Usage: luca-deal customer [options]'
74
- opt.on('--list', 'list all customers') { |v| params['mode'] = 'list' }
75
- opt.on('--create CustomerName', 'register new customer') do |v|
76
- params['mode'] = 'create'
77
- params['name'] = v
261
+ when /customers?/
262
+ subcmd = ARGV.shift
263
+ case subcmd
264
+ when 'create'
265
+ OptionParser.new do |opt|
266
+ opt.banner = 'Usage: luca-deal customers create CustomerName'
267
+ args = opt.parse(ARGV)
268
+ LucaCmd::Customer.create(args, params)
78
269
  end
79
- args = opt.parse(ARGV)
80
- customer(args, params)
270
+ when 'list'
271
+ OptionParser.new do |opt|
272
+ opt.banner = 'Usage: luca-deal customers list [options]'
273
+ opt.on('--nu', 'show table in nushell') { |_v| params[:output] = 'nu' }
274
+ opt.on('-o', '--output VAL', 'output serialized data') { |v| params[:output] = v }
275
+ args = opt.parse(ARGV)
276
+ LucaCmd::Customer.list(args, params)
277
+ end
278
+ when 'describe'
279
+ OptionParser.new do |opt|
280
+ opt.banner = 'Usage: luca-deal customers describe [options] customer_id'
281
+ opt.on('--nu', 'show table in nushell') { |_v| params[:output] = 'nu' }
282
+ opt.on('-o', '--output VAL', 'output serialized data') { |v| params[:output] = v }
283
+ args = opt.parse(ARGV)
284
+ LucaCmd::Customer.describe(args, params)
285
+ end
286
+ when 'delete'
287
+ LucaCmd::Customer.delete(ARGV)
288
+ else
289
+ puts 'Proper subcommand needed.'
290
+ puts
291
+ puts 'Usage: luca-deal customer[s] subcommands [--help|options]'
292
+ puts ' create'
293
+ puts ' list'
294
+ puts ' describe: show customer with contracts info'
295
+ puts ' delete'
296
+ exit 1
81
297
  end
82
- when 'contract'
83
- params = {}
84
- OptionParser.new do |opt|
85
- opt.banner = 'Usage: luca-deal contract [options]'
86
- opt.on('--create CustomerId', 'register new contract') do |v|
87
- params['mode'] = 'create'
88
- params['customer_id'] = v
298
+ when /contracts?/
299
+ subcmd = ARGV.shift
300
+ case subcmd
301
+ when 'create'
302
+ OptionParser.new do |opt|
303
+ opt.banner = 'Usage: luca-deal contracts create [options] CustomerId'
304
+ opt.on('--salesfee', 'create contract as sales fee definition') do |_v|
305
+ params['category'] = 'sales_fee'
306
+ end
307
+ args = opt.parse(ARGV)
308
+ LucaCmd::Contract.create(args, params)
89
309
  end
90
- opt.on('--salesfee', 'create contract as sales fee definition') do |_v|
91
- params['category'] = 'sales_fee'
310
+ when 'describe'
311
+ OptionParser.new do |opt|
312
+ opt.banner = 'Usage: luca-deal contracts describe [options] customer_id'
313
+ opt.on('--nu', 'show table in nushell') { |_v| params[:output] = 'nu' }
314
+ opt.on('-o', '--output VAL', 'output serialized data') { |v| params[:output] = v }
315
+ args = opt.parse(ARGV)
316
+ LucaCmd::Contract.describe(args, params)
92
317
  end
93
- args = opt.parse(ARGV)
94
- contract(args, params)
318
+ when 'delete'
319
+ LucaCmd::Contract.delete(ARGV)
320
+ else
321
+ puts 'Proper subcommand needed.'
322
+ puts
323
+ puts 'Usage: luca-deal contract[s] subcommand [--help|options]'
324
+ puts ' create'
325
+ puts ' describe: show contract with puroducts or items info'
326
+ puts ' delete'
327
+ exit 1
95
328
  end
96
- when 'invoice'
97
- params = {}
98
- OptionParser.new do |opt|
99
- opt.banner = 'Usage: luca-deal invoice [options] year month [date]'
100
- opt.on('--monthly', 'generate monthly data') { |v| params['mode'] = 'monthly' }
101
- opt.on('--mail', 'send to customers') { |v| params['mode'] = 'mail' }
102
- opt.on('--preview', 'send to preview user') { |v| params['mode'] = 'preview' }
103
- opt.on('--stats', 'list invoices') { |v| params['mode'] = 'stats' }
104
- args = opt.parse(ARGV)
105
- invoice(args, params)
329
+ when 'export'
330
+ LucaCmd::Invoice.export(ARGV)
331
+ when /invoices?/, 'i'
332
+ subcmd = ARGV.shift
333
+ case subcmd
334
+ when 'create'
335
+ OptionParser.new do |opt|
336
+ opt.banner = 'Usage: luca-deal invoices create [options] --monthly|contract_id year month [date]'
337
+ opt.on('--monthly', 'generate monthly data') { |_v| params['mode'] = 'monthly' }
338
+ args = opt.parse(ARGV)
339
+ LucaCmd::Invoice.create(args, params)
340
+ end
341
+ when 'delete'
342
+ LucaCmd::Invoice.delete(ARGV)
343
+ when 'list'
344
+ OptionParser.new do |opt|
345
+ opt.banner = 'Usage: luca-deal invoices list [options] year month [date]'
346
+ opt.on('--nu', 'show table in nushell') { |_v| params[:output] = 'nu' }
347
+ opt.on('-o', '--output VAL', 'output serialized data') { |v| params[:output] = v }
348
+ opt.on('--html', 'output html invoices') { |_v| params[:html] = 'monthly' }
349
+ opt.on('--mail', 'send payment list by email') { |_v| params[:mail] = true }
350
+ args = opt.parse(ARGV)
351
+ LucaCmd::Invoice.list(args, params)
352
+ end
353
+ when 'mail'
354
+ OptionParser.new do |opt|
355
+ opt.banner = 'Usage: luca-deal invoices mail [options] year month [date]'
356
+ opt.on('--preview', 'send to preview user') { |_v| params['mode'] = 'preview' }
357
+ args = opt.parse(ARGV)
358
+ LucaCmd::Invoice.mail(args, params)
359
+ end
360
+ else
361
+ puts 'Proper subcommand needed.'
362
+ puts
363
+ puts 'Usage: luca-deal invoices subcommand [--help|options]'
364
+ puts ' create'
365
+ puts ' delete'
366
+ puts ' list'
367
+ puts ' mail: send mail with invoice'
368
+ exit 1
106
369
  end
107
370
  when 'new'
108
371
  params = {}
109
372
  OptionParser.new do |opt|
373
+ opt.banner = 'Usage: luca-deal new DIR'
110
374
  args = opt.parse(ARGV)
111
375
  new_pj(args, params)
112
376
  end
377
+ when /fee/
378
+ subcmd = ARGV.shift
379
+ case subcmd
380
+ when 'create'
381
+ OptionParser.new do |opt|
382
+ opt.banner = 'Usage: luca-deal fee create [options] year month [date]'
383
+ opt.on('--monthly', 'generate monthly data') { |_v| params['mode'] = 'monthly' }
384
+ args = opt.parse(ARGV)
385
+ LucaCmd::Fee.create(args, params)
386
+ end
387
+ when 'delete'
388
+ LucaCmd::Fee.delete(ARGV)
389
+ when 'list'
390
+ OptionParser.new do |opt|
391
+ opt.banner = 'Usage: luca-deal fee list [options] year month [date]'
392
+ opt.on('--nu', 'show table in nushell') { |_v| params[:output] = 'nu' }
393
+ opt.on('-o', '--output VAL', 'output serialized data') { |v| params[:output] = v }
394
+ opt.on('--html', 'output html invoices') { |_v| params[:html] = 'monthly' }
395
+ args = opt.parse(ARGV)
396
+ LucaCmd::Fee.list(args, params)
397
+ end
398
+ when 'mail'
399
+ OptionParser.new do |opt|
400
+ opt.banner = 'Usage: luca-deal fee mail [options] year month [date]'
401
+ opt.on('--preview', 'send to preview user') { |_v| params['mode'] = 'preview' }
402
+ args = opt.parse(ARGV)
403
+ LucaCmd::Fee.mail(args, params)
404
+ end
405
+ else
406
+ puts 'Proper subcommand needed.'
407
+ puts
408
+ puts 'Usage: luca-deal fee subcommand [--help|options]'
409
+ puts ' create'
410
+ puts ' delete'
411
+ puts ' list'
412
+ puts ' mail: send mail with report'
413
+ exit 1
414
+ end
113
415
  else
114
- puts 'Usage: luca-deal sub-command [--help|options]'
115
- puts ' customer'
116
- puts ' contract'
117
- puts ' invoice'
416
+ puts 'Proper subcommand needed.'
417
+ puts
418
+ puts 'Usage: luca-deal subcommand [options]'
419
+ puts ' customers'
420
+ puts ' contracts'
421
+ puts ' invoices'
422
+ puts ' new: initialize project dir'
423
+ puts ' export: puts invoice data for LucaBook import'
424
+ exit 1
118
425
  end